Setting tag codemux-0.1-15
[codemux.git] / codemux.c
index 5ba4b01..0b6233c 100644 (file)
--- a/codemux.c
+++ b/codemux.c
@@ -37,8 +37,8 @@ int defaultTraceSync;
    among them */
 #define FAIRNESS_CUTOFF (MAX_CONNS * 0.85)
 
-/* codemux version */
-#define CODEMUX_VERSION "0.3"
+/* codemux version, from Makefile, or specfile */
+#define CODEMUX_VERSION RPM_VERSION
 
 typedef struct FlowBuf {
   int fb_refs;                 /* num refs */
@@ -64,6 +64,7 @@ typedef struct ServiceSig {
   char *ss_host;               /* suffix in host */
   char *ss_slice;
   short ss_port;
+  char *ss_ip;
   int ss_slicePos;             /* position in slices array */
 } ServiceSig;
 
@@ -94,6 +95,9 @@ static int numNeedingHeaders; /* how many conns waiting on headers? */
 
 static int numForks;
 
+/* PLC netflow domain name like netflow.planet-lab.org */
+static char* domainNamePLCNetflow = NULL;
+
 #ifndef SO_SETXID
 #define SO_SETXID SO_PEERCRED
 #endif
@@ -297,7 +301,7 @@ ReadConfFile(void)
       break;
 
     memset(&serv, 0, sizeof(serv));
-    if (WordCount(line) != 3) {
+    if (WordCount(line) < 3) {
       fprintf(stderr, "bad line: %s\n", line);
       continue;
     }
@@ -309,12 +313,21 @@ ReadConfFile(void)
 
     serv.ss_host = GetWord(line, 0);
     serv.ss_slice = GetWord(line, 1);
-
-    if (num == 0 && /* the first row must be an entry for apache */
-       (strcmp(serv.ss_host, "*") != 0 ||
-        strcmp(serv.ss_slice, "root") != 0)) {
-      fprintf(stderr, "first row has to be for webserver\n");
-      exit(-1);
+    serv.ss_ip = GetWord(line, 3);
+
+    if (num == 0) {
+      /* the first row must be an entry for apache */
+      if (strcmp(serv.ss_host, "*") != 0 ||
+         strcmp(serv.ss_slice, "root") != 0) {
+       fprintf(stderr, "first row has to be for webserver\n");
+       exit(-1);
+      }
+      /* see if there's PLC netflow's domain name */
+      if (domainNamePLCNetflow != NULL) {
+       xfree(domainNamePLCNetflow);
+       domainNamePLCNetflow = NULL;
+      }
+      domainNamePLCNetflow = GetWord(line, 3);
     }
     if (num >= numAlloc) {
       numAlloc = MAX(numAlloc * 2, 8);
@@ -330,6 +343,8 @@ ReadConfFile(void)
 
   fclose(f);
 
+#if 0
+  /* Faiyaz asked me to allow a single-entry codemux conf */
   if (num == 1) {
     if (numServices == 0) {
       fprintf(stderr, "nothing found in codemux.conf\n");
@@ -337,9 +352,15 @@ ReadConfFile(void)
     }
     return;
   }
+#endif
+  if (num < 1) {
+    fprintf(stderr, "no entry found in codemux.conf\n");
+    exit(-1);
+  }
 
   for (i = 0; i < numServices; i++) {
     xfree(serviceSig[i].ss_host);
+    xfree(serviceSig[i].ss_ip);
     xfree(serviceSig[i].ss_slice);
   }
   xfree(serviceSig);
@@ -439,7 +460,7 @@ static int
 FindService(FlowBuf *fb, int *whichService, struct in_addr addr)
 {
   char *end;
-  char *lowerBuf;
+  char lowerBuf[FB_ALLOCSIZE];
   char *hostVal;
   char *buf = fb->fb_buf;
   char orig[256];
@@ -448,7 +469,7 @@ FindService(FlowBuf *fb, int *whichService, struct in_addr addr)
   int i;
   int len;
 #endif
-    
+
   if (strstr(buf, "\n\r\n") == NULL && strstr(buf, "\n\n") == NULL)
     return(FAILURE);
 
@@ -457,7 +478,7 @@ FindService(FlowBuf *fb, int *whichService, struct in_addr addr)
   fb->fb_used += InsertHeader(buf, fb->fb_used + 1, orig);
     
   /* get just the header, so we can work on it */
-  LOCAL_STR_DUP_LOWER(lowerBuf, buf);
+  StrcpyLower(lowerBuf, buf);
   if ((end = strstr(lowerBuf, "\n\r\n")) == NULL)
     end = strstr(lowerBuf, "\n\n");
   *end = '\0';
@@ -485,7 +506,6 @@ FindService(FlowBuf *fb, int *whichService, struct in_addr addr)
            DoesDotlessSuffixMatch(hostVal, 0, serviceSig[i].ss_host)) {
          *whichService = i;
          free(hostVal);
-         /* printf("%s", buf); */
          return(SUCCESS);
        }
       }
@@ -549,8 +569,12 @@ StartConnect(int origFD, int whichService)
   memset(&dest, 0, sizeof(dest));
   dest.sin_family = AF_INET;
   dest.sin_port = htons(serviceSig[whichService].ss_port);
-  dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-  
+  if (serviceSig[whichService].ss_ip != NULL) {
+       dest.sin_addr.s_addr = inet_addr(serviceSig[whichService].ss_ip);
+  } else {
+       dest.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  }
+
   /* start connection process - we should be told that it's in
      progress */
   if (connect(sock, (struct sockaddr *) &dest, sizeof(dest)) != -1 || 
@@ -749,6 +773,25 @@ SocketReadyToRead(int fd)
     //    printf("found service %d\n", whichService);
     slice = ServiceToSlice(whichService);
 
+    /* if it needs to be redirected to PLC, let it be handled here */
+    if (whichService == 0 && domainNamePLCNetflow != NULL &&
+       strcmp(slice->si_sliceName, "root") == 0) {
+      char msg[1024];
+      int len;
+      static const char* resp302 = 
+       "HTTP/1.0 302 Found\r\n"
+       "Location: http://%s\r\n"
+       "Cache-Control: no-cache, no-store\r\n"
+       "Content-type: text/html\r\n"
+       "Connection: close\r\n"
+       "\r\n"
+       "Your request is being redirected to PLC Netflow http://%s\n";
+      len = snprintf(msg, sizeof(msg), resp302, 
+                    domainNamePLCNetflow, domainNamePLCNetflow);
+      write(fd, msg, len);
+      CloseSock(fd);
+      return;
+    }
     /* no service can have more than some absolute max number of
        connections. Also, when we're too busy, start enforcing
        fairness across the servers */
@@ -996,19 +1039,8 @@ static int
 OpenLogFile(void)
 {
   static const char* logfile = "/var/log/codemux.log";
-  static const char* oldlogfile = "/var/log/codemux.log.old";
   int logfd;
 
-  /* if the previous log file exists,
-     rename it to the oldlogfile */
-  if (access(logfile, F_OK) == 0) {
-    if (rename(logfile, oldlogfile) < 0) {
-      fprintf(stderr, "cannot rotate the logfile err=%s\n",
-             strerror(errno));
-      exit(-1);
-    }
-  }
-
   logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0600);
   if (logfd < 0) {
     fprintf(stderr, "cannot open the logfile err=%s\n",
@@ -1038,9 +1070,29 @@ main(int argc, char *argv[])
 {
   int lisSock;
   int logFd;
+  int doDaemon = 1;
+  int opt;
+  struct in_addr lisAddress = { .s_addr = htonl(INADDR_ANY) };
+
+  while ((opt = getopt(argc, argv, "dl:")) != -1) {
+    switch (opt) {
+      case 'd':
+       doDaemon = 0;
+       break;
+      case 'l':
+       if (inet_pton(AF_INET, optarg, &lisAddress) <= 0) {
+         fprintf(stderr, "`%s' is not a valid address\n", optarg);
+         exit(-1);
+       }
+       break;
+      default:
+       fprintf(stderr, "Usage: %s [-d] [-l <listening address>]\n", argv[0]);
+       exit(-1);
+    }
+  }
 
   /* do the daemon stuff */
-  if (argc <= 1 || strcmp(argv[1], "-d") != 0) {
+  if (doDaemon) {
     if (InitDaemon() < 0) {
       fprintf(stderr, "codemux daemon_init() failed\n");
       exit(-1);
@@ -1048,7 +1100,8 @@ main(int argc, char *argv[])
   }
 
   /* create the accept socket */
-  if ((lisSock = CreatePrivateAcceptSocket(DEMUX_PORT, TRUE)) < 0) {
+  if ((lisSock = CreatePrivateAcceptSocket(DEMUX_PORT, TRUE,
+                                          &lisAddress)) < 0) {
     fprintf(stderr, "failed creating accept socket\n");
     exit(-1);
   }