/[svn]/ircd-hybrid/trunk/src/hash.c
ViewVC logotype

Contents of /ircd-hybrid/trunk/src/hash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1654 - (show annotations)
Fri Nov 16 19:39:37 2012 UTC (7 years, 7 months ago) by michael
File MIME type: text/x-chdr
File size: 21553 byte(s)
- Implemented memory pool allocator which basically is taken from Tor's
  mempool allocator for Tor cells
- Fixed compile warnings in conf_class.c
- ./configure --enable-assert works again

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 "conf.h"
28 #include "channel.h"
29 #include "channel_mode.h"
30 #include "client.h"
31 #include "modules.h"
32 #include "hash.h"
33 #include "resv.h"
34 #include "rng_mt.h"
35 #include "userhost.h"
36 #include "irc_string.h"
37 #include "ircd.h"
38 #include "numeric.h"
39 #include "send.h"
40 #include "memory.h"
41 #include "mempool.h"
42 #include "dbuf.h"
43 #include "s_user.h"
44
45
46 static mp_pool_t *userhost_pool = NULL;
47 static mp_pool_t *namehost_pool = NULL;
48
49 static unsigned int hashf_xor_key = 0;
50
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 static struct MaskItem *resvchannelTable[HASHSIZE];
61
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_pool = mp_pool_new(sizeof(struct UserHost), MP_CHUNK_SIZE_CLIENT);
78 namehost_pool = mp_pool_new(sizeof(struct NameHost), MP_CHUNK_SIZE_CLIENT);
79
80 hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
81 }
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 hval ^= (ToLower(*p) ^ hashf_xor_key);
103 }
104
105 return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
106 }
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 hash_add_resv(struct MaskItem *conf)
157 {
158 unsigned int hashv = strhash(conf->name);
159
160 conf->hnext = resvchannelTable[hashv];
161 resvchannelTable[hashv] = conf;
162 }
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 hash_del_resv(struct MaskItem *chptr)
309 {
310 unsigned int hashv = strhash(chptr->name);
311 struct MaskItem *tmp = resvchannelTable[hashv];
312
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 /* hash_find_client()
333 *
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 hash_find_client(const char *name)
342 {
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 if (strcmp(name, client_p->id))
377 {
378 struct Client *prev;
379
380 while (prev = client_p, (client_p = client_p->idhnext) != NULL)
381 {
382 if (!strcmp(name, client_p->id))
383 {
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 hash_find_server(const char *name)
398 {
399 unsigned int hashv = strhash(name);
400 struct Client *client_p = NULL;
401
402 if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
403 return hash_find_id(name);
404
405 if ((client_p = clientTable[hashv]) != NULL)
406 {
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 return client_p;
427 }
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 struct MaskItem *
515 hash_find_resv(const char *name)
516 {
517 unsigned int hashv = strhash(name);
518 struct MaskItem *chptr;
519
520 if ((chptr = resvchannelTable[hashv]) != NULL)
521 {
522 if (irccmp(name, chptr->name))
523 {
524 struct MaskItem *prev;
525
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 count_user_host(const char *user, const char *host, unsigned int *global_p,
583 unsigned int *local_p, unsigned int *icount_p)
584 {
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 /* 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 = mp_pool_get(userhost_pool);
624
625 memset(userhost, 0, sizeof(*userhost));
626 strlcpy(userhost->host, host, sizeof(userhost->host));
627 hash_add_userhost(userhost);
628
629 return userhost;
630 }
631
632 /* add_user_host()
633 *
634 * inputs - user name
635 * - hostname
636 * - int flag 1 if global, 0 if local
637 * output - none
638 * side effects - add given user@host to hash tables
639 */
640 void
641 add_user_host(const char *user, const char *host, int global)
642 {
643 dlink_node *ptr;
644 struct UserHost *found_userhost;
645 struct NameHost *nameh;
646 int hasident = 1;
647
648 if (*user == '~')
649 {
650 hasident = 0;
651 ++user;
652 }
653
654 if ((found_userhost = find_or_add_userhost(host)) == NULL)
655 return;
656
657 DLINK_FOREACH(ptr, found_userhost->list.head)
658 {
659 nameh = ptr->data;
660
661 if (!irccmp(user, nameh->name))
662 {
663 nameh->gcount++;
664
665 if (!global)
666 {
667 if (hasident)
668 nameh->icount++;
669 nameh->lcount++;
670 }
671
672 return;
673 }
674 }
675
676 nameh = mp_pool_get(namehost_pool);
677 memset(nameh, 0, sizeof(*nameh));
678 strlcpy(nameh->name, user, sizeof(nameh->name));
679
680 nameh->gcount = 1;
681
682 if (!global)
683 {
684 if (hasident)
685 nameh->icount = 1;
686 nameh->lcount = 1;
687 }
688
689 dlinkAdd(nameh, &nameh->node, &found_userhost->list);
690 }
691
692 /* delete_user_host()
693 *
694 * inputs - user name
695 * - hostname
696 * - int flag 1 if global, 0 if local
697 * output - none
698 * side effects - delete given user@host to hash tables
699 */
700 void
701 delete_user_host(const char *user, const char *host, int global)
702 {
703 dlink_node *ptr = NULL, *next_ptr = NULL;
704 struct UserHost *found_userhost;
705 struct NameHost *nameh;
706 int hasident = 1;
707
708 if (*user == '~')
709 {
710 hasident = 0;
711 ++user;
712 }
713
714 if ((found_userhost = hash_find_userhost(host)) == NULL)
715 return;
716
717 DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
718 {
719 nameh = ptr->data;
720
721 if (!irccmp(user, nameh->name))
722 {
723 if (nameh->gcount > 0)
724 nameh->gcount--;
725 if (!global)
726 {
727 if (nameh->lcount > 0)
728 nameh->lcount--;
729 if (hasident && nameh->icount > 0)
730 nameh->icount--;
731 }
732
733 if (nameh->gcount == 0 && nameh->lcount == 0)
734 {
735 dlinkDelete(&nameh->node, &found_userhost->list);
736 mp_pool_release(nameh);
737 }
738
739 if (dlink_list_length(&found_userhost->list) == 0)
740 {
741 hash_del_userhost(found_userhost);
742 mp_pool_release(found_userhost);
743 }
744
745 return;
746 }
747 }
748 }
749
750 /*
751 * Safe list code.
752 *
753 * The idea is really quite simple. As the link lists pointed to in
754 * each "bucket" of the channel hash table are traversed atomically
755 * there is no locking needed. Overall, yes, inconsistent reported
756 * state can still happen, but normally this isn't a big deal.
757 * I don't like sticking the code into hash.c but oh well. Moreover,
758 * if a hash isn't used in future, oops.
759 *
760 * - Dianora
761 */
762
763 /* exceeding_sendq()
764 *
765 * inputs - pointer to client to check
766 * output - 1 if client is in danger of blowing its sendq
767 * 0 if it is not.
768 * side effects -
769 *
770 * Sendq limit is fairly conservative at 1/2 (In original anyway)
771 */
772 static int
773 exceeding_sendq(struct Client *to)
774 {
775 if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(&to->localClient->confs) / 2))
776 return 1;
777 else
778 return 0;
779 }
780
781 void
782 free_list_task(struct ListTask *lt, struct Client *source_p)
783 {
784 dlink_node *dl, *dln;
785
786 if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL)
787 free_dlink_node(dl);
788
789 DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head)
790 {
791 MyFree(dl->data);
792 free_dlink_node(dl);
793 }
794
795 DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head)
796 {
797 MyFree(dl->data);
798 free_dlink_node(dl);
799 }
800
801 MyFree(lt);
802
803 if (MyConnect(source_p))
804 source_p->localClient->list_task = NULL;
805 }
806
807 /* list_allow_channel()
808 *
809 * inputs - channel name
810 * - pointer to a list task
811 * output - 1 if the channel is to be displayed
812 * 0 otherwise
813 * side effects -
814 */
815 static int
816 list_allow_channel(const char *chname, struct ListTask *lt)
817 {
818 dlink_node *dl = NULL;
819
820 DLINK_FOREACH(dl, lt->show_mask.head)
821 if (match(dl->data, chname) != 0)
822 return 0;
823
824 DLINK_FOREACH(dl, lt->hide_mask.head)
825 if (match(dl->data, chname) == 0)
826 return 0;
827
828 return 1;
829 }
830
831 /* list_one_channel()
832 *
833 * inputs - client pointer to return result to
834 * - pointer to channel to list
835 * - pointer to ListTask structure
836 * output - none
837 * side effects -
838 */
839 static void
840 list_one_channel(struct Client *source_p, struct Channel *chptr,
841 struct ListTask *list_task)
842 {
843 if (SecretChannel(chptr) && !IsMember(source_p, chptr))
844 return;
845 if (dlink_list_length(&chptr->members) < list_task->users_min ||
846 dlink_list_length(&chptr->members) > list_task->users_max ||
847 (chptr->channelts != 0 &&
848 ((unsigned int)chptr->channelts < list_task->created_min ||
849 (unsigned int)chptr->channelts > list_task->created_max)) ||
850 (unsigned int)chptr->topic_time < list_task->topicts_min ||
851 (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
852 list_task->topicts_max)
853 return;
854
855 if (!list_allow_channel(chptr->chname, list_task))
856 return;
857 sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
858 chptr->chname, dlink_list_length(&chptr->members),
859 chptr->topic);
860 }
861
862 /* safe_list_channels()
863 *
864 * inputs - pointer to client requesting list
865 * output - 0/1
866 * side effects - safely list all channels to source_p
867 *
868 * Walk the channel buckets, ensure all pointers in a bucket are
869 * traversed before blocking on a sendq. This means, no locking is needed.
870 *
871 * N.B. This code is "remote" safe, but is not currently used for
872 * remote clients.
873 *
874 * - Dianora
875 */
876 void
877 safe_list_channels(struct Client *source_p, struct ListTask *list_task,
878 int only_unmasked_channels)
879 {
880 struct Channel *chptr = NULL;
881
882 if (!only_unmasked_channels)
883 {
884 unsigned int i;
885
886 for (i = list_task->hash_index; i < HASHSIZE; ++i)
887 {
888 if (exceeding_sendq(source_p->from))
889 {
890 list_task->hash_index = i;
891 return; /* still more to do */
892 }
893
894 for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
895 list_one_channel(source_p, chptr, list_task);
896 }
897 }
898 else
899 {
900 dlink_node *dl;
901
902 DLINK_FOREACH(dl, list_task->show_mask.head)
903 if ((chptr = hash_find_channel(dl->data)) != NULL)
904 list_one_channel(source_p, chptr, list_task);
905 }
906
907 free_list_task(list_task, source_p);
908 sendto_one(source_p, form_str(RPL_LISTEND),
909 me.name, source_p->name);
910 }

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28