mux/src/slave.cpp

Go to the documentation of this file.
00001 // slave.cpp -- This slave does iptoname conversions, and identquery lookups.
00002 //
00003 // $Id: slave.cpp,v 1.11 2005/11/24 20:07:06 sdennis Exp $
00004 //
00005 // The philosophy is to keep this program as simple/small as possible.  It
00006 // routinely performs non-vfork forks()s, so the conventional wisdom is that
00007 // the smaller it is, the faster it goes.  However, with modern memory
00008 // management support (including copy on reference paging), size is probably
00009 // not the issue it once was.
00010 //
00011 #include "autoconf.h"
00012 #include "config.h"
00013 
00014 #include <netdb.h>
00015 #include <netinet/in.h>
00016 #include <sys/wait.h>
00017 #include <sys/file.h>
00018 #include <sys/ioctl.h>
00019 #include <signal.h>
00020 #include "slave.h"
00021 #include <arpa/inet.h>
00022 
00023 #ifdef _SGI_SOURCE
00024 #define CAST_SIGNAL_FUNC (SIG_PF)
00025 #else
00026 #define CAST_SIGNAL_FUNC
00027 #endif
00028 
00029 pid_t parent_pid;
00030 
00031 #define MAX_STRING 1000
00032 char *arg_for_errors;
00033 
00034 #ifndef INADDR_NONE
00035 #define INADDR_NONE ((in_addr_t)-1)
00036 #endif
00037 
00038 char *format_inet_addr(char *dest, long addr)
00039 {
00040     sprintf(dest, "%ld.%ld.%ld.%ld",
00041         (addr & 0xFF000000) >> 24,
00042         (addr & 0x00FF0000) >> 16,
00043         (addr & 0x0000FF00) >> 8,
00044         (addr & 0x000000FF));
00045     return (dest + strlen(dest));
00046 }
00047 
00048 //
00049 // copy a string, returning pointer to the null terminator of dest
00050 //
00051 char *stpcpy(char *dest, const char *src)
00052 {
00053     while ((*dest = *src))
00054     {
00055         ++dest;
00056         ++src;
00057     }
00058     return (dest);
00059 }
00060 
00061 RETSIGTYPE child_timeout_signal(int iSig)
00062 {
00063     exit(1);
00064 }
00065 
00066 int query(char *ip, char *orig_arg)
00067 {
00068     char *comma;
00069     char *port_pair;
00070     struct hostent *hp;
00071     struct sockaddr_in sin;
00072     int s;
00073     FILE *f;
00074     char result[MAX_STRING];
00075     char buf[MAX_STRING * 2];
00076     char buf2[MAX_STRING * 2];
00077     char buf3[MAX_STRING * 4];
00078     char arg[MAX_STRING];
00079     size_t len;
00080     char *p;
00081     in_addr_t addr;
00082 
00083     addr = inet_addr(ip);
00084     if (addr == INADDR_NONE)
00085     {
00086         return -1;
00087     }
00088     const char *pHName = ip;
00089     hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
00090     if (  hp
00091        && strlen(hp->h_name) < MAX_STRING)
00092     {
00093         pHName = hp->h_name;
00094     }
00095     p = stpcpy(buf, ip);
00096     *p++ = ' ';
00097     p = stpcpy(p, pHName);
00098     *p++ = '\n';
00099     *p++ = '\0';
00100 
00101     arg_for_errors = orig_arg;
00102     strcpy(arg, orig_arg);
00103     comma = (char *)strrchr(arg, ',');
00104     if (comma == NULL)
00105     {
00106         return -1;
00107     }
00108     *comma = 0;
00109     port_pair = (char *)strrchr(arg, ',');
00110     if (port_pair == NULL)
00111     {
00112         return -1;
00113     }
00114     *port_pair++ = 0;
00115     *comma = ',';
00116 
00117     hp = gethostbyname(arg);
00118     if (hp == NULL)
00119     {
00120         static struct hostent def;
00121         static struct in_addr defaddr;
00122         static char *alist[1];
00123         static char namebuf[MAX_STRING];
00124 
00125         defaddr.s_addr = inet_addr(arg);
00126         if (defaddr.s_addr == INADDR_NONE)
00127         {
00128             return -1;
00129         }
00130         strcpy(namebuf, arg);
00131         def.h_name = namebuf;
00132         def.h_addr_list = alist;
00133         def.h_addr = (char *)&defaddr;
00134         def.h_length = sizeof(struct in_addr);
00135 
00136         def.h_addrtype = AF_INET;
00137         def.h_aliases = 0;
00138         hp = &def;
00139     }
00140     sin.sin_family = hp->h_addrtype;
00141     bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
00142     sin.sin_port = htons(113); // ident port
00143     s = socket(hp->h_addrtype, SOCK_STREAM, 0);
00144     if (s < 0)
00145     {
00146         return -1;
00147     }
00148     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
00149         if (   errno != ECONNREFUSED
00150             && errno != ETIMEDOUT
00151             && errno != ENETUNREACH
00152             && errno != EHOSTUNREACH)
00153         {
00154             close(s);
00155             return -1;
00156         }
00157         buf2[0] = '\0';
00158     }
00159     else
00160     {
00161         len = strlen(port_pair);
00162         if ((size_t)write(s, port_pair, len) != len)
00163         {
00164             close(s);
00165             return (-1);
00166         }
00167         if (write(s, "\r\n", 2) != 2)
00168         {
00169             close(s);
00170             return (-1);
00171         }
00172         f = fdopen(s, "r");
00173         {
00174             int c;
00175 
00176             p = result;
00177             while ((c = fgetc(f)) != EOF)
00178             {
00179                 if (c == '\n')
00180                 {
00181                     break;
00182                 }
00183                 if (0x20 <= c && c <= 0x7E)
00184                 {
00185                     *p++ = c;
00186                     if (p - result == MAX_STRING - 1)
00187                     {
00188                         break;
00189                     }
00190                 }
00191             }
00192             *p = '\0';
00193         }
00194         fclose(f);
00195         p = (char *)format_inet_addr(buf2, ntohl(sin.sin_addr.s_addr));
00196         *p++ = ' ';
00197         p = stpcpy(p, result);
00198         *p++ = '\n';
00199         *p++ = '\0';
00200     }
00201     sprintf(buf3, "%s%s", buf, buf2);
00202     write(1, buf3, strlen(buf3));
00203     return 0;
00204 }
00205 
00206 RETSIGTYPE alarm_signal(int iSig)
00207 {
00208     struct itimerval itime;
00209     struct timeval interval;
00210 
00211     if (getppid() != parent_pid)
00212     {
00213         exit(1);
00214     }
00215     signal(SIGALRM, CAST_SIGNAL_FUNC alarm_signal);
00216     interval.tv_sec = 120;  // 2 minutes.
00217     interval.tv_usec = 0;
00218     itime.it_interval = interval;
00219     itime.it_value = interval;
00220     setitimer(ITIMER_REAL, &itime, 0);
00221 }
00222 
00223 #define MAX_CHILDREN 20
00224 volatile int nChildrenStarted = 0;
00225 volatile int nChildrenEndedSIGCHLD = 0;
00226 volatile int nChildrenEndedMain = 0;
00227 
00228 RETSIGTYPE child_signal(int iSig)
00229 {
00230     // Collect the children.
00231     //
00232     while (waitpid(0, NULL, WNOHANG) > 0)
00233     {
00234         int nChildren = nChildrenStarted - nChildrenEndedSIGCHLD
00235             - nChildrenEndedMain;
00236         if (0 < nChildren)
00237         {
00238             nChildrenEndedSIGCHLD++;
00239         }
00240     }
00241 
00242     signal(SIGCHLD, CAST_SIGNAL_FUNC child_signal);
00243 }
00244 
00245 int main(int argc, char *argv[])
00246 {
00247     char arg[MAX_STRING];
00248     char *p;
00249     int len;
00250     pid_t child;
00251 
00252     parent_pid = getppid();
00253     if (parent_pid == 1)
00254     {
00255         // Our real parent process is gone, and we have been inherited by the
00256         // init process.
00257         //
00258         exit(1);
00259     }
00260 
00261     alarm_signal(SIGALRM);
00262     signal(SIGCHLD, CAST_SIGNAL_FUNC child_signal);
00263     signal(SIGPIPE, SIG_DFL);
00264 
00265     for (;;)
00266     {
00267         len = read(0, arg, MAX_STRING - 1);
00268         if (len == 0)
00269         {
00270             break;
00271         }
00272         if (len < 0)
00273         {
00274             if (errno == EINTR)
00275             {
00276                 errno = 0;
00277                 continue;
00278             }
00279             break;
00280         }
00281         arg[len] = '\0';
00282         p = strchr(arg, '\n');
00283         if (p)
00284         {
00285             *p = '\0';
00286         }
00287         child = fork();
00288         switch (child)
00289         {
00290         case -1:
00291             exit(1);
00292             break;
00293 
00294         case 0: // child.
00295             {
00296                 // We don't want to try this for more than 5 minutes.
00297                 //
00298                 struct itimerval itime;
00299                 struct timeval interval;
00300 
00301                 interval.tv_sec = 300;  // 5 minutes.
00302                 interval.tv_usec = 0;
00303                 itime.it_interval = interval;
00304                 itime.it_value = interval;
00305                 signal(SIGALRM, CAST_SIGNAL_FUNC child_timeout_signal);
00306                 setitimer(ITIMER_REAL, &itime, 0);
00307             }
00308             exit(query(arg, p + 1) != 0);
00309             break;
00310         }
00311         if (child > 0)
00312         {
00313             nChildrenStarted++;
00314         }
00315 
00316         int nChildren = nChildrenStarted - nChildrenEndedSIGCHLD
00317             - nChildrenEndedMain;
00318 
00319         // Collect the children.
00320         //
00321         while (waitpid(0, NULL, (nChildren < MAX_CHILDREN) ? WNOHANG : 0) > 0)
00322         {
00323             if (0 < nChildren)
00324             {
00325                 nChildrenEndedMain++;
00326             }
00327         }
00328     }
00329     exit(0);
00330 }

Generated on Mon May 28 04:40:11 2007 for MUX by  doxygen 1.4.7