1 /*
2     AWFFull - A Webalizer Fork, Full o' features
3 
4     hashtab.c
5         The various hashing functions for 'fast' access to data
6 
7     Copyright (C) 1997-2001  Bradford L. Barrett (brad@mrunix.net)
8     Copyright (C) 2006 by Alexander Lazic (al-awffull@none.at)
9     Copyright (C) 2006, 2007, 2008 by Stephen McInerney (spm@stedee.id.au)
10     Copyright (C) 2006 by John Heaton (john@manchester.ac.uk)
11     Copyright (C) 2007 by Benoît Dejean (benoit@placenet.org)
12 
13     This file is part of AWFFull.
14 
15     AWFFull is free software: you can redistribute it and/or modify
16     it under the terms of the GNU General Public License as published by
17     the Free Software Foundation, either version 3 of the License, or
18     (at your option) any later version.
19 
20     AWFFull is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU General Public License for more details.
24 
25     You should have received a copy of the GNU General Public License
26     along with AWFFull.  If not, see <http://www.gnu.org/licenses/>.
27 
28     This software uses the gd graphics library, which is copyright by
29     Quest Protein Database Center, Cold Spring Harbor Labs.  Please
30     see the documentation supplied with the library for additional
31     information and license terms, or visit www.boutell.com/gd/ for the
32     most recent version of the library and supporting documentation.
33 
34 */
35 
36 /*********************************************/
37 /* STANDARD INCLUDES                         */
38 /*********************************************/
39 
40 #include "awffull.h"                            /* main header              */
41 
42 /* internal function prototypes */
43 
44 HNODEPTR new_hnode(char *);                     /* new host node            */
45 UNODEPTR new_unode(char *);                     /* new url node             */
46 RNODEPTR new_rnode(char *);                     /* new referrer node        */
47 ANODEPTR new_anode(char *);                     /* new user agent node      */
48 SNODEPTR new_snode(char *);                     /* new search string..      */
49 INODEPTR new_inode(char *);                     /* new ident node           */
50 ENODEPTR new_enode(char *, char *);             /* new errorpage node       */
51 
52 void update_entry(char *);                      /* update entry/exit        */
53 void update_exit(char *, bool);                 /* page totals              */
54 
55 unsigned long hash(char *);                     /* hash function            */
56 
57 static void del_htab(NODEPTR * htab, const char *htab_name, size_t size, void (*free_node) (NODEPTR));
58 
59 /* local data */
60 
61 HNODEPTR sm_htab[MAXHASH];                      /* hash tables              */
62 HNODEPTR sd_htab[MAXHASH];
63 UNODEPTR um_htab[MAXHASH];                      /* for hits, sites,         */
64 RNODEPTR rm_htab[MAXHASH];                      /* referrers and agents...  */
65 ANODEPTR am_htab[MAXHASH];
66 SNODEPTR sr_htab[MAXHASH];                      /* search string table      */
67 INODEPTR im_htab[MAXHASH];                      /* ident table (username)   */
68 ENODEPTR ep_htab[MAXHASH];                      /* errorpage table          */
69 
70 SEGNODEPTR seg_ref_htab[MAXHASH];               /* Segment on Referrers.    */
71 
72 /* Arrays of Constant Node Information for generic Node Creation
73  * Also see the "#define NODE_H..." 's in hashtab.h for numerical ordering */
74 static unsigned int nodemax[] = { MAXHOST, MAXURL, MAXREF, MAXAGENT, MAXSRCHH, MAXIDENT, MAXURL, MAXHOST + MAXAGENT };
75 static char node_c[] = { 'h', 'u', 'r', 'a', 's', 'i', 'e', 'g' };
76 static unsigned int nodesizes[] =
77     { sizeof(struct hnode), sizeof(struct unode), sizeof(struct rnode), sizeof(struct anode), sizeof(struct snode), sizeof(struct inode), sizeof(struct enode),
78     sizeof(struct seg_node)
79 };
80 
81 
82 /************************************************************************
83  * DEL_HTABS - clear out our hash tables                                *
84  *                                                                      *
85  * Clear out our various hash tables here,                              *
86  * by calling the appropriate del_* function for each                   *
87  ************************************************************************/
88 void
del_htabs()89 del_htabs()
90 {
91     del_hlist(sd_htab);
92     del_ulist(um_htab);
93     del_hlist(sm_htab);
94     del_rlist(rm_htab);
95     del_alist(am_htab);
96     del_slist(sr_htab);
97     del_ilist(im_htab);
98     del_elist(ep_htab);
99 }
100 
101 
102 /************************************************************************
103  * check_hashstr_size                                                   *
104  *                                                                      *
105  * Check and, if necessary!, reset the incoming string size.            *
106  * Based off the maxsize for various strings from nodemax[]             *
107  *                                                                      *
108  * Arguments:                                                           *
109  * char *str:       The string to check. eg The URL, Hostname etc       *
110  * int nodetype:    The type of node. See hashtab.h for details         *
111  *                                                                      *
112  * Returns:                                                             *
113  * The new or existing length of the string                             *
114  ************************************************************************/
115 static int
check_hashstr_size(char * str,int nodetype)116 check_hashstr_size(char *str, int nodetype)
117 {
118     size_t len;
119 
120     len = strlen(str) + 1;
121     if (len >= nodemax[nodetype]) {
122         ERRVPRINT(VERBOSE1, "[new_%cnode] %s (%d)\n", node_c[nodetype], _("Warning: String exceeds storage size"), (int) len);
123         VPRINT(VERBOSE3, "STR: %s", str);
124         str[nodemax[nodetype]] = 0;
125         len = nodemax[nodetype];
126         VPRINT(VERBOSE3, "  --> %d %s\n", len, str);
127     }
128     return (len);
129 }
130 
131 
132 /************************************************************************
133  * new_node                                                             *
134  *                                                                      *
135  * Generic creator of all Chained-Hash-Table Nodes.                     *
136  *                                                                      *
137  * Arguments:                                                           *
138  * char *str:       The key to use. eg The URL, Hostname etc            *
139  * int nodetype:    The type of node. See hashtab.h for details         *
140  *                                                                      *
141  * Returns:                                                             *
142  * a pointer to the newly created (calloc'd) structure                  *
143  ************************************************************************/
144 static void *
new_node(char * str,int nodetype,size_t len)145 new_node(char *str, int nodetype, size_t len)
146 {
147     void *newptr, *string_offsetptr;
148     HNODEPTR hptr;
149     UNODEPTR uptr;
150     RNODEPTR rptr;
151     ANODEPTR aptr;
152     SNODEPTR sptr;
153     INODEPTR iptr;
154 
155 //    ENODEPTR eptr;
156     SEGNODEPTR gptr;
157 
158 //    if (nodetype == NODE_SEG) {
159 //        ERRVPRINT(0, "\nNODE: %d --> %s\n", nodetype, str);
160 //    }
161     newptr = xmalloc(nodesizes[nodetype] + (len * sizeof(char)));
162 
163     switch (nodetype) {
164     case NODE_H:
165         hptr = newptr;
166         string_offsetptr = hptr->string;
167         break;
168     case NODE_U:
169         uptr = newptr;
170         string_offsetptr = uptr->string;
171         break;
172     case NODE_R:
173         rptr = newptr;
174         string_offsetptr = rptr->string;
175         break;
176     case NODE_A:
177         aptr = newptr;
178         string_offsetptr = aptr->string;
179         break;
180     case NODE_S:
181         sptr = newptr;
182         string_offsetptr = sptr->string;
183         break;
184     case NODE_I:
185         iptr = newptr;
186         string_offsetptr = iptr->string;
187         break;
188     case NODE_SEG:
189         gptr = newptr;
190         string_offsetptr = gptr->string;
191         break;
192     default:
193         exit(1);                                /* FIXME! */
194     }
195 
196     memcpy(string_offsetptr, str, len);
197 //    if (nodetype == NODE_SEG) {
198 //        ERRVPRINT(0, "SEG: %s --> %s\n", str, gptr->string);
199 //    }
200 
201     return newptr;
202 }
203 
204 
205 /************************************************************************
206  * put_hnode                                                            *
207  *                                                                      *
208  * insert/update host node                                              *
209  *                                                                      *
210  * Arguments:                                                           *
211  * char *str:               Hostname                                    *
212  * int type:                obj type                                    *
213  * unsigned long count:     hit count                                   *
214  * unsigned long file:      File flag                                   *
215  * unsigned long long xfer: xfer size                                   *
216  * unsigned long *ctr:      counter                                     *
217  * unsigned long visit:     visits                                      *
218  * unsigned long page:      pages                                       *
219  * unsigned long tstamp:    timestamp                                   *
220  * char *url:               Current URL                                 *
221  * char *lasturl:           lasturl                                     *
222  * HNODEPTR * htab:         Host Hash Table                             *
223  * bool lasturl_is_entry:   TRUE if the last URL is an entry page.      *
224  *                            Only used for creating a new node from    *
225  *                            preserve/restore                          *
226  * bool isapage:            Is a Page Y/N                               *
227  * bool *isnewsite                                                      *
228  *                                                                      *
229  *   ---------------------------------------------------------------    *
230  * if visit > 0; then this is a "load" event from preserve.c            *
231  *   OR is a CreateGroup event from output.c                            *
232  *                                                                      *
233  * Returns:                                                             *
234  * 0 on Success, 1 on Failure                                           *
235  ************************************************************************/
236 int
put_hnode(char * str,int type,unsigned long count,unsigned long file,unsigned long long xfer,unsigned long * ctr,unsigned long visit,unsigned long page,unsigned long tstamp,char * url,char * lasturl,HNODEPTR * htab,bool lasturl_is_entry,bool isapage,bool * isnewsite)237 put_hnode(char *str,
238           int type,
239           unsigned long count,
240           unsigned long file,
241           unsigned long long xfer,
242           unsigned long *ctr,
243           unsigned long visit, unsigned long page, unsigned long tstamp, char *url, char *lasturl, HNODEPTR * htab, bool lasturl_is_entry, bool isapage, bool * isnewsite)
244 {
245     HNODEPTR cptr, nptr = NULL, prev_cptr = NULL;
246     size_t len;
247 
248     len = check_hashstr_size(str, NODE_H);
249     cptr = htab[hash(str)];
250     while (cptr != NULL) {
251         if (strncmp(cptr->string, str, MAXHOST) == 0) {
252             if ((type == cptr->flag) || ((type != OBJ_GRP) && (cptr->flag != OBJ_GRP))) {
253                 /* found... bump counters */
254                 cptr->count += count;
255                 cptr->files += file;
256                 cptr->xfer += xfer;
257                 cptr->pages += page;
258                 if (type == OBJ_GRP) {
259                     /* Updating a group */
260                     cptr->visit += visit;
261                 } else if (isapage) {
262                     if ((tstamp - cptr->tstamp) >= g_settings.settings.visit_timeout) {
263                         /* Is a new Visit */
264                         cptr->visit++;
265                         /* ONLY! Update entry/exit if working with Monthly table */
266                         if (htab == sm_htab) {
267                             update_exit(cptr->lasturl, cptr->lasturl_is_entry);
268                             update_entry(url);
269                             cptr->lasturl_is_entry = true;
270                             cptr->lasturl = find_url(url);
271                         }
272                     } else {                    /* Still in same visit */
273                         if (htab == sm_htab) {
274                             cptr->lasturl_is_entry = false;
275                             cptr->lasturl = find_url(url);
276                         }
277                     }
278                     /* Either way, update the last timestamp for this visit - we have a page! */
279                     cptr->tstamp = tstamp;
280                 }
281                 return 0;
282             }
283         }
284         prev_cptr = cptr;
285         cptr = cptr->next;
286     }
287     /* Failed to Hash, or doesn't already exist */
288     if ((nptr = new_node(str, NODE_H, len)) != NULL) {
289         nptr->flag = type;
290         nptr->count = count;
291         nptr->files = file;
292         nptr->xfer = xfer;
293         nptr->pages = page;
294         nptr->next = NULL;
295         nptr->lasturl = blank_str;
296         nptr->lasturl_is_entry = lasturl_is_entry;
297         if (prev_cptr != NULL) {
298             prev_cptr->next = nptr;
299         } else {
300             htab[hash(str)] = nptr;
301         }
302         if (type != OBJ_GRP) {
303             (*ctr)++;
304             if (!*isnewsite) {
305                 *isnewsite = true;
306             }
307         }
308         if (visit) {
309             nptr->visit = visit;
310             if (type != OBJ_GRP) {
311                 nptr->lasturl = find_url(lasturl);
312                 nptr->tstamp = tstamp;
313             }
314             return 0;
315         } else {
316             if (isapage) {
317                 /* ONLY! Update entry/exit if working with Monthly table */
318                 if (htab == sm_htab) {
319                     update_entry(url);
320                     nptr->lasturl = find_url(url);
321                     nptr->lasturl_is_entry = true;
322                 }
323                 nptr->tstamp = tstamp;
324                 nptr->visit = 1;
325             }
326         }
327     }
328     return nptr == NULL;
329 }
330 
331 
332 /*********************************************/
333 /* PUT_UNODE - insert/update URL node        */
334 /*********************************************/
335 int
put_unode(char * str,int type,unsigned long count,unsigned long long xfer,unsigned long * ctr,unsigned long entry_page_ctr,unsigned long exit_page_ctr,unsigned long single_access,int resp_code,UNODEPTR * htab)336 put_unode(char *str,                            /* Hostname  */
337           int type,                             /* obj type  */
338           unsigned long count,                  /* hit count */
339           unsigned long long xfer,              /* xfer size */
340           unsigned long *ctr,                   /* counter   */
341           unsigned long entry_page_ctr,         /* Entry Page Counter */
342           unsigned long exit_page_ctr,          /* Exit Page Counter */
343           unsigned long single_access,          /* Single Access Counter */
344           int resp_code, UNODEPTR * htab)
345 {
346     UNODEPTR cptr, nptr = NULL, prev_cptr = NULL;
347     size_t len;
348 
349     /* Ignore "Empty/Null" URL's */
350     if (str[0] == '-') {
351         return 0;
352     }
353 
354     len = check_hashstr_size(str, NODE_U);
355     cptr = htab[hash(str)];
356     while (cptr != NULL) {
357         if (strcmp(cptr->string, str) == 0) {
358             if ((type == cptr->flag) || ((type != OBJ_GRP) && (cptr->flag != OBJ_GRP))) {
359                 /* found... bump counters */
360                 if (resp_code == RC_PARTIALCONTENT) {
361                     cptr->pcount += count;
362                     cptr->pxfer += xfer;
363                     g_counters.month.partial_hit += count;
364                     g_counters.month.partial_vol += xfer;
365                 } else {
366                     cptr->count += count;
367                     cptr->xfer += xfer;
368                 }
369                 return 0;
370             }
371         }
372         prev_cptr = cptr;
373         cptr = cptr->next;
374     }
375     /* Failed to Hash, or doesn't already exist */
376     if ((nptr = new_node(str, NODE_U, len)) != NULL) {
377         nptr->flag = type;
378         if (resp_code == RC_PARTIALCONTENT) {
379             nptr->count = 0;
380             nptr->xfer = 0;
381             nptr->pcount = count;
382             nptr->pxfer = xfer;
383             g_counters.month.partial_hit += count;
384             g_counters.month.partial_vol += xfer;
385         } else {
386             nptr->count = count;
387             nptr->xfer = xfer;
388             nptr->pcount = 0;
389             nptr->pxfer = 0;
390         }
391         nptr->next = NULL;
392         nptr->entry = entry_page_ctr;
393         nptr->exit = exit_page_ctr;
394         nptr->single_access = single_access;
395         if (prev_cptr != NULL) {
396             prev_cptr->next = nptr;
397         } else {
398             htab[hash(str)] = nptr;
399         }
400         if (type != OBJ_GRP) {
401             (*ctr)++;
402         }
403     }
404     return nptr == NULL;
405 }
406 
407 
408 /*********************************************/
409 /* PUT_RNODE - insert/update referrer node   */
410 /*********************************************/
411 int
put_rnode(char * str,int type,unsigned long count,unsigned long * ctr,RNODEPTR * htab)412 put_rnode(char *str, int type, unsigned long count, unsigned long *ctr, RNODEPTR * htab)
413 {
414     RNODEPTR cptr, nptr = NULL, prev_cptr = NULL;
415     size_t len;
416 
417     /* Ignore "Empty/Null" URL's */
418     if (str[0] == '-' && str[1] == '\0') {
419         strcpy(str, "- (Direct Request)");
420     }
421 
422     len = check_hashstr_size(str, NODE_R);
423     cptr = htab[hash(str)];
424     while (cptr != NULL) {
425         if (strcmp(cptr->string, str) == 0) {
426             if ((type == cptr->flag) || ((type != OBJ_GRP) && (cptr->flag != OBJ_GRP))) {
427                 /* found... bump counter */
428                 cptr->count += count;
429                 return 0;
430             }
431         }
432         prev_cptr = cptr;
433         cptr = cptr->next;
434     }
435     if ((nptr = new_node(str, NODE_R, len)) != NULL) {
436         nptr->flag = type;
437         nptr->count = count;
438         nptr->next = NULL;
439         if (prev_cptr != NULL) {
440             prev_cptr->next = nptr;
441         } else {
442             htab[hash(str)] = nptr;
443         }
444         if (type != OBJ_GRP) {
445             (*ctr)++;
446         }
447     }
448     return nptr == NULL;
449 }
450 
451 
452 /*********************************************/
453 /* PUT_ANODE - insert/update user agent node */
454 /*********************************************/
455 int
put_anode(char * str,int type,unsigned long count,unsigned long * ctr,ANODEPTR * htab)456 put_anode(char *str, int type, unsigned long count, unsigned long *ctr, ANODEPTR * htab)
457 {
458     ANODEPTR cptr, nptr = NULL, prev_cptr = NULL;
459     size_t len;
460 
461     /* skip bad user agents */
462     if (str[0] == '-') {
463         return 0;
464     }
465 
466     len = check_hashstr_size(str, NODE_A);
467     cptr = htab[hash(str)];
468     while (cptr != NULL) {
469         if (strcmp(cptr->string, str) == 0) {
470             if ((type == cptr->flag) || ((type != OBJ_GRP) && (cptr->flag != OBJ_GRP))) {
471                 /* found... bump counter */
472                 cptr->count += count;
473                 return 0;
474             }
475         }
476         prev_cptr = cptr;
477         cptr = cptr->next;
478     }
479     if ((nptr = new_node(str, NODE_A, len)) != NULL) {
480         nptr->flag = type;
481         nptr->count = count;
482         nptr->next = NULL;
483         if (prev_cptr != NULL) {
484             prev_cptr->next = nptr;
485         } else {
486             htab[hash(str)] = nptr;
487         }
488         if (type != OBJ_GRP) {
489             (*ctr)++;
490         }
491     }
492     return nptr == NULL;
493 }
494 
495 
496 /*********************************************/
497 /* PUT_SNODE - insert/update search str node */
498 /*********************************************/
499 int
put_snode(char * str,unsigned long count,SNODEPTR * htab)500 put_snode(char *str, unsigned long count, SNODEPTR * htab)
501 {
502     SNODEPTR cptr, nptr = NULL, prev_cptr = NULL;
503     size_t len;
504 
505     /* skip bad search strs */
506     if (str[0] == '\0' || str[0] == ' ') {
507         return 0;
508     }
509 
510     len = check_hashstr_size(str, NODE_S);
511     cptr = htab[hash(str)];
512     while (cptr != NULL) {
513         if (strcmp(cptr->string, str) == 0) {
514             /* found... bump counter */
515             cptr->count += count;
516             return 0;
517         }
518         prev_cptr = cptr;
519         cptr = cptr->next;
520     }
521     if ((nptr = new_node(str, NODE_S, len)) != NULL) {
522         nptr->count = count;
523         nptr->next = NULL;
524         if (prev_cptr != NULL) {
525             prev_cptr->next = nptr;
526         } else {
527             htab[hash(str)] = nptr;
528         }
529     }
530     return nptr == NULL;
531 }
532 
533 
534 /*********************************************/
535 /* PUT_INODE - insert/update ident node      */
536 /*********************************************/
537 int
put_inode(char * str,int type,unsigned long count,unsigned long file,unsigned long long xfer,unsigned long * ctr,unsigned long visit,unsigned long tstamp,INODEPTR * htab,bool isapage)538 put_inode(char *str,                            /* ident str */
539           int type,                             /* obj type  */
540           unsigned long count,                  /* hit count */
541           unsigned long file,                   /* File flag */
542           unsigned long long xfer,              /* xfer size */
543           unsigned long *ctr,                   /* counter   */
544           unsigned long visit,                  /* visits    */
545           unsigned long tstamp,                 /* timestamp */
546           INODEPTR * htab, bool isapage)
547 {                                               /* hashtable */
548     INODEPTR cptr, nptr = NULL, prev_cptr = NULL;
549     size_t len;
550 
551     /* skip if no username */
552     if ((str[0] == '-') || (str[0] == '\0')) {
553         return 0;
554     }
555 
556     len = check_hashstr_size(str, NODE_I);
557     cptr = htab[hash(str)];
558     while (cptr != NULL) {
559         if (strcmp(cptr->string, str) == 0) {
560             if ((type == cptr->flag) || ((type != OBJ_GRP) && (cptr->flag != OBJ_GRP))) {
561                 /* found... bump counter */
562                 cptr->count += count;
563                 cptr->files += file;
564                 cptr->xfer += xfer;
565                 if (type == OBJ_GRP) {
566                     /* Updating a group */
567                     cptr->visit += visit;
568                 } else if (isapage) {
569                     if ((tstamp - cptr->tstamp) >= g_settings.settings.visit_timeout) {
570                         /* Is a new Visit */
571                         cptr->visit++;
572                     }
573                     /* Either way, update the last timestamp for this visit - we have a page! */
574                     cptr->tstamp = tstamp;
575                 }
576                 return 0;
577             }
578         }
579         prev_cptr = cptr;
580         cptr = cptr->next;
581     }
582     if ((nptr = new_node(str, NODE_I, len)) != NULL) {
583         nptr->flag = type;
584         nptr->count = count;
585         nptr->files = file;
586         nptr->xfer = xfer;
587         nptr->next = NULL;
588         if (prev_cptr != NULL) {
589             prev_cptr->next = nptr;
590         } else {
591             htab[hash(str)] = nptr;
592         }
593         if (type != OBJ_GRP) {
594             (*ctr)++;
595         }
596         if (visit) {
597             nptr->visit = visit;
598             if (type != OBJ_GRP) {
599                 /* Don't update timestamp for groups */
600                 nptr->tstamp = tstamp;
601             }
602             return 0;
603         } else {
604             if (isapage) {
605                 nptr->tstamp = tstamp;
606                 nptr->visit = 1;
607             }
608         }
609     }
610     return nptr == NULL;
611 }
612 
613 
614 /*********************************************/
615 /* NEW_ENODE - create errorpage node         */
616 /*********************************************/
617 
618 ENODEPTR
new_enode(char * url,char * refer)619 new_enode(char *url,                            /* url str   */
620           char *refer)
621 {                                               /* my referer */
622     ENODEPTR newptr;
623     char *url_ptr, *ref_ptr, *key_ptr;
624     size_t len_url = strlen(url);
625     size_t len_ref = strlen(refer);
626 
627     if (len_url >= MAXURL) {
628         ERRVPRINT(VERBOSE1, "[new_enode] %s (%d)\n", _("Warning: String exceeds storage size"), (int) len_url);
629         ERRVPRINT(VERBOSE3, "  --> %s\n", url);
630         url[MAXURL - 1] = 0;
631         len_url = MAXURL - 1;
632     }
633 
634     url_ptr = XMALLOC(char, len_url + 1);
635 
636     memcpy(url_ptr, url, len_url);
637 
638     if (len_ref >= MAXURL) {
639         ERRVPRINT(VERBOSE1, "[new_enode:referer] %s (%d)\n", _("Warning: String exceeds storage size"), (int) len_ref);
640         ERRVPRINT(VERBOSE3, "  --> %s\n", refer);
641         refer[MAXURL - 1] = 0;
642         len_ref = MAXURL - 1;
643     }
644 
645     ref_ptr = XMALLOC(char, len_ref + 1);
646 
647     memcpy(ref_ptr, refer, len_ref);
648 
649     /* Hash key can be sized MAXURL x 2 */
650     key_ptr = XMALLOC(char, len_url + len_ref + 1);
651 
652     memcpy(key_ptr, url, len_url);
653     strncat(key_ptr, refer, len_ref);
654 
655     newptr = XMALLOC(struct enode, 1);
656 
657     newptr->error_request = key_ptr;
658     newptr->url = url_ptr;
659     newptr->referer = ref_ptr;
660     newptr->count = 1;
661     newptr->next = NULL;
662     return newptr;
663 }
664 
665 /*********************************************/
666 /* PUT_ENODE - insert/update error node      */
667 /*********************************************/
668 int
put_enode(char * url,char * refer,int type,unsigned long count,unsigned long * ctr,ENODEPTR * htab)669 put_enode(char *url,                            /* url str   */
670           char *refer,                          /* my referer */
671           int type,                             /* obj type  */
672           unsigned long count,                  /* hit count */
673           unsigned long *ctr,                   /* counter   */
674           ENODEPTR * htab)
675 {                                               /* hashtable */
676     ENODEPTR cptr, nptr;
677     char *key_ptr;
678     size_t len_url = strlen(url);
679     size_t len_ref = strlen(refer);
680     unsigned long hash_val;
681 
682     key_ptr = XMALLOC(char, len_url + len_ref + 1);
683 
684     memcpy(key_ptr, url, len_url);
685     strncat(key_ptr, refer, len_ref);
686 
687     hash_val = hash(key_ptr);
688     /* check if hashed */
689     if ((cptr = htab[hash_val]) == NULL) {
690         /* not hashed */
691         if ((nptr = new_enode(url, refer)) != NULL) {
692             nptr->next = NULL;
693             htab[hash_val] = nptr;
694             (*ctr)++;
695             nptr->count = count;
696             XFREE(key_ptr);
697             return 0;
698         }
699     } else {
700         /* hashed */
701         while (cptr != NULL) {
702             if (strcmp(cptr->error_request, key_ptr) == 0) {
703                 /* found... bump counter */
704                 cptr->count += count;
705                 XFREE(key_ptr);
706                 return 0;
707             }
708             cptr = cptr->next;
709         }
710         /* not found... */
711         if ((nptr = new_enode(url, refer)) != NULL) {
712             nptr->next = htab[hash_val];
713             htab[hash_val] = nptr;
714             (*ctr)++;
715         }
716     }
717 
718     XFREE(key_ptr);
719     return nptr == NULL;
720 }
721 
722 
723 /*********************************************/
724 /* PUT_SEGNODE - insert/update segmenting ID node */
725 /*********************************************/
726 unsigned long
put_segnode(char * str,unsigned long new_tstamp,SEGNODEPTR * htab)727 put_segnode(char *str, unsigned long new_tstamp, SEGNODEPTR * htab)
728 {
729     SEGNODEPTR cptr, nptr = NULL, prev_cptr = NULL;
730     unsigned long old_tstamp = 0;
731     size_t len;
732 
733     len = check_hashstr_size(str, NODE_SEG);
734     cptr = htab[hash(str)];
735     while (cptr != NULL) {
736         if (strcmp(cptr->string, str) == 0) {
737             /* found */
738             old_tstamp = cptr->tstamp;
739             cptr->tstamp = new_tstamp;
740             return (old_tstamp);
741         }
742         prev_cptr = cptr;
743         cptr = cptr->next;
744     }
745     if ((nptr = new_node(str, NODE_SEG, len)) != NULL) {
746         nptr->next = NULL;
747         old_tstamp = new_tstamp;
748         nptr->tstamp = new_tstamp;
749         if (prev_cptr != NULL) {
750             prev_cptr->next = nptr;
751         } else {
752             htab[hash(str)] = nptr;
753         }
754 //        ERRVPRINT(0, "Leaving\n");
755     }
756     return (old_tstamp);
757 }
758 
759 
760 /* Return the timestamp when found */
761 unsigned long
get_segnode(char * str,SEGNODEPTR * htab)762 get_segnode(char *str, SEGNODEPTR * htab)
763 {
764     SEGNODEPTR cptr;
765 
766     check_hashstr_size(str, NODE_SEG);
767     cptr = htab[hash(str)];
768     while (cptr != NULL) {
769         if (strcmp(cptr->string, str) == 0) {
770             /* found */
771             return (cptr->tstamp);
772         }
773         cptr = cptr->next;
774     }
775     return (0);
776 }
777 
778 
779 /* Return 1 on success */
780 int
remove_segnode(char * str,SEGNODEPTR * htab)781 remove_segnode(char *str, SEGNODEPTR * htab)
782 {
783     SEGNODEPTR cptr, prev_cptr = NULL, next_cptr = NULL;
784 
785     check_hashstr_size(str, NODE_SEG);
786     cptr = htab[hash(str)];
787     while (cptr != NULL) {
788         if (strcmp(cptr->string, str) == 0) {
789             /* found */
790             next_cptr = cptr->next;
791             free(cptr);
792             if (prev_cptr == NULL) {
793                 htab[hash(str)] = NULL;
794             } else {
795                 prev_cptr->next = next_cptr;
796             }
797             return (1);
798         }
799         prev_cptr = cptr;
800         cptr = cptr->next;
801     }
802     return (0);
803 }
804 
805 
806 /* Remove all old visits from a given segmenting hash table. */
807 void
segment_htab_cleanup(SEGNODEPTR * htab)808 segment_htab_cleanup(SEGNODEPTR * htab)
809 {
810     SEGNODEPTR cptr, prev_cptr, next_cptr;
811     unsigned int i;
812 
813     for (i = 0; i < MAXHASH; i++) {
814         cptr = htab[i];
815         prev_cptr = NULL;
816         next_cptr = NULL;
817         while (cptr != NULL) {
818             if ((cur_tstamp - cptr->tstamp) >= g_settings.settings.visit_timeout) {
819                 /* Is now an "old" Visit? Throw away. */
820                 next_cptr = cptr->next;
821                 free(cptr);
822                 if (prev_cptr == NULL) {
823                     htab[i] = NULL;
824                 } else {
825                     prev_cptr->next = next_cptr;
826                 }
827                 break;
828             }
829             prev_cptr = cptr;
830             cptr = cptr->next;
831         }
832     }
833 }
834 
835 
836 /*********************************************/
837 /* HASH - return hash value for string       */
838 /*********************************************/
839 unsigned long
hash(char * str)840 hash(char *str)
841 {
842     unsigned long hashval = MAXHASH;
843 
844     while (*str != '\0') {
845         hashval = (hashval << 5) + hashval + *str;
846         str++;
847     }
848     return hashval % MAXHASH;
849 }
850 
851 
852 /*********************************************/
853 /* FIND_URL - Find URL in hash table         */
854 /*********************************************/
855 char *
find_url(char * str)856 find_url(char *str)
857 {
858     UNODEPTR cptr;
859 
860     if ((cptr = um_htab[hash(str)]) != NULL) {
861         while (cptr != NULL) {
862             if (strcmp(cptr->string, str) == 0)
863                 return cptr->string;
864             cptr = cptr->next;
865         }
866     }
867     return blank_str;                           /* shouldn't get here */
868 }
869 
870 
871 /*********************************************/
872 /* UPDATE_ENTRY - update entry page total    */
873 /*********************************************/
874 void
update_entry(char * str)875 update_entry(char *str)
876 {
877     UNODEPTR uptr;
878 
879     if (str == NULL)
880         return;
881     if ((uptr = um_htab[hash(str)]) == NULL)
882         return;
883     else {
884         while (uptr != NULL) {
885             if (strcmp(uptr->string, str) == 0) {
886                 if (uptr->flag != OBJ_GRP) {
887                     uptr->entry++;
888                     return;
889                 }
890             }
891             uptr = uptr->next;
892         }
893     }
894 }
895 
896 
897 /*********************************************/
898 /* UPDATE_EXIT  - update exit page total     */
899 /*********************************************/
900 void
update_exit(char * str,bool is_single_access)901 update_exit(char *str, bool is_single_access)
902 {
903     UNODEPTR uptr;
904 
905     if (str == NULL)
906         return;
907     if ((uptr = um_htab[hash(str)]) == NULL)
908         return;
909     else {
910         while (uptr != NULL) {
911             if (strcmp(uptr->string, str) == 0) {
912                 if (uptr->flag != OBJ_GRP) {
913                     uptr->exit++;
914                     if (is_single_access) {
915                         uptr->single_access++;
916                     }
917                     return;
918                 }
919             }
920             uptr = uptr->next;
921         }
922     }
923 }
924 
925 
926 /*********************************************/
927 /* MONTH_UPDATE_EXIT  - eom exit page update */
928 /*********************************************/
929 void
month_update_exit(unsigned long tstamp)930 month_update_exit(unsigned long tstamp)
931 {
932     HNODEPTR nptr;
933     int i;
934 
935     for (i = 0; i < MAXHASH; i++) {
936         nptr = sm_htab[i];
937         while (nptr != NULL) {
938             if (nptr->flag != OBJ_GRP) {
939                 if ((tstamp - nptr->tstamp) >= g_settings.settings.visit_timeout) {
940                     /* End of month, update all "still open" sessions; and count as closed sessions that would be expired */
941                     update_exit(nptr->lasturl, nptr->lasturl_is_entry);
942                 }
943             }
944             nptr = nptr->next;
945         }
946     }
947 }
948 
949 
950 /*********************************************/
951 /* TOT_VISIT - calculate total visits        */
952 /*********************************************/
953 unsigned long
tot_visit(HNODEPTR * list)954 tot_visit(HNODEPTR * list)
955 {
956     HNODEPTR hptr;
957     unsigned long tot = 0;
958     int i;
959 
960     for (i = 0; i < MAXHASH; i++) {
961         hptr = list[i];
962         while (hptr != NULL) {
963             if (hptr->flag != OBJ_GRP) {
964                 tot += hptr->visit;
965             }
966             hptr = hptr->next;
967         }
968     }
969     return tot;
970 }
971 
972 
973 /* DEL_HLIST - delete host hash table        */
974 void
del_hlist(HNODEPTR * htab)975 del_hlist(HNODEPTR * htab)
976 {
977     del_htab((NODEPTR *) htab, "hlist", MAXHASH, (void (*)(NODEPTR)) free);
978 }
979 
980 /* DEL_ULIST - delete URL hash table         */
981 void
del_ulist(UNODEPTR * htab)982 del_ulist(UNODEPTR * htab)
983 {
984     del_htab((NODEPTR *) htab, "ulist", MAXHASH, (void (*)(NODEPTR)) free);
985 }
986 
987 /* DEL_RLIST - delete referrer hash table    */
988 void
del_rlist(RNODEPTR * htab)989 del_rlist(RNODEPTR * htab)
990 {
991     del_htab((NODEPTR *) htab, "rlist", MAXHASH, (void (*)(NODEPTR)) free);
992 }
993 
994 /* DEL_ALIST - delete user agent hash table  */
995 void
del_alist(ANODEPTR * htab)996 del_alist(ANODEPTR * htab)
997 {
998     del_htab((NODEPTR *) htab, "alist", MAXHASH, (void (*)(NODEPTR)) free);
999 }
1000 
1001 /* DEL_SLIST - delete search str hash table  */
1002 void
del_slist(SNODEPTR * htab)1003 del_slist(SNODEPTR * htab)
1004 {
1005     del_htab((NODEPTR *) htab, "slist", MAXHASH, (void (*)(NODEPTR)) free);
1006 }
1007 
1008 /* DEL_ILIST - delete ident hash table       */
1009 void
del_ilist(INODEPTR * htab)1010 del_ilist(INODEPTR * htab)
1011 {
1012     del_htab((NODEPTR *) htab, "ilist", MAXHASH, (void (*)(NODEPTR)) free);
1013 }
1014 
1015 /* DEL_ELIST - delete errorpage hash table   */
1016 void
free_ENODEPTR(ENODEPTR ptr)1017 free_ENODEPTR(ENODEPTR ptr)
1018 {
1019     XFREE(ptr->error_request);
1020     XFREE(ptr->referer);
1021     XFREE(ptr->url);
1022     XFREE(ptr);
1023 }
1024 
1025 void
del_elist(ENODEPTR * htab)1026 del_elist(ENODEPTR * htab)
1027 {
1028     del_htab((NODEPTR *) htab, "elist", MAXHASH, (void (*)(NODEPTR)) free_ENODEPTR);
1029 }
1030 
1031 
1032 /*********************************************
1033  * del_htab - Generic delete all hash table entries
1034  *********************************************/
1035 void
del_htab(NODEPTR * htab,const char * htab_name,size_t size,void (* free_node)(NODEPTR))1036 del_htab(NODEPTR * htab, const char *htab_name, size_t size, void (*free_node) (NODEPTR))
1037 {
1038     unsigned long long count = 0;
1039     unsigned long long maxdeep = 1;
1040     unsigned long long deep = 0;
1041     size_t i;
1042 
1043     for (i = 0; i != size; ++i) {
1044         if (htab[i]) {
1045             NODEPTR node = htab[i];
1046 
1047             deep = 1;
1048             while (node) {
1049                 NODEPTR next = node->next;
1050 
1051                 free_node(node);
1052                 node = next;
1053                 count++;
1054                 deep++;
1055             }
1056             if (deep > maxdeep) {
1057                 maxdeep = deep;
1058             }
1059             htab[i] = NULL;
1060         }
1061     }
1062     if (count == 0) {
1063         maxdeep = 0;
1064     }
1065     VPRINT(VERBOSE2, "htab#%s freed %7llu nodes; Max Depth: %llu\n", htab_name, count, maxdeep);
1066 }
1067 
1068 /************************************************************************
1069  ************************************************************************
1070  *                      END OF FILE                                     *
1071  ************************************************************************/
1072