ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 4502
Committed: Sat Aug 16 19:10:20 2014 UTC (11 years ago) by michael
Content type: text/x-csrc
File size: 19904 byte(s)
Log Message:
- hash.c:safe_list_channels(): removed outdated comment

File Contents

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

Properties

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