ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 3347
Committed: Sun Apr 20 14:03:06 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 20044 byte(s)
Log Message:
- Moved files:
  s_user.c -> user.c
  s_misc.c -> misc.c
  s_serv.c -> server.c

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     memset(userhost, 0, sizeof(*userhost));
550 michael 1396 strlcpy(userhost->host, host, sizeof(userhost->host));
551     hash_add_userhost(userhost);
552    
553     return userhost;
554     }
555    
556 adx 30 /* add_user_host()
557     *
558     * inputs - user name
559     * - hostname
560     * - int flag 1 if global, 0 if local
561     * output - none
562     * side effects - add given user@host to hash tables
563     */
564     void
565     add_user_host(const char *user, const char *host, int global)
566     {
567     dlink_node *ptr;
568     struct UserHost *found_userhost;
569     struct NameHost *nameh;
570     int hasident = 1;
571    
572     if (*user == '~')
573     {
574     hasident = 0;
575     ++user;
576     }
577    
578     if ((found_userhost = find_or_add_userhost(host)) == NULL)
579     return;
580    
581     DLINK_FOREACH(ptr, found_userhost->list.head)
582     {
583     nameh = ptr->data;
584    
585     if (!irccmp(user, nameh->name))
586     {
587     nameh->gcount++;
588 michael 1396
589 adx 30 if (!global)
590     {
591 michael 1396 if (hasident)
592     nameh->icount++;
593     nameh->lcount++;
594 adx 30 }
595 michael 1396
596 adx 30 return;
597     }
598     }
599    
600 michael 1654 nameh = mp_pool_get(namehost_pool);
601     memset(nameh, 0, sizeof(*nameh));
602 adx 30 strlcpy(nameh->name, user, sizeof(nameh->name));
603    
604     nameh->gcount = 1;
605 michael 1396
606 adx 30 if (!global)
607     {
608     if (hasident)
609     nameh->icount = 1;
610     nameh->lcount = 1;
611     }
612    
613     dlinkAdd(nameh, &nameh->node, &found_userhost->list);
614     }
615    
616     /* delete_user_host()
617     *
618     * inputs - user name
619     * - hostname
620     * - int flag 1 if global, 0 if local
621     * output - none
622     * side effects - delete given user@host to hash tables
623     */
624     void
625     delete_user_host(const char *user, const char *host, int global)
626     {
627 michael 3287 dlink_node *ptr = NULL;
628     struct UserHost *found_userhost = NULL;
629     unsigned int hasident = 1;
630 adx 30
631     if (*user == '~')
632     {
633     hasident = 0;
634     ++user;
635     }
636    
637     if ((found_userhost = hash_find_userhost(host)) == NULL)
638     return;
639    
640 michael 3287 DLINK_FOREACH(ptr, found_userhost->list.head)
641 adx 30 {
642 michael 3287 struct NameHost *nameh = ptr->data;
643 adx 30
644     if (!irccmp(user, nameh->name))
645     {
646     if (nameh->gcount > 0)
647     nameh->gcount--;
648     if (!global)
649     {
650 michael 1396 if (nameh->lcount > 0)
651     nameh->lcount--;
652     if (hasident && nameh->icount > 0)
653     nameh->icount--;
654 adx 30 }
655    
656     if (nameh->gcount == 0 && nameh->lcount == 0)
657     {
658 michael 1396 dlinkDelete(&nameh->node, &found_userhost->list);
659 michael 1654 mp_pool_release(nameh);
660 adx 30 }
661    
662     if (dlink_list_length(&found_userhost->list) == 0)
663     {
664 michael 1396 hash_del_userhost(found_userhost);
665 michael 1654 mp_pool_release(found_userhost);
666 adx 30 }
667    
668     return;
669     }
670     }
671     }
672    
673     /*
674     * Safe list code.
675     *
676     * The idea is really quite simple. As the link lists pointed to in
677     * each "bucket" of the channel hash table are traversed atomically
678     * there is no locking needed. Overall, yes, inconsistent reported
679     * state can still happen, but normally this isn't a big deal.
680     * I don't like sticking the code into hash.c but oh well. Moreover,
681     * if a hash isn't used in future, oops.
682     *
683     * - Dianora
684     */
685    
686     /* exceeding_sendq()
687     *
688     * inputs - pointer to client to check
689     * output - 1 if client is in danger of blowing its sendq
690     * 0 if it is not.
691     * side effects -
692     *
693     * Sendq limit is fairly conservative at 1/2 (In original anyway)
694     */
695     static int
696 michael 2757 exceeding_sendq(const struct Client *to)
697 adx 30 {
698 michael 1632 if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(&to->localClient->confs) / 2))
699 adx 30 return 1;
700     else
701     return 0;
702     }
703    
704     void
705 michael 3289 free_list_task(struct Client *source_p)
706 adx 30 {
707 michael 3289 struct ListTask *lt = source_p->localClient->list_task;
708 michael 3242 dlink_node *ptr = NULL, *ptr_next = NULL;
709 adx 30
710 michael 3242 if ((ptr = dlinkFindDelete(&listing_client_list, source_p)))
711     free_dlink_node(ptr);
712 adx 30
713 michael 3242 DLINK_FOREACH_SAFE(ptr, ptr_next, lt->show_mask.head)
714 adx 30 {
715 michael 3242 MyFree(ptr->data);
716     free_dlink_node(ptr);
717 adx 30 }
718    
719 michael 3242 DLINK_FOREACH_SAFE(ptr, ptr_next, lt->hide_mask.head)
720 adx 30 {
721 michael 3242 MyFree(ptr->data);
722     free_dlink_node(ptr);
723 adx 30 }
724    
725     MyFree(lt);
726    
727     if (MyConnect(source_p))
728     source_p->localClient->list_task = NULL;
729     }
730    
731     /* list_allow_channel()
732     *
733     * inputs - channel name
734     * - pointer to a list task
735     * output - 1 if the channel is to be displayed
736     * 0 otherwise
737     * side effects -
738     */
739     static int
740 michael 1826 list_allow_channel(const char *chname, const struct ListTask *lt)
741 adx 30 {
742 michael 3242 const dlink_node *ptr = NULL;
743 adx 30
744 michael 3242 DLINK_FOREACH(ptr, lt->show_mask.head)
745     if (match(ptr->data, chname) != 0)
746 adx 30 return 0;
747    
748 michael 3242 DLINK_FOREACH(ptr, lt->hide_mask.head)
749     if (match(ptr->data, chname) == 0)
750 adx 30 return 0;
751    
752     return 1;
753     }
754    
755     /* list_one_channel()
756     *
757     * inputs - client pointer to return result to
758     * - pointer to channel to list
759     * - pointer to ListTask structure
760     * output - none
761     * side effects -
762     */
763     static void
764 michael 3288 list_one_channel(struct Client *source_p, struct Channel *chptr)
765 adx 30 {
766 michael 3288 struct ListTask *lt = source_p->localClient->list_task;
767 michael 2616 char listbuf[MODEBUFLEN] = "";
768     char modebuf[MODEBUFLEN] = "";
769     char parabuf[MODEBUFLEN] = "";
770    
771 michael 2495 if (SecretChannel(chptr) &&
772     !(IsMember(source_p, chptr) || HasUMode(source_p, UMODE_ADMIN)))
773 adx 30 return;
774 michael 3288 if (dlink_list_length(&chptr->members) < lt->users_min ||
775     dlink_list_length(&chptr->members) > lt->users_max ||
776 adx 30 (chptr->channelts != 0 &&
777 michael 3288 ((unsigned int)chptr->channelts < lt->created_min ||
778     (unsigned int)chptr->channelts > lt->created_max)) ||
779     (unsigned int)chptr->topic_time < lt->topicts_min ||
780 adx 30 (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
781 michael 3288 lt->topicts_max)
782 adx 30 return;
783    
784 michael 3288 if (!list_allow_channel(chptr->chname, lt))
785 adx 30 return;
786 michael 2616
787     if (HasUMode(source_p, UMODE_ADMIN))
788     {
789     channel_modes(chptr, source_p, modebuf, parabuf);
790    
791     if (chptr->topic[0])
792     snprintf(listbuf, sizeof(listbuf), "[%s] ", modebuf);
793     else
794     snprintf(listbuf, sizeof(listbuf), "[%s]", modebuf);
795     }
796    
797 michael 3109 sendto_one_numeric(source_p, &me, RPL_LIST, chptr->chname,
798     dlink_list_length(&chptr->members),
799     listbuf, chptr->topic);
800 adx 30 }
801    
802     /* safe_list_channels()
803     *
804     * inputs - pointer to client requesting list
805     * output - 0/1
806     * side effects - safely list all channels to source_p
807     *
808     * Walk the channel buckets, ensure all pointers in a bucket are
809     * traversed before blocking on a sendq. This means, no locking is needed.
810     *
811     * N.B. This code is "remote" safe, but is not currently used for
812     * remote clients.
813     *
814     * - Dianora
815     */
816     void
817 michael 3288 safe_list_channels(struct Client *source_p, int only_unmasked_channels)
818 adx 30 {
819 michael 3288 struct ListTask *lt = source_p->localClient->list_task;
820 adx 30 struct Channel *chptr = NULL;
821    
822     if (!only_unmasked_channels)
823     {
824 michael 3288 for (unsigned int i = lt->hash_index; i < HASHSIZE; ++i)
825 adx 30 {
826 michael 3291 if (exceeding_sendq(source_p))
827 adx 30 {
828 michael 3288 lt->hash_index = i;
829     return; /* Still more to do */
830 adx 30 }
831    
832     for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
833 michael 3288 list_one_channel(source_p, chptr);
834 adx 30 }
835     }
836     else
837     {
838 michael 3288 dlink_node *ptr = NULL;
839 adx 30
840 michael 3288 DLINK_FOREACH(ptr, lt->show_mask.head)
841 michael 3242 if ((chptr = hash_find_channel(ptr->data)))
842 michael 3288 list_one_channel(source_p, chptr);
843 adx 30 }
844    
845 michael 3289 free_list_task(source_p);
846 michael 3109 sendto_one_numeric(source_p, &me, RPL_LISTEND);
847 adx 30 }

Properties

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