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 3324 by michael, Tue Apr 15 16:18:07 2014 UTC vs.
Revision 8399 by michael, Sun Mar 18 14:43:15 2018 UTC

# Line 1 | Line 1
1   /*
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (c) 1997-2014 ircd-hybrid development team
4 > *  Copyright (c) 1997-2018 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 15 | Line 15
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18 < *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20   */
21  
# Line 35 | Line 35
35   #include "auth.h"
36   #include "s_bsd.h"
37   #include "conf.h"
38 + #include "conf_gecos.h"
39   #include "log.h"
40 < #include "s_misc.h"
41 < #include "s_serv.h"
40 > #include "misc.h"
41 > #include "server.h"
42   #include "send.h"
43   #include "whowas.h"
44 < #include "s_user.h"
44 > #include "user.h"
45   #include "memory.h"
45 #include "mempool.h"
46   #include "hostmask.h"
47   #include "listener.h"
48   #include "userhost.h"
49   #include "watch.h"
50   #include "rng_mt.h"
51   #include "parse.h"
52 + #include "ipcache.h"
53  
53 dlink_list listing_client_list = { NULL, NULL, 0 };
54 /* Pointer to beginning of Client list */
55 dlink_list global_client_list = {NULL, NULL, 0};
56 /* unknown/client pointer lists */
57 dlink_list unknown_list = {NULL, NULL, 0};
58 dlink_list local_client_list = {NULL, NULL, 0};
59 dlink_list serv_list = {NULL, NULL, 0};
60 dlink_list global_serv_list = {NULL, NULL, 0};
61 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 dlink_list dead_list, abort_list;
64   static dlink_node *eac_next;  /* next aborted client to exit */
65  
73 static void check_pings_list(dlink_list *);
74 static void check_unknowns_list(void);
75
76
77 /* client_init()
78 *
79 * inputs       - NONE
80 * output       - NONE
81 * side effects - initialize client free memory
82 */
83 void
84 client_init(void)
85 {
86  /* start off the check ping event ..  -- adrian
87   * Every 30 seconds is plenty -- db
88   */
89  client_pool = mp_pool_new(sizeof(struct Client), MP_CHUNK_SIZE_CLIENT);
90  lclient_pool = mp_pool_new(sizeof(struct LocalUser), MP_CHUNK_SIZE_LCLIENT);
91  eventAdd("check_pings", check_pings, NULL, 5);
92 }
66  
67   /*
68   * make_client - create a new Client struct and set it to initial state.
# Line 107 | Line 80 | client_init(void)
80   *                      'from'). ('from' is a local client!!).
81   */
82   struct Client *
83 < make_client(struct Client *from)
83 > client_make(struct Client *from)
84   {
85 <  struct Client *client_p = mp_pool_get(client_pool);
113 <
114 <  memset(client_p, 0, sizeof(*client_p));
85 >  struct Client *const client_p = xcalloc(sizeof(*client_p));
86  
87 <  if (!from)
87 >  if (from)
88 >    client_p->from = from;
89 >  else
90    {
91 <    client_p->from                      = client_p; /* 'from' of local client is self! */
92 <    client_p->localClient               = mp_pool_get(lclient_pool);
93 <
94 <    memset(client_p->localClient, 0, sizeof(*client_p->localClient));
95 <
96 <    client_p->localClient->since        = CurrentTime;
124 <    client_p->localClient->lasttime     = CurrentTime;
125 <    client_p->localClient->firsttime    = CurrentTime;
126 <    client_p->localClient->registration = REG_INIT;
91 >    client_p->from = client_p;  /* 'from' of local client is self! */
92 >    client_p->connection = xcalloc(sizeof(*client_p->connection));
93 >    client_p->connection->since = CurrentTime;
94 >    client_p->connection->lasttime = CurrentTime;
95 >    client_p->connection->firsttime = CurrentTime;
96 >    client_p->connection->registration = REG_INIT;
97  
98      /* as good a place as any... */
99 <    dlinkAdd(client_p, &client_p->localClient->lclient_node, &unknown_list);
99 >    dlinkAdd(client_p, &client_p->connection->lclient_node, &unknown_list);
100    }
131  else
132    client_p->from = from; /* 'from' of local client is self! */
101  
102    client_p->idhnext = client_p;
103 <  client_p->hnext  = client_p;
103 >  client_p->hnext = client_p;
104    SetUnknown(client_p);
105    strcpy(client_p->username, "unknown");
106 <  strcpy(client_p->svid, "0");
106 >  strcpy(client_p->account, "*");
107  
108    return client_p;
109   }
110  
111   /*
112 < * free_client
112 > * client_free
113   *
114   * inputs       - pointer to client
115   * output       - NONE
116   * side effects - client pointed to has its memory freed
117   */
118   static void
119 < free_client(struct Client *client_p)
119 > client_free(struct Client *client_p)
120   {
121 <  assert(client_p);
121 >  assert(!IsMe(client_p));
122    assert(client_p != &me);
123    assert(client_p->hnext == client_p);
124    assert(client_p->idhnext == client_p);
125 <  assert(client_p->channel.head == NULL);
125 >
126 >  assert(client_p->node.data == NULL);
127 >  assert(client_p->node.prev == NULL);
128 >  assert(client_p->node.next == NULL);
129 >
130 >  assert(client_p->lnode.data == NULL);
131 >  assert(client_p->lnode.prev == NULL);
132 >  assert(client_p->lnode.next == NULL);
133 >
134 >  assert(dlink_list_length(&client_p->whowas_list) == 0);
135 >  assert(client_p->whowas_list.head == NULL);
136 >  assert(client_p->whowas_list.tail == NULL);
137 >
138    assert(dlink_list_length(&client_p->channel) == 0);
139 <  assert(dlink_list_length(&client_p->whowas) == 0);
140 <  assert(!IsServer(client_p) || (IsServer(client_p) && client_p->serv));
139 >  assert(client_p->channel.head == NULL);
140 >  assert(client_p->channel.tail == NULL);
141 >
142 >  assert(dlink_list_length(&client_p->svstags) == 0);
143 >  assert(client_p->svstags.head == NULL);
144 >  assert(client_p->svstags.tail == NULL);
145  
146 <  MyFree(client_p->serv);
147 <  MyFree(client_p->certfp);
146 >
147 >  xfree(client_p->serv);
148 >  xfree(client_p->certfp);
149  
150    if (MyConnect(client_p))
151    {
152 <    assert(client_p->localClient->invited.head == NULL);
153 <    assert(dlink_list_length(&client_p->localClient->invited) == 0);
154 <    assert(dlink_list_length(&client_p->localClient->watches) == 0);
155 <    assert(IsClosing(client_p) && IsDead(client_p));
152 >    assert(client_p->connection->lclient_node.data == NULL);
153 >    assert(client_p->connection->lclient_node.prev == NULL);
154 >    assert(client_p->connection->lclient_node.next == NULL);
155 >
156 >    assert(client_p->connection->list_task == NULL);
157 >    assert(client_p->connection->auth == NULL);
158  
159 <    MyFree(client_p->localClient->response);
160 <    MyFree(client_p->localClient->auth_oper);
159 >    assert(dlink_list_length(&client_p->connection->acceptlist) == 0);
160 >    assert(client_p->connection->acceptlist.head == NULL);
161 >    assert(client_p->connection->acceptlist.tail == NULL);
162 >
163 >
164 >    assert(dlink_list_length(&client_p->connection->watches) == 0);
165 >    assert(client_p->connection->watches.head == NULL);
166 >    assert(client_p->connection->watches.tail == NULL);
167 >
168 >    assert(dlink_list_length(&client_p->connection->confs) == 0);
169 >    assert(client_p->connection->confs.head == NULL);
170 >    assert(client_p->connection->confs.tail == NULL);
171 >
172 >    assert(dlink_list_length(&client_p->connection->invited) == 0);
173 >    assert(client_p->connection->invited.head == NULL);
174 >    assert(client_p->connection->invited.tail == NULL);
175 >
176 >    assert(client_p->connection->fd == NULL);
177 >
178 >    assert(HasFlag(client_p, FLAGS_CLOSING) && IsDead(client_p));
179  
180      /*
181 <     * clean up extra sockets from P-lines which have been discarded.
181 >     * Clean up extra sockets from listen {} blocks which have been discarded.
182       */
183 <    if (client_p->localClient->listener)
183 >    if (client_p->connection->listener)
184      {
185 <      assert(0 < client_p->localClient->listener->ref_count);
186 <      if (0 == --client_p->localClient->listener->ref_count &&
182 <          !client_p->localClient->listener->active)
183 <        free_listener(client_p->localClient->listener);
185 >      listener_release(client_p->connection->listener);
186 >      client_p->connection->listener = NULL;
187      }
188  
189 <    dbuf_clear(&client_p->localClient->buf_recvq);
190 <    dbuf_clear(&client_p->localClient->buf_sendq);
189 >    dbuf_clear(&client_p->connection->buf_recvq);
190 >    dbuf_clear(&client_p->connection->buf_sendq);
191  
192 <    mp_pool_release(client_p->localClient);
192 >    xfree(client_p->connection);
193 >    client_p->connection = NULL;
194    }
195  
196 <  mp_pool_release(client_p);
196 >  xfree(client_p);
197   }
198  
199 < /*
200 < * check_pings - go through the local client list and check activity
201 < * kill off stuff that should die
202 < *
203 < * inputs       - NOT USED (from event)
204 < * output       - next time_t when check_pings() should be called again
205 < * side effects -
202 < *
203 < *
204 < * A PING can be sent to clients as necessary.
205 < *
206 < * Client/Server ping outs are handled.
207 < */
199 > static void
200 > svstag_free(struct ServicesTag *svstag, dlink_list *list)
201 > {
202 >  dlinkDelete(&svstag->node, list);
203 >  xfree(svstag->tag);
204 >  xfree(svstag);
205 > }
206  
207 < /*
208 < * Addon from adrian. We used to call this after nextping seconds,
209 < * however I've changed it to run once a second. This is only for
210 < * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
213 < * run once a second makes life a lot easier - when a new client connects
214 < * and they need a ping in 4 seconds, if nextping was set to 20 seconds
215 < * we end up waiting 20 seconds. This is stupid. :-)
216 < * I will optimise (hah!) check_pings() once I've finished working on
217 < * tidying up other network IO evilnesses.
218 < *     -- adrian
219 < */
207 > void
208 > client_detach_svstag(dlink_list *list, unsigned int numeric)
209 > {
210 >  dlink_node *node, *node_next;
211  
212 < static void
213 < check_pings(void *notused)
212 >  DLINK_FOREACH_SAFE(node, node_next, list->head)
213 >  {
214 >    struct ServicesTag *svstag = node->data;
215 >
216 >    if (svstag->numeric == numeric)
217 >      svstag_free(svstag, list);
218 >  }
219 > }
220 >
221 > void
222 > client_attach_svstag(dlink_list *list, unsigned int numeric,
223 >                     const char *umodes, const char *tag)
224   {
225 <  check_pings_list(&local_client_list);
226 <  check_pings_list(&serv_list);
227 <  check_unknowns_list();
225 >  const struct user_modes *tab = NULL;
226 >
227 >  if (numeric >= ERR_LAST_ERR_MSG || *umodes != '+')
228 >    return;
229 >
230 >  struct ServicesTag *svstag = xcalloc(sizeof(*svstag));
231 >  svstag->numeric = numeric;
232 >  svstag->tag = xstrdup(tag);
233 >
234 >  for (const char *m = umodes + 1; *m; ++m)
235 >    if ((tab = umode_map[(unsigned char)*m]))
236 >      svstag->umodes |= tab->flag;
237 >
238 >  if (numeric != RPL_WHOISOPERATOR)
239 >    dlinkAddTail(svstag, &svstag->node, list);
240 >  else
241 >    dlinkAdd(svstag, &svstag->node, list);
242 > }
243 >
244 > void
245 > client_clear_svstags(dlink_list *list)
246 > {
247 >  while (list->head)
248 >    svstag_free(list->head->data, list);
249   }
250  
251   /* check_pings_list()
# Line 235 | Line 257 | check_pings(void *notused)
257   static void
258   check_pings_list(dlink_list *list)
259   {
260 <  char scratch[IRCD_BUFSIZE];
261 <  int ping = 0;      /* ping time value from client */
262 <  dlink_node *ptr = NULL, *next_ptr = NULL;
260 >  char buf[32] = "";  /* 32 = sizeof("Ping timeout: 999999999 seconds") */
261 >  unsigned int ping = 0;      /* ping time value from client */
262 >  dlink_node *node = NULL, *node_next = NULL;
263  
264 <  DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
264 >  DLINK_FOREACH_SAFE(node, node_next, list->head)
265    {
266 <    struct Client *client_p = ptr->data;
266 >    struct Client *client_p = node->data;
267  
246    /*
247    ** Note: No need to notify opers here. It's
248    ** already done when "FLAGS_DEADSOCKET" is set.
249    */
268      if (IsDead(client_p))
269 <    {
252 <      /* Ignore it, its been exited already */
253 <      continue;
254 <    }
269 >      continue;  /* Ignore it, its been exited already */
270  
271 <    if (!IsRegistered(client_p))
272 <      ping = CONNECTTIMEOUT;
271 >    if (IsClient(client_p) || IsServer(client_p))
272 >      ping = get_client_ping(&client_p->connection->confs);
273      else
274 <      ping = get_client_ping(&client_p->localClient->confs);
274 >      ping = CONNECTTIMEOUT;
275  
276 <    if (ping < CurrentTime - client_p->localClient->lasttime)
276 >    if (ping < CurrentTime - client_p->connection->lasttime)
277      {
278 <      if (!IsPingSent(client_p))
278 >      if (!HasFlag(client_p, FLAGS_PINGSENT))
279        {
280          /*
281 <         * if we havent PINGed the connection and we havent
281 >         * If we haven't PINGed the connection and we haven't
282           * heard from it in a while, PING it to make sure
283           * it is still alive.
284           */
285 <        SetPingSent(client_p);
286 <        client_p->localClient->lasttime = CurrentTime - ping;
285 >        AddFlag(client_p, FLAGS_PINGSENT);
286 >        client_p->connection->lasttime = CurrentTime - ping;
287          sendto_one(client_p, "PING :%s", ID_or_name(&me, client_p));
288        }
289        else
290        {
291 <        if (CurrentTime - client_p->localClient->lasttime >= 2 * ping)
291 >        if (CurrentTime - client_p->connection->lasttime >= 2 * ping)
292          {
293            /*
294             * If the client/server hasn't talked to us in 2*ping seconds
# Line 281 | Line 296 | check_pings_list(dlink_list *list)
296             */
297            if (IsServer(client_p) || IsHandshake(client_p))
298            {
299 <            sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
299 >            sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
300                                   "No response from %s, closing link",
301 <                                 get_client_name(client_p, HIDE_IP));
302 <            sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
301 >                                 client_get_name(client_p, SHOW_IP));
302 >            sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
303                                   "No response from %s, closing link",
304 <                                 get_client_name(client_p, MASK_IP));
304 >                                 client_get_name(client_p, MASK_IP));
305              ilog(LOG_TYPE_IRCD, "No response from %s, closing link",
306 <                 get_client_name(client_p, HIDE_IP));
306 >                 client_get_name(client_p, SHOW_IP));
307            }
308  
309 <          snprintf(scratch, sizeof(scratch), "Ping timeout: %d seconds",
310 <                   (int)(CurrentTime - client_p->localClient->lasttime));
311 <          exit_client(client_p, scratch);
309 >          snprintf(buf, sizeof(buf), "Ping timeout: %ji seconds",
310 >                   (CurrentTime - client_p->connection->lasttime));
311 >          exit_client(client_p, buf);
312          }
313        }
314      }
# Line 309 | Line 324 | check_pings_list(dlink_list *list)
324   static void
325   check_unknowns_list(void)
326   {
327 <  dlink_node *ptr = NULL, *ptr_next = NULL;
327 >  dlink_node *node = NULL, *node_next = NULL;
328  
329 <  DLINK_FOREACH_SAFE(ptr, ptr_next, unknown_list.head)
329 >  DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
330    {
331 <    struct Client *client_p = ptr->data;
331 >    struct Client *client_p = node->data;
332  
333      /*
334       * Check UNKNOWN connections - if they have been in this state
335       * for > 30s, close them.
336       */
337 <    if (IsAuthFinished(client_p) && (CurrentTime - client_p->localClient->firsttime) > 30)
337 >    if (HasFlag(client_p, FLAGS_FINISHED_AUTH) && (CurrentTime - client_p->connection->firsttime) > 30)
338        exit_client(client_p, "Registration timed out");
339    }
340   }
341  
342 + /*
343 + * check_pings - go through the local client list and check activity
344 + * kill off stuff that should die
345 + *
346 + * inputs       - NOT USED (from event)
347 + * side effects -
348 + *
349 + *
350 + * A PING can be sent to clients as necessary.
351 + *
352 + * Client/Server ping outs are handled.
353 + */
354 +
355 + /*
356 + * Addon from adrian. We used to call this after nextping seconds,
357 + * however I've changed it to run once a second. This is only for
358 + * PING timeouts, not K/etc-line checks (thanks dianora!). Having it
359 + * run once a second makes life a lot easier - when a new client connects
360 + * and they need a ping in 4 seconds, if nextping was set to 20 seconds
361 + * we end up waiting 20 seconds. This is stupid. :-)
362 + * I will optimise (hah!) check_pings() once I've finished working on
363 + * tidying up other network IO evilnesses.
364 + *     -- adrian
365 + */
366 +
367 + static void
368 + check_pings(void *unused)
369 + {
370 +  check_pings_list(&local_client_list);
371 +  check_pings_list(&local_server_list);
372 +  check_unknowns_list();
373 + }
374 +
375   /* check_conf_klines()
376   *
377   * inputs       - NONE
# Line 334 | Line 382 | check_unknowns_list(void)
382   void
383   check_conf_klines(void)
384   {
385 <  struct Client *client_p = NULL;       /* current local client_p being examined */
386 <  struct MaskItem *conf = NULL;
339 <  dlink_node *ptr, *next_ptr;
385 >  dlink_node *node = NULL, *node_next = NULL;
386 >  const void *ptr;
387  
388 <  DLINK_FOREACH_SAFE(ptr, next_ptr, local_client_list.head)
388 >  DLINK_FOREACH_SAFE(node, node_next, local_client_list.head)
389    {
390 <    client_p = ptr->data;
390 >    struct Client *client_p = node->data;
391  
392 <    /* If a client is already being exited
393 <     */
347 <    if (IsDead(client_p) || !IsClient(client_p))
392 >    /* If a client is already being exited */
393 >    if (IsDead(client_p))
394        continue;
395  
396 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
397 <                                  client_p->localClient->aftype)))
352 <    {
353 <      if (conf->type == CONF_EXEMPT)
354 <        continue;
355 <
356 <      conf_try_ban(client_p, conf);
357 <      continue; /* and go examine next fd/client_p */
358 <    }
359 <
360 <    if (ConfigFileEntry.glines)
396 >    if ((ptr = find_conf_by_address(NULL, &client_p->connection->ip, CONF_DLINE,
397 >                                    client_p->connection->aftype, NULL, NULL, 1)))
398      {
399 <      if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
400 <                                       CONF_GLINE, client_p->localClient->aftype,
401 <                                       client_p->username, NULL, 1)))
365 <      {
366 <        conf_try_ban(client_p, conf);
367 <        /* and go examine next fd/client_p */
368 <        continue;
369 <      }
399 >      const struct MaskItem *conf = ptr;
400 >      conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
401 >      continue;  /* and go examine next Client */
402      }
403  
404 <    if ((conf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
405 <                                     CONF_KLINE, client_p->localClient->aftype,
406 <                                     client_p->username, NULL, 1)))
404 >    if ((ptr = find_conf_by_address(client_p->host, &client_p->connection->ip,
405 >                                    CONF_KLINE, client_p->connection->aftype,
406 >                                    client_p->username, NULL, 1)))
407      {
408 <      conf_try_ban(client_p, conf);
409 <      continue;
408 >      const struct MaskItem *conf = ptr;
409 >      conf_try_ban(client_p, CLIENT_BAN_KLINE, conf->reason);
410 >      continue;  /* and go examine next Client */
411      }
412  
413 <    if ((conf = find_matching_name_conf(CONF_XLINE,  client_p->info,
381 <                                        NULL, NULL, 0)))
413 >    if ((ptr = gecos_find(client_p->info, match)))
414      {
415 <      conf_try_ban(client_p, conf);
416 <      continue;
415 >      const struct GecosItem *conf = ptr;
416 >      conf_try_ban(client_p, CLIENT_BAN_XLINE, conf->reason);
417 >      continue;  /* and go examine next Client */
418      }
419    }
420  
421 <  /* also check the unknowns list for new dlines */
422 <  DLINK_FOREACH_SAFE(ptr, next_ptr, unknown_list.head)
421 >  /* Also check the unknowns list for new dlines */
422 >  DLINK_FOREACH_SAFE(node, node_next, unknown_list.head)
423    {
424 <    client_p = ptr->data;
424 >    struct Client *client_p = node->data;
425  
426 <    if ((conf = find_dline_conf(&client_p->localClient->ip,
427 <                                 client_p->localClient->aftype)))
426 >    if ((ptr = find_conf_by_address(NULL, &client_p->connection->ip, CONF_DLINE,
427 >                                    client_p->connection->aftype, NULL, NULL, 1)))
428      {
429 <      if (conf->type == CONF_EXEMPT)
430 <        continue;
431 <
399 <      exit_client(client_p, "D-lined");
429 >      const struct MaskItem *conf = ptr;
430 >      conf_try_ban(client_p, CLIENT_BAN_DLINE, conf->reason);
431 >      continue;  /* and go examine next Client */
432      }
433    }
434   }
# Line 410 | Line 442 | check_conf_klines(void)
442   * side effects - given client_p is banned
443   */
444   void
445 < conf_try_ban(struct Client *client_p, struct MaskItem *conf)
445 > conf_try_ban(struct Client *client_p, int type, const char *reason)
446   {
447 <  const char *user_reason = NULL;  /* What is sent to user */
416 <  const char *type_string = NULL;
417 <  const char dline_string[] = "D-line";
418 <  const char kline_string[] = "K-line";
419 <  const char gline_string[] = "G-line";
420 <  const char xline_string[] = "X-line";
447 >  char ban_type = '?';
448  
449 <  switch (conf->type)
449 >  switch (type)
450    {
451 <    case CONF_KLINE:
452 <      if (IsExemptKline(client_p))
451 >    case CLIENT_BAN_KLINE:
452 >      if (HasFlag(client_p, FLAGS_EXEMPTKLINE))
453        {
454 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
454 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
455                               "KLINE over-ruled for %s, client is kline_exempt",
456 <                             get_client_name(client_p, HIDE_IP));
456 >                             client_get_name(client_p, HIDE_IP));
457          return;
458        }
459  
460 <      type_string = kline_string;
460 >      ban_type = 'K';
461        break;
462 <    case CONF_DLINE:
463 <      type_string = dline_string;
462 >    case CLIENT_BAN_DLINE:
463 >      if (find_conf_by_address(NULL, &client_p->connection->ip, CONF_EXEMPT,
464 >                               client_p->connection->aftype, NULL, NULL, 1))
465 >        return;
466 >      ban_type = 'D';
467        break;
468 <    case CONF_GLINE:
469 <      if (IsExemptKline(client_p) ||
440 <          IsExemptGline(client_p))
468 >    case CLIENT_BAN_XLINE:
469 >      if (HasFlag(client_p, FLAGS_EXEMPTXLINE))
470        {
471 <        sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
472 <                             "GLINE over-ruled for %s, client is %sline_exempt",
473 <                             get_client_name(client_p, HIDE_IP), IsExemptKline(client_p) ? "k" : "g");
471 >        sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
472 >                             "XLINE over-ruled for %s, client is xline_exempt",
473 >                             client_get_name(client_p, HIDE_IP));
474          return;
475        }
476  
477 <      type_string = gline_string;
449 <      break;
450 <    case CONF_XLINE:
451 <      type_string = xline_string;
452 <      ++conf->count;
477 >      ban_type = 'X';
478        break;
479      default:
480        assert(0);
481        break;
482    }
483  
484 <  user_reason = conf->reason ? conf->reason : type_string;
485 <
461 <  sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, "%s active for %s",
462 <                       type_string, get_client_name(client_p, HIDE_IP));
484 >  sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE, "%c-line active for %s",
485 >                       ban_type, client_get_name(client_p, HIDE_IP));
486  
487    if (IsClient(client_p))
488 <    sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, user_reason);
488 >    sendto_one_numeric(client_p, &me, ERR_YOUREBANNEDCREEP, reason);
489  
490 <  exit_client(client_p, user_reason);
468 < }
469 <
470 < /* update_client_exit_stats()
471 < *
472 < * input        - pointer to client
473 < * output       - NONE
474 < * side effects -
475 < */
476 < static void
477 < update_client_exit_stats(struct Client *client_p)
478 < {
479 <  if (IsClient(client_p))
480 <  {
481 <    assert(Count.total > 0);
482 <    --Count.total;
483 <    if (HasUMode(client_p, UMODE_OPER))
484 <      --Count.oper;
485 <    if (HasUMode(client_p, UMODE_INVISIBLE))
486 <      --Count.invisi;
487 <  }
488 <  else if (IsServer(client_p))
489 <    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
490 <                         "Server %s split from %s",
491 <                         client_p->name, client_p->servptr->name);
492 <
493 <  if (splitchecking && !splitmode)
494 <    check_splitmode(NULL);
490 >  exit_client(client_p, reason);
491   }
492  
493   /* find_person()
# Line 501 | Line 497 | update_client_exit_stats(struct Client *
497   * side effects - find person by (nick)name
498   */
499   struct Client *
500 < find_person(const struct Client *const source_p, const char *name)
500 > find_person(const struct Client *source_p, const char *name)
501   {
502    struct Client *target_p = NULL;
503  
# Line 524 | Line 520 | find_person(const struct Client *const s
520   struct Client *
521   find_chasing(struct Client *source_p, const char *name)
522   {
523 <  struct Client *who = find_person(source_p, name);
523 >  struct Client *target_p = find_person(source_p, name);
524  
525 <  if (who)
526 <    return who;
525 >  if (target_p)
526 >    return target_p;
527  
528    if (IsDigit(*name))
529      return NULL;
530  
531 <  if ((who = whowas_get_history(name,
532 <                         (time_t)ConfigFileEntry.kill_chase_time_limit))
537 <                         == NULL)
538 <  {
531 >  target_p = whowas_get_history(name, ConfigGeneral.kill_chase_time_limit);
532 >  if (!target_p)
533      sendto_one_numeric(source_p, &me, ERR_NOSUCHNICK, name);
540    return NULL;
541  }
534  
535 <  return who;
535 >  return target_p;
536   }
537  
538   /*
539 < * get_client_name -  Return the name of the client
539 > * client_get_name -  Return the name of the client
540   *    for various tracking and
541   *      admin purposes. The main purpose of this function is to
542   *      return the "socket host" name of the client, if that
# Line 552 | Line 544 | find_chasing(struct Client *source_p, co
544   *        But, this can be used to any client structure.
545   *
546   * NOTE 1:
547 < *        Watch out the allocation of "nbuf", if either source_p->name
547 > *        Watch out the allocation of "buf", if either source_p->name
548   *        or source_p->sockhost gets changed into pointers instead of
549   *        directly allocated within the structure...
550   *
551   * NOTE 2:
552   *        Function return either a pointer to the structure (source_p) or
553 < *        to internal buffer (nbuf). *NEVER* use the returned pointer
553 > *        to internal buffer (buf). *NEVER* use the returned pointer
554   *        to modify what it points!!!
555   */
556   const char *
557 < get_client_name(const struct Client *client_p, enum addr_mask_type type)
557 > client_get_name(const struct Client *client_p, enum addr_mask_type type)
558   {
559 <  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
568 <
569 <  assert(client_p);
559 >  static char buf[HOSTLEN * 2 + USERLEN + 4];  /* +4 for [,@,],\0 */
560  
561    if (!MyConnect(client_p))
562      return client_p->name;
# Line 579 | Line 569 | get_client_name(const struct Client *cli
569        type = MASK_IP;
570    }
571  
582  if (ConfigFileEntry.hide_spoof_ips)
583    if (type == SHOW_IP && IsIPSpoof(client_p))
584      type = MASK_IP;
585
572    /* And finally, let's get the host information, ip or name */
573    switch (type)
574    {
575      case SHOW_IP:
576 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
576 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
577                 client_p->name,
578                 client_p->username, client_p->sockhost);
579        break;
580      case MASK_IP:
581 <      if (client_p->localClient->aftype == AF_INET)
582 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@255.255.255.255]",
581 >      if (client_p->connection->aftype == AF_INET)
582 >        snprintf(buf, sizeof(buf), "%s[%s@255.255.255.255]",
583                   client_p->name, client_p->username);
584        else
585 <        snprintf(nbuf, sizeof(nbuf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
585 >        snprintf(buf, sizeof(buf), "%s[%s@ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
586                   client_p->name, client_p->username);
587        break;
588 <    default:
589 <      snprintf(nbuf, sizeof(nbuf), "%s[%s@%s]",
588 >    default:  /* HIDE_IP */
589 >      snprintf(buf, sizeof(buf), "%s[%s@%s]",
590                 client_p->name,
591                 client_p->username, client_p->host);
592    }
593  
594 <  return nbuf;
594 >  return buf;
595   }
596  
597   void
598   free_exited_clients(void)
599   {
600 <  dlink_node *ptr = NULL, *next = NULL;
600 >  dlink_node *node, *node_next;
601  
602 <  DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
602 >  DLINK_FOREACH_SAFE(node, node_next, dead_list.head)
603    {
604 <    free_client(ptr->data);
605 <    dlinkDelete(ptr, &dead_list);
606 <    free_dlink_node(ptr);
604 >    client_free(node->data);
605 >    dlinkDelete(node, &dead_list);
606 >    free_dlink_node(node);
607    }
608   }
609  
610   /*
611 + * client_close_connection
612 + *        Close the physical connection. This function must make
613 + *        MyConnect(client_p) == FALSE, and set client_p->from == NULL.
614 + */
615 + static void
616 + client_close_connection(struct Client *client_p)
617 + {
618 +  assert(client_p);
619 +
620 +  if (!IsDead(client_p))
621 +  {
622 +    /* attempt to flush any pending dbufs. Evil, but .. -- adrian */
623 +    /* there is still a chance that we might send data to this socket
624 +     * even if it is marked as blocked (COMM_SELECT_READ handler is called
625 +     * before COMM_SELECT_WRITE). Let's try, nothing to lose.. -adx
626 +     */
627 +    DelFlag(client_p, FLAGS_BLOCKED);
628 +    send_queued_write(client_p);
629 +  }
630 +
631 +  if (IsClient(client_p))
632 +  {
633 +    ++ServerStats.is_cl;
634 +    ServerStats.is_cbs += client_p->connection->send.bytes;
635 +    ServerStats.is_cbr += client_p->connection->recv.bytes;
636 +    ServerStats.is_cti += CurrentTime - client_p->connection->firsttime;
637 +  }
638 +  else if (IsServer(client_p))
639 +  {
640 +    dlink_node *node = NULL;
641 +
642 +    ++ServerStats.is_sv;
643 +    ServerStats.is_sbs += client_p->connection->send.bytes;
644 +    ServerStats.is_sbr += client_p->connection->recv.bytes;
645 +    ServerStats.is_sti += CurrentTime - client_p->connection->firsttime;
646 +
647 +    DLINK_FOREACH(node, connect_items.head)
648 +    {
649 +      struct MaskItem *conf = node->data;
650 +
651 +      if (irccmp(conf->name, client_p->name))
652 +        continue;
653 +
654 +      /*
655 +       * Reset next-connect cycle of all connect{} blocks that match
656 +       * this servername.
657 +       */
658 +      conf->until = CurrentTime + conf->class->con_freq;
659 +    }
660 +  }
661 +  else
662 +    ++ServerStats.is_ni;
663 +
664 +  if (tls_isusing(&client_p->connection->fd->ssl))
665 +    tls_shutdown(&client_p->connection->fd->ssl);
666 +
667 +  if (client_p->connection->fd)
668 +  {
669 +    fd_close(client_p->connection->fd);
670 +    client_p->connection->fd = NULL;
671 +  }
672 +
673 +  dbuf_clear(&client_p->connection->buf_sendq);
674 +  dbuf_clear(&client_p->connection->buf_recvq);
675 +
676 +  xfree(client_p->connection->password);
677 +  client_p->connection->password = NULL;
678 +
679 +  conf_detach(client_p, CONF_CLIENT | CONF_OPER | CONF_SERVER);
680 + }
681 +
682 + /*
683   * Exit one client, local or remote. Assuming all dependents have
684   * been already removed, and socket closed for local client.
685   *
686   * The only messages generated are QUITs on channels.
687   */
688   static void
689 < exit_one_client(struct Client *source_p, const char *quitmsg)
689 > exit_one_client(struct Client *source_p, const char *comment)
690   {
691 <  dlink_node *ptr = NULL, *ptr_next = NULL;
691 >  dlink_node *node, *node_next;
692  
693    assert(!IsMe(source_p));
694 +  assert(source_p != &me);
695  
696    if (IsClient(source_p))
697    {
698 +    if (HasUMode(source_p, UMODE_OPER))
699 +      --Count.oper;
700 +    if (HasUMode(source_p, UMODE_INVISIBLE))
701 +      --Count.invisi;
702 +
703      dlinkDelete(&source_p->lnode, &source_p->servptr->serv->client_list);
704 +    dlinkDelete(&source_p->node, &global_client_list);
705  
706      /*
707       * If a person is on a channel, send a QUIT notice
# Line 644 | Line 709 | exit_one_client(struct Client *source_p,
709       * that the client can show the "**signoff" message).
710       * (Note: The notice is to the local clients *only*)
711       */
712 <    sendto_common_channels_local(source_p, 0, 0, ":%s!%s@%s QUIT :%s",
712 >    sendto_common_channels_local(source_p, 0, 0, 0, ":%s!%s@%s QUIT :%s",
713                                   source_p->name, source_p->username,
714 <                                 source_p->host, quitmsg);
715 <    DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->channel.head)
716 <      remove_user_from_channel(ptr->data);
714 >                                 source_p->host, comment);
715 >
716 >    DLINK_FOREACH_SAFE(node, node_next, source_p->channel.head)
717 >      remove_user_from_channel(node->data);
718 >
719 >    client_clear_svstags(&source_p->svstags);
720  
721      whowas_add_history(source_p, 0);
722      whowas_off_history(source_p);
723  
724      watch_check_hash(source_p, RPL_LOGOFF);
657
658    if (MyConnect(source_p))
659    {
660      /* Clean up invitefield */
661      DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->localClient->invited.head)
662        del_invite(ptr->data, source_p);
663
664      del_all_accepts(source_p);
665    }
725    }
726    else if (IsServer(source_p))
727    {
728 <    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
728 >    sendto_realops_flags(UMODE_EXTERNAL, L_ALL, SEND_NOTICE,
729 >                         "Server %s split from %s",
730 >                         source_p->name, source_p->servptr->name);
731  
732 <    if ((ptr = dlinkFindDelete(&global_serv_list, source_p)))
733 <      free_dlink_node(ptr);
732 >    dlinkDelete(&source_p->lnode, &source_p->servptr->serv->server_list);
733 >    dlinkDelete(&source_p->node, &global_server_list);
734    }
735  
736    /* Remove source_p from the client lists */
737    if (source_p->id[0])
738      hash_del_id(source_p);
739 +
740    if (source_p->name[0])
741      hash_del_client(source_p);
742  
743 <  if (IsUserHostIp(source_p))
744 <    delete_user_host(source_p->username, source_p->host, !MyConnect(source_p));
683 <
684 <  /* remove from global client list
685 <   * NOTE: source_p->node.next cannot be NULL if the client is added
686 <   *       to global_client_list (there is always &me at its end)
687 <   */
688 <  if (source_p->node.next) /* XXX: not needed? */
689 <    dlinkDelete(&source_p->node, &global_client_list);
690 <
691 <  update_client_exit_stats(source_p);
743 >  if (HasFlag(source_p, FLAGS_USERHOST))
744 >    userhost_del(source_p->sockhost, !MyConnect(source_p));
745  
746    /* Check to see if the client isn't already on the dead list */
747    assert(dlinkFind(&dead_list, source_p) == NULL);
# Line 705 | Line 758 | exit_one_client(struct Client *source_p,
758   * actually removing things off llists.   tweaked from +CSr31  -orabidoo
759   */
760   static void
761 < recurse_remove_clients(struct Client *source_p, const char *quitmsg)
761 > recurse_remove_clients(struct Client *source_p, const char *comment)
762   {
763 <  dlink_node *ptr = NULL, *ptr_next = NULL;
763 >  dlink_node *node, *node_next;
764  
765 <  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->client_list.head)
766 <    exit_one_client(ptr->data, quitmsg);
765 >  DLINK_FOREACH_SAFE(node, node_next, source_p->serv->client_list.head)
766 >    exit_one_client(node->data, comment);
767  
768 <  DLINK_FOREACH_SAFE(ptr, ptr_next, source_p->serv->server_list.head)
768 >  DLINK_FOREACH_SAFE(node, node_next, source_p->serv->server_list.head)
769    {
770 <    recurse_remove_clients(ptr->data, quitmsg);
771 <    exit_one_client(ptr->data, quitmsg);
770 >    recurse_remove_clients(node->data, comment);
771 >    exit_one_client(node->data, comment);
772    }
773   }
774  
# Line 739 | Line 792 | recurse_remove_clients(struct Client *so
792   void
793   exit_client(struct Client *source_p, const char *comment)
794   {
795 <  dlink_node *m = NULL;
795 >  assert(!IsMe(source_p));
796 >  assert(source_p != &me);
797  
798    if (MyConnect(source_p))
799    {
800 <    /* DO NOT REMOVE. exit_client can be called twice after a failed
801 <     * read/write.
800 >    /*
801 >     * DO NOT REMOVE. exit_client can be called twice after a failed read/write.
802       */
803 <    if (IsClosing(source_p))
803 >    if (HasFlag(source_p, FLAGS_CLOSING))
804        return;
805  
806 <    SetClosing(source_p);
753 <
754 <    if (IsIpHash(source_p))
755 <      remove_one_ip(&source_p->localClient->ip);
806 >    AddFlag(source_p, FLAGS_CLOSING);
807  
808 <    delete_auth(&source_p->localClient->auth);
758 <
759 <    /*
760 <     * This source_p could have status of one of STAT_UNKNOWN, STAT_CONNECTING
761 <     * STAT_HANDSHAKE or STAT_UNKNOWN
762 <     * all of which are lumped together into unknown_list
763 <     *
764 <     * In all above cases IsRegistered() will not be true.
765 <     */
766 <    if (!IsRegistered(source_p))
808 >    if (HasFlag(source_p, FLAGS_IPHASH))
809      {
810 <      assert(dlinkFind(&unknown_list, source_p));
810 >      DelFlag(source_p, FLAGS_IPHASH);
811 >      ipcache_remove_address(&source_p->connection->ip);
812 >    }
813  
814 <      dlinkDelete(&source_p->localClient->lclient_node, &unknown_list);
814 >    if (source_p->connection->auth)
815 >    {
816 >      auth_delete(source_p->connection->auth);
817 >      source_p->connection->auth = NULL;
818      }
819 <    else if (IsClient(source_p))
819 >
820 >    if (IsClient(source_p))
821      {
822 <      time_t on_for = CurrentTime - source_p->localClient->firsttime;
775 <      assert(Count.local > 0);
776 <      Count.local--;
822 >      dlink_node *node;
823  
824        if (HasUMode(source_p, UMODE_OPER))
825 <        if ((m = dlinkFindDelete(&oper_list, source_p)))
826 <          free_dlink_node(m);
825 >        if ((node = dlinkFindDelete(&oper_list, source_p)))
826 >          free_dlink_node(node);
827  
828        assert(dlinkFind(&local_client_list, source_p));
829 <      dlinkDelete(&source_p->localClient->lclient_node, &local_client_list);
829 >      dlinkDelete(&source_p->connection->lclient_node, &local_client_list);
830  
831 <      if (source_p->localClient->list_task)
831 >      if (source_p->connection->list_task)
832          free_list_task(source_p);
833  
834 +      clear_invite_list(&source_p->connection->invited);
835 +      del_all_accepts(source_p);
836        watch_del_watch_list(source_p);
837 +
838        sendto_realops_flags(UMODE_CCONN, L_ALL, SEND_NOTICE,
839                             "Client exiting: %s (%s@%s) [%s] [%s]",
840 <                           source_p->name, source_p->username, source_p->host, comment,
841 <                           ConfigFileEntry.hide_spoof_ips && IsIPSpoof(source_p) ?
842 <                           "255.255.255.255" : source_p->sockhost);
843 <      ilog(LOG_TYPE_USER, "%s (%3u:%02u:%02u): %s!%s@%s %llu/%llu",
844 <           myctime(source_p->localClient->firsttime), (unsigned int)(on_for / 3600),
845 <           (unsigned int)((on_for % 3600)/60), (unsigned int)(on_for % 60),
840 >                           source_p->name, source_p->username, source_p->realhost,
841 >                           source_p->sockhost, comment);
842 >
843 >      ilog(LOG_TYPE_USER, "%s (%ju): %s!%s@%s %s %s %ju/%ju :%s",
844 >           date_ctime(source_p->connection->firsttime),
845 >           CurrentTime - source_p->connection->firsttime,
846             source_p->name, source_p->username, source_p->host,
847 <           source_p->localClient->send.bytes>>10,
848 <           source_p->localClient->recv.bytes>>10);
847 >           source_p->sockhost, source_p->account,
848 >           source_p->connection->send.bytes >> 10,
849 >           source_p->connection->recv.bytes >> 10, source_p->info);
850      }
851      else if (IsServer(source_p))
852      {
853 <      assert(Count.myserver > 0);
854 <      --Count.myserver;
855 <
856 <      assert(dlinkFind(&serv_list, source_p));
857 <      dlinkDelete(&source_p->localClient->lclient_node, &serv_list);
853 >      assert(dlinkFind(&local_server_list, source_p));
854 >      dlinkDelete(&source_p->connection->lclient_node, &local_server_list);
855 >    }
856 >    else
857 >    {
858 >      assert(dlinkFind(&unknown_list, source_p));
859 >      dlinkDelete(&source_p->connection->lclient_node, &unknown_list);
860      }
861  
862      if (!IsDead(source_p))
# Line 823 | Line 875 | exit_client(struct Client *source_p, con
875                   source_p->host, comment);
876      }
877  
878 <    close_connection(source_p);
878 >    client_close_connection(source_p);
879    }
880    else if (IsClient(source_p) && HasFlag(source_p->servptr, FLAGS_EOB))
881      sendto_realops_flags(UMODE_FARCONNECT, L_ALL, SEND_NOTICE,
882 <                         "Client exiting at %s: %s (%s@%s) [%s]",
882 >                         "Client exiting at %s: %s (%s@%s) [%s] [%s]",
883                           source_p->servptr->name, source_p->name,
884 <                         source_p->username, source_p->host, comment);
884 >                         source_p->username, source_p->realhost, source_p->sockhost, comment);
885  
886    if (IsServer(source_p))
887    {
888      char splitstr[HOSTLEN + HOSTLEN + 2] = "";
889  
890 <    /* This shouldn't ever happen */
891 <    assert(source_p->serv && source_p->servptr);
890 >    assert(source_p->serv);
891 >    assert(source_p->servptr);
892  
893      if (ConfigServerHide.hide_servers)
894        /*
# Line 848 | Line 900 | exit_client(struct Client *source_p, con
900        snprintf(splitstr, sizeof(splitstr), "%s %s",
901                 source_p->servptr->name, source_p->name);
902  
903 <    /* Send SQUIT for source_p in every direction. source_p is already off of serv_list here */
903 >    /* Send SQUIT for source_p in every direction. source_p is already off of local_server_list here */
904      if (!HasFlag(source_p, FLAGS_SQUIT))
905 <      sendto_server(NULL, NOCAPS, NOCAPS, "SQUIT %s :%s", source_p->id, comment);
905 >      sendto_server(NULL, 0, 0, "SQUIT %s :%s", source_p->id, comment);
906  
907      /* Now exit the clients internally */
908      recurse_remove_clients(source_p, splitstr);
909  
910      if (MyConnect(source_p))
911      {
912 <      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
913 <                           "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
914 <                           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
915 <                           source_p->localClient->send.bytes >> 10,
916 <                           source_p->localClient->recv.bytes >> 10);
917 <      ilog(LOG_TYPE_IRCD, "%s was connected for %d seconds.  %llu/%llu sendK/recvK.",
918 <           source_p->name, (int)(CurrentTime - source_p->localClient->firsttime),
919 <           source_p->localClient->send.bytes >> 10,
920 <           source_p->localClient->recv.bytes >> 10);
912 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
913 >                           "%s was connected for %s. %ju/%ju sendK/recvK.",
914 >                           source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
915 >                           source_p->connection->send.bytes >> 10,
916 >                           source_p->connection->recv.bytes >> 10);
917 >      ilog(LOG_TYPE_IRCD, "%s was connected for %s. %ju/%ju sendK/recvK.",
918 >           source_p->name, time_dissect(CurrentTime - source_p->connection->firsttime),
919 >           source_p->connection->send.bytes >> 10,
920 >           source_p->connection->recv.bytes >> 10);
921      }
922    }
923    else if (IsClient(source_p) && !HasFlag(source_p, FLAGS_KILLED))
924 <    sendto_server(source_p->from, NOCAPS, NOCAPS, ":%s QUIT :%s",
873 <                  source_p->id, comment);
924 >    sendto_server(source_p->from, 0, 0, ":%s QUIT :%s", source_p->id, comment);
925  
926    /* The client *better* be off all of the lists */
927    assert(dlinkFind(&unknown_list, source_p) == NULL);
928    assert(dlinkFind(&local_client_list, source_p) == NULL);
929 <  assert(dlinkFind(&serv_list, source_p) == NULL);
929 >  assert(dlinkFind(&local_server_list, source_p) == NULL);
930    assert(dlinkFind(&oper_list, source_p) == NULL);
931 +  assert(dlinkFind(&listing_client_list, source_p) == NULL);
932  
933    exit_one_client(source_p, comment);
934   }
# Line 888 | Line 940 | exit_client(struct Client *source_p, con
940   void
941   dead_link_on_write(struct Client *client_p, int ierrno)
942   {
943 <  dlink_node *ptr;
943 >  dlink_node *node;
944  
945    if (IsDefunct(client_p))
946      return;
947  
948 <  dbuf_clear(&client_p->localClient->buf_recvq);
949 <  dbuf_clear(&client_p->localClient->buf_sendq);
948 >  dbuf_clear(&client_p->connection->buf_recvq);
949 >  dbuf_clear(&client_p->connection->buf_sendq);
950  
951    assert(dlinkFind(&abort_list, client_p) == NULL);
952 <  ptr = make_dlink_node();
952 >  node = make_dlink_node();
953    /* don't let exit_aborted_clients() finish yet */
954 <  dlinkAddTail(client_p, ptr, &abort_list);
954 >  dlinkAddTail(client_p, node, &abort_list);
955  
956    if (eac_next == NULL)
957 <    eac_next = ptr;
957 >    eac_next = node;
958  
959    SetDead(client_p); /* You are dead my friend */
960   }
# Line 920 | Line 972 | dead_link_on_read(struct Client *client_
972    if (IsDefunct(client_p))
973      return;
974  
975 <  dbuf_clear(&client_p->localClient->buf_recvq);
976 <  dbuf_clear(&client_p->localClient->buf_sendq);
975 >  dbuf_clear(&client_p->connection->buf_recvq);
976 >  dbuf_clear(&client_p->connection->buf_sendq);
977  
978 <  current_error = get_sockerr(client_p->localClient->fd.fd);
978 >  current_error = get_sockerr(client_p->connection->fd->fd);
979  
980    if (IsServer(client_p) || IsHandshake(client_p))
981    {
930    int connected = CurrentTime - client_p->localClient->firsttime;
931
982      if (error == 0)
983      {
984 <      /* Admins get the real IP */
935 <      sendto_realops_flags(UMODE_ALL, L_ADMIN, SEND_NOTICE,
984 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
985                             "Server %s closed the connection",
986 <                           get_client_name(client_p, SHOW_IP));
987 <
939 <      /* Opers get a masked IP */
940 <      sendto_realops_flags(UMODE_ALL, L_OPER, SEND_NOTICE,
986 >                           client_get_name(client_p, SHOW_IP));
987 >      sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
988                             "Server %s closed the connection",
989 <                           get_client_name(client_p, MASK_IP));
943 <
989 >                           client_get_name(client_p, MASK_IP));
990        ilog(LOG_TYPE_IRCD, "Server %s closed the connection",
991 <           get_client_name(client_p, SHOW_IP));
991 >           client_get_name(client_p, SHOW_IP));
992      }
993      else
994      {
995 <      report_error(L_ADMIN, "Lost connection to %s: %s",
996 <                   get_client_name(client_p, SHOW_IP), current_error);
997 <      report_error(L_OPER, "Lost connection to %s: %s",
998 <                   get_client_name(client_p, MASK_IP), current_error);
995 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ADMIN, SEND_NOTICE,
996 >                           "Lost connection to %s: %s",
997 >                           client_get_name(client_p, SHOW_IP), strerror(current_error));
998 >      sendto_realops_flags(UMODE_SERVNOTICE, L_OPER, SEND_NOTICE,
999 >                           "Lost connection to %s: %s",
1000 >                           client_get_name(client_p, MASK_IP), strerror(current_error));
1001 >      ilog(LOG_TYPE_IRCD, "Lost connection to %s: %s",
1002 >           client_get_name(client_p, SHOW_IP), strerror(current_error));
1003      }
1004  
1005 <    sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1006 <                         "%s had been connected for %d day%s, %2d:%02d:%02d",
1007 <                         client_p->name, connected/86400,
958 <                         (connected/86400 == 1) ? "" : "s",
959 <                         (connected % 86400) / 3600, (connected % 3600) / 60,
960 <                         connected % 60);
1005 >    sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
1006 >                         "%s was connected for %s",
1007 >                         client_p->name, time_dissect(CurrentTime - client_p->connection->firsttime));
1008    }
1009  
1010    if (error == 0)
# Line 982 | Line 1029 | exit_aborted_clients(void)
1029      target_p = ptr->data;
1030      eac_next = ptr->next;
1031  
1032 +    dlinkDelete(ptr, &abort_list);
1033 +    free_dlink_node(ptr);
1034 +
1035      if (target_p == NULL)
1036      {
1037 <      sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE,
1037 >      sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
1038                             "Warning: null client on abort_list!");
989      dlinkDelete(ptr, &abort_list);
990      free_dlink_node(ptr);
1039        continue;
1040      }
1041  
1042 <    dlinkDelete(ptr, &abort_list);
995 <
996 <    if (IsSendQExceeded(target_p))
1042 >    if (HasFlag(target_p, FLAGS_SENDQEX))
1043        notice = "Max SendQ exceeded";
1044      else
1045        notice = "Write error: connection closed";
1046  
1047      exit_client(target_p, notice);
1002    free_dlink_node(ptr);
1048    }
1049   }
1050  
# Line 1016 | Line 1061 | exit_aborted_clients(void)
1061   void
1062   del_accept(struct split_nuh_item *accept_p, struct Client *client_p)
1063   {
1064 <  dlinkDelete(&accept_p->node, &client_p->localClient->acceptlist);
1064 >  dlinkDelete(&accept_p->node, &client_p->connection->acceptlist);
1065  
1066 <  MyFree(accept_p->nickptr);
1067 <  MyFree(accept_p->userptr);
1068 <  MyFree(accept_p->hostptr);
1069 <  MyFree(accept_p);
1066 >  xfree(accept_p->nickptr);
1067 >  xfree(accept_p->userptr);
1068 >  xfree(accept_p->hostptr);
1069 >  xfree(accept_p);
1070   }
1071  
1072   struct split_nuh_item *
# Line 1029 | Line 1074 | find_accept(const char *nick, const char
1074              const char *host, struct Client *client_p,
1075              int (*cmpfunc)(const char *, const char *))
1076   {
1077 <  dlink_node *ptr = NULL;
1077 >  dlink_node *node;
1078  
1079 <  DLINK_FOREACH(ptr, client_p->localClient->acceptlist.head)
1079 >  DLINK_FOREACH(node, client_p->connection->acceptlist.head)
1080    {
1081 <    struct split_nuh_item *accept_p = ptr->data;
1081 >    struct split_nuh_item *accept_p = node->data;
1082  
1083      if (!cmpfunc(accept_p->nickptr, nick) &&
1084          !cmpfunc(accept_p->userptr, user) &&
# Line 1055 | Line 1100 | int
1100   accept_message(struct Client *source,
1101                 struct Client *target)
1102   {
1103 <  dlink_node *ptr = NULL;
1103 >  dlink_node *node;
1104 >
1105 >  if (HasFlag(source, FLAGS_SERVICE) ||
1106 >      (HasUMode(source, UMODE_OPER) && ConfigGeneral.opers_bypass_callerid))
1107 >    return 1;
1108  
1109    if (source == target || find_accept(source->name, source->username,
1110                                        source->host, target, match))
1111      return 1;
1112  
1113 <  if (HasUMode(target, UMODE_SOFTCALLERID))
1114 <    DLINK_FOREACH(ptr, target->channel.head)
1115 <      if (IsMember(source, ((struct Membership *)ptr->data)->chptr))
1113 >  if (!HasUMode(target, UMODE_CALLERID) && HasUMode(target, UMODE_SOFTCALLERID))
1114 >    DLINK_FOREACH(node, target->channel.head)
1115 >      if (IsMember(source, ((struct Membership *)node->data)->chptr))
1116          return 1;
1117  
1118    return 0;
# Line 1078 | Line 1127 | accept_message(struct Client *source,
1127   void
1128   del_all_accepts(struct Client *client_p)
1129   {
1130 <  dlink_node *ptr = NULL, *ptr_next = NULL;
1130 >  dlink_node *node, *node_next;
1131  
1132 <  DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->acceptlist.head)
1133 <    del_accept(ptr->data, client_p);
1132 >  DLINK_FOREACH_SAFE(node, node_next, client_p->connection->acceptlist.head)
1133 >    del_accept(node->data, client_p);
1134   }
1135  
1136   unsigned int
1137 < idle_time_get(const struct Client *source_p, const struct Client *target_p)
1137 > client_get_idle_time(const struct Client *source_p,
1138 >                     const struct Client *target_p)
1139   {
1140    unsigned int idle = 0;
1141 <  unsigned int min_idle = 0;
1092 <  unsigned int max_idle = 0;
1093 <  const struct ClassItem *class = get_class_ptr(&target_p->localClient->confs);
1141 >  const struct ClassItem *const class = get_class_ptr(&target_p->connection->confs);
1142  
1143    if (!(class->flags & CLASS_FLAGS_FAKE_IDLE) || target_p == source_p)
1144 <    return CurrentTime - target_p->localClient->last_privmsg;
1144 >    return CurrentTime - target_p->connection->last_privmsg;
1145 >
1146    if (HasUMode(source_p, UMODE_OPER) &&
1147        !(class->flags & CLASS_FLAGS_HIDE_IDLE_FROM_OPERS))
1148 <    return CurrentTime - target_p->localClient->last_privmsg;
1148 >    return CurrentTime - target_p->connection->last_privmsg;
1149  
1150 <  min_idle = class->min_idle;
1151 <  max_idle = class->max_idle;
1150 >  const unsigned int min_idle = class->min_idle;
1151 >  const unsigned int max_idle = class->max_idle;
1152  
1153    if (min_idle == max_idle)
1154      return min_idle;
# Line 1107 | Line 1156 | idle_time_get(const struct Client *sourc
1156    if (class->flags & CLASS_FLAGS_RANDOM_IDLE)
1157      idle = genrand_int32();
1158    else
1159 <    idle = CurrentTime - target_p->localClient->last_privmsg;
1159 >    idle = CurrentTime - target_p->connection->last_privmsg;
1160  
1161 <  if (!max_idle)
1113 <    idle = 0;
1114 <  else
1161 >  if (max_idle)
1162      idle %= max_idle;
1163 +  else
1164 +    idle = 0;
1165  
1166    if (idle < min_idle)
1167      idle = min_idle + (idle % (max_idle - min_idle));
1168  
1169    return idle;
1170   }
1171 +
1172 + /* client_init()
1173 + *
1174 + * inputs       - NONE
1175 + * output       - NONE
1176 + * side effects - initialize client free memory
1177 + */
1178 + void
1179 + client_init(void)
1180 + {
1181 +  static struct event event_ping =
1182 +  {
1183 +    .name = "check_pings",
1184 +    .handler = check_pings,
1185 +    .when = 5
1186 +  };
1187 +
1188 +  event_add(&event_ping, NULL);
1189 + }

Comparing ircd-hybrid/trunk/src/client.c (property svn:keywords):
Revision 3324 by michael, Tue Apr 15 16:18:07 2014 UTC vs.
Revision 8399 by michael, Sun Mar 18 14:43:15 2018 UTC

# Line 1 | Line 1
1 < Id Revision
1 > Id

Diff Legend

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