Q
Quentin Carbonneaux
Hello,
I'm writing a little program which has to get a FQDN on his stdin and
return the IP on stdout, we can do it easily with gethostbyname call
but I would like to set up a timeout to this blocking system call. So
I read texts about this and I planed to use a hack with alarm and
setjmp/longjmp. My program works until there is a timeout, when it
occurs, all the gethostbyname calls which follow fail, backtrace in
gdb give me this :
#0 0xb7eac469 in pthread_setcanceltype () from /lib/tls/libc.so.6
#1 0x080486d7 in dnslookup (request=0xbfe1dc9c "free.fr") at dnsserver.c:53
#2 0x080488aa in main (argc=1, argv=0xbfe1df24) at dnsserver.c:102
I give you the code :
/* $Id: dnsserver.c,v 1.5 2006-01-31 20:10:30 quentin Exp $ */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <signal.h>
#define REQUEST_SIZE 512
#define DNS_TIMEOUT 2 /* Set here the timeout for the gethostbyname call */
static jmp_buf env;
static void sighandler (int signum)
{
longjmp (env, 1);
}
static void dnslookup (char *request)
{
struct hostent *host;
signal (SIGALRM, sighandler);
if (setjmp (env) == 0) {
alarm (DNS_TIMEOUT);
host = gethostbyname (request);
signal (SIGALRM, SIG_DFL);
alarm (0);
if (host == NULL) {
switch (h_errno) {
case HOST_NOT_FOUND:
case NO_ADDRESS:
case NO_RECOVERY:
puts ("$error");
break;
case TRY_AGAIN:
puts ("$tryagain");
break;
}
return;
}
puts (inet_ntoa (*((struct in_addr *) (host->h_addr)))); /* Display the address */
}
else { /* We come from the longjmp */
puts ("$timeout");
return;
}
}
int main (int argc, char **argv)
{
char req [REQUEST_SIZE];
char *p;
/* the stdout is not a buffered stream */
setvbuf (stdout, NULL, _IONBF, 0);
for (; { /* Main loop */
if (fgets (req, REQUEST_SIZE, stdin) == NULL) {
exit (EXIT_SUCCESS);
}
if (strncmp (req, "$goodbye", 8) == 0) {
exit (EXIT_SUCCESS);
} else if (strncmp (req, "$hello", 6) == 0) {
puts ("$olleh");
continue;
}
p = strrchr (req, '\n');
*p = '\0';
dnslookup (req);
}
/* NOTREACHED */
}
I'm writing a little program which has to get a FQDN on his stdin and
return the IP on stdout, we can do it easily with gethostbyname call
but I would like to set up a timeout to this blocking system call. So
I read texts about this and I planed to use a hack with alarm and
setjmp/longjmp. My program works until there is a timeout, when it
occurs, all the gethostbyname calls which follow fail, backtrace in
gdb give me this :
#0 0xb7eac469 in pthread_setcanceltype () from /lib/tls/libc.so.6
#1 0x080486d7 in dnslookup (request=0xbfe1dc9c "free.fr") at dnsserver.c:53
#2 0x080488aa in main (argc=1, argv=0xbfe1df24) at dnsserver.c:102
I give you the code :
/* $Id: dnsserver.c,v 1.5 2006-01-31 20:10:30 quentin Exp $ */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <setjmp.h>
#include <signal.h>
#define REQUEST_SIZE 512
#define DNS_TIMEOUT 2 /* Set here the timeout for the gethostbyname call */
static jmp_buf env;
static void sighandler (int signum)
{
longjmp (env, 1);
}
static void dnslookup (char *request)
{
struct hostent *host;
signal (SIGALRM, sighandler);
if (setjmp (env) == 0) {
alarm (DNS_TIMEOUT);
host = gethostbyname (request);
signal (SIGALRM, SIG_DFL);
alarm (0);
if (host == NULL) {
switch (h_errno) {
case HOST_NOT_FOUND:
case NO_ADDRESS:
case NO_RECOVERY:
puts ("$error");
break;
case TRY_AGAIN:
puts ("$tryagain");
break;
}
return;
}
puts (inet_ntoa (*((struct in_addr *) (host->h_addr)))); /* Display the address */
}
else { /* We come from the longjmp */
puts ("$timeout");
return;
}
}
int main (int argc, char **argv)
{
char req [REQUEST_SIZE];
char *p;
/* the stdout is not a buffered stream */
setvbuf (stdout, NULL, _IONBF, 0);
for (; { /* Main loop */
if (fgets (req, REQUEST_SIZE, stdin) == NULL) {
exit (EXIT_SUCCESS);
}
if (strncmp (req, "$goodbye", 8) == 0) {
exit (EXIT_SUCCESS);
} else if (strncmp (req, "$hello", 6) == 0) {
puts ("$olleh");
continue;
}
p = strrchr (req, '\n');
*p = '\0';
dnslookup (req);
}
/* NOTREACHED */
}