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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1013 - (show annotations)
Sun Oct 18 14:26:49 2009 UTC (9 years, 10 months ago) by michael
File MIME type: text/x-chdr
File size: 22889 byte(s)
- Add -Wextra -Wcast-align -Wbad-function-cast to CFLAGS if --enable-warnings is specified
- Fixed several compile warnings
- 64-bit cleanliness fixes, e.g., reorganize data structures to reduce storage/unnecessary padding

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

Properties

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

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