/[svn]/ircd-hybrid-7.2/src/hash.c
ViewVC logotype

Annotation of /ircd-hybrid-7.2/src/hash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 982 - (hide annotations)
Thu Aug 13 22:15:08 2009 UTC (10 years, 10 months ago) by michael
File MIME type: text/x-chdr
File size: 22907 byte(s)
- added a mersenne twister basedn prng

1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * hash.c: Maintains hashtables.
4     *
5     * Copyright (C) 2002 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26     #include "tools.h"
27     #include "s_conf.h"
28     #include "channel.h"
29     #include "channel_mode.h"
30     #include "client.h"
31     #include "common.h"
32     #include "handlers.h"
33     #include "list.h"
34     #include "modules.h"
35     #include "hash.h"
36     #include "resv.h"
37 michael 982 #include "rng_mt.h"
38 adx 30 #include "userhost.h"
39     #include "irc_string.h"
40     #include "ircd.h"
41     #include "numeric.h"
42     #include "send.h"
43     #include "memory.h"
44     #include "dbuf.h"
45     #include "s_user.h"
46    
47    
48     static BlockHeap *userhost_heap = NULL;
49     static BlockHeap *namehost_heap = NULL;
50     static struct UserHost *find_or_add_userhost(const char *);
51    
52 michael 982 static unsigned int hashf_xor_key = 0;
53 adx 30
54     /* The actual hash tables, They MUST be of the same HASHSIZE, variable
55     * size tables could be supported but the rehash routine should also
56     * rebuild the transformation maps, I kept the tables of equal size
57     * so that I can use one hash function.
58     */
59     static struct Client *idTable[HASHSIZE];
60     static struct Client *clientTable[HASHSIZE];
61     static struct Channel *channelTable[HASHSIZE];
62     static struct UserHost *userhostTable[HASHSIZE];
63     static struct ResvChannel *resvchannelTable[HASHSIZE];
64    
65    
66     /* init_hash()
67     *
68     * inputs - NONE
69     * output - NONE
70     * side effects - Initialize the maps used by hash
71     * functions and clear the tables
72     */
73     void
74     init_hash(void)
75     {
76     unsigned int i;
77    
78     /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now,
79     * should be a good close approximation anyway
80     * - Dianora
81     */
82     userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE);
83     namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE);
84    
85 michael 982 hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
86 adx 30
87     /* Clear the hash tables first */
88     for (i = 0; i < HASHSIZE; ++i)
89     {
90     idTable[i] = NULL;
91     clientTable[i] = NULL;
92     channelTable[i] = NULL;
93     userhostTable[i] = NULL;
94     resvchannelTable[i] = NULL;
95     }
96     }
97    
98     /*
99     * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from
100     * http://www.isthe.com/chongo/tech/comp/fnv/
101     *
102     * Here, we use the FNV-1 method, which gives slightly better results
103     * than FNV-1a. -Michael
104     */
105     unsigned int
106     strhash(const char *name)
107     {
108     const unsigned char *p = (const unsigned char *)name;
109     unsigned int hval = FNV1_32_INIT;
110    
111     if (*p == '\0')
112     return 0;
113     for (; *p != '\0'; ++p)
114     {
115     hval += (hval << 1) + (hval << 4) + (hval << 7) +
116     (hval << 8) + (hval << 24);
117 michael 982 hval ^= (ToLower(*p) ^ hashf_xor_key);
118 adx 30 }
119    
120 michael 982 return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
121 adx 30 }
122    
123     /************************** Externally visible functions ********************/
124    
125     /* Optimization note: in these functions I supposed that the CSE optimization
126     * (Common Subexpression Elimination) does its work decently, this means that
127     * I avoided introducing new variables to do the work myself and I did let
128     * the optimizer play with more free registers, actual tests proved this
129     * solution to be faster than doing things like tmp2=tmp->hnext... and then
130     * use tmp2 myself which would have given less freedom to the optimizer.
131     */
132    
133     /* hash_add_client()
134     *
135     * inputs - pointer to client
136     * output - NONE
137     * side effects - Adds a client's name in the proper hash linked
138     * list, can't fail, client_p must have a non-null
139     * name or expect a coredump, the name is infact
140     * taken from client_p->name
141     */
142     void
143     hash_add_client(struct Client *client_p)
144     {
145     unsigned int hashv = strhash(client_p->name);
146    
147     client_p->hnext = clientTable[hashv];
148     clientTable[hashv] = client_p;
149     }
150    
151     /* hash_add_channel()
152     *
153     * inputs - pointer to channel
154     * output - NONE
155     * side effects - Adds a channel's name in the proper hash linked
156     * list, can't fail. chptr must have a non-null name
157     * or expect a coredump. As before the name is taken
158     * from chptr->name, we do hash its entire lenght
159     * since this proved to be statistically faster
160     */
161     void
162     hash_add_channel(struct Channel *chptr)
163     {
164     unsigned int hashv = strhash(chptr->chname);
165    
166     chptr->hnextch = channelTable[hashv];
167     channelTable[hashv] = chptr;
168     }
169    
170     void
171     hash_add_resv(struct ResvChannel *chptr)
172     {
173     unsigned int hashv = strhash(chptr->name);
174    
175     chptr->hnext = resvchannelTable[hashv];
176     resvchannelTable[hashv] = chptr;
177     }
178    
179     void
180     hash_add_userhost(struct UserHost *userhost)
181     {
182     unsigned int hashv = strhash(userhost->host);
183    
184     userhost->next = userhostTable[hashv];
185     userhostTable[hashv] = userhost;
186     }
187    
188     void
189     hash_add_id(struct Client *client_p)
190     {
191     unsigned int hashv = strhash(client_p->id);
192    
193     client_p->idhnext = idTable[hashv];
194     idTable[hashv] = client_p;
195     }
196    
197     /* hash_del_id()
198     *
199     * inputs - pointer to client
200     * output - NONE
201     * side effects - Removes an ID from the hash linked list
202     */
203     void
204     hash_del_id(struct Client *client_p)
205     {
206     unsigned int hashv = strhash(client_p->id);
207     struct Client *tmp = idTable[hashv];
208    
209     if (tmp != NULL)
210     {
211     if (tmp == client_p)
212     {
213     idTable[hashv] = client_p->idhnext;
214     client_p->idhnext = client_p;
215     }
216     else
217     {
218     while (tmp->idhnext != client_p)
219     {
220     if ((tmp = tmp->idhnext) == NULL)
221     return;
222     }
223    
224     tmp->idhnext = tmp->idhnext->idhnext;
225     client_p->idhnext = client_p;
226     }
227     }
228     }
229    
230     /* hash_del_client()
231     *
232     * inputs - pointer to client
233     * output - NONE
234     * side effects - Removes a Client's name from the hash linked list
235     */
236     void
237     hash_del_client(struct Client *client_p)
238     {
239     unsigned int hashv = strhash(client_p->name);
240     struct Client *tmp = clientTable[hashv];
241    
242     if (tmp != NULL)
243     {
244     if (tmp == client_p)
245     {
246     clientTable[hashv] = client_p->hnext;
247     client_p->hnext = client_p;
248     }
249     else
250     {
251     while (tmp->hnext != client_p)
252     {
253     if ((tmp = tmp->hnext) == NULL)
254     return;
255     }
256    
257     tmp->hnext = tmp->hnext->hnext;
258     client_p->hnext = client_p;
259     }
260     }
261     }
262    
263     /* hash_del_userhost()
264     *
265     * inputs - pointer to userhost
266     * output - NONE
267     * side effects - Removes a userhost from the hash linked list
268     */
269     void
270     hash_del_userhost(struct UserHost *userhost)
271     {
272     unsigned int hashv = strhash(userhost->host);
273     struct UserHost *tmp = userhostTable[hashv];
274    
275     if (tmp != NULL)
276     {
277     if (tmp == userhost)
278     {
279     userhostTable[hashv] = userhost->next;
280     userhost->next = userhost;
281     }
282     else
283     {
284     while (tmp->next != userhost)
285     {
286     if ((tmp = tmp->next) == NULL)
287     return;
288     }
289    
290     tmp->next = tmp->next->next;
291     userhost->next = userhost;
292     }
293     }
294     }
295    
296     /* hash_del_channel()
297     *
298     * inputs - pointer to client
299     * output - NONE
300     * side effects - Removes the channel's name from the corresponding
301     * hash linked list
302     */
303     void
304     hash_del_channel(struct Channel *chptr)
305     {
306     unsigned int hashv = strhash(chptr->chname);
307     struct Channel *tmp = channelTable[hashv];
308    
309     if (tmp != NULL)
310     {
311     if (tmp == chptr)
312     {
313     channelTable[hashv] = chptr->hnextch;
314     chptr->hnextch = chptr;
315     }
316     else
317     {
318     while (tmp->hnextch != chptr)
319     {
320     if ((tmp = tmp->hnextch) == NULL)
321     return;
322     }
323    
324     tmp->hnextch = tmp->hnextch->hnextch;
325     chptr->hnextch = chptr;
326     }
327     }
328     }
329    
330     void
331     hash_del_resv(struct ResvChannel *chptr)
332     {
333     unsigned int hashv = strhash(chptr->name);
334     struct ResvChannel *tmp = resvchannelTable[hashv];
335    
336     if (tmp != NULL)
337     {
338     if (tmp == chptr)
339     {
340     resvchannelTable[hashv] = chptr->hnext;
341     chptr->hnext = chptr;
342     }
343     else
344     {
345     while (tmp->hnext != chptr)
346     {
347     if ((tmp = tmp->hnext) == NULL)
348     return;
349     }
350    
351     tmp->hnext = tmp->hnext->hnext;
352     chptr->hnext = chptr;
353     }
354     }
355     }
356    
357     /* find_client()
358     *
359     * inputs - pointer to name
360     * output - NONE
361     * side effects - New semantics: finds a client whose name is 'name'
362     * if can't find one returns NULL. If it finds one moves
363     * it to the top of the list and returns it.
364     */
365     struct Client *
366     find_client(const char *name)
367     {
368     unsigned int hashv = strhash(name);
369     struct Client *client_p;
370    
371     if ((client_p = clientTable[hashv]) != NULL)
372     {
373     if (irccmp(name, client_p->name))
374     {
375     struct Client *prev;
376    
377     while (prev = client_p, (client_p = client_p->hnext) != NULL)
378     {
379     if (!irccmp(name, client_p->name))
380     {
381     prev->hnext = client_p->hnext;
382     client_p->hnext = clientTable[hashv];
383     clientTable[hashv] = client_p;
384     break;
385     }
386     }
387     }
388     }
389    
390     return client_p;
391     }
392    
393     struct Client *
394     hash_find_id(const char *name)
395     {
396     unsigned int hashv = strhash(name);
397     struct Client *client_p;
398    
399     if ((client_p = idTable[hashv]) != NULL)
400     {
401 michael 880 if (strcmp(name, client_p->id))
402 adx 30 {
403     struct Client *prev;
404    
405     while (prev = client_p, (client_p = client_p->idhnext) != NULL)
406     {
407 michael 880 if (!strcmp(name, client_p->id))
408 adx 30 {
409     prev->idhnext = client_p->idhnext;
410     client_p->idhnext = idTable[hashv];
411     idTable[hashv] = client_p;
412     break;
413     }
414     }
415     }
416     }
417    
418     return client_p;
419     }
420    
421     /*
422     * Whats happening in this next loop ? Well, it takes a name like
423     * foo.bar.edu and proceeds to earch for *.edu and then *.bar.edu.
424     * This is for checking full server names against masks although
425     * it isnt often done this way in lieu of using matches().
426     *
427     * Rewrote to do *.bar.edu first, which is the most likely case,
428     * also made const correct
429     * --Bleep
430     */
431     static struct Client *
432     hash_find_masked_server(const char *name)
433     {
434     char buf[HOSTLEN + 1];
435     char *p = buf;
436     char *s = NULL;
437     struct Client *server = NULL;
438    
439     if (*name == '*' || *name == '.')
440     return NULL;
441    
442     /*
443     * copy the damn thing and be done with it
444     */
445     strlcpy(buf, name, sizeof(buf));
446    
447     while ((s = strchr(p, '.')) != NULL)
448     {
449     *--s = '*';
450    
451     /* Dont need to check IsServer() here since nicknames cant
452     * have *'s in them anyway.
453     */
454     if ((server = find_client(s)) != NULL)
455     return server;
456     p = s + 2;
457     }
458    
459     return NULL;
460     }
461    
462     struct Client *
463     find_server(const char *name)
464     {
465     unsigned int hashv = strhash(name);
466     struct Client *client_p = NULL;
467    
468     if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
469     client_p = hash_find_id(name);
470    
471     if ((client_p == NULL) && (client_p = clientTable[hashv]) != NULL)
472     {
473     if ((!IsServer(client_p) && !IsMe(client_p)) ||
474     irccmp(name, client_p->name))
475     {
476     struct Client *prev;
477    
478     while (prev = client_p, (client_p = client_p->hnext) != NULL)
479     {
480     if ((IsServer(client_p) || IsMe(client_p)) &&
481     !irccmp(name, client_p->name))
482     {
483     prev->hnext = client_p->hnext;
484     client_p->hnext = clientTable[hashv];
485     clientTable[hashv] = client_p;
486     break;
487     }
488     }
489     }
490     }
491    
492     return (client_p != NULL) ? client_p : hash_find_masked_server(name);
493     }
494    
495     /* hash_find_channel()
496     *
497     * inputs - pointer to name
498     * output - NONE
499     * side effects - New semantics: finds a channel whose name is 'name',
500     * if can't find one returns NULL, if can find it moves
501     * it to the top of the list and returns it.
502     */
503     struct Channel *
504     hash_find_channel(const char *name)
505     {
506     unsigned int hashv = strhash(name);
507     struct Channel *chptr = NULL;
508    
509     if ((chptr = channelTable[hashv]) != NULL)
510     {
511     if (irccmp(name, chptr->chname))
512     {
513     struct Channel *prev;
514    
515     while (prev = chptr, (chptr = chptr->hnextch) != NULL)
516     {
517     if (!irccmp(name, chptr->chname))
518     {
519     prev->hnextch = chptr->hnextch;
520     chptr->hnextch = channelTable[hashv];
521     channelTable[hashv] = chptr;
522     break;
523     }
524     }
525     }
526     }
527    
528     return chptr;
529     }
530    
531     /* hash_get_bucket(int type, unsigned int hashv)
532     *
533     * inputs - hash value (must be between 0 and HASHSIZE - 1)
534     * output - NONE
535     * returns - pointer to first channel in channelTable[hashv]
536     * if that exists;
537     * NULL if there is no channel in that place;
538     * NULL if hashv is an invalid number.
539     * side effects - NONE
540     */
541     void *
542     hash_get_bucket(int type, unsigned int hashv)
543     {
544     assert(hashv < HASHSIZE);
545     if (hashv >= HASHSIZE)
546     return NULL;
547    
548     switch (type)
549     {
550     case HASH_TYPE_ID:
551     return idTable[hashv];
552     break;
553     case HASH_TYPE_CHANNEL:
554     return channelTable[hashv];
555     break;
556     case HASH_TYPE_CLIENT:
557     return clientTable[hashv];
558     break;
559     case HASH_TYPE_USERHOST:
560     return userhostTable[hashv];
561     break;
562     case HASH_TYPE_RESERVED:
563     return resvchannelTable[hashv];
564     break;
565     default:
566     assert(0);
567     }
568    
569     return NULL;
570     }
571    
572     /* hash_find_resv()
573     *
574     * inputs - pointer to name
575     * output - NONE
576     * side effects - New semantics: finds a reserved channel whose name is 'name',
577     * if can't find one returns NULL, if can find it moves
578     * it to the top of the list and returns it.
579     */
580     struct ResvChannel *
581     hash_find_resv(const char *name)
582     {
583     unsigned int hashv = strhash(name);
584     struct ResvChannel *chptr;
585    
586     if ((chptr = resvchannelTable[hashv]) != NULL)
587     {
588     if (irccmp(name, chptr->name))
589     {
590     struct ResvChannel *prev;
591    
592     while (prev = chptr, (chptr = chptr->hnext) != NULL)
593     {
594     if (!irccmp(name, chptr->name))
595     {
596     prev->hnext = chptr->hnext;
597     chptr->hnext = resvchannelTable[hashv];
598     resvchannelTable[hashv] = chptr;
599     break;
600     }
601     }
602     }
603     }
604    
605     return chptr;
606     }
607    
608     struct UserHost *
609     hash_find_userhost(const char *host)
610     {
611     unsigned int hashv = strhash(host);
612     struct UserHost *userhost;
613    
614     if ((userhost = userhostTable[hashv]))
615     {
616     if (irccmp(host, userhost->host))
617     {
618     struct UserHost *prev;
619    
620     while (prev = userhost, (userhost = userhost->next) != NULL)
621     {
622     if (!irccmp(host, userhost->host))
623     {
624     prev->next = userhost->next;
625     userhost->next = userhostTable[hashv];
626     userhostTable[hashv] = userhost;
627     break;
628     }
629     }
630     }
631     }
632    
633     return userhost;
634     }
635    
636     /* count_user_host()
637     *
638     * inputs - user name
639     * - hostname
640     * - int flag 1 if global, 0 if local
641     * - pointer to where global count should go
642     * - pointer to where local count should go
643     * - pointer to where identd count should go (local clients only)
644     * output - none
645     * side effects -
646     */
647     void
648     count_user_host(const char *user, const char *host, int *global_p,
649     int *local_p, int *icount_p)
650     {
651     dlink_node *ptr;
652     struct UserHost *found_userhost;
653     struct NameHost *nameh;
654    
655     if ((found_userhost = hash_find_userhost(host)) == NULL)
656     return;
657    
658     DLINK_FOREACH(ptr, found_userhost->list.head)
659     {
660     nameh = ptr->data;
661    
662     if (!irccmp(user, nameh->name))
663     {
664     if (global_p != NULL)
665     *global_p = nameh->gcount;
666     if (local_p != NULL)
667     *local_p = nameh->lcount;
668     if (icount_p != NULL)
669     *icount_p = nameh->icount;
670     return;
671     }
672     }
673     }
674    
675     /* add_user_host()
676     *
677     * inputs - user name
678     * - hostname
679     * - int flag 1 if global, 0 if local
680     * output - none
681     * side effects - add given user@host to hash tables
682     */
683     void
684     add_user_host(const char *user, const char *host, int global)
685     {
686     dlink_node *ptr;
687     struct UserHost *found_userhost;
688     struct NameHost *nameh;
689     int hasident = 1;
690    
691     if (*user == '~')
692     {
693     hasident = 0;
694     ++user;
695     }
696    
697     if ((found_userhost = find_or_add_userhost(host)) == NULL)
698     return;
699    
700     DLINK_FOREACH(ptr, found_userhost->list.head)
701     {
702     nameh = ptr->data;
703    
704     if (!irccmp(user, nameh->name))
705     {
706     nameh->gcount++;
707     if (!global)
708     {
709     if (hasident)
710     nameh->icount++;
711     nameh->lcount++;
712     }
713     return;
714     }
715     }
716    
717     nameh = BlockHeapAlloc(namehost_heap);
718     strlcpy(nameh->name, user, sizeof(nameh->name));
719    
720     nameh->gcount = 1;
721     if (!global)
722     {
723     if (hasident)
724     nameh->icount = 1;
725     nameh->lcount = 1;
726     }
727    
728     dlinkAdd(nameh, &nameh->node, &found_userhost->list);
729     }
730    
731     /* delete_user_host()
732     *
733     * inputs - user name
734     * - hostname
735     * - int flag 1 if global, 0 if local
736     * output - none
737     * side effects - delete given user@host to hash tables
738     */
739     void
740     delete_user_host(const char *user, const char *host, int global)
741     {
742     dlink_node *ptr = NULL, *next_ptr = NULL;
743     struct UserHost *found_userhost;
744     struct NameHost *nameh;
745     int hasident = 1;
746    
747     if (*user == '~')
748     {
749     hasident = 0;
750     ++user;
751     }
752    
753     if ((found_userhost = hash_find_userhost(host)) == NULL)
754     return;
755    
756     DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
757     {
758     nameh = ptr->data;
759    
760     if (!irccmp(user, nameh->name))
761     {
762     if (nameh->gcount > 0)
763     nameh->gcount--;
764     if (!global)
765     {
766     if (nameh->lcount > 0)
767     nameh->lcount--;
768     if (hasident && nameh->icount > 0)
769     nameh->icount--;
770     }
771    
772     if (nameh->gcount == 0 && nameh->lcount == 0)
773     {
774     dlinkDelete(&nameh->node, &found_userhost->list);
775     BlockHeapFree(namehost_heap, nameh);
776     }
777    
778     if (dlink_list_length(&found_userhost->list) == 0)
779     {
780     hash_del_userhost(found_userhost);
781     BlockHeapFree(userhost_heap, found_userhost);
782     }
783    
784     return;
785     }
786     }
787     }
788    
789     /* find_or_add_userhost()
790     *
791     * inputs - host name
792     * output - none
793     * side effects - find UserHost * for given host name
794     */
795     static struct UserHost *
796     find_or_add_userhost(const char *host)
797     {
798     struct UserHost *userhost;
799    
800     if ((userhost = hash_find_userhost(host)) != NULL)
801     return userhost;
802    
803     userhost = BlockHeapAlloc(userhost_heap);
804     strlcpy(userhost->host, host, sizeof(userhost->host));
805     hash_add_userhost(userhost);
806    
807     return userhost;
808     }
809    
810     /*
811     * Safe list code.
812     *
813     * The idea is really quite simple. As the link lists pointed to in
814     * each "bucket" of the channel hash table are traversed atomically
815     * there is no locking needed. Overall, yes, inconsistent reported
816     * state can still happen, but normally this isn't a big deal.
817     * I don't like sticking the code into hash.c but oh well. Moreover,
818     * if a hash isn't used in future, oops.
819     *
820     * - Dianora
821     */
822    
823     /* exceeding_sendq()
824     *
825     * inputs - pointer to client to check
826     * output - 1 if client is in danger of blowing its sendq
827     * 0 if it is not.
828     * side effects -
829     *
830     * Sendq limit is fairly conservative at 1/2 (In original anyway)
831     */
832     static int
833     exceeding_sendq(struct Client *to)
834     {
835     if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2))
836     return 1;
837     else
838     return 0;
839     }
840    
841     void
842     free_list_task(struct ListTask *lt, struct Client *source_p)
843     {
844     dlink_node *dl, *dln;
845    
846     if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL)
847     free_dlink_node(dl);
848    
849     DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head)
850     {
851     MyFree(dl->data);
852     free_dlink_node(dl);
853     }
854    
855     DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head)
856     {
857     MyFree(dl->data);
858     free_dlink_node(dl);
859     }
860    
861     MyFree(lt);
862    
863     if (MyConnect(source_p))
864     source_p->localClient->list_task = NULL;
865     }
866    
867     /* list_allow_channel()
868     *
869     * inputs - channel name
870     * - pointer to a list task
871     * output - 1 if the channel is to be displayed
872     * 0 otherwise
873     * side effects -
874     */
875     static int
876     list_allow_channel(const char *chname, struct ListTask *lt)
877     {
878     dlink_node *dl = NULL;
879    
880     DLINK_FOREACH(dl, lt->show_mask.head)
881     if (!match_chan(dl->data, chname))
882     return 0;
883    
884     DLINK_FOREACH(dl, lt->hide_mask.head)
885     if (match_chan(dl->data, chname))
886     return 0;
887    
888     return 1;
889     }
890    
891     /* list_one_channel()
892     *
893     * inputs - client pointer to return result to
894     * - pointer to channel to list
895     * - pointer to ListTask structure
896     * output - none
897     * side effects -
898     */
899     static void
900     list_one_channel(struct Client *source_p, struct Channel *chptr,
901 michael 896 struct ListTask *list_task)
902 adx 30 {
903 michael 896 if (SecretChannel(chptr) && !IsMember(source_p, chptr))
904 adx 30 return;
905     if ((unsigned int)dlink_list_length(&chptr->members) < list_task->users_min ||
906     (unsigned int)dlink_list_length(&chptr->members) > list_task->users_max ||
907     (chptr->channelts != 0 &&
908     ((unsigned int)chptr->channelts < list_task->created_min ||
909     (unsigned int)chptr->channelts > list_task->created_max)) ||
910     (unsigned int)chptr->topic_time < list_task->topicts_min ||
911     (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
912     list_task->topicts_max)
913     return;
914    
915     if (!list_allow_channel(chptr->chname, list_task))
916     return;
917     sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
918     chptr->chname, dlink_list_length(&chptr->members),
919     chptr->topic == NULL ? "" : chptr->topic);
920     }
921    
922     /* safe_list_channels()
923     *
924     * inputs - pointer to client requesting list
925     * output - 0/1
926     * side effects - safely list all channels to source_p
927     *
928     * Walk the channel buckets, ensure all pointers in a bucket are
929     * traversed before blocking on a sendq. This means, no locking is needed.
930     *
931     * N.B. This code is "remote" safe, but is not currently used for
932     * remote clients.
933     *
934     * - Dianora
935     */
936     void
937     safe_list_channels(struct Client *source_p, struct ListTask *list_task,
938 michael 896 int only_unmasked_channels)
939 adx 30 {
940     struct Channel *chptr = NULL;
941    
942     if (!only_unmasked_channels)
943     {
944     int i;
945    
946 michael 896 for (i = list_task->hash_index; i < HASHSIZE; ++i)
947 adx 30 {
948     if (exceeding_sendq(source_p->from))
949     {
950     list_task->hash_index = i;
951 michael 880 return; /* still more to do */
952 adx 30 }
953    
954     for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
955 michael 896 list_one_channel(source_p, chptr, list_task);
956 adx 30 }
957     }
958     else
959     {
960     dlink_node *dl;
961    
962     DLINK_FOREACH(dl, list_task->show_mask.head)
963     if ((chptr = hash_find_channel(dl->data)) != NULL)
964 michael 896 list_one_channel(source_p, chptr, list_task);
965 adx 30 }
966    
967     free_list_task(list_task, source_p);
968     sendto_one(source_p, form_str(RPL_LISTEND),
969     me.name, source_p->name);
970     }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28