2 #include <sys/socket.h>
4 #include <netinet/in.h>
13 #include "codemuxlib.h"
16 /*-----------------------------------------------------------------*/
18 GetNextLineBack(FILE *file, int lower, int stripComments)
20 /* reads the next non-blank line of the file. strips off any leading
21 space, any comments, and any trailing space. returns a lowercase
22 version of the line that has been malloc'd */
25 while (fgets(line, sizeof(line), file) != NULL) {
29 /* strip off any comments, leading and trailing whitespace */
31 if ((temp = strchr(line, '#')) != NULL)
35 while (len > 0 && isspace((int) line[len-1])) {
40 while (isspace((int) *temp))
43 continue; /* blank line, move on */
46 return(StrdupLower(temp));
47 return(xstrdup(temp));
52 /*-----------------------------------------------------------------*/
54 GetLowerNextLine(FILE *file)
56 return(GetNextLineBack(file, TRUE, TRUE));
58 /*-----------------------------------------------------------------*/
60 GetNextLine(FILE *file)
62 return(GetNextLineBack(file, FALSE, TRUE));
64 /*-----------------------------------------------------------------*/
66 GetNextLineNoCommStrip(FILE *file)
68 return(GetNextLineBack(file, FALSE, FALSE));
70 /*-----------------------------------------------------------------*/
72 DoesSuffixMatch(char *start, int len, char *suffix)
74 int sufLen = strlen(suffix);
80 if (strncasecmp(start+len-sufLen, suffix, sufLen))
84 /*-----------------------------------------------------------------*/
86 DoesDotlessSuffixMatch(char *start, int len, char *suffix)
88 /* ignores any dots on end of start, suffix */
89 int sufLen = strlen(suffix);
94 while (len > 1 && start[len-1] == '.')
96 while (sufLen > 1 && suffix[sufLen-1] == '.')
101 if (strncasecmp(start+len-sufLen, suffix, sufLen))
105 /*-----------------------------------------------------------------*/
112 while (*buf != '\0') {
113 int isSpace = isspace(*buf);
114 if (wasSpace && (!isSpace))
121 /*-----------------------------------------------------------------*/
123 GetField(const char *start, int whichField)
127 /* move to first non-blank char */
128 while (isspace(*start))
134 for (currField = 0; currField < whichField; currField++) {
135 /* move over this field */
136 while (*start != '\0' && (!isspace(*start)))
138 /* move over blanks before next field */
139 while (isspace(*start))
144 return((char *) start);
146 /* ---------------------------------------------------------------- */
148 GetWord(const char *start, int whichWord)
150 /* returns a newly allocated string containing the desired word,
151 or NULL if there was a problem */
156 temp = (unsigned char *) GetField(start, whichWord);
159 while (!(temp[len] == '\0' || isspace(temp[len])))
162 NiceExit(-1, "internal error");
163 res = (char *)xcalloc(1, len+1);
165 NiceExit(-1, "out of memory");
166 memcpy(res, temp, len);
169 /*-----------------------------------------------------------------*/
171 CreatePrivateAcceptSocketEx(int portNum, int nonBlocking, int loopbackOnly)
174 struct linger doLinger;
176 struct sockaddr_in sa;
179 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
182 /* don't linger on close */
183 doLinger.l_onoff = doLinger.l_linger = 0;
184 if (setsockopt(sock, SOL_SOCKET, SO_LINGER,
185 &doLinger, sizeof(doLinger)) == -1) {
190 /* reuse addresses */
191 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
192 &doReuse, sizeof(doReuse)) == -1) {
198 /* make listen socket nonblocking */
199 if (fcntl(sock, F_SETFL, O_NDELAY) == -1) {
205 /* set up info for binding listen */
206 memset(&sa, 0, sizeof(sa));
207 sa.sin_family = AF_INET;
208 sa.sin_addr.s_addr = (loopbackOnly) ? htonl(INADDR_LOOPBACK)
210 sa.sin_port = htons(portNum);
213 if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
218 /* start listening */
219 if (listen(sock, 32) == -1) {
226 /*-----------------------------------------------------------------*/
228 CreatePrivateAcceptSocket(int portNum, int nonBlocking)
230 return CreatePrivateAcceptSocketEx(portNum, nonBlocking, FALSE);
232 /*-----------------------------------------------------------------*/
234 StrdupLower(const char *orig)
239 if ((temp = xstrdup(orig)) == NULL)
240 NiceExit(-1, "no memory in strduplower");
241 for (i = 0; temp[i]; i++) {
242 if (isupper((int) temp[i]))
243 temp[i] = tolower(temp[i]);
248 /*-----------------------------------------------------------------*/
250 StrcpyLower(char *dest, const char *src)
252 /* copy 'src' to 'dest' in lower cases.
253 'dest' should have enough free space to hold src */
256 for (i = 0; src[i]; i++) {
257 dest[i] = (isupper((int) src[i])) ? tolower(src[i]) : src[i];
260 /* mark it as NULL */
263 /*-----------------------------------------------------------------*/
265 NiceExitBack(int val, char *reason, char *file, int line)
268 time_t currT = time(NULL);
270 sprintf(buf, "[%s, %d] %.24s %s\n", file, line, ctime(&currT), reason);
271 fprintf(stderr, "%s", buf);
274 /*-----------------------------------------------------------------*/
275 /* Logging & Trace support */
277 /* buffer threshold : when the size hits this value, it flushes its content
279 #define LOG_BYTES_THRESHOLD (32*1024)
281 /* this flag indicates that it preserves the base file name for the current
282 one, and changes its name when it actually closes it off */
283 #define CHANGE_FILE_NAME_ON_SAVE 0x01
285 /* size of the actual log buffer */
286 #define LOG_BYTES_MAX (2*LOG_BYTES_THRESHOLD)
288 /* log/trace book keeping information */
289 typedef struct ExtendedLog {
290 char buffer[LOG_BYTES_MAX]; /* 64 KB */
291 int bytes; /* number of bytes written */
292 int filesize; /* number of bytes written into this file so far */
293 int fd; /* file descriptor */
294 char* sig; /* base file name */
295 int flags; /* flags */
297 } ExtendedLog, *PExtendedLog;
299 /* maximum single file size */
300 int maxSingleLogSize = 100 * (1024*1024);
303 GetNextLogFileName(char* file, int size, const char* sig)
305 #define COMPRESS_EXT1 ".bz2"
306 #define COMPRESS_EXT2 ".gz"
313 cur_tm = *gmtime(&cur_t);
316 /* check if .bz2 exists */
317 snprintf(file, size, "%s.%04d%02d%02d_%03d%s",
318 sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday,
321 if (access(file, F_OK) == 0) {
326 /* check if .gz exists */
327 snprintf(file, size, "%s.%04d%02d%02d_%03d%s",
328 sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday,
329 idx++, COMPRESS_EXT2);
331 if (access(file, F_OK) == 0)
334 /* strip the extension and see if the (uncompressed) file exists */
335 file[strlen(file) - sizeof(COMPRESS_EXT2) + 1] = 0;
336 if (access(file, F_OK) != 0)
340 /* calculate & return the next day */
341 cur_t -= (3600*cur_tm.tm_hour + 60*cur_tm.tm_min + cur_tm.tm_sec);
342 return cur_t + 60*60*24;
347 /*-----------------------------------------------------------------*/
349 FlushBuffer(HANDLE file)
351 /* write data into the file */
352 ExtendedLog* pel = (ExtendedLog *)file;
355 if (pel == NULL || pel->fd < 0)
358 if ((written = write(pel->fd, pel->buffer, pel->bytes)) > 0) {
359 pel->bytes -= written;
361 /* if it hasn't written all data, then we need to move memory */
363 memmove(pel->buffer, pel->buffer + written, pel->bytes);
364 pel->buffer[pel->bytes] = 0;
365 pel->filesize += written;
368 /* if the filesize is bigger than maxSignleLogSize, then close it off */
369 if (pel->filesize >= maxSingleLogSize)
373 /*-----------------------------------------------------------------*/
375 CreateLogFHandle(const char* signature, int change_file_name_on_save)
380 /* check if the file can be created */
381 if ((temp = strrchr(signature, '/')) != NULL) {
382 int dirlen = temp - signature + 1;
383 char pardir[dirlen+1];
385 memcpy(pardir, signature, dirlen);
387 if (access(pardir, W_OK) != 0)
390 /* assume it's the current directory */
391 if (access("./", W_OK) != 0)
395 if ((pel = (ExtendedLog *)xcalloc(1, sizeof(ExtendedLog))) == NULL)
396 NiceExit(-1, "failed");
399 pel->sig = xstrdup(signature);
400 if (pel->sig == NULL)
401 NiceExit(-1, "signature copying failed");
402 if (change_file_name_on_save)
403 pel->flags |= CHANGE_FILE_NAME_ON_SAVE;
409 /*-----------------------------------------------------------------*/
411 OpenLogF(HANDLE file)
414 ExtendedLog* pel = (ExtendedLog *)file;
422 pel->nextday = GetNextLogFileName(filename, sizeof(filename), pel->sig);
424 /* change the file name only at saving time
425 use pel->sig as current file name */
426 if (pel->flags & CHANGE_FILE_NAME_ON_SAVE) {
427 if (access(pel->sig, F_OK) == 0)
428 rename(pel->sig, filename);
429 strcpy(filename, pel->sig);
433 if ((pel->fd = open(filename, O_RDWR | O_CREAT | O_APPEND,
434 S_IRUSR | S_IWUSR)) == -1) {
435 char errMessage[2048];
436 sprintf(errMessage, "couldn't open the extended log file %s\n", filename);
437 NiceExit(-1, errMessage);
440 /* reset the file size */
445 /*-----------------------------------------------------------------*/
447 WriteLog(HANDLE file, const char* data, int size, int forceFlush)
449 ExtendedLog* pel = (ExtendedLog *)file;
451 /* if an error might occur, then stop here */
452 if (pel == NULL || pel->fd < 0 || size > LOG_BYTES_MAX)
456 /* flush the previous data, if this data would overfill the buffer */
457 if (pel->bytes + size >= LOG_BYTES_MAX)
460 /* write into the buffer */
461 memcpy(pel->buffer + pel->bytes, data, size);
465 /* need to flush ? */
466 if ((forceFlush && (pel->bytes > 0)) || (pel->bytes >= LOG_BYTES_THRESHOLD))
471 /*-----------------------------------------------------------------*/
473 DailyReopenLogF(HANDLE file)
475 /* check if current file is a day long,
476 opens another for today's file */
477 ExtendedLog* pel = (ExtendedLog *)file;
479 if (pel && (time(NULL) >= pel->nextday)) {
480 FlushLogF(file); /* flush */
481 OpenLogF(file); /* close previous one & reopen today's */
484 /*-----------------------------------------------------------------*/
486 HandleToFileNo(HANDLE file)
488 ExtendedLog* pel = (ExtendedLog *)file;
490 return (pel != NULL) ? pel->fd : -1;
492 /*-----------------------------------------------------------------*/
494 HashString(const char *name, unsigned int hash, int endOnQuery,
497 /* if endOnQuery, we stop the hashing when we hit the question mark.
498 if skipLastIfDot, we check the last component of the path to see
499 if it includes a dot, and it so, we skip it. if both are specified,
500 we first try the query, and if that exists, we don't trim the path */
510 if (endOnQuery && (temp = strchr(name, '?')) != NULL)
512 else if (skipLastIfDot) {
513 /* first, find last component by searching backward */
514 if ((temp = strrchr(name, '/')) != NULL) {
515 /* now search forward for the dot */
516 if (strchr(temp, '.') != NULL)
521 for (i = 0; i < len; i ++)
522 hash += (_rotl(hash, 19) + name[i]);