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, struct in_addr *addr)
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;
209 sa.sin_port = htons(portNum);
212 if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
217 /* start listening */
218 if (listen(sock, 32) == -1) {
225 /*-----------------------------------------------------------------*/
227 CreatePrivateAcceptSocket(int portNum, int nonBlocking, struct in_addr *addr)
229 return CreatePrivateAcceptSocketEx(portNum, nonBlocking, addr);
231 /*-----------------------------------------------------------------*/
233 StrdupLower(const char *orig)
238 if ((temp = xstrdup(orig)) == NULL)
239 NiceExit(-1, "no memory in strduplower");
240 for (i = 0; temp[i]; i++) {
241 if (isupper((int) temp[i]))
242 temp[i] = tolower(temp[i]);
247 /*-----------------------------------------------------------------*/
249 StrcpyLower(char *dest, const char *src)
251 /* copy 'src' to 'dest' in lower cases.
252 'dest' should have enough free space to hold src */
255 for (i = 0; src[i]; i++) {
256 dest[i] = (isupper((int) src[i])) ? tolower(src[i]) : src[i];
259 /* mark it as NULL */
262 /*-----------------------------------------------------------------*/
264 NiceExitBack(int val, char *reason, char *file, int line)
267 time_t currT = time(NULL);
269 sprintf(buf, "[%s, %d] %.24s %s\n", file, line, ctime(&currT), reason);
270 fprintf(stderr, "%s", buf);
273 /*-----------------------------------------------------------------*/
274 /* Logging & Trace support */
276 /* buffer threshold : when the size hits this value, it flushes its content
278 #define LOG_BYTES_THRESHOLD (32*1024)
280 /* this flag indicates that it preserves the base file name for the current
281 one, and changes its name when it actually closes it off */
282 #define CHANGE_FILE_NAME_ON_SAVE 0x01
284 /* size of the actual log buffer */
285 #define LOG_BYTES_MAX (2*LOG_BYTES_THRESHOLD)
287 /* log/trace book keeping information */
288 typedef struct ExtendedLog {
289 char buffer[LOG_BYTES_MAX]; /* 64 KB */
290 int bytes; /* number of bytes written */
291 int filesize; /* number of bytes written into this file so far */
292 int fd; /* file descriptor */
293 char* sig; /* base file name */
294 int flags; /* flags */
296 } ExtendedLog, *PExtendedLog;
298 /* maximum single file size */
299 int maxSingleLogSize = 100 * (1024*1024);
302 GetNextLogFileName(char* file, int size, const char* sig)
304 #define COMPRESS_EXT1 ".bz2"
305 #define COMPRESS_EXT2 ".gz"
312 cur_tm = *gmtime(&cur_t);
315 /* check if .bz2 exists */
316 snprintf(file, size, "%s.%04d%02d%02d_%03d%s",
317 sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday,
320 if (access(file, F_OK) == 0) {
325 /* check if .gz exists */
326 snprintf(file, size, "%s.%04d%02d%02d_%03d%s",
327 sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday,
328 idx++, COMPRESS_EXT2);
330 if (access(file, F_OK) == 0)
333 /* strip the extension and see if the (uncompressed) file exists */
334 file[strlen(file) - sizeof(COMPRESS_EXT2) + 1] = 0;
335 if (access(file, F_OK) != 0)
339 /* calculate & return the next day */
340 cur_t -= (3600*cur_tm.tm_hour + 60*cur_tm.tm_min + cur_tm.tm_sec);
341 return cur_t + 60*60*24;
346 /*-----------------------------------------------------------------*/
348 FlushBuffer(HANDLE file)
350 /* write data into the file */
351 ExtendedLog* pel = (ExtendedLog *)file;
354 if (pel == NULL || pel->fd < 0)
357 if ((written = write(pel->fd, pel->buffer, pel->bytes)) > 0) {
358 pel->bytes -= written;
360 /* if it hasn't written all data, then we need to move memory */
362 memmove(pel->buffer, pel->buffer + written, pel->bytes);
363 pel->buffer[pel->bytes] = 0;
364 pel->filesize += written;
367 /* if the filesize is bigger than maxSignleLogSize, then close it off */
368 if (pel->filesize >= maxSingleLogSize)
372 /*-----------------------------------------------------------------*/
374 CreateLogFHandle(const char* signature, int change_file_name_on_save)
379 /* check if the file can be created */
380 if ((temp = strrchr(signature, '/')) != NULL) {
381 int dirlen = temp - signature + 1;
382 char pardir[dirlen+1];
384 memcpy(pardir, signature, dirlen);
386 if (access(pardir, W_OK) != 0)
389 /* assume it's the current directory */
390 if (access("./", W_OK) != 0)
394 if ((pel = (ExtendedLog *)xcalloc(1, sizeof(ExtendedLog))) == NULL)
395 NiceExit(-1, "failed");
398 pel->sig = xstrdup(signature);
399 if (pel->sig == NULL)
400 NiceExit(-1, "signature copying failed");
401 if (change_file_name_on_save)
402 pel->flags |= CHANGE_FILE_NAME_ON_SAVE;
408 /*-----------------------------------------------------------------*/
410 OpenLogF(HANDLE file)
413 ExtendedLog* pel = (ExtendedLog *)file;
421 pel->nextday = GetNextLogFileName(filename, sizeof(filename), pel->sig);
423 /* change the file name only at saving time
424 use pel->sig as current file name */
425 if (pel->flags & CHANGE_FILE_NAME_ON_SAVE) {
426 if (access(pel->sig, F_OK) == 0)
427 rename(pel->sig, filename);
428 strcpy(filename, pel->sig);
432 if ((pel->fd = open(filename, O_RDWR | O_CREAT | O_APPEND,
433 S_IRUSR | S_IWUSR)) == -1) {
434 char errMessage[2048];
435 sprintf(errMessage, "couldn't open the extended log file %s\n", filename);
436 NiceExit(-1, errMessage);
439 /* reset the file size */
444 /*-----------------------------------------------------------------*/
446 WriteLog(HANDLE file, const char* data, int size, int forceFlush)
448 ExtendedLog* pel = (ExtendedLog *)file;
450 /* if an error might occur, then stop here */
451 if (pel == NULL || pel->fd < 0 || size > LOG_BYTES_MAX)
455 /* flush the previous data, if this data would overfill the buffer */
456 if (pel->bytes + size >= LOG_BYTES_MAX)
459 /* write into the buffer */
460 memcpy(pel->buffer + pel->bytes, data, size);
464 /* need to flush ? */
465 if ((forceFlush && (pel->bytes > 0)) || (pel->bytes >= LOG_BYTES_THRESHOLD))
470 /*-----------------------------------------------------------------*/
472 DailyReopenLogF(HANDLE file)
474 /* check if current file is a day long,
475 opens another for today's file */
476 ExtendedLog* pel = (ExtendedLog *)file;
478 if (pel && (time(NULL) >= pel->nextday)) {
479 FlushLogF(file); /* flush */
480 OpenLogF(file); /* close previous one & reopen today's */
483 /*-----------------------------------------------------------------*/
485 HandleToFileNo(HANDLE file)
487 ExtendedLog* pel = (ExtendedLog *)file;
489 return (pel != NULL) ? pel->fd : -1;
491 /*-----------------------------------------------------------------*/
493 HashString(const char *name, unsigned int hash, int endOnQuery,
496 /* if endOnQuery, we stop the hashing when we hit the question mark.
497 if skipLastIfDot, we check the last component of the path to see
498 if it includes a dot, and it so, we skip it. if both are specified,
499 we first try the query, and if that exists, we don't trim the path */
509 if (endOnQuery && (temp = strchr(name, '?')) != NULL)
511 else if (skipLastIfDot) {
512 /* first, find last component by searching backward */
513 if ((temp = strrchr(name, '/')) != NULL) {
514 /* now search forward for the dot */
515 if (strchr(temp, '.') != NULL)
520 for (i = 0; i < len; i ++)
521 hash += (_rotl(hash, 19) + name[i]);