ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 1149
Committed: Sun Jul 31 20:04:17 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/src/hash.c
File size: 21577 byte(s)
Log Message:
- Style cleanups
- Doxify hook.c

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

Properties

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