src/dnschild.c

Go to the documentation of this file.
00001 /*
00002  * dnschild.c
00003  *
00004  * Copyright (c) 2004,2005 Martin Murray <mmurray@monkey.org>
00005  * All rights reserved.
00006  *
00007  */
00008 
00009 #include "copyright.h"
00010 #include "config.h"
00011 
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 #include <unistd.h>
00015 #include <string.h>
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018 #include <sys/file.h>
00019 #include <sys/ioctl.h>
00020 #include <sys/wait.h>
00021 #include <signal.h>
00022 #include <errno.h>
00023 #include "externs.h"
00024 #include "debug.h"
00025 
00026 static struct dns_query_state_t {
00027         DESC *desc;
00028         struct event ev;
00029         struct dns_query_state_t *next;
00030         int pid;
00031         int fd;
00032 } *running = NULL;
00033 
00034 static int running_queries = 0;
00035 static int dnschild_state = 0;
00036 
00037 static struct timeval query_timeout = { 60, 0 };
00038 
00039 static void dnschild_finish(int fd, short event, void *arg);
00040 
00041 int dnschild_init()
00042 {
00043         dprintk("dnschild initialized.");
00044         dnschild_state = 1;
00045         return 1;
00046 }
00047 
00048 void *dnschild_request(DESC * d)
00049 {
00050         int fds[2];
00051         struct dns_query_state_t *dqst;
00052         char address[1024];
00053         char outbuffer[255];
00054         int length;
00055     int result;
00056 
00057         if(!dnschild_state) {
00058                 dprintk("bailing query, dnschild is shut down.");
00059                 return 0;
00060         }
00061 
00062         dqst = malloc(sizeof(struct dns_query_state_t));
00063         memset(dqst, 0, sizeof(struct dns_query_state_t));
00064 
00065         dqst->desc = d;
00066 
00067         if(pipe(fds) < 0) {
00068                 log_perror("DNS", "ERR", NULL, "pipe");
00069         }
00070 
00071         event_set(&dqst->ev, fds[0], EV_TIMEOUT | EV_READ, dnschild_finish, dqst);
00072         event_add(&dqst->ev, &query_timeout);
00073 
00074         dqst->pid = fork();
00075         if(dqst->pid == 0) {
00076         close(fds[0]);
00077                 /* begin child section */
00078                 unbind_signals();
00079         memset(address, 0, 1023);
00080                 if((result=getnameinfo((struct sockaddr *) &d->saddr, d->saddr_len,
00081                                            address, 1023, NULL, 0, NI_NAMEREQD))) {
00082                         length = snprintf(outbuffer, 255, "0%s/%s", gai_strerror(result), strerror(errno));
00083                         outbuffer[length++] = '\0';
00084                         write(fds[1], outbuffer, length);
00085                 } else {
00086                         length = snprintf(outbuffer, 255, "1%s", address);
00087                         outbuffer[length++] = '\0';
00088                         write(fds[1], outbuffer, length);
00089                 }
00090                 close(fds[1]);
00091                 exit(0);
00092                 /* end child section */
00093         }
00094         dqst->fd = fds[0];
00095     close(fds[1]);
00096         dqst->next = running;
00097         running = dqst;
00098         running_queries++;
00099         return (void *) dqst;
00100 }
00101 
00102 void dnschild_destruct()
00103 {
00104         struct dns_query_state_t *dqst;
00105         dprintk("dnschild expiring queries and shutting down.");
00106         dnschild_state = 0;
00107         while (running) {
00108                 dqst = running;
00109                 dprintk("dnschild query for %s aborting early.", dqst->desc->addr);
00110                 if(event_pending(&dqst->ev, EV_READ, NULL))
00111                         event_del(&dqst->ev);
00112                 close(dqst->fd);
00113                 dqst->desc->outstanding_dnschild_query = NULL;
00114                 running = running->next;
00115                 free(dqst);
00116         }
00117 }
00118 
00119 void dnschild_kill(void *arg)
00120 {
00121         struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;
00122 
00123         dprintk("dnschild query for %s aborting early.", dqst->desc->addr);
00124 
00125         iter = running;
00126         if(running == dqst) {
00127                 running = dqst->next;
00128         } else {
00129                 while (iter) {
00130                         if(iter->next == dqst) {
00131                                 iter->next = dqst->next;
00132                                 break;
00133                         }
00134                         iter = iter->next;
00135                 }
00136         }
00137 
00138         if(event_pending(&dqst->ev, EV_READ, NULL))
00139                 event_del(&dqst->ev);
00140         dqst->desc->outstanding_dnschild_query = NULL;
00141         close(dqst->fd);
00142         free(dqst);
00143 }
00144 
00145 static void dnschild_finish(int fd, short event, void *arg)
00146 {
00147         char buffer[2048];
00148         struct dns_query_state_t *dqst = (struct dns_query_state_t *) arg, *iter;
00149 
00150         iter = running;
00151         if(running == dqst) {
00152                 running = dqst->next;
00153         } else {
00154                 while (iter) {
00155                         if(iter->next == dqst) {
00156                                 iter->next = dqst->next;
00157                                 break;
00158                         }
00159                         iter = iter->next;
00160                 }
00161         }
00162 
00163         dqst->desc->outstanding_dnschild_query = NULL;
00164 
00165         if(event & EV_TIMEOUT || !dnschild_state) {
00166                 kill(dqst->pid, SIGTERM);
00167                 log_perror("DNS", "ERR", NULL, "dnschild failed to finish.");
00168                 close(fd);
00169                 free(dqst);
00170                 return;
00171         }
00172 
00173         read(fd, buffer, 2048);
00174 
00175         if(buffer[0] == '0') {
00176                 dprintk("dnschild failed with error: %s", buffer + 1);
00177                 close(fd);
00178                 free(dqst);
00179                 return;
00180         }
00181 
00182         strncpy(dqst->desc->addr, buffer + 1, sizeof(dqst->desc->addr) - 1);
00183         dprintk("dnschild resolved %s correctly.", buffer + 1);
00184         close(fd);
00185         free(dqst);
00186         return;
00187 }

Generated on Mon May 28 04:25:19 2007 for BattletechMUX by  doxygen 1.4.7