ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 5460
Committed: Tue Feb 3 22:24:57 2015 UTC (10 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 19983 byte(s)
Log Message:
- Minor cleanups here and there

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

Properties

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