- added Sean's opendht entry
[codemux.git] / codemux.c
index 732059a..34ffc30 100644 (file)
--- a/codemux.c
+++ b/codemux.c
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
-#include "applib.h"
+#include <string.h>
+#include "codemuxlib.h"
+
+#define DEBUG 0
+
+#ifdef DEBUG
+#define TRACE(fmt, msg...) fprintf(stderr, "[%s,%d] " fmt, __FUNCTION__, __LINE__, ##msg)
+#else
+#define TRACE(fmt, msg...) (void)0
+#endif
 
 #define CONF_FILE "/etc/codemux/codemux.conf"
 #define DEMUX_PORT 80
-#define REAL_WEBSERVER_CONFLINE "* root 1080"
+#define PIDFILE "/var/run/codemux.pid"
 #define TARG_SETSIZE 4096
 
 /* set aside some small number of fds for us, allow the rest for
@@ -30,6 +39,8 @@
    among them */
 #define FAIRNESS_CUTOFF (MAX_CONNS * 0.85)
 
+/* codemux version */
+#define CODEMUX_VERSION "0.3"
 
 typedef struct FlowBuf {
   int fb_refs;                 /* num refs */
@@ -85,8 +96,6 @@ static int numNeedingHeaders; /* how many conns waiting on headers? */
 
 static int numForks;
 
-HANDLE hdebugLog;
-
 #ifndef SO_SETXID
 #define SO_SETXID SO_PEERCRED
 #endif
@@ -108,8 +117,10 @@ DumpStatus(int fd)
   int len;
 
   sprintf(start, 
+         "CoDemux version %s\n"
          "numForks %d, numActiveSlices %d, numTotalSliceConns %d\n"
          "numNeedingHeaders %d, anySliceXidsNeeded %d\n",
+         CODEMUX_VERSION,
          numForks, numActiveSlices, numTotalSliceConns,
          numNeedingHeaders, anySliceXidsNeeded);
   start += strlen(start);
@@ -280,14 +291,9 @@ ReadConfFile(void)
     int port;
     if (line != NULL)
       free(line);
-
-    /* on the first pass, put in a fake entry for apache */
-    if (num == 0)
-      line = strdup(REAL_WEBSERVER_CONFLINE);
-    else {
-      if ((line = GetNextLine(f)) == NULL)
-       break;
-    }
+    
+    if ((line = GetNextLine(f)) == NULL)
+      break;
 
     memset(&serv, 0, sizeof(serv));
     if (WordCount(line) != 3) {
@@ -302,6 +308,13 @@ 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);
+    }
     if (num >= numAlloc) {
       numAlloc = MAX(numAlloc * 2, 8);
       servs = realloc(servs, numAlloc * sizeof(ServiceSig));
@@ -644,6 +657,10 @@ ReallyCloseSocks(void)
       SliceConnsDec(sockInfo[fd].si_whichService);
       sockInfo[fd].si_whichService = -1;
     }
+    /* KyoungSoo*/
+    if (sockInfo[fd].si_peerFd >= 0) {
+      sockInfo[sockInfo[fd].si_peerFd].si_peerFd = -1;
+    }
   }
   numSocksToClose = 0;
 }
@@ -675,7 +692,7 @@ SocketReadyToRead(int fd)
     fb->fb_buf = malloc(FB_ALLOCSIZE);
 
   /* determine read buffer size - if 0, then block reads and return */
-  if ((spaceLeft = FB_SIZE - fb->fb_used) < 0) {
+  if ((spaceLeft = FB_SIZE - fb->fb_used) <= 0) {
     if (si->si_needsHeaderSince) {
       write(fd, err400BadRequest, strlen(err400BadRequest));
       CloseSock(fd);
@@ -685,8 +702,8 @@ SocketReadyToRead(int fd)
       ClearFd(fd, &masterReadSet);
       return;
     }
-  }
-
+  } 
+  
   /* read as much as allowed, and is available */
   if ((res = read(fd, &fb->fb_buf[fb->fb_used], spaceLeft)) == 0) {
     CloseSock(fd);
@@ -699,6 +716,7 @@ SocketReadyToRead(int fd)
   if (res == -1) {
     if (errno == EAGAIN)
       return;
+    TRACE("fd=%d errno=%d errstr=%s\n",fd, errno, strerror(errno));
     CloseSock(fd);
     if (fb->fb_used == 0 && si->si_peerFd >= 0) {
       CloseSock(si->si_peerFd);
@@ -708,7 +726,7 @@ SocketReadyToRead(int fd)
   }
   fb->fb_used += res;
   fb->fb_buf[fb->fb_used] = 0; /* terminate it for convenience */
-  printf("sock %d, read %d, total %d\n", fd, res, fb->fb_used);
+  //  printf("sock %d, read %d, total %d\n", fd, res, fb->fb_used);
 
   /* if we need header, check if we've gotten it. if so, do
      modifications and continue. if not, check if we've read the
@@ -724,10 +742,10 @@ SocketReadyToRead(int fd)
       return;
     }
 
-    printf("trying to find service\n");
+    //    printf("trying to find service\n");
     if (FindService(fb, &whichService, si->si_cliAddr) != SUCCESS)
       return;
-    printf("found service %d\n", whichService);
+    //    printf("found service %d\n", whichService);
     slice = ServiceToSlice(whichService);
 
     /* no service can have more than some absolute max number of
@@ -737,21 +755,28 @@ SocketReadyToRead(int fd)
        (numTotalSliceConns > FAIRNESS_CUTOFF && 
         slice->si_numConns > MAX_CONNS/numActiveSlices)) {
       write(fd, err503TooBusy, strlen(err503TooBusy));
+      TRACE("CloseSock(): fd=%d too busy\n", fd);
       CloseSock(fd);
       return;
     }
 
     if (slice->si_xid > 0) {
+      static int first = 1;
       setsockopt(fd, SOL_SOCKET, SO_SETXID, 
                 &slice->si_xid, sizeof(slice->si_xid));
-      fprintf(stderr, "setsockopt() with XID = %d name = %s\n", 
-             slice->si_xid, slice->si_sliceName);
+      if (first) {
+       /* just to log it for once */
+       fprintf(stderr, "setsockopt() with XID = %d name = %s\n", 
+               slice->si_xid, slice->si_sliceName);
+       first = 0;
+      }
     }
 
     si->si_needsHeaderSince = 0;
     numNeedingHeaders--;
     if (StartConnect(fd, whichService) != SUCCESS) {
       write(fd, err503Unavailable, strlen(err503Unavailable));
+      TRACE("CloseSock(): fd=%d StartConnect() failed\n", fd);
       CloseSock(fd);
       return;
     }
@@ -761,9 +786,13 @@ SocketReadyToRead(int fd)
   /* write anything possible */
   if (WriteAvailData(si->si_peerFd) != SUCCESS) {
     /* assume the worst and close */
+    TRACE("CloseSock(): fd=%d WriteAvailData() failed errno=%d errstr=%s\n", 
+         fd, errno, strerror(errno));
     CloseSock(fd);
-    CloseSock(si->si_peerFd);
-    si->si_peerFd = -1;
+    if (si->si_peerFd >=0) {
+      CloseSock(si->si_peerFd);
+      si->si_peerFd = -1;
+    }
   }
 }
 /*-----------------------------------------------------------------*/
@@ -784,6 +813,8 @@ SocketReadyToWrite(int fd)
   /* if we have data, write it */
   if (WriteAvailData(fd) != SUCCESS) {
    /* assume the worst and close */
+    TRACE("CloseSock(): fd=%d WriteAvailData() failed errno=%d errstr=%s\n", 
+         fd, errno, strerror(errno));
     CloseSock(fd);
     if (si->si_peerFd >= 0) {
       CloseSock(si->si_peerFd);
@@ -793,8 +824,9 @@ SocketReadyToWrite(int fd)
   }
 
   /* if peer is closed and we're done writing, we should close */
-  if (si->si_peerFd < 0 && si->si_writeBuf->fb_used == 0)
+  if (si->si_peerFd < 0 && si->si_writeBuf->fb_used == 0) {
     CloseSock(fd);
+  }
 }
 /*-----------------------------------------------------------------*/
 static void
@@ -830,7 +862,7 @@ CloseReqlessConns(void)
   /* if it's too old, close it */
   for (i = 0; i < highestSetFd+1; i++) {
     if (sockInfo[i].si_needsHeaderSince &&
-       (now - sockInfo[i].si_needsHeaderSince) > maxAge)
+       (now - sockInfo[i].si_needsHeaderSince) > maxAge) 
       CloseSock(i);
   }
 }
@@ -904,6 +936,11 @@ MainLoop(int lisSock)
       socklen_t lenAddr = sizeof(addr);
       if ((newSock = accept(lisSock, (struct sockaddr *) &addr, 
                            &lenAddr)) >= 0) {
+       /* make socket non-blocking */
+       if (fcntl(newSock, F_SETFL, O_NONBLOCK) < 0) {
+         close(newSock);
+         continue;
+       }
        memset(&sockInfo[newSock], 0, sizeof(SockInfo));
        sockInfo[newSock].si_needsHeaderSince = now;
        numNeedingHeaders++;
@@ -916,17 +953,113 @@ MainLoop(int lisSock)
   }
 }
 /*-----------------------------------------------------------------*/
+static int 
+InitDaemon(void)
+{
+  pid_t pid;
+  FILE *pidfile;
+  
+  pidfile = fopen(PIDFILE, "w");
+  if (pidfile == NULL) {
+    fprintf(stderr, "%s creation failed\n", PIDFILE);
+    return(-1);
+  }
+
+  if ((pid = fork()) < 0) {
+    fclose(pidfile);
+    return(-1);
+  }
+  else if (pid != 0) {
+    /* i'm the parent, writing down the child pid  */
+    fprintf(pidfile, "%u\n", pid);
+    fclose(pidfile);
+    exit(0);
+  }
+
+  /* close the pid file */
+  fclose(pidfile);
+
+  /* routines for any daemon process
+     1. create a new session 
+     2. change directory to the root
+     3. change the file creation permission 
+  */
+  setsid();
+  chdir("/");
+  umask(0);
+
+  return(0);
+}
+/*-----------------------------------------------------------------*/
+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",
+           strerror(errno));
+    exit(-1);
+  }
+
+  /* duplicate logfile to stderr */
+  if (dup2(logfd, STDERR_FILENO) != STDERR_FILENO) {
+    fprintf(stderr, "cannot open the logfile err=%s\n",
+           strerror(errno));
+    exit(-1);
+  }
+  
+  /* set the close-on-exec flag */
+  if (fcntl(STDERR_FILENO, F_SETFD, 1) != 0) {
+    fprintf(stderr, "fcntl to set the close-on-exec flag failed err=%s\n",
+           strerror(errno));
+    exit(-1);
+  }
+
+  return logfd;
+}
+/*-----------------------------------------------------------------*/
 int
 main(int argc, char *argv[])
 {
   int lisSock;
+  int logFd;
 
+  /* do the daemon stuff */
+  if (argc <= 1 || strcmp(argv[1], "-d") != 0) {
+    if (InitDaemon() < 0) {
+      fprintf(stderr, "codemux daemon_init() failed\n");
+      exit(-1);
+    }
+  }
+
+  /* create the accept socket */
   if ((lisSock = CreatePrivateAcceptSocket(DEMUX_PORT, TRUE)) < 0) {
     fprintf(stderr, "failed creating accept socket\n");
     exit(-1);
   }
   SetFd(lisSock, &masterReadSet);
 
+  /* open the log file */
+  logFd = OpenLogFile();
+
+
+  /* write down the version */
+  fprintf(stderr, "CoDemux version %s started\n", CODEMUX_VERSION);
+
   while (1) {
     numForks++;
     if (fork()) {