ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/client.c
(Generate patch)

Comparing ircd-hybrid/trunk/src/client.c (file contents):
Revision 3140 by michael, Wed Mar 12 19:23:20 2014 UTC vs.
Revision 4428 by michael, Thu Aug 7 17:46:02 2014 UTC

# Line 27 | Line 27
27   #include "stdinc.h"
28   #include "list.h"
29   #include "client.h"
30 #include "channel_mode.h"
30   #include "event.h"
32 #include "fdlist.h"
31   #include "hash.h"
32   #include "irc_string.h"
33   #include "ircd.h"
36 #include "s_gline.h"
34   #include "numeric.h"
35 < #include "packet.h"
39 < #include "s_auth.h"
35 > #include "auth.h"
36   #include "s_bsd.h"
37   #include "conf.h"
38   #include "log.h"
39 < #include "s_misc.h"
40 < #include "s_serv.h"
39 > #include "misc.h"
40 > #include "server.h"
41   #include "send.h"
42   #include "whowas.h"
43 < #include "s_user.h"
48 < #include "dbuf.h"
43 > #include "user.h"
44   #include "memory.h"
45   #include "mempool.h"
46   #include "hostmask.h"
47   #include "listener.h"
53 #include "irc_res.h"
48   #include "userhost.h"
49   #include "watch.h"
50   #include "rng_mt.h"
51   #include "parse.h"
52 + #include "ipcache.h"
53  
59 dlink_list listing_client_list = { NULL, NULL, 0 };
60 /* Pointer to beginning of Client list */
61 dlink_list global_client_list = {NULL, NULL, 0};
62 /* unknown/client pointer lists */
63 dlink_list unknown_list = {NULL, NULL, 0};
64 dlink_list local_client_list = {NULL, NULL, 0};
65 dlink_list serv_list = {NULL, NULL, 0};
66 dlink_list global_serv_list = {NULL, NULL, 0};
67 dlink_list oper_list = {NULL, NULL, 0};
54  
55 < static EVH check_pings;
56 <
57 < static mp_pool_t *client_pool  = NULL;
58 < static mp_pool_t *lclient_pool = NULL;
59 <
60 < static dlink_list dead_list  = { NULL, NULL, 0};
61 < static dlink_list abort_list = { NULL, NULL, 0};
55 > dlink_list listing_client_list;
56 > dlink_list unknown_list;
57 > dlink_list local_client_list;
58 > dlink_list local_server_list;
59 > dlink_list global_client_list;
60 > dlink_list global_server_list;
61 > dlink_list oper_list;
62  
63 + static mp_pool_t *client_pool, *lclient_pool;
64 + static dlink_list dead_list, abort_list;
65   static dlink_node *eac_next;  /* next aborted client to exit */
66  
79 static void check_pings_list(dlink_list *);
80 static void check_unknowns_list(void);
81
82
83 /* client_init()
84 *
85 * inputs       - NONE
86 * output       - NONE
87 * side effects - initialize client free memory
88 */
89 void
90 client_init(void)
91 {
92  /* start off the check ping event ..  -- adrian
93   * Every 30 seconds is plenty -- db
94   */
95  client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
96  lclient_pool = mp_pool_new(sizeof(struct LocalUser), MP_CHUNK_SIZE_LCLIENT);
97  eventAdd("check_pings", check_pings, NULL, 5);
98 }
67  
68   /*
69   * make_client - create a new Client struct and set it to initial state.
# Line 117 | Line 85 | make_client(struct Client *from)
85   {
86    struct Client *client_p = mp_pool_get(client_pool);
87  
88 <  memset(client_p, 0, sizeof(*client_p));
121 <
122 <  if (from == NULL)
88 >  if (!from)
89    {
90      client_p->from                      = client_p; /* 'from' of local client is self! */
91      client_p->localClient               = mp_pool_get(lclient_pool);
126
127    memset(client_p->localClient, 0, sizeof(*client_p->localClient));
128
92      client_p->localClient->since        = CurrentTime;
93      client_p->localClient->lasttime     = CurrentTime;
94      client_p->localClient->firsttime    = CurrentTime;
# Line 156 | Line 119 | make_client(struct Client *from)
119   static void
120   free_client(struct Client *client_p)
121   {
122 <  assert(client_p != NULL);
122 >  assert(client_p);
123    assert(client_p != &me);
124    assert(client_p->hnext == client_p);
125    assert(client_p->idhnext == client_p);
126    assert(client_p->channel.head == NULL);
127    assert(dlink_list_length(&client_p->channel) == 0);
128    assert(dlink_list_length(&client_p->whowas) == 0);
129 <  assert(!IsServer(client_p) || (IsServer(client_p) && client_p->serv));
129 >  assert(!IsServer(client_p) || client_p->serv);
130  
131    MyFree(client_p->serv);
132    MyFree(client_p->certfp);
# Line 183 | Line 146 | free_client(struct Client *client_p)
146       */
147      if (client_p->localClient->listener)
148      {
149 <      assert(0 < client_p->localClient->listener->ref_count);
150 <      if (0 == --client_p->localClient->listener->ref_count &&
188 <          !client_p->localClient->listener->active)
189 <        free_listener(client_p->localClient->listener);
149 >      listener_release(client_p->localClient->listener);
150 >      client_p->localClient->listener = NULL;
151      }
152  
153      dbuf_clear(&client_p->localClient->buf_recvq);
# Line 198 | Line 159 | free_client(struct Client *client_p)
159    mp_pool_release(client_p);
160   }
161  
201 /*
202 * check_pings - go through the local client list and check activity
203 * kill off stuff that should die
204 *
205 * inputs       - NOT USED (from event)
206 * output       - next time_t when check_pings() should be called again
207 * side effects -
208 *
209 *
210 * A PING can be sent to clients as necessary.
211 *
212 * Client/Server ping outs are handled.
213 */
214
215 /*
216 * Addon from adrian. We used to call this after nextping seconds,
217 * however I've changed it to run once a second. This is only for
218 * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
219 * run once a second makes life a lot easier - when a new client connects
220 * and they need a ping in 4 seconds, if nextping was set to 20 seconds
221 * we end up waiting 20 seconds. This is stupid. :-)
222 * I will optimise (hah!) check_pings() once I've finished working on
223 * tidying up other network IO evilnesses.
224 *     -- adrian
225 */
226
227 static void
228 check_pings(void *notused)
229 {
230  check_pings_list(&local_client_list);
231  check_pings_list(&serv_list);
232  check_unknowns_list();
233 }
234
162   /* check_pings_list()
163   *
164   * inputs       - pointer to list to check
# Line 241 | Line 168 | check_pings(void *notused)
168   static void
169   check_pings_list(dlink_list *list)
170   {
171 <  char scratch[IRCD_BUFSIZE];
171 >  char buf[IRCD_BUFSIZE] = "";
172    int ping = 0;      /* ping time value from client */
173 <  dlink_node *ptr = NULL, *next_ptr = NULL;
173 >  dlink_node *ptr = NULL, *ptr_next = NULL;
174  
175 <  DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
175 >  DLINK_FOREACH_SAFE(ptr, ptr_next, list->head)
176    {
177      struct Client *client_p = ptr->data;
178  
252    /*
253    ** Note: No need to notify opers here. It's
254    ** already done when "FLAGS_DEADSOCKET" is set.
255    */
179      if (IsDead(client_p))
180 <    {
258 <      /* Ignore it, its been exited already */
259 <      continue;
260 <    }
180 >      continue;  /* Ignore it, its been exited already */
181  
182      if (!IsRegistered(client_p))
183        ping = CONNECTTIMEOUT;
# Line 269 | Line 189 | check_pings_list(dlink_list *list)
189        if (!IsPingSent(client_p))
190        {
191          /*
192 <         * if we havent PINGed the connection and we havent
192 >         * If we haven't PINGed the connection and we haven't
193           * heard from it in a while, PING it to make sure
194           * it is still alive.
195           */
# Line 297 | Line 217 | check_pings_list(dlink_list *list)
217                   get_client_name(client_p, HIDE_IP));
218            }
219  
220 <          snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
220 >          snprintf(buf, sizeof(buf), "Ping timeout: %d seconds",
221                     (int)(CurrentTime - client_p->localClient->lasttime));
222 <          exit_client(client_p, &me, scratch);
222 >          exit_client(client_p, buf);
223          }
224        }
225      }
# Line 315 | Line 235 | check_pings_list(dlink_list *list)
235   static void
236   check_unknowns_list(void)
237   {
238 <  dlink_node *ptr, *next_ptr;
238 >  dlink_node *ptr = NULL, *ptr_next = NULL;
239  
240 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
240 >  DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
241    {
242      struct Client *client_p = ptr->data;
243  
# Line 326 | Line 246 | check_unknowns_list(void)
246       * for > 30s, close them.
247       */
248      if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
249 <      exit_client(client_p, &me, "Registration timed out");
249 >      exit_client(client_p, "Registration timed out");
250    }
251   }
252  
253 + /*
254 + * check_pings - go through the local client list and check activity
255 + * kill off stuff that should die
256 + *
257 + * inputs       - NOT USED (from event)
258 + * output       - next time_t when check_pings() should be called again
259 + * side effects -
260 + *
261 + *
262 + * A PING can be sent to clients as necessary.
263 + *
264 + * Client/Server ping outs are handled.
265 + */
266 +
267 + /*
268 + * Addon from adrian. We used to call this after nextping seconds,
269 + * however I've changed it to run once a second. This is only for
270 + * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
271 + * run once a second makes life a lot easier - when a new client connects
272 + * and they need a ping in 4 seconds, if nextping was set to 20 seconds
273 + * we end up waiting 20 seconds. This is stupid. :-)
274 + * I will optimise (hah!) check_pings() once I've finished working on
275 + * tidying up other network IO evilnesses.
276 + *     -- adrian
277 + */
278 +
279 + static void
280 + check_pings(void *notused)
281 + {
282 +  check_pings_list(&local_client_list);
283 +  check_pings_list(&local_server_list);
284 +  check_unknowns_list();
285 + }
286 +
287   /* check_conf_klines()
288   *
289   * inputs       - NONE
# Line 340 | Line 294 | check_unknowns_list(void)
294   void
295   check_conf_klines(void)
296   {
343  struct Client *client_p = NULL;       /* current local client_p being examined */
297    struct MaskItem *conf = NULL;
298 <  dlink_node *ptr, *next_ptr;
298 >  dlink_node *ptr = NULL, *ptr_next = NULL;
299  
300 <  DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
300 >  DLINK_FOREACH_SAFE(ptr, ptr_next, local_client_list.head)
301    {
302 <    client_p = ptr->data;
302 >    struct Client *client_p = ptr->data;
303  
304      /* If a client is already being exited
305       */
306      if (IsDead(client_p) || !IsClient(client_p))
307        continue;
308  
309 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
310 <                                  client_p->localClient->aftype)) != NULL)
309 >    if ((conf = find_conf_by_address(NULL, &client_p->localClient->ip, CONF_DLINE,
310 >                                     client_p->localClient->aftype, NULL, NULL, 1)))
311      {
359      if (conf->type == CONF_EXEMPT)
360        continue;
361
312        conf_try_ban(client_p, conf);
313        continue; /* and go examine next fd/client_p */
314      }
315  
316 <    if (ConfigFileEntry.glines)
316 >    if (ConfigGeneral.glines)
317      {
318        if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
319                                         CONF_GLINE, client_p->localClient->aftype,
# Line 392 | Line 342 | check_conf_klines(void)
342    }
343  
344    /* also check the unknowns list for new dlines */
345 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
345 >  DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
346    {
347 <    client_p = ptr->data;
347 >    struct Client *client_p = ptr->data;
348  
349 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
350 <                                 client_p->localClient->aftype)))
349 >    if ((conf = find_conf_by_address(NULL, &client_p->localClient->ip, CONF_DLINE,
350 >                                     client_p->localClient->aftype, NULL, NULL, 1)))
351      {
352 <      if (conf->type == CONF_EXEMPT)
353 <        continue;
404 <
405 <      exit_client(client_p, &me, "D-lined");
352 >      conf_try_ban(client_p, conf);
353 >      continue; /* and go examine next fd/client_p */
354      }
355    }
356   }
# Line 439 | Line 387 | conf_try_ban(struct Client *client_p, st
387        type_string = kline_string;
388        break;
389      case CONF_DLINE:
390 +      if (find_conf_by_address(NULL, &client_p->localClient->ip, CONF_EXEMPT,
391 +                               client_p->localClient->aftype, NULL, NULL, 1))
392 +        return;
393        type_string = dline_string;
394        break;
395      case CONF_GLINE:
# Line 470 | Line 421 | conf_try_ban(struct Client *client_p, st
421    if (IsClient(client_p))
422      sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, user_reason);
423  
424 <  exit_client(client_p, &me, user_reason);
424 >  exit_client(client_p, user_reason);
425   }
426  
427   /* update_client_exit_stats()
# Line 507 | Line 458 | update_client_exit_stats(struct Client *
458   * side effects - find person by (nick)name
459   */
460   struct Client *
461 < find_person(const struct Client *const client_p, const char *name)
461 > find_person(const struct Client *const source_p, const char *name)
462   {
463    struct Client *target_p = NULL;
464  
465    if (IsDigit(*name))
466    {
467 <    if (IsServer(client_p) || HasFlag(client_p, FLAGS_SERVICE))
467 >    if (IsServer(source_p->from))
468        target_p = hash_find_id(name);
469    }
470    else
# Line 525 | Line 476 | find_person(const struct Client *const c
476   /*
477   * find_chasing - find the client structure for a nick name (name)
478   *      using history mechanism if necessary. If the client is not found,
479 < *      an error message (NO SUCH NICK) is generated. If the client was found
529 < *      through the history, chasing will be 1 and otherwise 0.
479 > *      an error message (NO SUCH NICK) is generated.
480   */
481   struct Client *
482 < find_chasing(struct Client *source_p, const char *name, int *const chasing)
482 > find_chasing(struct Client *source_p, const char *name)
483   {
484 <  struct Client *who = find_person(source_p->from, name);
535 <
536 <  if (chasing)
537 <    *chasing = 0;
484 >  struct Client *who = find_person(source_p, name);
485  
486    if (who)
487      return who;
# Line 543 | Line 490 | find_chasing(struct Client *source_p, co
490      return NULL;
491  
492    if ((who = whowas_get_history(name,
493 <                         (time_t)ConfigFileEntry.kill_chase_time_limit))
493 >                         (time_t)ConfigGeneral.kill_chase_time_limit))
494                           == NULL)
495    {
496      sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
497      return NULL;
498    }
499  
553  if (chasing)
554    *chasing = 1;
555
500    return who;
501   }
502  
# Line 565 | Line 509 | find_chasing(struct Client *source_p, co
509   *        But, this can be used to any client structure.
510   *
511   * NOTE 1:
512 < *        Watch out the allocation of "nbuf", if either source_p->name
512 > *        Watch out the allocation of "buf", if either source_p->name
513   *        or source_p->sockhost gets changed into pointers instead of
514   *        directly allocated within the structure...
515   *
516   * NOTE 2:
517   *        Function return either a pointer to the structure (source_p) or
518 < *        to internal buffer (nbuf). *NEVER* use the returned pointer
518 > *        to internal buffer (buf). *NEVER* use the returned pointer
519   *        to modify what it points!!!
520   */
521   const char *
522 < get_client_name(const struct Client *client, enum addr_mask_type type)
522 > get_client_name(const struct Client *client_p, enum addr_mask_type type)
523   {
524 <  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
524 >  static char buf[HOSTLEN * 2 + USERLEN + 5];
525  
526 <  assert(client != NULL);
526 >  assert(client_p);
527  
528 <  if (!MyConnect(client))
529 <    return client->name;
528 >  if (!MyConnect(client_p))
529 >    return client_p->name;
530  
531 <  if (IsServer(client) || IsConnecting(client) || IsHandshake(client))
531 >  if (IsServer(client_p) || IsConnecting(client_p) || IsHandshake(client_p))
532    {
533 <    if (!irccmp(client->name, client->host))
534 <      return client->name;
533 >    if (!irccmp(client_p->name, client_p->host))
534 >      return client_p->name;
535      else if (ConfigServerHide.hide_server_ips)
536        type = MASK_IP;
537    }
538  
539 <  if (ConfigFileEntry.hide_spoof_ips)
540 <    if (type == SHOW_IP && IsIPSpoof(client))
539 >  if (ConfigGeneral.hide_spoof_ips)
540 >    if (IsIPSpoof(client_p) && type == SHOW_IP)
541        type = MASK_IP;
542  
543    /* And finally, let's get the host information, ip or name */
544    switch (type)
545    {
546      case SHOW_IP:
547 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
548 <               client->name,
549 <               client->username, client->sockhost);
547 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
548 >               client_p->name,
549 >               client_p->username, client_p->sockhost);
550        break;
551      case MASK_IP:
552 <      if (client->localClient->aftype == AF_INET)
553 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
554 <                 client->name, client->username);
552 >      if (client_p->localClient->aftype == AF_INET)
553 >        snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
554 >                 client_p->name, client_p->username);
555        else
556 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
557 <                 client->name, client->username);
556 >        snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
557 >                 client_p->name, client_p->username);
558        break;
559      default:
560 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
561 <               client->name,
562 <               client->username, client->host);
560 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
561 >               client_p->name,
562 >               client_p->username, client_p->host);
563    }
564  
565 <  return nbuf;
565 >  return buf;
566   }
567  
568   void
# Line 641 | Line 585 | free_exited_clients(void)
585   * The only messages generated are QUITs on channels.
586   */
587   static void
588 < exit_one_client(struct Client *source_p, const char *quitmsg)
588 > exit_one_client(struct Client *source_p, const char *comment)
589   {
590 <  dlink_node *lp = NULL, *next_lp = NULL;
590 >  dlink_node *ptr = NULL, *ptr_next = NULL;
591  
592    assert(!IsMe(source_p));
593 +  assert(source_p != &me);
594  
595    if (IsClient(source_p))
596    {
597 <    if (source_p->servptr->serv != NULL)
598 <      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
597 >    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
598 >    dlinkDelete(&source_p->node, &global_client_list);
599  
600      /*
601       * If a person is on a channel, send a QUIT notice
# Line 660 | Line 605 | exit_one_client(struct Client *source_p,
605       */
606      sendto_common_channels_local(source_p, 0, 0, ":%s!%s@%s QUIT :%s",
607                                   source_p->name, source_p->username,
608 <                                 source_p->host, quitmsg);
609 <    DLINK_FOREACH_SAFE(lp, next_lp, source_p->channel.head)
610 <      remove_user_from_channel(lp->data);
608 >                                 source_p->host, comment);
609 >    DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
610 >      remove_user_from_channel(ptr->data);
611  
612      whowas_add_history(source_p, 0);
613      whowas_off_history(source_p);
# Line 672 | Line 617 | exit_one_client(struct Client *source_p,
617      if (MyConnect(source_p))
618      {
619        /* Clean up invitefield */
620 <      DLINK_FOREACH_SAFE(lp, next_lp, source_p->localClient->invited.head)
621 <        del_invite(lp->data, source_p);
620 >      DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->localClient->invited.head)
621 >        del_invite(ptr->data, source_p);
622  
623        del_all_accepts(source_p);
624      }
# Line 681 | Line 626 | exit_one_client(struct Client *source_p,
626    else if (IsServer(source_p))
627    {
628      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
629 +    dlinkDelete(&source_p->node, &global_client_list);
630  
631 <    if ((lp = dlinkFindDelete(&global_serv_list, source_p)) != NULL)
632 <      free_dlink_node(lp);
631 >    if ((ptr = dlinkFindDelete(&global_server_list, source_p)))
632 >      free_dlink_node(ptr);
633    }
634  
635    /* Remove source_p from the client lists */
636 <  if (HasID(source_p))
636 >  if (source_p->id[0])
637      hash_del_id(source_p);
638    if (source_p->name[0])
639      hash_del_client(source_p);
# Line 695 | Line 641 | exit_one_client(struct Client *source_p,
641    if (IsUserHostIp(source_p))
642      delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
643  
698  /* remove from global client list
699   * NOTE: source_p->node.next cannot be NULL if the client is added
700   *       to global_client_list (there is always &me at its end)
701   */
702  if (source_p != NULL && source_p->node.next != NULL)
703    dlinkDelete(&source_p->node, &global_client_list);
704
644    update_client_exit_stats(source_p);
645  
646    /* Check to see if the client isn't already on the dead list */
# Line 712 | Line 651 | exit_one_client(struct Client *source_p,
651    dlinkAdd(source_p, make_dlink_node(), &dead_list);
652   }
653  
715 /* Recursively send QUITs and SQUITs for source_p and all its dependent clients
716 * and servers to those servers that need them.  A server needs the client
717 * QUITs if it can't figure them out from the SQUIT (ie pre-TS4) or if it
718 * isn't getting the SQUIT because of @#(*&@)# hostmasking.  With TS4, once
719 * a link gets a SQUIT, it doesn't need any QUIT/SQUITs for clients depending
720 * on that one -orabidoo
721 *
722 * This is now called on each local server -adx
723 */
724 static void
725 recurse_send_quits(struct Client *original_source_p, struct Client *source_p,
726                   struct Client *from, struct Client *to, const char *comment,
727                   const char *splitstr)
728 {
729  dlink_node *ptr, *next;
730  struct Client *target_p;
731
732  assert(to != source_p);  /* should be already removed from serv_list */
733
734  /* If this server can handle quit storm (QS) removal
735   * of dependents, just send the SQUIT
736   */
737  if (!IsCapable(to, CAP_QS))
738    DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
739    {
740      target_p = ptr->data;
741      sendto_one(to, ":%s QUIT :%s", target_p->name, splitstr);
742    }
743
744  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
745    recurse_send_quits(original_source_p, ptr->data, from, to,
746                       comment, splitstr);
747
748  if ((source_p == original_source_p && to != from) ||
749                  !IsCapable(to, CAP_QS))
750  {
751    /* don't use a prefix here - we have to be 100% sure the message
752     * will be accepted without Unknown prefix etc.. */
753    sendto_one(to, "SQUIT %s :%s", ID_or_name(source_p, to), comment);
754  }
755 }
756
654   /*
655   * Remove all clients that depend on source_p; assumes all (S)QUITs have
656   * already been sent.  we make sure to exit a server's dependent clients
# Line 761 | Line 658 | recurse_send_quits(struct Client *origin
658   * actually removing things off llists.   tweaked from +CSr31  -orabidoo
659   */
660   static void
661 < recurse_remove_clients(struct Client *source_p, const char *quitmsg)
661 > recurse_remove_clients(struct Client *source_p, const char *comment)
662   {
663 <  dlink_node *ptr, *next;
663 >  dlink_node *ptr = NULL, *ptr_next = NULL;
664  
665 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->client_list.head)
666 <    exit_one_client(ptr->data, quitmsg);
665 >  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->client_list.head)
666 >    exit_one_client(ptr->data, comment);
667  
668 <  DLINK_FOREACH_SAFE(ptr, next, source_p->serv->server_list.head)
668 >  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->server_list.head)
669    {
670 <    recurse_remove_clients(ptr->data, quitmsg);
671 <    exit_one_client(ptr->data, quitmsg);
670 >    recurse_remove_clients(ptr->data, comment);
671 >    exit_one_client(ptr->data, comment);
672    }
673   }
674  
675   /*
779 ** Remove *everything* that depends on source_p, from all lists, and sending
780 ** all necessary QUITs and SQUITs.  source_p itself is still on the lists,
781 ** and its SQUITs have been sent except for the upstream one  -orabidoo
782 */
783 static void
784 remove_dependents(struct Client *source_p, struct Client *from,
785                  const char *comment, const char *splitstr)
786 {
787  dlink_node *ptr = NULL;
788
789  DLINK_FOREACH(ptr, serv_list.head)
790    recurse_send_quits(source_p, source_p, from, ptr->data,
791                       comment, splitstr);
792
793  recurse_remove_clients(source_p, splitstr);
794 }
795
796 /*
676   * exit_client - exit a client of any type. Generally, you can use
677   * this on any struct Client, regardless of its state.
678   *
679   * Note, you shouldn't exit remote _users_ without first doing
680   * AddFlag(x, FLAGS_KILLED) and propagating a kill or similar message.
681 + *
682   * However, it is perfectly correct to call exit_client to force a _server_
683   * quit (either local or remote one).
684   *
685 + *
686   * inputs:       - a client pointer that is going to be exited
806 *               - for servers, the second argument is a pointer to who
807 *                 is firing the server. This side won't get any generated
808 *                 messages. NEVER NULL!
687   * output:       none
688   * side effects: the client is delinked from all lists, disconnected,
689   *               and the rest of IRC network is notified of the exit.
690   *               Client memory is scheduled to be freed
691   */
692   void
693 < exit_client(struct Client *source_p, struct Client *from, const char *comment)
693 > exit_client(struct Client *source_p, const char *comment)
694   {
695    dlink_node *m = NULL;
696  
697 +  assert(!IsMe(source_p));
698 +  assert(source_p != &me);
699 +
700    if (MyConnect(source_p))
701    {
702      /* DO NOT REMOVE. exit_client can be called twice after a failed
# Line 826 | Line 707 | exit_client(struct Client *source_p, str
707  
708      SetClosing(source_p);
709  
710 <    if (IsIpHash(source_p))
711 <      remove_one_ip(&source_p->localClient->ip);
710 >    if (HasFlag(source_p, FLAGS_IPHASH))
711 >    {
712 >      DelFlag(source_p, FLAGS_IPHASH);
713 >      ipcache_remove_address(&source_p->localClient->ip);
714 >    }
715  
716      delete_auth(&source_p->localClient->auth);
717  
# Line 851 | Line 735 | exit_client(struct Client *source_p, str
735        Count.local--;
736  
737        if (HasUMode(source_p, UMODE_OPER))
738 <        if ((m = dlinkFindDelete(&oper_list, source_p)) != NULL)
738 >        if ((m = dlinkFindDelete(&oper_list, source_p)))
739            free_dlink_node(m);
740  
741        assert(dlinkFind(&local_client_list, source_p));
742        dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
743  
744 <      if (source_p->localClient->list_task != NULL)
745 <        free_list_task(source_p->localClient->list_task, source_p);
744 >      if (source_p->localClient->list_task)
745 >        free_list_task(source_p);
746  
747        watch_del_watch_list(source_p);
748        sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
749                             "Client exiting: %s (%s@%s) [%s] [%s]",
750                             source_p->name, source_p->username, source_p->host, comment,
751 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
751 >                           ConfigGeneral.hide_spoof_ips && IsIPSpoof(source_p) ?
752                             "255.255.255.255" : source_p->sockhost);
753        ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
754             myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
# Line 878 | Line 762 | exit_client(struct Client *source_p, str
762        assert(Count.myserver > 0);
763        --Count.myserver;
764  
765 <      assert(dlinkFind(&serv_list, source_p));
766 <      dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
765 >      assert(dlinkFind(&local_server_list, source_p));
766 >      dlinkDelete(&source_p->localClient->lclient_node, &local_server_list);
767      }
768  
769      if (!IsDead(source_p))
770      {
771        if (IsServer(source_p))
772        {
773 <        /* for them, we are exiting the network */
774 <        sendto_one(source_p, ":%s SQUIT %s :%s",
775 <                   ID_or_name(from, source_p), me.name, comment);
773 >        if (!HasFlag(source_p, FLAGS_SQUIT))
774 >        {
775 >          /* for them, we are exiting the network */
776 >          sendto_one(source_p, ":%s SQUIT %s :%s",
777 >                     me.id, me.id, comment);
778 >        }
779        }
780  
781        sendto_one(source_p, "ERROR :Closing Link: %s (%s)",
782                   source_p->host, comment);
783      }
784  
898    /*
899    ** Currently only server connections can have
900    ** depending remote clients here, but it does no
901    ** harm to check for all local clients. In
902    ** future some other clients than servers might
903    ** have remotes too...
904    **
905    ** Close the Client connection first and mark it
906    ** so that no messages are attempted to send to it.
907    ** Remember it makes source_p->from == NULL.
908    */
785      close_connection(source_p);
786    }
787    else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
# Line 916 | Line 792 | exit_client(struct Client *source_p, str
792  
793    if (IsServer(source_p))
794    {
795 <    char splitstr[HOSTLEN + HOSTLEN + 2];
795 >    char splitstr[HOSTLEN + HOSTLEN + 2] = "";
796  
797      /* This shouldn't ever happen */
798 <    assert(source_p->serv != NULL && source_p->servptr != NULL);
798 >    assert(source_p->serv && source_p->servptr);
799  
800      if (ConfigServerHide.hide_servers)
801        /*
802         * Set netsplit message to "*.net *.split" to still show
803         * that its a split, but hide the servers splitting
804         */
805 <      strcpy(splitstr, "*.net *.split");
805 >      strlcpy(splitstr, "*.net *.split", sizeof(splitstr));
806      else
807        snprintf(splitstr, sizeof(splitstr), "%s %s",
808                 source_p->servptr->name, source_p->name);
809  
810 <    remove_dependents(source_p, from->from, comment, splitstr);
810 >    /* Send SQUIT for source_p in every direction. source_p is already off of local_server_list here */
811 >    if (!HasFlag(source_p, FLAGS_SQUIT))
812 >      sendto_server(NULL, NOCAPS, NOCAPS, "SQUIT %s :%s", source_p->id, comment);
813 >
814 >    /* Now exit the clients internally */
815 >    recurse_remove_clients(source_p, splitstr);
816  
817 <    if (source_p->servptr == &me)
817 >    if (MyConnect(source_p))
818      {
819        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
820                             "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
# Line 947 | Line 828 | exit_client(struct Client *source_p, str
828      }
829    }
830    else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
831 <    sendto_server(from->from, NOCAPS, NOCAPS, ":%s QUIT :%s",
832 <                  ID(source_p), comment);
831 >    sendto_server(source_p->from, NOCAPS, NOCAPS, ":%s QUIT :%s",
832 >                  source_p->id, comment);
833  
834    /* The client *better* be off all of the lists */
835    assert(dlinkFind(&unknown_list, source_p) == NULL);
836    assert(dlinkFind(&local_client_list, source_p) == NULL);
837 <  assert(dlinkFind(&serv_list, source_p) == NULL);
837 >  assert(dlinkFind(&local_server_list, source_p) == NULL);
838    assert(dlinkFind(&oper_list, source_p) == NULL);
839  
840    exit_one_client(source_p, comment);
# Line 1045 | Line 926 | dead_link_on_read(struct Client *client_
926      snprintf(errmsg, sizeof(errmsg), "Read error: %s",
927               strerror(current_error));
928  
929 <  exit_client(client_p, &me, errmsg);
929 >  exit_client(client_p, errmsg);
930   }
931  
932   void
# Line 1076 | Line 957 | exit_aborted_clients(void)
957      else
958        notice = "Write error: connection closed";
959  
960 <    exit_client(target_p, &me, notice);
960 >    exit_client(target_p, notice);
961      free_dlink_node(ptr);
962    }
963   }
# Line 1156 | Line 1037 | accept_message(struct Client *source,
1037   void
1038   del_all_accepts(struct Client *client_p)
1039   {
1040 <  dlink_node *ptr = NULL, *next_ptr = NULL;
1040 >  dlink_node *ptr = NULL, *ptr_next = NULL;
1041  
1042 <  DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->acceptlist.head)
1042 >  DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->acceptlist.head)
1043      del_accept(ptr->data, client_p);
1044   }
1045  
# Line 1187 | Line 1068 | idle_time_get(const struct Client *sourc
1068    else
1069      idle = CurrentTime - target_p->localClient->last_privmsg;
1070  
1071 <  if (max_idle == 0)
1071 >  if (!max_idle)
1072      idle = 0;
1073    else
1074      idle %= max_idle;
# Line 1197 | Line 1078 | idle_time_get(const struct Client *sourc
1078  
1079    return idle;
1080   }
1081 +
1082 + /* client_init()
1083 + *
1084 + * inputs       - NONE
1085 + * output       - NONE
1086 + * side effects - initialize client free memory
1087 + */
1088 + void
1089 + client_init(void)
1090 + {
1091 +  static struct event event_ping =
1092 +  {
1093 +    .name = "check_pings",
1094 +    .handler = check_pings,
1095 +    .when = 5
1096 +  };
1097 +
1098 +  client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
1099 +  lclient_pool = mp_pool_new(sizeof(struct LocalUser), MP_CHUNK_SIZE_LCLIENT);
1100 +  event_add(&event_ping, NULL);
1101 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)