ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 1149
Committed: Sun Jul 31 20:04:17 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/src/hash.c
File size: 21577 byte(s)
Log Message:
- Style cleanups
- Doxify hook.c

File Contents

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

Properties

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