ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (13 years, 10 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/hash.c
File size: 21522 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

File Contents

# Content
1 /*
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 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h"
27 #include "balloc.h"
28 #include "s_conf.h"
29 #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 #include "rng_mt.h"
36 #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 static struct UserHost *find_or_add_userhost(const char *);
49
50 static unsigned int hashf_xor_key = 0;
51
52 /* The actual hash tables, They MUST be of the same HASHSIZE, variable
53 * size tables could be supported but the rehash routine should also
54 * rebuild the transformation maps, I kept the tables of equal size
55 * so that I can use one hash function.
56 */
57 static struct Client *idTable[HASHSIZE];
58 static struct Client *clientTable[HASHSIZE];
59 static struct Channel *channelTable[HASHSIZE];
60 static struct UserHost *userhostTable[HASHSIZE];
61 static struct ResvChannel *resvchannelTable[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 init_hash(void)
73 {
74 unsigned int i;
75
76 /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now,
77 * should be a good close approximation anyway
78 * - Dianora
79 */
80 userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE);
81 namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE);
82
83 hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
84 }
85
86 /*
87 * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from
88 * http://www.isthe.com/chongo/tech/comp/fnv/
89 *
90 * Here, we use the FNV-1 method, which gives slightly better results
91 * than FNV-1a. -Michael
92 */
93 unsigned int
94 strhash(const char *name)
95 {
96 const unsigned char *p = (const unsigned char *)name;
97 unsigned int hval = FNV1_32_INIT;
98
99 if (*p == '\0')
100 return 0;
101 for (; *p != '\0'; ++p)
102 {
103 hval += (hval << 1) + (hval << 4) + (hval << 7) +
104 (hval << 8) + (hval << 24);
105 hval ^= (ToLower(*p) ^ hashf_xor_key);
106 }
107
108 return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
109 }
110
111 /************************** Externally visible functions ********************/
112
113 /* Optimization note: in these functions I supposed that the CSE optimization
114 * (Common Subexpression Elimination) does its work decently, this means that
115 * I avoided introducing new variables to do the work myself and I did let
116 * the optimizer play with more free registers, actual tests proved this
117 * solution to be faster than doing things like tmp2=tmp->hnext... and then
118 * use tmp2 myself which would have given less freedom to the optimizer.
119 */
120
121 /* hash_add_client()
122 *
123 * inputs - pointer to client
124 * output - NONE
125 * side effects - Adds a client's name in the proper hash linked
126 * list, can't fail, client_p must have a non-null
127 * name or expect a coredump, the name is infact
128 * taken from client_p->name
129 */
130 void
131 hash_add_client(struct Client *client_p)
132 {
133 unsigned int hashv = strhash(client_p->name);
134
135 client_p->hnext = clientTable[hashv];
136 clientTable[hashv] = client_p;
137 }
138
139 /* hash_add_channel()
140 *
141 * inputs - pointer to channel
142 * output - NONE
143 * side effects - Adds a channel's name in the proper hash linked
144 * list, can't fail. chptr must have a non-null name
145 * or expect a coredump. As before the name is taken
146 * from chptr->name, we do hash its entire lenght
147 * since this proved to be statistically faster
148 */
149 void
150 hash_add_channel(struct Channel *chptr)
151 {
152 unsigned int hashv = strhash(chptr->chname);
153
154 chptr->hnextch = channelTable[hashv];
155 channelTable[hashv] = chptr;
156 }
157
158 void
159 hash_add_resv(struct ResvChannel *chptr)
160 {
161 unsigned int hashv = strhash(chptr->name);
162
163 chptr->hnext = resvchannelTable[hashv];
164 resvchannelTable[hashv] = chptr;
165 }
166
167 void
168 hash_add_userhost(struct UserHost *userhost)
169 {
170 unsigned int hashv = strhash(userhost->host);
171
172 userhost->next = userhostTable[hashv];
173 userhostTable[hashv] = userhost;
174 }
175
176 void
177 hash_add_id(struct Client *client_p)
178 {
179 unsigned int hashv = strhash(client_p->id);
180
181 client_p->idhnext = idTable[hashv];
182 idTable[hashv] = client_p;
183 }
184
185 /* hash_del_id()
186 *
187 * inputs - pointer to client
188 * output - NONE
189 * side effects - Removes an ID from the hash linked list
190 */
191 void
192 hash_del_id(struct Client *client_p)
193 {
194 unsigned int hashv = strhash(client_p->id);
195 struct Client *tmp = idTable[hashv];
196
197 if (tmp != NULL)
198 {
199 if (tmp == client_p)
200 {
201 idTable[hashv] = client_p->idhnext;
202 client_p->idhnext = client_p;
203 }
204 else
205 {
206 while (tmp->idhnext != client_p)
207 if ((tmp = tmp->idhnext) == NULL)
208 return;
209
210 tmp->idhnext = tmp->idhnext->idhnext;
211 client_p->idhnext = client_p;
212 }
213 }
214 }
215
216 /* hash_del_client()
217 *
218 * inputs - pointer to client
219 * output - NONE
220 * side effects - Removes a Client's name from the hash linked list
221 */
222 void
223 hash_del_client(struct Client *client_p)
224 {
225 unsigned int hashv = strhash(client_p->name);
226 struct Client *tmp = clientTable[hashv];
227
228 if (tmp != NULL)
229 {
230 if (tmp == client_p)
231 {
232 clientTable[hashv] = client_p->hnext;
233 client_p->hnext = client_p;
234 }
235 else
236 {
237 while (tmp->hnext != client_p)
238 if ((tmp = tmp->hnext) == NULL)
239 return;
240
241 tmp->hnext = tmp->hnext->hnext;
242 client_p->hnext = client_p;
243 }
244 }
245 }
246
247 /* hash_del_userhost()
248 *
249 * inputs - pointer to userhost
250 * output - NONE
251 * side effects - Removes a userhost from the hash linked list
252 */
253 void
254 hash_del_userhost(struct UserHost *userhost)
255 {
256 unsigned int hashv = strhash(userhost->host);
257 struct UserHost *tmp = userhostTable[hashv];
258
259 if (tmp != NULL)
260 {
261 if (tmp == userhost)
262 {
263 userhostTable[hashv] = userhost->next;
264 userhost->next = userhost;
265 }
266 else
267 {
268 while (tmp->next != userhost)
269 if ((tmp = tmp->next) == NULL)
270 return;
271
272 tmp->next = tmp->next->next;
273 userhost->next = userhost;
274 }
275 }
276 }
277
278 /* hash_del_channel()
279 *
280 * inputs - pointer to client
281 * output - NONE
282 * side effects - Removes the channel's name from the corresponding
283 * hash linked list
284 */
285 void
286 hash_del_channel(struct Channel *chptr)
287 {
288 unsigned int hashv = strhash(chptr->chname);
289 struct Channel *tmp = channelTable[hashv];
290
291 if (tmp != NULL)
292 {
293 if (tmp == chptr)
294 {
295 channelTable[hashv] = chptr->hnextch;
296 chptr->hnextch = chptr;
297 }
298 else
299 {
300 while (tmp->hnextch != chptr)
301 if ((tmp = tmp->hnextch) == NULL)
302 return;
303
304 tmp->hnextch = tmp->hnextch->hnextch;
305 chptr->hnextch = chptr;
306 }
307 }
308 }
309
310 void
311 hash_del_resv(struct ResvChannel *chptr)
312 {
313 unsigned int hashv = strhash(chptr->name);
314 struct ResvChannel *tmp = resvchannelTable[hashv];
315
316 if (tmp != NULL)
317 {
318 if (tmp == chptr)
319 {
320 resvchannelTable[hashv] = chptr->hnext;
321 chptr->hnext = chptr;
322 }
323 else
324 {
325 while (tmp->hnext != chptr)
326 if ((tmp = tmp->hnext) == NULL)
327 return;
328
329 tmp->hnext = tmp->hnext->hnext;
330 chptr->hnext = chptr;
331 }
332 }
333 }
334
335 /* hash_find_client()
336 *
337 * inputs - pointer to name
338 * output - NONE
339 * side effects - New semantics: finds a client whose name is 'name'
340 * if can't find one returns NULL. If it finds one moves
341 * it to the top of the list and returns it.
342 */
343 struct Client *
344 hash_find_client(const char *name)
345 {
346 unsigned int hashv = strhash(name);
347 struct Client *client_p;
348
349 if ((client_p = clientTable[hashv]) != NULL)
350 {
351 if (irccmp(name, client_p->name))
352 {
353 struct Client *prev;
354
355 while (prev = client_p, (client_p = client_p->hnext) != NULL)
356 {
357 if (!irccmp(name, client_p->name))
358 {
359 prev->hnext = client_p->hnext;
360 client_p->hnext = clientTable[hashv];
361 clientTable[hashv] = client_p;
362 break;
363 }
364 }
365 }
366 }
367
368 return client_p;
369 }
370
371 struct Client *
372 hash_find_id(const char *name)
373 {
374 unsigned int hashv = strhash(name);
375 struct Client *client_p;
376
377 if ((client_p = idTable[hashv]) != NULL)
378 {
379 if (strcmp(name, client_p->id))
380 {
381 struct Client *prev;
382
383 while (prev = client_p, (client_p = client_p->idhnext) != NULL)
384 {
385 if (!strcmp(name, client_p->id))
386 {
387 prev->idhnext = client_p->idhnext;
388 client_p->idhnext = idTable[hashv];
389 idTable[hashv] = client_p;
390 break;
391 }
392 }
393 }
394 }
395
396 return client_p;
397 }
398
399 struct Client *
400 hash_find_server(const char *name)
401 {
402 unsigned int hashv = strhash(name);
403 struct Client *client_p = NULL;
404
405 if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
406 client_p = hash_find_id(name);
407
408 if ((client_p == NULL) && (client_p = clientTable[hashv]) != NULL)
409 {
410 if ((!IsServer(client_p) && !IsMe(client_p)) ||
411 irccmp(name, client_p->name))
412 {
413 struct Client *prev;
414
415 while (prev = client_p, (client_p = client_p->hnext) != NULL)
416 {
417 if ((IsServer(client_p) || IsMe(client_p)) &&
418 !irccmp(name, client_p->name))
419 {
420 prev->hnext = client_p->hnext;
421 client_p->hnext = clientTable[hashv];
422 clientTable[hashv] = client_p;
423 break;
424 }
425 }
426 }
427 }
428
429 return client_p;
430 }
431
432 /* hash_find_channel()
433 *
434 * inputs - pointer to name
435 * output - NONE
436 * side effects - New semantics: finds a channel whose name is 'name',
437 * if can't find one returns NULL, if can find it moves
438 * it to the top of the list and returns it.
439 */
440 struct Channel *
441 hash_find_channel(const char *name)
442 {
443 unsigned int hashv = strhash(name);
444 struct Channel *chptr = NULL;
445
446 if ((chptr = channelTable[hashv]) != NULL)
447 {
448 if (irccmp(name, chptr->chname))
449 {
450 struct Channel *prev;
451
452 while (prev = chptr, (chptr = chptr->hnextch) != NULL)
453 {
454 if (!irccmp(name, chptr->chname))
455 {
456 prev->hnextch = chptr->hnextch;
457 chptr->hnextch = channelTable[hashv];
458 channelTable[hashv] = chptr;
459 break;
460 }
461 }
462 }
463 }
464
465 return chptr;
466 }
467
468 /* hash_get_bucket(int type, unsigned int hashv)
469 *
470 * inputs - hash value (must be between 0 and HASHSIZE - 1)
471 * output - NONE
472 * returns - pointer to first channel in channelTable[hashv]
473 * if that exists;
474 * NULL if there is no channel in that place;
475 * NULL if hashv is an invalid number.
476 * side effects - NONE
477 */
478 void *
479 hash_get_bucket(int type, unsigned int hashv)
480 {
481 assert(hashv < HASHSIZE);
482 if (hashv >= HASHSIZE)
483 return NULL;
484
485 switch (type)
486 {
487 case HASH_TYPE_ID:
488 return idTable[hashv];
489 break;
490 case HASH_TYPE_CHANNEL:
491 return channelTable[hashv];
492 break;
493 case HASH_TYPE_CLIENT:
494 return clientTable[hashv];
495 break;
496 case HASH_TYPE_USERHOST:
497 return userhostTable[hashv];
498 break;
499 case HASH_TYPE_RESERVED:
500 return resvchannelTable[hashv];
501 break;
502 default:
503 assert(0);
504 }
505
506 return NULL;
507 }
508
509 /* hash_find_resv()
510 *
511 * inputs - pointer to name
512 * output - NONE
513 * side effects - New semantics: finds a reserved channel whose name is 'name',
514 * if can't find one returns NULL, if can find it moves
515 * it to the top of the list and returns it.
516 */
517 struct ResvChannel *
518 hash_find_resv(const char *name)
519 {
520 unsigned int hashv = strhash(name);
521 struct ResvChannel *chptr;
522
523 if ((chptr = resvchannelTable[hashv]) != NULL)
524 {
525 if (irccmp(name, chptr->name))
526 {
527 struct ResvChannel *prev;
528
529 while (prev = chptr, (chptr = chptr->hnext) != NULL)
530 {
531 if (!irccmp(name, chptr->name))
532 {
533 prev->hnext = chptr->hnext;
534 chptr->hnext = resvchannelTable[hashv];
535 resvchannelTable[hashv] = chptr;
536 break;
537 }
538 }
539 }
540 }
541
542 return chptr;
543 }
544
545 struct UserHost *
546 hash_find_userhost(const char *host)
547 {
548 unsigned int hashv = strhash(host);
549 struct UserHost *userhost;
550
551 if ((userhost = userhostTable[hashv]))
552 {
553 if (irccmp(host, userhost->host))
554 {
555 struct UserHost *prev;
556
557 while (prev = userhost, (userhost = userhost->next) != NULL)
558 {
559 if (!irccmp(host, userhost->host))
560 {
561 prev->next = userhost->next;
562 userhost->next = userhostTable[hashv];
563 userhostTable[hashv] = userhost;
564 break;
565 }
566 }
567 }
568 }
569
570 return userhost;
571 }
572
573 /* count_user_host()
574 *
575 * inputs - user name
576 * - hostname
577 * - int flag 1 if global, 0 if local
578 * - pointer to where global count should go
579 * - pointer to where local count should go
580 * - pointer to where identd count should go (local clients only)
581 * output - none
582 * side effects -
583 */
584 void
585 count_user_host(const char *user, const char *host, int *global_p,
586 int *local_p, int *icount_p)
587 {
588 dlink_node *ptr;
589 struct UserHost *found_userhost;
590 struct NameHost *nameh;
591
592 if ((found_userhost = hash_find_userhost(host)) == NULL)
593 return;
594
595 DLINK_FOREACH(ptr, found_userhost->list.head)
596 {
597 nameh = ptr->data;
598
599 if (!irccmp(user, nameh->name))
600 {
601 if (global_p != NULL)
602 *global_p = nameh->gcount;
603 if (local_p != NULL)
604 *local_p = nameh->lcount;
605 if (icount_p != NULL)
606 *icount_p = nameh->icount;
607 return;
608 }
609 }
610 }
611
612 /* add_user_host()
613 *
614 * inputs - user name
615 * - hostname
616 * - int flag 1 if global, 0 if local
617 * output - none
618 * side effects - add given user@host to hash tables
619 */
620 void
621 add_user_host(const char *user, const char *host, int global)
622 {
623 dlink_node *ptr;
624 struct UserHost *found_userhost;
625 struct NameHost *nameh;
626 int hasident = 1;
627
628 if (*user == '~')
629 {
630 hasident = 0;
631 ++user;
632 }
633
634 if ((found_userhost = find_or_add_userhost(host)) == NULL)
635 return;
636
637 DLINK_FOREACH(ptr, found_userhost->list.head)
638 {
639 nameh = ptr->data;
640
641 if (!irccmp(user, nameh->name))
642 {
643 nameh->gcount++;
644 if (!global)
645 {
646 if (hasident)
647 nameh->icount++;
648 nameh->lcount++;
649 }
650 return;
651 }
652 }
653
654 nameh = BlockHeapAlloc(namehost_heap);
655 strlcpy(nameh->name, user, sizeof(nameh->name));
656
657 nameh->gcount = 1;
658 if (!global)
659 {
660 if (hasident)
661 nameh->icount = 1;
662 nameh->lcount = 1;
663 }
664
665 dlinkAdd(nameh, &nameh->node, &found_userhost->list);
666 }
667
668 /* delete_user_host()
669 *
670 * inputs - user name
671 * - hostname
672 * - int flag 1 if global, 0 if local
673 * output - none
674 * side effects - delete given user@host to hash tables
675 */
676 void
677 delete_user_host(const char *user, const char *host, int global)
678 {
679 dlink_node *ptr = NULL, *next_ptr = NULL;
680 struct UserHost *found_userhost;
681 struct NameHost *nameh;
682 int hasident = 1;
683
684 if (*user == '~')
685 {
686 hasident = 0;
687 ++user;
688 }
689
690 if ((found_userhost = hash_find_userhost(host)) == NULL)
691 return;
692
693 DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
694 {
695 nameh = ptr->data;
696
697 if (!irccmp(user, nameh->name))
698 {
699 if (nameh->gcount > 0)
700 nameh->gcount--;
701 if (!global)
702 {
703 if (nameh->lcount > 0)
704 nameh->lcount--;
705 if (hasident && nameh->icount > 0)
706 nameh->icount--;
707 }
708
709 if (nameh->gcount == 0 && nameh->lcount == 0)
710 {
711 dlinkDelete(&nameh->node, &found_userhost->list);
712 BlockHeapFree(namehost_heap, nameh);
713 }
714
715 if (dlink_list_length(&found_userhost->list) == 0)
716 {
717 hash_del_userhost(found_userhost);
718 BlockHeapFree(userhost_heap, found_userhost);
719 }
720
721 return;
722 }
723 }
724 }
725
726 /* find_or_add_userhost()
727 *
728 * inputs - host name
729 * output - none
730 * side effects - find UserHost * for given host name
731 */
732 static struct UserHost *
733 find_or_add_userhost(const char *host)
734 {
735 struct UserHost *userhost;
736
737 if ((userhost = hash_find_userhost(host)) != NULL)
738 return userhost;
739
740 userhost = BlockHeapAlloc(userhost_heap);
741 strlcpy(userhost->host, host, sizeof(userhost->host));
742 hash_add_userhost(userhost);
743
744 return userhost;
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 if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2))
773 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 if (!match_chan(dl->data, chname))
819 return 0;
820
821 DLINK_FOREACH(dl, lt->hide_mask.head)
822 if (match_chan(dl->data, chname))
823 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 struct ListTask *list_task)
839 {
840 if (SecretChannel(chptr) && !IsMember(source_p, chptr))
841 return;
842 if (dlink_list_length(&chptr->members) < list_task->users_min ||
843 dlink_list_length(&chptr->members) > list_task->users_max ||
844 (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 chptr->topic);
857 }
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 int only_unmasked_channels)
876 {
877 struct Channel *chptr = NULL;
878
879 if (!only_unmasked_channels)
880 {
881 unsigned int i;
882
883 for (i = list_task->hash_index; i < HASHSIZE; ++i)
884 {
885 if (exceeding_sendq(source_p->from))
886 {
887 list_task->hash_index = i;
888 return; /* still more to do */
889 }
890
891 for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
892 list_one_channel(source_p, chptr, list_task);
893 }
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 list_one_channel(source_p, chptr, list_task);
902 }
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