erroneously checked in
[codemux.git] / applib.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/time.h>
4 #include <netinet/in.h>
5 #include <ctype.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include "applib.h"
14 #include "debug.h"
15 #include "codns.h"
16
17
18
19 int defaultTraceSync = TRUE;
20
21 /*-----------------------------------------------------------------*/
22 float
23 DiffTimeVal(const struct timeval *start, const struct timeval *end)
24 {
25   struct timeval temp;
26   if (end == NULL) {
27     end = &temp;
28     gettimeofday(&temp, NULL);
29   }
30   return(end->tv_sec - start->tv_sec + 
31          1e-6*(end->tv_usec - start->tv_usec));
32 }
33 /*-----------------------------------------------------------------*/
34 int 
35 CreatePrivateAcceptSocketEx(int portNum, int nonBlocking, int loopbackOnly)
36 {
37   int doReuse = 1;
38   struct linger doLinger;
39   int sock;
40   struct sockaddr_in sa;
41   
42   /* Create socket. */
43   if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
44     return(-1);
45   
46   /* don't linger on close */
47   doLinger.l_onoff = doLinger.l_linger = 0;
48   if (setsockopt(sock, SOL_SOCKET, SO_LINGER, 
49                  &doLinger, sizeof(doLinger)) == -1) {
50     close(sock);
51     return(-1);
52   }
53   
54   /* reuse addresses */
55   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
56                  &doReuse, sizeof(doReuse)) == -1) {
57     close(sock);
58     return(-1);
59   }
60
61   if (nonBlocking) {
62     /* make listen socket nonblocking */
63     if (fcntl(sock, F_SETFL, O_NDELAY) == -1) {
64       close(sock);
65       return(-1);
66     }
67   }
68   
69   /* set up info for binding listen */
70   memset(&sa, 0, sizeof(sa));
71   sa.sin_family = AF_INET;
72   sa.sin_addr.s_addr = (loopbackOnly) ? htonl(INADDR_LOOPBACK) 
73                                       : htonl(INADDR_ANY);
74   sa.sin_port = htons(portNum);
75
76   /* bind the sock */
77   if (bind(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
78     close(sock);
79     return(-1);
80   }
81   
82   /* start listening */
83   if (listen(sock, 32) == -1) {
84     close(sock);
85     return(-1);
86   }
87   
88   return(sock);
89 }
90 /*-----------------------------------------------------------------*/
91 int
92 CreatePrivateAcceptSocket(int portNum, int nonBlocking)
93 {
94   return CreatePrivateAcceptSocketEx(portNum, nonBlocking, FALSE);
95 }
96 /*-----------------------------------------------------------------*/
97 int
98 CreatePublicUDPSocket(int portNum)
99 {
100   struct sockaddr_in hb_sin;
101   int sock;
102
103   if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
104     return(-1);
105
106   memset(&hb_sin, 0, sizeof(hb_sin));
107   hb_sin.sin_family = AF_INET;
108   hb_sin.sin_addr.s_addr = INADDR_ANY;
109   hb_sin.sin_port = htons(portNum);
110
111   if (bind(sock, (struct sockaddr *) &hb_sin, sizeof(hb_sin)) < 0) {
112     close(sock);
113     return(-1);
114   }
115   return(sock);
116 }
117 /*-----------------------------------------------------------------*/
118 int
119 MakeConnection(char *name, in_addr_t netAddr, int portNum, int nonBlocking)
120 {
121   struct sockaddr_in saddr;
122   int fd;
123
124   if (name != NULL) {
125     struct hostent *ent;
126     if ((ent = gethostbyname(name)) == NULL) {
127       if (hdebugLog)
128         TRACE("failed in name lookup - %s\n", name);
129       return(-1);
130     }
131     memcpy(&netAddr, ent->h_addr, sizeof(netAddr));
132   }
133
134   if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
135     if (hdebugLog)
136       TRACE("failed creating socket - %d\n", errno);
137     return(-1);
138   }
139
140   if (nonBlocking) {
141     if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
142       if (hdebugLog)
143         TRACE("failed fcntl'ing socket - %d\n", errno);
144       close(fd);
145       return(-1);
146     }
147   }
148
149   saddr.sin_family = AF_INET;
150   saddr.sin_addr.s_addr = netAddr;
151   saddr.sin_port = htons(portNum);
152   
153   if (connect(fd, (struct sockaddr *) &saddr, 
154               sizeof(struct sockaddr_in)) < 0) {
155     if (errno == EINPROGRESS)
156       return(fd);
157     if (hdebugLog)
158       TRACE("failed connecting socket - %d\n", errno);
159     close(fd);
160     return(-1);
161   }
162
163   return(fd);
164 }
165 /*-----------------------------------------------------------------*/
166 int
167 MakeLoopbackConnection(int portNum, int nonBlocking)
168 {
169   return(MakeConnection(NULL, htonl(INADDR_LOOPBACK), 
170                         portNum, nonBlocking));
171 }
172 /*-----------------------------------------------------------------*/
173 char *
174 GetField(const unsigned char *start, int whichField)
175 {
176   int currField;
177
178   /* move to first non-blank char */
179   while (isspace(*start))
180     start++;
181
182   if (*start == '\0')
183     return(NULL);
184
185   for (currField = 0; currField < whichField; currField++) {
186     /* move over this field */
187     while (*start != '\0' && (!isspace(*start)))
188       start++;
189     /* move over blanks before next field */
190     while (isspace(*start))
191       start++;
192     if (*start == '\0')
193       return(NULL);
194   }
195   return((char *) start);
196 }
197 /* ---------------------------------------------------------------- */
198 char *
199 GetWord(const unsigned char *start, int whichWord)
200 {
201   /* returns a newly allocated string containing the desired word,
202      or NULL if there was a problem */
203   unsigned char *temp;
204   int len = 0;
205   char *res;
206
207   temp = (unsigned char *) GetField(start, whichWord);
208   if (!temp)
209     return(NULL);
210   while (!(temp[len] == '\0' || isspace(temp[len])))
211     len++;
212   if (!len)
213     NiceExit(-1, "internal error");
214   res = (char *)xcalloc(1, len+1);
215   if (!res) 
216     NiceExit(-1, "out of memory");
217   memcpy(res, temp, len);
218   return(res);
219 }
220 /* ---------------------------------------------------------------- */
221 char *
222 GetWordEx(const unsigned char *start, int whichWord, 
223           char* dest, int max)
224 {
225   /* returns a newly allocated string containing the desired word,
226      or NULL if there was a problem */
227   unsigned char *temp;
228   int len = 0;
229
230   memset(dest, 0, max);
231   temp = (unsigned char *) GetField(start, whichWord);
232   if (!temp)
233     return(NULL);
234   while (!(temp[len] == '\0' || isspace(temp[len])))
235     len++;
236   if (!len)
237     NiceExit(-1, "internal error");
238   if (len >= max-1)
239     len = max-1;
240   memcpy(dest, temp, len);
241   return(dest);
242 }
243 /*-----------------------------------------------------------------*/
244 int
245 Base36Digit(int a)
246 {
247   if (a < 0)
248     return('0');
249   if (a > 35)
250     return('z');
251   if (a < 10)
252     return('0' + a);
253   return('a' + a-10);
254 }
255 /*-----------------------------------------------------------------*/
256 int
257 Base36To10(int a)
258 {
259   if (a >= '0' && a <= '9')
260     return(a - '0');
261   if (a >= 'a' && a <= 'z')
262     return(10 + a - 'a');
263   if (a >= 'A' && a <= 'Z')
264     return(10 + a - 'A');
265   return(0);
266 }
267 /*-----------------------------------------------------------------*/
268 int
269 PopCount(int val)
270 {
271   int i;
272   int count = 0;
273
274   for (i = 0; i < (int)sizeof(int) * 8; i++) {
275     if (val & (1<<i))
276       count++;
277   }
278   return(count);
279 }
280 /*-----------------------------------------------------------------*/
281 int
282 PopCountChar(int val)
283 {
284   int i;
285   int count = 0;
286
287   for (i = 0; i < (int)sizeof(int) * 8; i++) {
288     if (val & (1<<i))
289       count++;
290   }
291   return(Base36Digit(count));
292 }
293 /*-----------------------------------------------------------------*/
294 int
295 LogValChar(int val)
296 {
297   int i;
298
299   for (i = 0; i < 32; i++) {
300     if (val <= (1<<i))
301       return(Base36Digit(i));
302   }
303   return(Base36Digit(32));
304 }
305 /*-----------------------------------------------------------------*/
306 const char *
307 StringOrNull(const char *s)
308 {
309   if (s)
310     return(s);
311   return("(null)");
312 }
313 /*-----------------------------------------------------------------*/
314 char *
315 strchars(const char *string, const char *list)
316 {
317   /* acts like strchr, but works with multiple characters */
318   int numChars = strlen(list);
319   int i;
320   const char *walk;
321
322   if (numChars < 1)
323     return(NULL);
324   
325   for (walk = string; *walk; walk++) {
326     for (i = 0; i < numChars; i++) {
327       if (*walk == list[i])
328         return (char *)(walk);
329     }
330   }
331   return(NULL);
332 }
333 /*-----------------------------------------------------------------*/
334 char *
335 strnchars(const char *string, int length, const char *list)
336 {
337   /* acts like strchr, but works with multiple characters, and 
338      reads exactly length characters from string.  */
339   int searchingfor[256] = {0};
340   const char *walk;
341
342   if ('\0' == *list)
343     return(NULL);
344
345   for (; *list; list++) {
346     /*
347      * Be careful with this cast.
348      * If *list == (char) -98 (extended ascii), then
349      *     (unsigned)*list == (unsigned int)*list == 4294967198
350      *     (int)(unsigned char)*list == (unsigned char)*list == 158
351      * The compiler automatically casts the character to an int before
352      * doing the array index.
353      */
354     searchingfor[(int)(unsigned char)*list] = 1;
355   }
356
357   for (walk = string; walk - string < length; walk++) {
358     /* likewise */
359     if (searchingfor[(int)(unsigned char)*walk]) {
360         return (char *)(walk);
361     }
362   }
363   return(NULL);
364 }
365 /*-----------------------------------------------------------------*/
366 int
367 strncspn(const char* string, int length, const char* reject)
368      /* like strcspn but reads to length characters */
369 {
370   int count = 0;
371   int searchingfor[256] = {0};
372   const char* walk;
373
374   for (; *reject; reject++) {
375     /*
376      * Be careful with this cast.
377      * If *list == (char) -98 (extended ascii), then
378      *     (unsigned)*list == (unsigned int)*list == 4294967198
379      *     (int)(unsigned char)*list == (unsigned char)*list == 158
380      * The compiler automatically casts the character to an int before
381      * doing the array index.
382      */
383     searchingfor[(int)(unsigned char)*reject] = 1;
384   }
385
386   for(walk = string; walk - string < length; walk++) {
387     /* likewise */
388     if (searchingfor[(int)(unsigned char)*walk]) {
389       break;
390     } else {
391       count++;
392     }
393   }
394   return count;
395 }
396 /*-----------------------------------------------------------------*/
397 char *
398 strnchr(const char *string, int length, const char needle)
399 {
400   /* acts like strchr, but 
401      reads exactly length characters from string.  */
402   const char *walk;
403
404   for (walk = string; walk - string < length; walk++) {
405     if (needle == *walk) {
406         return (char *)(walk);
407     }
408   }
409   return(NULL);
410 }
411
412 /*-----------------------------------------------------------------*/
413 #ifndef HAS_STRNSTR
414 /* same as strstr, except that si doesn't have to end at '\0' */
415 char * strnstr(const char * s1, int s1_len, const char * s2)
416 {
417   int l1, l2;
418   
419   l2 = strlen(s2);
420   if (!l2)
421     return (char *) s1;
422   
423   l1 = s1_len;
424   while (l1 >= l2) {
425     l1--;
426     if (!memcmp(s1,s2,l2))
427       return (char *) s1;
428     s1++;
429   }
430   return NULL;
431 }
432 #endif
433 /*-----------------------------------------------------------------*/
434 /* same as strnstr, except case insensitive */
435 char * strncasestr(const char * s1, int s1_len, const char * s2)
436 {
437   int l1, l2;
438   
439   l2 = strlen(s2);
440   if (!l2)
441     return (char *) s1;
442   
443   l1 = s1_len;
444   while (l1 >= l2) {
445     l1--;
446     if (!strncasecmp(s1,s2,l2))
447       return (char *) s1;
448     s1++;
449   }
450   return NULL;
451 }
452
453 /*-----------------------------------------------------------------*/
454 char *
455 StrdupLower(const char *orig)
456 {
457   char *temp;
458   int i;
459
460   if ((temp = xstrdup(orig)) == NULL)
461     NiceExit(-1, "no memory in strduplower");
462   for (i = 0; temp[i]; i++) {
463     if (isupper((int) temp[i]))
464       temp[i] = tolower(temp[i]);
465   }
466   return(temp);
467 }
468
469 /*-----------------------------------------------------------------*/
470 void 
471 StrcpyLower(char *dest, const char *src)
472 {
473   /* copy 'src' to 'dest' in lower cases. 
474      'dest' should have enough free space to hold src */
475   int i;
476
477   for (i = 0; src[i]; i++) {
478     dest[i] = (isupper((int) src[i])) ? tolower(src[i]) : src[i];
479   }
480
481   /* mark it as NULL */
482   dest[i] = 0;
483 }
484 /*-----------------------------------------------------------------*/
485 void
486 StrcpyLowerExcept(char *dest, int dest_max, const char* src, const char* except)
487 {
488   /* copy 'src' to 'dest' in lower cases, skipping the chars in except.
489      'dest' should have enough free space to hold src */
490   int i, j;
491
492   if (src == NULL)
493     return;
494   
495   for (i = 0, j= 0; src[i]; i++) {
496     if (strchr(except, src[i]))
497       continue;
498
499     if (j == dest_max - 1)
500       break;
501     dest[j++] = (isupper((int) src[i])) ? tolower(src[i]) : src[i];
502   }
503
504   /* mark it as NULL */
505   dest[j] = 0;
506 }
507
508 /*-----------------------------------------------------------------*/
509 static char *
510 GetNextLineBack(FILE *file, int lower, int stripComments)
511 {
512   /* reads the next non-blank line of the file. strips off any leading
513      space, any comments, and any trailing space.  returns a lowercase
514      version of the line that has been malloc'd */
515   char line[1024];
516
517   while (fgets(line, sizeof(line), file) != NULL) {
518     char *temp;
519     int len;
520
521     /* strip off any comments, leading and trailing whitespace */
522     if (stripComments) {
523       if ((temp = strchr(line, '#')) != NULL)
524         *temp = 0;
525     }
526     len = strlen(line);
527     while (len > 0 && isspace((int) line[len-1])) {
528       len--;
529       line[len] = 0;
530     }
531     temp = line;
532     while (isspace((int) *temp))
533       temp++;
534     if (temp[0] == 0)
535       continue;                 /* blank line, move on */
536
537     if (lower)
538       return(StrdupLower(temp));
539     return(xstrdup(temp));
540   }
541
542   return(NULL);
543 }
544 /*-----------------------------------------------------------------*/
545 char *
546 GetLowerNextLine(FILE *file)
547 {
548   return(GetNextLineBack(file, TRUE, TRUE));
549 }
550 /*-----------------------------------------------------------------*/
551 char *
552 GetNextLine(FILE *file)
553 {
554   return(GetNextLineBack(file, FALSE, TRUE));
555 }
556 /*-----------------------------------------------------------------*/
557 char *
558 GetNextLineNoCommStrip(FILE *file)
559 {
560   return(GetNextLineBack(file, FALSE, FALSE));
561 }
562 /*-----------------------------------------------------------------*/
563 int
564 DoesSuffixMatch(char *start, int len, char *suffix)
565 {
566   int sufLen = strlen(suffix);
567
568   if (len < 1)
569     len = strlen(start);
570   if (len < sufLen)
571     return(FALSE);
572   if (strncasecmp(start+len-sufLen, suffix, sufLen))
573     return(FALSE);
574   return(TRUE);
575 }
576 /*-----------------------------------------------------------------*/
577 int
578 DoesDotlessSuffixMatch(char *start, int len, char *suffix)
579 {
580   /* ignores any dots on end of start, suffix */
581   int sufLen = strlen(suffix);
582
583   if (len < 1)
584     len = strlen(start);
585
586   while (len > 1 && start[len-1] == '.')
587     len--;
588   while (sufLen > 1 && suffix[sufLen-1] == '.')
589     sufLen--;
590
591   if (len < sufLen)
592     return(FALSE);
593   if (strncasecmp(start+len-sufLen, suffix, sufLen))
594     return(FALSE);
595   return(TRUE);
596 }
597
598 /*-----------------------------------------------------------------*/
599 /*                                                                 */
600 /* Bit Vector Implementation                                       */
601 /*                                                                 */
602 /*-----------------------------------------------------------------*/
603 #define BIT_INDEX (0x0000001F)
604
605 void
606 SetBits(int* bits, int idx, int maxNum)
607 {
608   if (idx > (maxNum << 5)) {
609     TRACE("Invalid index: %d", idx);
610     return;
611   }
612   bits[(idx >> 5)] |= (1 << (idx & BIT_INDEX));
613 }
614 /*-----------------------------------------------------------------*/
615 int
616 GetBits(int* bits, int idx, int maxNum)
617 {
618   if (idx > (maxNum << 5)) {
619     TRACE("Invalid index: %d", idx);
620     return FALSE;
621   }
622   return (bits[(idx >> 5)] & (1 << (idx & BIT_INDEX)));
623 }
624
625 /*-----------------------------------------------------------------*/
626 static inline int
627 GetNumBits_I(int bitvec)
628 {
629   int i, count;
630
631   for (i = 0, count = 0; i < 32; i++)
632     if (bitvec & (1 << i)) count++;
633   return count;
634 }
635
636 /*-----------------------------------------------------------------*/
637 int 
638 GetNumBits(int* bitvecs, int maxNum)
639 {
640   int i, count;
641
642   /* get the number of bits that have been set to 1 */
643   for (i = 0, count = 0; i < maxNum; i++)
644     count += GetNumBits_I(bitvecs[i]);
645   return count;
646 }
647
648 /*-----------------------------------------------------------------*/
649
650 /* Logging & Trace support */
651
652 /* buffer threshold : when the size hits this value, it flushes its content
653    to the file  */
654 #define LOG_BYTES_THRESHOLD (32*1024)
655
656 /* this flag indicates that it preserves the base file name for the current
657    one, and changes its name when it actually closes it off */
658 #define CHANGE_FILE_NAME_ON_SAVE 0x01 
659
660 /* size of the actual log buffer */
661 #define LOG_BYTES_MAX       (2*LOG_BYTES_THRESHOLD)
662
663 /* log/trace book keeping information */
664 typedef struct ExtendedLog {
665   char buffer[LOG_BYTES_MAX]; /* 64 KB */
666   int  bytes;           /* number of bytes written */
667   int  filesize;        /* number of bytes written into this file so far */
668   int  fd;              /* file descriptor */
669   char* sig;            /* base file name */
670   int flags;            /* flags */
671   time_t nextday;
672 } ExtendedLog, *PExtendedLog;
673
674 /* maximum single file size */
675 int maxSingleLogSize = 100 * (1024*1024);
676
677 static time_t
678 GetNextLogFileName(char* file, int size, const char* sig)
679 {
680 #define COMPRESS_EXT1 ".bz2"
681 #define COMPRESS_EXT2 ".gz"
682
683   struct tm cur_tm;
684   time_t cur_t;
685   int idx = 0;
686
687   cur_t = timeex(NULL);
688   cur_tm = *gmtime(&cur_t);
689
690   for (;;) {
691     /* check if .bz2 exists */
692     snprintf(file, size, "%s.%04d%02d%02d_%03d%s", 
693              sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday, 
694              idx, COMPRESS_EXT1);
695
696     if (access(file, F_OK) == 0) {
697       idx++;
698       continue;
699     }
700
701     /* check if .gz exists */
702     snprintf(file, size, "%s.%04d%02d%02d_%03d%s", 
703              sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday, 
704              idx++, COMPRESS_EXT2);
705
706     if (access(file, F_OK) == 0) 
707       continue;
708
709     /* strip the extension and see if the (uncompressed) file exists */
710     file[strlen(file) - sizeof(COMPRESS_EXT2) + 1] = 0;
711     if (access(file, F_OK) != 0)
712       break;
713   }
714   
715   /* calculate & return the next day */
716   cur_t -= (3600*cur_tm.tm_hour + 60*cur_tm.tm_min + cur_tm.tm_sec);
717   return cur_t + 60*60*24;
718
719 #undef COMPRESS_EXT1
720 #undef COMPRESS_EXT2
721 }
722
723 /*-----------------------------------------------------------------*/
724 static void
725 FlushBuffer(HANDLE file) 
726 {
727   /* write data into the file */
728   ExtendedLog* pel = (ExtendedLog *)file;
729   int written;
730
731   if (pel == NULL || pel->fd < 0)
732     return;
733   
734   if ((written = write(pel->fd, pel->buffer, pel->bytes)) > 0) {
735     pel->bytes -= written;
736
737     /* if it hasn't written all data, then we need to move memory */
738     if (pel->bytes > 0) 
739       memmove(pel->buffer, pel->buffer + written, pel->bytes);
740     pel->buffer[pel->bytes] = 0;
741     pel->filesize += written;
742   }
743   
744   /* if the filesize is bigger than maxSignleLogSize, then close it off */
745   if (pel->filesize >= maxSingleLogSize) 
746     OpenLogF(file);
747 }
748
749 /*-----------------------------------------------------------------*/
750 HANDLE
751 CreateLogFHandle(const char* signature, int change_file_name_on_save)
752 {
753   ExtendedLog* pel;
754
755   if ((pel = (ExtendedLog *)xcalloc(1, sizeof(ExtendedLog))) == NULL)
756     NiceExit(-1, "failed");
757
758   pel->fd = -1;
759   pel->sig = xstrdup(signature);
760   if (pel->sig == NULL)
761     NiceExit(-1, "signature copying failed");
762   if (change_file_name_on_save)
763     pel->flags |= CHANGE_FILE_NAME_ON_SAVE;
764
765   return pel;
766 }
767
768
769 /*-----------------------------------------------------------------*/
770 int
771 OpenLogF(HANDLE file)
772 {
773   char filename[1024];
774   ExtendedLog* pel = (ExtendedLog *)file;
775
776   if (pel == NULL)
777     return -1;
778
779   if (pel->fd != -1) 
780     close(pel->fd);
781
782   pel->nextday = GetNextLogFileName(filename, sizeof(filename), pel->sig);
783
784   /* change the file name only at saving time 
785      use pel->sig as current file name         */
786   if (pel->flags & CHANGE_FILE_NAME_ON_SAVE) {
787     if (access(pel->sig, F_OK) == 0) 
788       rename(pel->sig, filename);
789     strcpy(filename, pel->sig);
790   }
791
792   /* file opening */
793   if ((pel->fd = open(filename, O_RDWR | O_CREAT | O_APPEND, 
794                       S_IRUSR | S_IWUSR)) == -1) {
795     char errMessage[2048];
796     sprintf(errMessage, "couldn't open the extended log file %s\n", filename);
797     NiceExit(-1, errMessage);
798   }
799
800   /* reset the file size */
801   pel->filesize = 0;
802   return 0;
803 }
804
805 /*-----------------------------------------------------------------*/
806 int 
807 WriteLog(HANDLE file, const char* data, int size, int forceFlush)
808 {
809   ExtendedLog* pel = (ExtendedLog *)file;
810
811   /* if an error might occur, then stop here */
812   if (pel == NULL || pel->fd < 0 || size > LOG_BYTES_MAX)
813     return -1;
814
815   if (data != NULL) {
816     /* flush the previous data, if this data would overfill the buffer */
817     if (pel->bytes + size >= LOG_BYTES_MAX) 
818       FlushBuffer(file);
819
820     /* write into the buffer */
821     memcpy(pel->buffer + pel->bytes, data, size);
822     pel->bytes += size;
823   }
824
825   /* need to flush ? */
826   if ((forceFlush && (pel->bytes > 0)) || (pel->bytes >= LOG_BYTES_THRESHOLD))
827     FlushBuffer(file);
828
829   return 0;
830 }
831
832 /*-----------------------------------------------------------------*/
833 void
834 DailyReopenLogF(HANDLE file) 
835 {
836   /* check if current file is a day long,
837      opens another for today's file         */
838   ExtendedLog* pel = (ExtendedLog *)file;
839
840   if (pel && (timeex(NULL) >= pel->nextday)) {
841     FlushLogF(file);               /* flush */
842     OpenLogF(file);                /* close previous one & reopen today's */
843   }
844 }
845 /*-----------------------------------------------------------------*/
846 int 
847 HandleToFileNo(HANDLE file)
848 {
849   ExtendedLog* pel = (ExtendedLog *)file;
850
851   return (pel != NULL) ? pel->fd : -1;
852 }
853 /*-----------------------------------------------------------------*/
854 #define TO_HOST_L(x) x = ntohl(x);
855 #define TO_NETWORK_L(x) x = htonl(x);
856 void 
857 HtoN_LocalQueryInfo(LocalQueryInfo *p)
858 {
859   TO_NETWORK_L(p->lqi_size);
860   TO_NETWORK_L(p->lqi_id);
861   TO_NETWORK_L(p->lqi_cache);
862 }
863 /*----------------------------------------------------------------*/
864 void 
865 NtoH_LocalQueryResult(LocalQueryResult* p)
866 {
867   TO_HOST_L(p->lq_id);
868   TO_HOST_L(p->lq_ttl);
869 }
870 /*----------------------------------------------------------------*/
871 int
872 CoDNSGetHostByNameSync(const char *name, struct in_addr *res)
873 {
874   static int fd = -1;
875   LocalQuery query;
876   int size;
877   LocalQueryResult result;
878
879   /* create a connection to CoDNS */
880   if (fd == -1 && (fd = MakeLoopbackConnection(CODNS_PORT, 0)) < 0) {
881     TRACE("CoDNS connection try has failed!\n");
882
883     /* try to resolve names using gethostbyname() */
884     {
885       struct hostent* hp;
886       if ((hp = gethostbyname(name)) == NULL)
887         NiceExit(-1, "gethostbyname also failed!");
888       if (res)
889         *res = *(struct in_addr *)hp->h_addr;
890     }
891     return 0;
892   }
893
894   memset(&query, 0, sizeof(query));
895   size = strlen(name) + 1;
896   query.lq_info.lqi_size = size;      /* length of name */
897   query.lq_info.lqi_cache = TRUE;
898   strcpy(query.lq_name, name);
899   size += sizeof(query.lq_info) + sizeof(query.lq_zero);
900
901   /* send a query */
902   HtoN_LocalQueryInfo(&query.lq_info);
903   if (write(fd, &query, size) != size) {
904     close(fd);
905     fd  = -1;
906     return(-1);
907   }
908
909   /* get answer */
910   do {
911     size = read(fd, &result, sizeof(result));
912   } while (size == -1 && errno == EINTR);
913   /*  close(fd); */
914   NtoH_LocalQueryResult(&result);
915
916   if (size != sizeof(result))
917     return(-1);
918
919   *res = result.lq_address[0];
920   return 0;
921 }
922 /*-----------------------------------------------------------------*/
923 void
924 FeedbackDelay(struct timeval *start, float minSec, float maxSec)
925 {
926   float diff = DiffTimeVal(start, NULL);
927   if (diff < minSec)
928     diff = minSec;
929   if (diff > maxSec)
930     diff = maxSec;
931   usleep((unsigned int)(diff * 1e6));
932 }
933 /*-----------------------------------------------------------------*/
934 static int niceExitLogFD = -1;
935 int
936 NiceExitOpenLog(char *logName)
937 {
938   /* log file to record exit reasons */
939   if (niceExitLogFD >= 0)
940     close(niceExitLogFD);
941
942   niceExitLogFD = open(logName, O_WRONLY | O_APPEND | O_CREAT, 
943                        S_IRUSR | S_IWUSR);
944   return((niceExitLogFD >= 0) ? SUCCESS : FAILURE);
945 }
946 /*-----------------------------------------------------------------*/
947 void
948 NiceExitBack(int val, char *reason, char *file, int line)
949 {
950   char buf[1024];
951   time_t currT = time(NULL);
952
953   sprintf(buf, "[%s, %d] %.24s %s\n", file, line, ctime(&currT), reason);
954   if (hdebugLog) {
955     TRACE("%s", buf);
956     FlushLogF(hdebugLog);
957   }
958   else
959     fprintf(stderr, "%s", buf);
960
961   if (niceExitLogFD >= 0)
962     write(niceExitLogFD, buf, strlen(buf));
963   exit(val);
964 }
965 /*-----------------------------------------------------------------*/
966 int
967 WordCount(char *buf)
968 {
969   int count = 0;
970   int wasSpace = TRUE;
971
972   while (*buf != '\0') {
973     int isSpace = isspace(*buf);
974     if (wasSpace && (!isSpace))
975       count++;
976     wasSpace = isSpace;
977     buf++;
978   }
979   return(count);
980 }
981 /*-----------------------------------------------------------------*/
982 char * 
983 ReadFile(const char *filename)
984 {
985   int dummySize;
986   return(ReadFileEx(filename, &dummySize));
987 }
988 /*-----------------------------------------------------------------*/
989 char * 
990 ReadFileEx(const char *filename, int *size)
991 {
992   /* allocate a buffer, read the file into it and
993      return the buffer */
994   char *content = NULL;
995   struct stat buf;
996   int fd;
997
998   *size = -1;
999   if (access(filename, R_OK) < 0 
1000       || stat(filename, &buf) < 0
1001       || (fd = open(filename, O_RDONLY)) < 0) {
1002     TRACE("opening captcha file %s failed\n", filename);
1003     exit(-1);
1004   }
1005
1006   if ((content = (char *)xmalloc(buf.st_size + 1)) == NULL) {
1007     TRACE("memory alloc failed\n");
1008     exit(-1);
1009   }
1010
1011   if (read(fd, content, buf.st_size) != buf.st_size) {
1012     TRACE("opening captcha test file failed\n");
1013     exit(-1);
1014   }
1015   close(fd);
1016   content[buf.st_size] = 0;
1017   *size = buf.st_size;
1018   return content;
1019 }
1020 /*-----------------------------------------------------------------*/
1021 char * 
1022 MmapFile(const char *filename, int *size)
1023 {
1024   /* allocate a buffer, read the file into it and
1025      return the buffer */
1026   char *content = NULL;
1027   struct stat buf;
1028   int fd;
1029
1030   *size = -1;
1031   if (access(filename, R_OK) < 0 
1032       || stat(filename, &buf) < 0
1033       || (fd = open(filename, O_RDONLY)) < 0) {
1034     TRACE("opening captcha file %s failed\n", filename);
1035     exit(-1);
1036   }
1037
1038   content = (char *)mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
1039   close(fd);
1040   if (content != MAP_FAILED) {
1041     *size = buf.st_size;
1042     return content;
1043   }
1044   return(NULL);
1045 }
1046 /*-----------------------------------------------------------------*/
1047 unsigned int 
1048 HashString(const char *name, unsigned int hash, int endOnQuery, 
1049            int skipLastIfDot)
1050 {
1051   /* if endOnQuery, we stop the hashing when we hit the question mark.
1052      if skipLastIfDot, we check the last component of the path to see
1053      if it includes a dot, and it so, we skip it. if both are specified,
1054      we first try the query, and if that exists, we don't trim the path */
1055
1056   int i;
1057   int len;
1058   char *temp;
1059
1060   if (name == NULL)
1061     return 0;
1062
1063   len = strlen(name);
1064   if (endOnQuery && (temp = strchr(name, '?')) != NULL)
1065     len = temp - name;
1066   else if (skipLastIfDot) {
1067     /* first, find last component by searching backward */
1068     if ((temp = strrchr(name, '/')) != NULL) {
1069       /* now search forward for the dot */
1070       if (strchr(temp, '.') != NULL)
1071         len = temp - name;
1072     }
1073   }
1074
1075   for (i = 0; i < len; i ++)
1076     hash += (_rotl(hash, 19) + name[i]);
1077
1078   return hash;
1079 }
1080 /*-------------------------------------------------------------*/
1081 unsigned int
1082 CalcAgentHash(const char* agent) 
1083 {
1084   char p[strlen(agent)+1];
1085   int i;
1086
1087   if (agent == NULL)
1088     return 0;
1089
1090   /* we remove all spaces */
1091   for (i = 0; *agent; agent++) {
1092     if (isspace(*agent))
1093       continue;
1094     p[i++] = *agent;
1095   }
1096   p[i] = 0;
1097
1098   return HashString(p, 0, FALSE, FALSE);
1099 }
1100 /*-----------------------------------------------------------------*/
1101 char *
1102 ZapSpacesAndZeros(char *src)
1103 {
1104   /* get rid of excess spaces between words, and remove any trailing
1105      (post-decimal) zeros from floating point numbers */
1106   static char smallLine[4096];
1107   char *dst = smallLine;
1108   char *word;
1109   int addSpace = FALSE;
1110
1111   while (src != NULL &&
1112          (word = GetWord((const unsigned char*)src, 0)) != NULL) {
1113     char *temp;
1114     int isDotNumber = TRUE;
1115
1116     src = GetField((const unsigned char*)src, 1);       /* advance to next */
1117
1118     /* check to make sure it has exactly one decimal point */
1119     if ((temp = strchr(word, '.')) != NULL &&
1120         (temp = strchr(temp+1, '.')) == NULL) {
1121       /* make sure it's all digits or the dot */
1122       for (temp = word; *temp != '\0'; temp++) {
1123         if (!(isdigit(*temp) || *temp == '.')) {
1124           isDotNumber = FALSE;
1125           break;
1126         }
1127       }
1128     }
1129     else
1130       isDotNumber = FALSE;
1131     
1132     if (isDotNumber) {
1133       /* strip off any trailing zeros and possibly the decimal point */
1134       int len = strlen(word) - 1;
1135       
1136       while (word[len] == '0') {
1137         word[len] = '\0';
1138         len--;
1139       }
1140       if (word[len] == '.')
1141         word[len] = '\0';
1142     }
1143
1144     if (addSpace)
1145       sprintf(dst, " %s", word);
1146     else
1147       sprintf(dst, "%s", word);
1148     dst += strlen(dst);
1149     addSpace = TRUE;
1150     xfree(word);
1151   }
1152
1153   *dst = 0;
1154   return(smallLine);
1155 }
1156 /*-----------------------------------------------------------------*/