pserv/tests/getaddrinfo.c
Godmar Back 7cbe3af927 updates for summer 2020
this update adds the unit tests as part of the student distribution
2020-08-03 23:33:16 -04:00

103 lines
2.5 KiB
C

/*
* Intercept getaddrinfo to simulate IPv4-only, IPv6-only, and
* environment in which addresses are returned in a different order.
*
* Written for CS 3214 Virginia Tech, Spring 2018.
*
* Godmar Back <godmar@gmail.com>
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#define __USE_GNU 1 /* for RTLD_NEXT */
#include <dlfcn.h>
static int (*real_getaddrinfo)(const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
static void (*real_freeaddrinfo)(struct addrinfo *res);
static void
init()
{
static int inited;
if (inited++ > 0) {
return;
}
real_getaddrinfo = dlsym(RTLD_NEXT, "getaddrinfo");
if (!real_getaddrinfo) {
printf("error in dlsym getaddrinfo %s\n", dlerror());
exit(-1);
}
real_freeaddrinfo = dlsym(RTLD_NEXT, "freeaddrinfo");
if (!real_freeaddrinfo) {
printf("error in dlsym freeaddrinfo %s\n", dlerror());
exit(-1);
}
}
int getaddrinfo(
const char *node,
const char *service,
const struct addrinfo *hints,
struct addrinfo **res)
{
init();
struct addrinfo * reallist;
int rc = real_getaddrinfo(node, service, hints, &reallist);
if (rc != 0)
return rc;
int skipipv4 = getenv("SKIPIPV4") != NULL;
int skipipv6 = getenv("SKIPIPV6") != NULL;
int reverse = getenv("REVERSEIPADDR") != NULL;
if (reverse) {
struct addrinfo * rp = reallist;
struct addrinfo * last = NULL;
while (rp != NULL) {
struct addrinfo * next = rp->ai_next;
rp->ai_next = last;
last = rp;
rp = next;
}
*res = last;
} else if (skipipv4 || skipipv6) {
struct addrinfo * rp, ** last = &reallist;
for (rp = reallist; rp != NULL; ) {
if ((skipipv4 && rp->ai_family == AF_INET) || (skipipv6 && rp->ai_family == AF_INET6)) {
// skip and free
(*last) = rp->ai_next;
struct addrinfo * old = rp;
rp = rp->ai_next;
old->ai_next = NULL;
real_freeaddrinfo(old);
} else {
// include
last = &rp->ai_next;
rp = rp->ai_next;
}
}
*res = reallist;
} else {
*res = reallist;
}
return rc;
}
void freeaddrinfo(struct addrinfo *res)
{
init();
real_freeaddrinfo(res);
}