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

Properties

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