Here is the test code.
There are two programs, gethostbyname_threads.cpp and dnsserver.cpp.
Suggested compile command is in a comment at the top of each file.
Set up dnsserver as your DNS server (e.g. starting it as root and
modifying /etc/resolv.conf to use 127.0.0.1), and then run:
gethostbyname_threads washingtonpost.com
(The dns server is extremely simpleminded and only knows to provide a
canned response to a very specific question.)
gethostbyname_threads will start two threads and look up the same
hostname in both threads. It will then print out the result and exit.
The way the ifdefs in dnsserver.cpp is set up, it will wait for the
second request, immediately send a response to the first request and
then it will never send another packet.
Thus, I would expect the first gethostbyname2_r() call (in
gethostbyname_threads) to succeed and the second call to time out,
giving this output:
$ ./gethostbyname_threads washingtonpost.com
got: washingtonpost.com, IPv4: 12.129.147.65
gethostbyname2_r errored
Instead, both calls times out, and I get this output instead:
$ ./gethostbyname_threads washingtonpost.com
gethostbyname2_r errored
gethostbyname2_r errored
eirik
/*
g++ -o gethostbyname_threads gethostbyname_threads.cpp -lpthread
Permission to share code granted in Opera bug DSK-325405
*/
#include stdio.h
#include errno.h
#include netdb.h
#include pthread.h
#include sys/socket.h
void lookup(const char * hostname, int type);
void* lookup_both(void * hostname);
int main(int argc, const char ** argv)
{
if (argc != 2)
{
printf(usage: gethostbyname_threads hostname\n);
return 1;
}
const char * hostname = argv[1];
pthread_t t1;
pthread_t t2;
pthread_create(t1, 0, lookup_both, (void*)hostname);
pthread_create(t2, 0, lookup_both, (void*)hostname);
void * r;
pthread_join(t1, r);
pthread_join(t2, r);
return 0;
};
void * lookup_both(void * hostname)
{
lookup((char*)hostname, AF_INET);
return 0;
};
void print_hostent(struct hostent * res);
void lookup(const char * hostname, int type)
{
int error = 0;
struct hostent hostent;
struct hostent *res = 0;
const int BUFFER_SIZE=512;
char buffer[BUFFER_SIZE];
int err = gethostbyname2_r(hostname, type, hostent,
buffer, BUFFER_SIZE,
res, error);
if (err == ENOMEM || err == ENOBUFS)
printf(gethostbyname2_r OOMed\n);
else if (res)
print_hostent(res);
else
printf(gethostbyname2_r errored\n);
};
void print_hostent(struct hostent * res)
{
const char * type = UNKNOWN;
char addr[100];
addr[0] = 0;
if (res-h_addrtype == AF_INET)
{
type = IPv4;
unsigned char * a = (unsigned char*)res-h_addr_list[0];
if (a != 0)
snprintf(addr, 100, %d.%d.%d.%d, a[0], a[1], a[2], a[3]);
}
else if (res-h_addrtype == AF_INET6)
{
type = IPv6;
unsigned char * a = (unsigned char*)res-h_addr_list[0];
if (a != 0)
{
int next = 0;
for (int i = 0; i res-h_length next 90; i++)
{
if (i != 0 (i1) == 0)
{
addr[next] = ':';
next ++;
};
int len = snprintf(addr + next, 100 - next, %02x, a[i]);
next += len;
};
};
};
printf(got: %s, %s: %s\n, res-h_name, type, addr);
};
/*
g++ -o dnsserver dnsserver.cpp
Permission to share code granted in Opera bug DSK-325405
*/
#include sys/types.h
#include errno.h
#include netinet/in.h
#include stdio.h
#include string.h
#include sys/socket.h
#include unistd.h
int run_dns_server();
int main(int argc, const char ** argv)
{
return run_dns_server();
};
void handle_request(int sock, unsigned char * buf, size_t buflen, const struct sockaddr_in * addr);
void read_and_handle_single_request(int sock);
int run_dns_server()
{
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock 0)
{
fprintf(stderr, Failed to create socket (errno: %s)\n, strerror(errno));
return 1;
};
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(53);
saddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (struct sockaddr*)saddr, sizeof(saddr)) != 0)
{
close(sock);
fprintf(stderr, Failed to bind socket (errno: %s)\n, strerror(errno));
return 1;
};
while (true)
{
read_and_handle_single_request(sock);
};
};
void read_and_handle_single_request(int sock)
{
const size_t bufsize = 1024;
unsigned char actual_buf[bufsize];
unsigned char * buf = actual_buf;
struct sockaddr_in remoteaddr;
socklen_t addrbuflen = sizeof(remoteaddr);
ssize_t got = recvfrom(sock, buf, bufsize, MSG_TRUNC, (struct sockaddr*)remoteaddr, addrbuflen);
if (got 0)
{
fprintf(stderr, Failed