ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/ircd-hybrid-newconf/modules/m_stats.c
Revision: 1027
Committed: Sun Nov 8 13:01:13 2009 UTC (16 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 33783 byte(s)
Log Message:
- Move old 7.3 sources to branches/ircd-hybrid-newconf

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_stats.c: Sends the user statistics or config information.
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 "conf/conf.h"
27 #include "handlers.h" /* m_pass prototype */
28 #include "client.h" /* Client */
29 #include "common.h" /* TRUE/FALSE */
30 #include "hash.h"
31 #include "ircd.h" /* me */
32 #include "listener.h" /* show_ports */
33 #include "ircd_handler.h"
34 #include "msg.h" /* Message */
35 #include "numeric.h" /* ERR_xxx */
36 #include "send.h" /* sendto_one */
37 #include "server.h" /* hunt_server */
38 #include "user.h" /* show_opers */
39 #include "parse.h"
40 #include "whowas.h"
41 #include "watch.h"
42 #include "channel.h"
43
44 static void *do_stats(va_list args);
45 static void m_stats(struct Client *, struct Client *, int, char *[]);
46 static void mo_stats(struct Client *, struct Client *, int, char *[]);
47
48 struct Message stats_msgtab = {
49 "STATS", 0, 0, 2, 0, MFLG_SLOW, 0,
50 { m_unregistered, m_stats, mo_stats, m_ignore, mo_stats, m_ignore }
51 };
52
53 static struct Callback *stats_cb;
54
55 INIT_MODULE(m_stats, "$Revision$")
56 {
57 stats_cb = register_callback("doing_stats", do_stats);
58 mod_add_cmd(&stats_msgtab);
59 }
60
61 CLEANUP_MODULE
62 {
63 mod_del_cmd(&stats_msgtab);
64 uninstall_hook(stats_cb, do_stats);
65 }
66
67 static char *parse_stats_args(int, char **, int *, int *);
68 static void stats_L(struct Client *, char *, int, int, char);
69 static void stats_L_list(struct Client *s, char *, int, int, dlink_list *, char);
70
71 static void stats_dns_servers(struct Client *);
72 static void stats_events(struct Client *);
73 static void stats_operedup(struct Client *);
74 static void stats_ports(struct Client *);
75 static void stats_usage(struct Client *);
76 static void stats_tstats(struct Client *);
77 static void stats_uptime(struct Client *);
78 static void stats_servers(struct Client *);
79 static void stats_memory(struct Client *);
80 static void stats_servlinks(struct Client *);
81 static void stats_ltrace(struct Client *, int, char **);
82 static void stats_ziplinks(struct Client *);
83 static void stats_hooks(struct Client *);
84 static void fd_dump(struct Client *);
85
86 /* This table contains the possible stats items, in order:
87 * /stats name, function to call, operonly? adminonly? /stats letter
88 * case only matters in the stats letter column.. -- fl_ */
89 static const struct StatsStruct
90 {
91 const unsigned char letter;
92 void (*handler)();
93 const unsigned int need_oper;
94 const unsigned int need_admin;
95 } stats_cmd_table[] = {
96 // letter function need_oper need_admin
97 { 'a', stats_dns_servers, 1, 1, },
98 { 'A', stats_dns_servers, 1, 1, },
99 { 'c', report_connect, 1, 0, },
100 { 'C', report_connect, 1, 0, },
101 { 'd', report_tdeny, 1, 0, },
102 { 'D', report_deny, 1, 0, },
103 { 'e', report_exempt, 1, 0, },
104 { 'E', stats_events, 1, 1, },
105 { 'f', fd_dump, 1, 1, },
106 { 'F', fd_dump, 1, 1, },
107 { 'g', report_pending_glines, 1, 0, },
108 { 'G', report_glines, 1, 0, },
109 { 'h', stats_hooks, 1, 1, },
110 { 'H', report_hubleaf, 1, 0, },
111 { 'i', report_auth, 0, 0, },
112 { 'I', report_auth, 0, 0, },
113 { 'k', report_tklines, 0, 0, },
114 { 'K', report_klines, 0, 0, },
115 { 'l', stats_ltrace, 1, 0, },
116 { 'L', stats_ltrace, 1, 0, },
117 { 'm', report_messages, 0, 0, },
118 { 'M', report_messages, 0, 0, },
119 { 'o', report_oper, 0, 0, },
120 { 'O', report_oper, 0, 0, },
121 { 'p', stats_operedup, 0, 0, },
122 { 'P', stats_ports, 0, 0, },
123 { 'q', report_resv, 1, 0, },
124 { 'Q', report_resv, 1, 0, },
125 { 'r', stats_usage, 1, 0, },
126 { 'R', stats_usage, 1, 0, },
127 { 't', stats_tstats, 1, 0, },
128 { 'T', stats_tstats, 1, 0, },
129 { 'u', stats_uptime, 0, 0, },
130 { 'U', report_shared, 1, 0, },
131 { 'v', stats_servers, 1, 0, },
132 { 'V', report_gline_deny, 1, 0, },
133 { 'x', report_gecos, 1, 0, },
134 { 'X', report_gecos, 1, 0, },
135 { 'y', report_class, 1, 0, },
136 { 'Y', report_class, 1, 0, },
137 { 'z', stats_memory, 1, 0, },
138 { 'Z', stats_ziplinks, 1, 0, },
139 { '?', stats_servlinks, 0, 0, },
140 { 0, NULL, 0, 0, }
141 };
142
143 const char *from, *to;
144
145 static void *
146 do_stats(va_list args)
147 {
148 struct Client *source_p = va_arg(args, struct Client *);
149 int parc = va_arg(args, int);
150 char **parv = va_arg(args, char **);
151 char statchar = *parv[1];
152 int i;
153
154 if (statchar == '\0')
155 {
156 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
157 from, to, '*');
158 return NULL;
159 }
160
161 for (i = 0; stats_cmd_table[i].handler; i++)
162 {
163 if (stats_cmd_table[i].letter == statchar)
164 {
165 /* The stats table says what privs are needed, so check --fl_ */
166 if ((stats_cmd_table[i].need_admin && !IsAdmin(source_p)) ||
167 (stats_cmd_table[i].need_oper && !IsOper(source_p)))
168 {
169 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
170 from, to);
171 break;
172 }
173
174 /* Blah, stats L needs the parameters, none of the others do.. */
175 if (statchar == 'L' || statchar == 'l')
176 stats_cmd_table[i].handler(source_p, parc, parv);
177 else
178 stats_cmd_table[i].handler(source_p);
179
180 break;
181 }
182 }
183
184 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
185 from, to, statchar);
186 return NULL;
187 }
188
189 /*
190 * m_stats()
191 * parv[0] = sender prefix
192 * parv[1] = stat letter/command
193 * parv[2] = (if present) server/mask in stats L
194 *
195 * This will search the tables for the appropriate stats letter/command,
196 * if found execute it.
197 */
198 static void
199 m_stats(struct Client *client_p, struct Client *source_p,
200 int parc, char *parv[])
201 {
202 static time_t last_used = 0;
203
204 /* Is the stats meant for us? */
205 if (!General.disable_remote_commands)
206 if (hunt_server(source_p, ":%s STATS %s :%s", 2,
207 parc, parv) != HUNTED_ISME)
208 return;
209
210 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
211 {
212 from = me.id;
213 to = source_p->id;
214 }
215 else
216 {
217 from = me.name;
218 to = source_p->name;
219 }
220
221 /* Check the user is actually allowed to do /stats, and isnt flooding */
222 if ((last_used + General.pace_wait) > CurrentTime)
223 {
224 sendto_one(source_p,form_str(RPL_LOAD2HI),
225 from, to);
226 return;
227 }
228
229 last_used = CurrentTime;
230
231 execute_callback(stats_cb, source_p, parc, parv);
232 }
233
234 /*
235 * mo_stats()
236 * parv[0] = sender prefix
237 * parv[1] = stat letter/command
238 * parv[2] = (if present) server/mask in stats L, or target
239 *
240 * This will search the tables for the appropriate stats letter,
241 * if found execute it.
242 */
243 static void
244 mo_stats(struct Client *client_p, struct Client *source_p,
245 int parc, char *parv[])
246 {
247 if (!IsClient(source_p))
248 return;
249
250 if (hunt_server(source_p, ":%s STATS %s :%s", 2,
251 parc, parv) != HUNTED_ISME)
252 return;
253
254 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
255 {
256 from = me.id;
257 to = source_p->id;
258 }
259 else
260 {
261 from = me.name;
262 to = source_p->name;
263 }
264
265 execute_callback(stats_cb, source_p, parc, parv);
266 }
267
268 /*
269 * This is part of the STATS replies. There is no offical numeric for this
270 * since this isnt an official command, in much the same way as HASH isnt.
271 * It is also possible that some systems wont support this call or have
272 * different field names for "struct rusage".
273 * -avalon
274 */
275 static void
276 stats_usage(struct Client *source_p)
277 {
278 #ifndef _WIN32
279 struct rusage rus;
280 time_t secs;
281 time_t rup;
282 #ifdef hz
283 # define hzz hz
284 #else
285 # ifdef HZ
286 # define hzz HZ
287 # else
288 int hzz = 1;
289 # endif
290 #endif
291
292 if (getrusage(RUSAGE_SELF, &rus) == -1)
293 {
294 sendto_one(source_p, ":%s NOTICE %s :Getruseage error: %s",
295 me.name, source_p->name, strerror(errno));
296 return;
297 }
298
299 secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
300
301 if (secs == 0)
302 secs = 1;
303
304 rup = (CurrentTime - me.since) * hzz;
305
306 if (rup == 0)
307 rup = 1;
308
309 sendto_one(source_p,
310 ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
311 me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
312 (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
313 (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
314 sendto_one(source_p, ":%s %d %s R :RSS %ld ShMem %ld Data %ld Stack %ld",
315 me.name, RPL_STATSDEBUG, source_p->name, rus.ru_maxrss,
316 (rus.ru_ixrss / rup), (rus.ru_idrss / rup),
317 (rus.ru_isrss / rup));
318 sendto_one(source_p, ":%s %d %s R :Swaps %d Reclaims %d Faults %d",
319 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nswap,
320 (int)rus.ru_minflt, (int)rus.ru_majflt);
321 sendto_one(source_p, ":%s %d %s R :Block in %d out %d",
322 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_inblock,
323 (int)rus.ru_oublock);
324 sendto_one(source_p, ":%s %d %s R :Msg Rcv %d Send %d",
325 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_msgrcv,
326 (int)rus.ru_msgsnd);
327 sendto_one(source_p, ":%s %d %s R :Signals %d Context Vol. %d Invol %d",
328 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nsignals,
329 (int)rus.ru_nvcsw, (int)rus.ru_nivcsw);
330 #endif
331 }
332
333 static void
334 stats_memory(struct Client *source_p)
335 {
336 const dlink_node *gptr = NULL;
337 const dlink_node *dlink = NULL;
338
339 int users_counted = 0; /* real Clients counted, i.e. not a server */
340
341 int channel_users = 0; /* XXX */
342 unsigned int channel_invites = 0;
343 int channel_bans = 0;
344 int channel_except = 0;
345 int channel_invex = 0;
346
347 int class_count = 0; /* classes */
348 int aways_counted = 0;
349 int number_ips_stored; /* number of ip addresses hashed */
350
351 size_t channel_memory = 0;
352 size_t channel_ban_memory = 0;
353 size_t channel_except_memory = 0;
354 size_t channel_invex_memory = 0;
355
356 unsigned int safelist_count = 0;
357 size_t safelist_memory = 0;
358
359 size_t away_memory = 0; /* memory used by aways */
360 size_t mem_ips_stored; /* memory used by ip address hash */
361 size_t total_channel_memory = 0;
362
363 unsigned int local_client_count = 0;
364 unsigned int remote_client_count = 0;
365
366 unsigned int local_client_memory_used = 0;
367 unsigned int remote_client_memory_used = 0;
368
369 size_t total_memory = 0;
370 unsigned int topic_count = 0;
371
372 unsigned int wlh = 0; /* watchlist headers */
373 unsigned int wle = 0; /* watchlist entries */
374 size_t wlhm = 0; /* watchlist memory used */
375
376 DLINK_FOREACH(gptr, global_client_list.head)
377 {
378 struct Client *target_p = gptr->data;
379
380 if (MyConnect(target_p))
381 {
382 ++local_client_count;
383 wle += dlink_list_length(&target_p->localClient->watches);
384 }
385 else
386 ++remote_client_count;
387
388 if (IsClient(target_p))
389 {
390 ++users_counted;
391
392 if (target_p->away != NULL)
393 {
394 ++aways_counted;
395 away_memory += strlen(target_p->away) + 1;
396 }
397 }
398 }
399
400 /* Count up all channels, ban lists, except lists, Invex lists */
401 channel_memory = dlink_list_length(&global_channel_list) *
402 sizeof(struct Channel);
403 DLINK_FOREACH(gptr, global_channel_list.head)
404 {
405 struct Ban *actualBan;
406 struct Channel *chptr = gptr->data;
407
408 channel_users += dlink_list_length(&chptr->members);
409 channel_invites += dlink_list_length(&chptr->invites);
410
411 if (chptr->topic != NULL)
412 ++topic_count;
413
414 if ((channel_bans = dlink_list_length(&chptr->banlist)))
415 {
416 channel_ban_memory = channel_bans * sizeof(struct Ban);
417
418 DLINK_FOREACH(dlink, chptr->banlist.head)
419 {
420 actualBan = dlink->data;
421 assert(actualBan->who);
422
423 channel_ban_memory += actualBan->len + 3;
424 channel_ban_memory += strlen(actualBan->who) + 1;
425 }
426 }
427
428 if ((channel_except = dlink_list_length(&chptr->exceptlist)))
429 {
430 channel_except_memory = channel_except * sizeof(struct Ban);
431
432 DLINK_FOREACH(dlink, chptr->exceptlist.head)
433 {
434 actualBan = dlink->data;
435 assert(actualBan->who);
436
437 channel_except_memory += actualBan->len + 3;
438 channel_except_memory += strlen(actualBan->who) + 1;
439 }
440 }
441
442 if ((channel_invex = dlink_list_length(&chptr->invexlist)))
443 {
444 channel_invex_memory = channel_invex * sizeof(struct Ban);
445
446 DLINK_FOREACH(dlink, chptr->invexlist.head)
447 {
448 actualBan = dlink->data;
449 assert(actualBan->who);
450
451 channel_invex_memory += actualBan->len + 3;
452 channel_invex_memory += strlen(actualBan->who) + 1;
453 }
454 }
455 }
456
457 if ((safelist_count = dlink_list_length(&listing_client_list)))
458 {
459 safelist_memory = safelist_count * sizeof(struct ListTask);
460 DLINK_FOREACH(gptr, listing_client_list.head)
461 {
462 struct Client *acptr = gptr->data;
463
464 DLINK_FOREACH(dlink, acptr->localClient->list_task->show_mask.head)
465 safelist_memory += strlen(dlink->data);
466
467 DLINK_FOREACH(dlink, acptr->localClient->list_task->hide_mask.head)
468 safelist_memory += strlen(dlink->data);
469 }
470 }
471
472 watch_count_memory(&wlh, &wlhm);
473
474 sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%d)",
475 me.name, RPL_STATSDEBUG, source_p->name, wlh, wlhm, wle,
476 wle * sizeof(dlink_node));
477
478 /* count up all classes */
479 class_count = dlink_list_length(&class_list);
480
481 sendto_one(source_p, ":%s %d %s z :Clients %u(%lu)",
482 me.name, RPL_STATSDEBUG, source_p->name, users_counted,
483 (unsigned long)(users_counted * sizeof(struct Client)));
484
485 sendto_one(source_p, ":%s %d %s z :User aways %u(%u)",
486 me.name, RPL_STATSDEBUG, source_p->name,
487 aways_counted, away_memory);
488
489 sendto_one(source_p, ":%s %d %s z :Resv channels %u(%u) nicks %u(%u) hash %u(%u)",
490 me.name, RPL_STATSDEBUG, source_p->name,
491 dlink_list_length(&cresv_confs),
492 dlink_list_length(&cresv_confs) * sizeof(struct ResvConf),
493 dlink_list_length(&nresv_confs),
494 dlink_list_length(&nresv_confs) * sizeof(struct ResvConf),
495 num_hashed_resvs, num_hashed_resvs * sizeof(struct ResvConf));
496
497 sendto_one(source_p, ":%s %d %s z :Classes %u(%lu)",
498 me.name, RPL_STATSDEBUG, source_p->name,
499 class_count, (unsigned long)(class_count * sizeof(struct Class)));
500
501 sendto_one(source_p, ":%s %d %s z :Channels %lu(%u) Topics %u(%d)",
502 me.name, RPL_STATSDEBUG, source_p->name,
503 dlink_list_length(&global_channel_list),
504 channel_memory, topic_count, topic_count *
505 (TOPICLEN + 1 + USERHOST_REPLYLEN));
506
507 sendto_one(source_p, ":%s %d %s z :Bans %u(%u)",
508 me.name, RPL_STATSDEBUG, source_p->name,
509 channel_bans, channel_ban_memory);
510
511 sendto_one(source_p, ":%s %d %s z :Exceptions %u(%u)",
512 me.name, RPL_STATSDEBUG, source_p->name,
513 channel_except, channel_except_memory);
514
515 sendto_one(source_p, ":%s %d %s z :Invex %u(%u)",
516 me.name, RPL_STATSDEBUG, source_p->name,
517 channel_invex, channel_invex_memory);
518
519 sendto_one(source_p, ":%s %d %s z :Channel members %u(%lu) invites %u(%u)",
520 me.name, RPL_STATSDEBUG, source_p->name, channel_users,
521 (unsigned long)(channel_users * sizeof(struct Membership)),
522 channel_invites, channel_invites * sizeof(dlink_node) * 2);
523
524 total_channel_memory = channel_memory + channel_ban_memory +
525 channel_users * sizeof(struct Membership) +
526 channel_invites * sizeof(dlink_node);
527
528 sendto_one(source_p, ":%s %d %s z :Safelist %u(%u)",
529 me.name, RPL_STATSDEBUG, source_p->name,
530 safelist_count, safelist_memory);
531
532 count_ip_hash(&number_ips_stored, &mem_ips_stored);
533
534 sendto_one(source_p, ":%s %d %s z :iphash %u(%u)",
535 me.name, RPL_STATSDEBUG, source_p->name,
536 number_ips_stored, mem_ips_stored);
537
538 total_memory = total_channel_memory + class_count *
539 sizeof(struct Class);
540
541 sendto_one(source_p, ":%s %d %s z :Total: channel %u",
542 me.name, RPL_STATSDEBUG, source_p->name,
543 total_channel_memory);
544
545 local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
546 total_memory += local_client_memory_used;
547 sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %d(%d)",
548 me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
549 local_client_memory_used);
550
551 remote_client_memory_used = remote_client_count * sizeof(struct Client);
552 total_memory += remote_client_memory_used;
553 sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %d(%d)",
554 me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
555 remote_client_memory_used);
556
557 DLINK_FOREACH(gptr, block_heap_get_heap_list()->head)
558 {
559 const struct BlockHeap *bh = gptr->data;
560 sendto_one(source_p,
561 ":%s %d %s z :%s mempool: used %u/%u free %u/%u (size %u/%u)",
562 me.name, RPL_STATSDEBUG, source_p->name, bh->name,
563 block_heap_get_used_elm(bh),
564 block_heap_get_used_mem(bh),
565 block_heap_get_free_elm(bh),
566 block_heap_get_free_mem(bh),
567 block_heap_get_size_elm(bh),
568 block_heap_get_size_mem(bh));
569 }
570
571 sendto_one(source_p, ":%s %d %s z :TOTAL: %u",
572 me.name, RPL_STATSDEBUG, source_p->name,
573 total_memory);
574 }
575
576 /* stats_operedup()
577 *
578 * input - client pointer
579 * output - none
580 * side effects - client is shown a list of active opers
581 */
582 static void
583 stats_operedup(struct Client *source_p)
584 {
585 dlink_node *ptr;
586
587 DLINK_FOREACH(ptr, oper_list.head)
588 {
589 const struct Client *target_p = ptr->data;
590
591 if (IsOperHidden(target_p) && !IsOper(source_p))
592 continue;
593
594 if (MyClient(source_p) && IsOper(source_p))
595 sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
596 from, RPL_STATSDEBUG, to,
597 IsAdmin(target_p) ?
598 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
599 oper_privs_as_string(target_p->localClient->operflags),
600 target_p->name, target_p->username, target_p->host,
601 (int)(CurrentTime - target_p->localClient->last));
602 else
603 sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
604 from, RPL_STATSDEBUG, to,
605 IsAdmin(target_p) ?
606 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
607 target_p->name, target_p->username, target_p->host,
608 (int)(CurrentTime - target_p->localClient->last));
609 }
610
611 sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
612 from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
613 }
614
615 /* show_ports()
616 *
617 * inputs - pointer to client to show ports to
618 * output - none
619 * side effects - send port listing to a client
620 */
621 static void
622 show_ports(struct Client *source_p)
623 {
624 char buf[4];
625 char *p = NULL;
626 const dlink_node *ptr = NULL;
627
628 DLINK_FOREACH(ptr, listener_get_list()->head)
629 {
630 const struct Listener *listener = ptr->data;
631 p = buf;
632
633 if (listener->flags & LISTENER_HIDDEN) {
634 if (!IsAdmin(source_p))
635 continue;
636 *p++ = 'H';
637 }
638
639 if (listener->flags & LISTENER_SSL)
640 *p++ = 's';
641 *p = '\0';
642 sendto_one(source_p, form_str(RPL_STATSPLINE),
643 me.name, source_p->name, 'P', listener->port,
644 IsAdmin(source_p) ? listener->name : me.name,
645 listener->ref_count, buf,
646 listener->active ? "active" : "disabled");
647 }
648 }
649
650 static void
651 stats_ports(struct Client *source_p)
652 {
653 if (!IsOper(source_p) && General.stats_P_oper_only)
654 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
655 from, to);
656 else
657 show_ports(source_p);
658 }
659
660 static void
661 stats_tstats(struct Client *source_p)
662 {
663 const struct Client *target_p = NULL;
664 struct ServerStatistics sp;
665 dlink_node *ptr = NULL;
666
667 memcpy(&sp, &ServerStats, sizeof(sp));
668
669 /*
670 * must use the += operator. is_sv is not the number of currently
671 * active server connections. Note the incrementation in
672 * s_bsd.c:close_connection.
673 */
674 sp.is_sv += dlink_list_length(&serv_list);
675
676 DLINK_FOREACH(ptr, serv_list.head)
677 {
678 target_p = ptr->data;
679
680 sp.is_sbs += target_p->localClient->send.bytes;
681 sp.is_sbr += target_p->localClient->recv.bytes;
682 sp.is_sti += CurrentTime - target_p->firsttime;
683 }
684
685 sp.is_cl += dlink_list_length(&local_client_list);
686
687 DLINK_FOREACH(ptr, local_client_list.head)
688 {
689 target_p = ptr->data;
690
691 sp.is_cbs += target_p->localClient->send.bytes;
692 sp.is_cbr += target_p->localClient->recv.bytes;
693 sp.is_cti += CurrentTime - target_p->firsttime;
694 }
695
696 sp.is_ni += dlink_list_length(&unknown_list);
697
698 sendto_one(source_p, ":%s %d %s T :accepts %u refused %u",
699 me.name, RPL_STATSDEBUG, source_p->name, sp.is_ac, sp.is_ref);
700 sendto_one(source_p, ":%s %d %s T :unknown commands %u prefixes %u",
701 me.name, RPL_STATSDEBUG, source_p->name, sp.is_unco, sp.is_unpf);
702 sendto_one(source_p, ":%s %d %s T :nick collisions %u unknown closes %u",
703 me.name, RPL_STATSDEBUG, source_p->name, sp.is_kill, sp.is_ni);
704 sendto_one(source_p, ":%s %d %s T :wrong direction %u empty %u",
705 me.name, RPL_STATSDEBUG, source_p->name, sp.is_wrdi, sp.is_empt);
706 sendto_one(source_p, ":%s %d %s T :numerics seen %u",
707 me.name, RPL_STATSDEBUG, source_p->name, sp.is_num);
708 sendto_one(source_p, ":%s %d %s T :auth successes %u fails %u",
709 me.name, RPL_STATSDEBUG, source_p->name, sp.is_asuc, sp.is_abad);
710 sendto_one(source_p, ":%s %d %s T :Client Server",
711 me.name, RPL_STATSDEBUG, source_p->name);
712
713 sendto_one(source_p, ":%s %d %s T :connected %u %u",
714 me.name, RPL_STATSDEBUG, source_p->name,
715 (unsigned int)sp.is_cl,
716 (unsigned int)sp.is_sv);
717 sendto_one(source_p, ":%s %d %s T :bytes sent %llu %llu",
718 me.name, RPL_STATSDEBUG, source_p->name,
719 sp.is_cbs, sp.is_sbs);
720 sendto_one(source_p, ":%s %d %s T :bytes recv %llu %llu",
721 me.name, RPL_STATSDEBUG, source_p->name,
722 sp.is_cbr, sp.is_sbr);
723 sendto_one(source_p, ":%s %d %s T :time connected %u %u",
724 me.name, RPL_STATSDEBUG, source_p->name,
725 (unsigned int)sp.is_cti,
726 (unsigned int)sp.is_sti);
727 }
728
729 static void
730 stats_uptime(struct Client *source_p)
731 {
732 time_t now = CurrentTime - me.since;
733 sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
734 now/86400, (now/3600)%24, (now/60)%60, now%60);
735 if (!General.disable_remote_commands || IsOper(source_p))
736 sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
737 MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
738 }
739
740 /* stats_servers()
741 *
742 * input - client pointer
743 * output - none
744 * side effects - client is shown lists of who connected servers
745 */
746 static void
747 stats_servers(struct Client *source_p)
748 {
749 dlink_node *ptr = NULL;
750
751 DLINK_FOREACH(ptr, serv_list.head)
752 {
753 const struct Client *target_p = ptr->data;
754
755 sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
756 from, RPL_STATSDEBUG, to,
757 target_p->name,
758 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
759 "*", "*", (int)(CurrentTime - target_p->lasttime));
760 }
761
762 sendto_one(source_p, ":%s %d %s v :%lu Server(s)",
763 from, RPL_STATSDEBUG, to,
764 dlink_list_length(&serv_list));
765 }
766
767 static void
768 stats_ziplinks(struct Client *source_p)
769 {
770 dlink_node *ptr;
771 struct Client *target_p;
772 unsigned int sent_data = 0;
773
774 DLINK_FOREACH(ptr, serv_list.head)
775 {
776 target_p = ptr->data;
777
778 if (IsCapable(target_p, CAP_ZIP))
779 {
780 /*
781 * we use memcpy(3) and a local copy of the structure to
782 * work around a register use bug on GCC on the SPARC.
783 * -jmallett, 04/27/2002
784 */
785 struct ZipStats zipstats;
786 memcpy(&zipstats, &target_p->localClient->zipstats, sizeof (struct ZipStats));
787
788 sendto_one(source_p, ":%s %d %s Z :ZipLinks stats for %s send[%.2f%% "
789 "compression (%lu bytes data/%lu bytes wire)] recv[%.2f%% "
790 "compression (%lu bytes data/%lu bytes wire)]",
791 from, RPL_STATSDEBUG, to, target_p->name,
792 zipstats.out_ratio, zipstats.out, zipstats.out_wire,
793 zipstats.in_ratio, zipstats.in, zipstats.in_wire);
794 ++sent_data;
795 }
796 }
797
798 sendto_one(source_p, ":%s %d %s Z :%u ziplink(s)",
799 from, RPL_STATSDEBUG, to, sent_data);
800 }
801
802 static void
803 stats_servlinks(struct Client *source_p)
804 {
805 uint64_t sendB = 0, recvB = 0;
806 time_t uptime = 0;
807 dlink_node *ptr = NULL;
808
809 if (ServerHide.flatten_links && !IsOper(source_p))
810 {
811 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
812 from, to);
813 return;
814 }
815
816 DLINK_FOREACH(ptr, serv_list.head)
817 {
818 const struct Client *target_p = ptr->data;
819
820 sendB += target_p->localClient->send.bytes;
821 recvB += target_p->localClient->recv.bytes;
822
823 /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
824 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
825 from, to,
826 get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
827 dbuf_length(&target_p->localClient->buf_sendq),
828 target_p->localClient->send.messages,
829 target_p->localClient->send.bytes >> 10,
830 target_p->localClient->recv.messages,
831 target_p->localClient->recv.bytes >> 10,
832 (unsigned)(CurrentTime - target_p->firsttime),
833 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
834 IsOper(source_p) ? show_capabilities(target_p) : "TS");
835 }
836
837 sendB >>= 10;
838 recvB >>= 10;
839
840 uptime = (CurrentTime - me.since);
841
842 sendto_one(source_p, ":%s %d %s ? :%u total server(s)",
843 from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
844 sendto_one(source_p, ":%s %d %s ? :Sent total : %7.2f %s",
845 from, RPL_STATSDEBUG, to,
846 _GMKv(sendB), _GMKs(sendB));
847 sendto_one(source_p, ":%s %d %s ? :Recv total : %7.2f %s",
848 from, RPL_STATSDEBUG, to,
849 _GMKv(recvB), _GMKs(recvB));
850
851 sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
852 from, RPL_STATSDEBUG, to,
853 _GMKv((me.localClient->send.bytes>>10)),
854 _GMKs((me.localClient->send.bytes>>10)),
855 (float)((float)(me.localClient->send.bytes >> 10) /
856 (float)uptime));
857 sendto_one(source_p, ":%s %d %s ? :Server recv: %7.2f %s (%4.1f K/s)",
858 from, RPL_STATSDEBUG, to,
859 _GMKv((me.localClient->recv.bytes>>10)),
860 _GMKs((me.localClient->recv.bytes>>10)),
861 (float)((float)(me.localClient->recv.bytes >> 10) /
862 (float)uptime));
863 }
864
865 static void
866 stats_ltrace(struct Client *source_p, int parc, char *parv[])
867 {
868 int doall = 0;
869 int wilds = 0;
870 char *name = NULL;
871 char statchar;
872
873 if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
874 {
875 statchar = *parv[1];
876
877 stats_L(source_p, name, doall, wilds, statchar);
878 }
879 else
880 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
881 from, to, "STATS");
882 }
883
884 static void
885 stats_hooks(struct Client *source_p)
886 {
887 dlink_node *ptr;
888 struct Callback *cb;
889 char lastused[32];
890
891 sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
892 RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
893 sendto_one(source_p, ":%s %d %s : ------------------------------------"
894 "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
895
896 DLINK_FOREACH(ptr, callback_list.head)
897 {
898 cb = ptr->data;
899
900 if (cb->last != 0)
901 snprintf(lastused, sizeof(lastused), "%d seconds ago",
902 (int) (CurrentTime - cb->last));
903 else
904 strcpy(lastused, "NEVER");
905
906 sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
907 RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
908 dlink_list_length(&cb->chain));
909 }
910
911 sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
912 source_p->name);
913 }
914
915 static void
916 stats_events(struct Client *source_p)
917 {
918 int i;
919
920 if (last_event_ran)
921 {
922 sendto_one(source_p, ":%s %d %s :Last event to run: %s",
923 me.name, RPL_STATSDEBUG, source_p->name, last_event_ran);
924 sendto_one(source_p, ":%s %d %s : ",
925 me.name, RPL_STATSDEBUG, source_p->name);
926 }
927
928 sendto_one(source_p,
929 ":%s %d %s : Operation Next Execution",
930 me.name, RPL_STATSDEBUG, source_p->name);
931 sendto_one(source_p,
932 ":%s %d %s : -------------------------------------------",
933 me.name, RPL_STATSDEBUG, source_p->name);
934
935 for (i = 0; i < MAX_EVENTS; ++i)
936 if (event_table[i].active)
937 sendto_one(source_p, ":%s %d %s : %-28s %-4d seconds",
938 me.name, RPL_STATSDEBUG, source_p->name,
939 event_table[i].name,
940 (int)(event_table[i].when - CurrentTime));
941
942 sendto_one(source_p, ":%s %d %s : ",
943 me.name, RPL_STATSDEBUG, source_p->name);
944 }
945
946 static void
947 stats_dns_servers(struct Client *source_p)
948 {
949 int i;
950 char ipaddr[HOSTIPLEN];
951
952 for (i = 0; i < irc_nscount; ++i)
953 {
954 irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
955 irc_nsaddr_list[i].ss_len, ipaddr, sizeof(ipaddr), NULL, 0,
956 NI_NUMERICHOST);
957 sendto_one(source_p, form_str(RPL_STATSALINE),
958 me.name, source_p->name, ipaddr);
959 }
960 }
961
962 static void
963 fd_dump(struct Client *source_p)
964 {
965 int i;
966 fde_t *F;
967
968 for (i = 0; i < FD_HASH_SIZE; ++i)
969 for (F = fd_hash[i]; F != NULL; F = F->hnext)
970 sendto_one(source_p, ":%s %d %s :fd %-5d desc '%s'",
971 me.name, RPL_STATSDEBUG, source_p->name,
972 F->fd, F->desc);
973 }
974
975 /*
976 * stats_L
977 *
978 * inputs - pointer to client to report to
979 * - doall flag
980 * - wild card or not
981 * output - NONE
982 * side effects -
983 */
984 static void
985 stats_L(struct Client *source_p,char *name,int doall,
986 int wilds,char statchar)
987 {
988 stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
989 stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
990 stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
991 }
992
993 static void
994 stats_L_list(struct Client *source_p, char *name, int doall, int wilds,
995 dlink_list *list, char statchar)
996 {
997 dlink_node *ptr = NULL;
998
999 /*
1000 * send info about connections which match, or all if the
1001 * mask matches from. Only restrictions are on those who
1002 * are invisible not being visible to 'foreigners' who use
1003 * a wild card based search to list it.
1004 */
1005 DLINK_FOREACH(ptr, list->head)
1006 {
1007 int ip_action = 0;
1008 const struct Client *target_p = ptr->data;
1009
1010 if (IsInvisible(target_p) && (doall || wilds) &&
1011 !(MyConnect(source_p) && IsOper(source_p)) &&
1012 !IsOper(target_p) && (target_p != source_p))
1013 continue;
1014 if (!doall && wilds && !match(name, target_p->name))
1015 continue;
1016 if (!(doall || wilds) && irccmp(name, target_p->name))
1017 continue;
1018
1019 if (IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p) ||
1020 IsHandshake(target_p) || IsConnecting(target_p))
1021 ip_action = MASK_IP;
1022 else if (IsUpper(statchar))
1023 ip_action = SHOW_IP;
1024 else
1025 ip_action = HIDE_IP;
1026
1027 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1028 from, to, get_client_name(target_p, ip_action),
1029 dbuf_length(&target_p->localClient->buf_sendq),
1030 target_p->localClient->send.messages,
1031 target_p->localClient->send.bytes>>10,
1032 target_p->localClient->recv.messages,
1033 target_p->localClient->recv.bytes>>10,
1034 (unsigned)(CurrentTime - target_p->firsttime),
1035 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1036 IsServer(target_p) ? show_capabilities(target_p) : "-");
1037 }
1038 }
1039
1040 /* parse_stats_args()
1041 *
1042 * inputs - arg count
1043 * - args
1044 * - doall flag
1045 * - wild card or not
1046 * output - pointer to name to use
1047 * side effects -
1048 * common parse routine for m_stats args
1049 *
1050 */
1051 static char *
1052 parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1053 {
1054 char *name = NULL;
1055
1056 if (parc > 2)
1057 {
1058 name = parv[2];
1059
1060 if (!irccmp(name, from))
1061 *doall = 2;
1062 else if (match(name, from))
1063 *doall = 1;
1064
1065 *wilds = has_wildcards(name, NO);
1066
1067 return name;
1068 }
1069
1070 return NULL;
1071 }

Properties

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