#include <unistd.h>
#include <string.h>
#include "codemuxlib.h"
-
-#define DEBUG 0
+#include "debug.h"
#ifdef DEBUG
-#define TRACE(fmt, msg...) fprintf(stderr, "[%s,%d] " fmt, __FUNCTION__, __LINE__, ##msg)
-#else
-#define TRACE(fmt, msg...) (void)0
+HANDLE hdebugLog;
+int defaultTraceSync;
#endif
#define CONF_FILE "/etc/codemux/codemux.conf"
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 */
char *ss_host; /* suffix in host */
char *ss_slice;
short ss_port;
+ char *ss_ip;
int ss_slicePos; /* position in slices array */
} ServiceSig;
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
int xid;
if ((temp = strchr(line, ':')) == NULL)
- continue; /* weird line */
+ goto next_line; /* weird line */
*temp = '\0'; /* terminate slice name */
temp++;
if ((temp = strchr(temp+1, ':')) == NULL)
- continue; /* weird line */
+ goto next_line; /* weird line */
if ((xid = atoi(temp+1)) < 1)
- continue; /* weird xid */
-
+ goto next_line; /* weird xid */
+
/* we've got a slice name and xid, let's try to match */
for (i = 0; i < numSlices; i++) {
if (slices[i].si_xid == 0 &&
break;
}
}
+ next_line:
+ if (line)
+ xfree(line);
}
/* assume service 0 is the root service, and don't check it since
if (numSlices >= numSlicesAlloc) {
numSlicesAlloc = MAX(8, numSlicesAlloc * 2);
- slices = realloc(slices, numSlicesAlloc * sizeof(SliceInfo));
+ slices = xrealloc(slices, numSlicesAlloc * sizeof(SliceInfo));
}
memset(&slices[numSlices], 0, sizeof(SliceInfo));
- slices[numSlices].si_sliceName = strdup(slice);
+ slices[numSlices].si_sliceName = xstrdup(slice);
numSlices++;
return(numSlices-1);
}
ServiceSig serv;
int port;
if (line != NULL)
- free(line);
+ xfree(line);
if ((line = GetNextLine(f)) == NULL)
break;
memset(&serv, 0, sizeof(serv));
- if (WordCount(line) != 3) {
+ if (WordCount(line) < 3) {
fprintf(stderr, "bad line: %s\n", line);
continue;
}
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);
- servs = realloc(servs, numAlloc * sizeof(ServiceSig));
+ servs = xrealloc(servs, numAlloc * sizeof(ServiceSig));
}
serv.ss_slicePos = WhichSlicePos(serv.ss_slice);
if (slices[serv.ss_slicePos].si_inUse == 0 &&
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");
}
return;
}
+#endif
+ if (num < 1) {
+ fprintf(stderr, "no entry found in codemux.conf\n");
+ exit(-1);
+ }
for (i = 0; i < numServices; i++) {
- free(serviceSig[i].ss_host);
- free(serviceSig[i].ss_slice);
+ xfree(serviceSig[i].ss_host);
+ xfree(serviceSig[i].ss_ip);
+ xfree(serviceSig[i].ss_slice);
}
- free(serviceSig);
+ xfree(serviceSig);
serviceSig = servs;
numServices = num;
confFileReadTime = statBuf.st_mtime;
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];
int i;
int len;
#endif
-
+
if (strstr(buf, "\n\r\n") == NULL && strstr(buf, "\n\n") == NULL)
return(FAILURE);
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';
DoesDotlessSuffixMatch(hostVal, 0, serviceSig[i].ss_host)) {
*whichService = i;
free(hostVal);
- /* printf("%s", buf); */
return(SUCCESS);
}
}
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 ||
}
if ((fb = si->si_readBuf) == NULL) {
- fb = si->si_readBuf = calloc(1, sizeof(FlowBuf));
+ fb = si->si_readBuf = xcalloc(1, sizeof(FlowBuf));
fb->fb_refs = 1;
if (si->si_peerFd >= 0) {
sockInfo[si->si_peerFd].si_writeBuf = fb;
}
if (fb->fb_buf == NULL)
- fb->fb_buf = malloc(FB_ALLOCSIZE);
+ fb->fb_buf = xmalloc(FB_ALLOCSIZE);
/* determine read buffer size - if 0, then block reads and return */
if ((spaceLeft = FB_SIZE - fb->fb_used) <= 0) {
// 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 */
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",
{
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);
}
/* 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);
}