ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/ircd.c
Revision: 163
Committed: Thu Oct 20 21:09:02 2005 UTC (18 years, 5 months ago) by adx
Content type: text/x-csrc
File size: 19148 byte(s)
Log Message:
- MFC iorecv/iosend changes to allow charset recoding

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * ircd.c: Starts up and runs the ircd.
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 "s_user.h"
27 #include "tools.h"
28 #include "ircd.h"
29 #include "channel.h"
30 #include "channel_mode.h"
31 #include "client.h"
32 #include "common.h"
33 #include "event.h"
34 #include "fdlist.h"
35 #include "hash.h"
36 #include "irc_string.h"
37 #include "sprintf_irc.h"
38 #include "ircd_signal.h"
39 #include "list.h"
40 #include "s_gline.h"
41 #include "motd.h"
42 #include "ircd_handler.h"
43 #include "msg.h" /* msgtab */
44 #include "hostmask.h"
45 #include "numeric.h"
46 #include "packet.h"
47 #include "parse.h"
48 #include "irc_res.h"
49 #include "restart.h"
50 #include "s_auth.h"
51 #include "s_bsd.h"
52 #include "s_conf.h"
53 #include "s_log.h"
54 #include "s_misc.h"
55 #include "s_serv.h" /* try_connections */
56 #include "s_stats.h"
57 #include "send.h"
58 #include "whowas.h"
59 #include "modules.h"
60 #include "memory.h"
61 #include "hook.h"
62 #include "ircd_getopt.h"
63 #include "balloc.h"
64 #include "motd.h"
65 #include "supported.h"
66
67 /* Try and find the correct name to use with getrlimit() for setting the max.
68 * number of files allowed to be open by this process.
69 */
70
71 /* /quote set variables */
72 struct SetOptions GlobalSetOptions;
73
74 /* configuration set from ircd.conf */
75 struct config_file_entry ConfigFileEntry;
76 /* server info set from ircd.conf */
77 struct server_info ServerInfo;
78 /* admin info set from ircd.conf */
79 struct admin_info AdminInfo = { NULL, NULL, NULL };
80 struct Counter Count = { 0, 0, 0, 0, 0, 0, 0, 0 };
81 struct ServerState_t server_state = { 0 };
82 struct logging_entry ConfigLoggingEntry = { 1, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0} };
83 struct timeval SystemTime;
84 struct Client me; /* That's me */
85 struct LocalUser meLocalUser; /* That's also part of me */
86 unsigned long connect_id = 0; /* unique connect ID */
87
88 static unsigned long initialVMTop = 0; /* top of virtual memory at init */
89 const char *logFileName = LPATH;
90 const char *pidFileName = PPATH;
91
92 char **myargv;
93 char ircd_platform[PLATFORMLEN];
94
95 int dorehash = 0;
96 int doremotd = 0;
97 time_t nextconnect = 1; /* time for next try_connections call */
98
99 /* Set to zero because it should be initialized later using
100 * initialize_server_capabs
101 */
102 int default_server_capabs = 0;
103
104 #ifdef HAVE_LIBCRYPTO
105 int bio_spare_fd = -1;
106 #endif
107
108 int splitmode;
109 int splitchecking;
110 int split_users;
111 unsigned int split_servers;
112
113 /* Do klines the same way hybrid-6 did them, i.e. at the
114 * top of the next io_loop instead of in the same loop as
115 * the klines are being applied.
116 *
117 * This should fix strange CPU starvation as very indirectly reported.
118 * (Why do you people not email bug reports? WHY? WHY?)
119 *
120 * - Dianora
121 */
122
123 int rehashed_klines = 0;
124
125 /*
126 * get_vm_top - get the operating systems notion of the resident set size
127 */
128 #ifndef _WIN32
129 static unsigned long
130 get_vm_top(void)
131 {
132 /*
133 * NOTE: sbrk is not part of the ANSI C library or the POSIX.1 standard
134 * however it seems that everyone defines it. Calling sbrk with a 0
135 * argument will return a pointer to the top of the process virtual
136 * memory without changing the process size, so this call should be
137 * reasonably safe (sbrk returns the new value for the top of memory).
138 * This code relies on the notion that the address returned will be an
139 * offset from 0 (NULL), so the result of sbrk is cast to a size_t and
140 * returned. We really shouldn't be using it here but...
141 */
142
143 void *vptr = sbrk(0);
144 return((unsigned long)vptr);
145 }
146
147 /*
148 * print_startup - print startup information
149 */
150 static void
151 print_startup(int pid)
152 {
153 printf("ircd: version %s\n", ircd_version);
154 printf("ircd: pid %d\n", pid);
155 printf("ircd: running in %s mode from %s\n", !server_state.foreground ? "background"
156 : "foreground", ConfigFileEntry.dpath);
157 }
158
159 static void
160 make_daemon(void)
161 {
162 int pid;
163
164 if ((pid = fork()) < 0)
165 {
166 perror("fork");
167 exit(EXIT_FAILURE);
168 }
169 else if (pid > 0)
170 {
171 print_startup(pid);
172 exit(EXIT_SUCCESS);
173 }
174
175 setsid();
176 }
177 #endif
178
179 /*
180 * get_maxrss - get the operating systems notion of the resident set size
181 */
182 unsigned long
183 get_maxrss(void)
184 {
185 #ifdef _WIN32
186 return (0); /* FIXME */
187 #else
188 return (get_vm_top() - initialVMTop);
189 #endif
190 }
191
192 static int printVersion = 0;
193
194 struct lgetopt myopts[] = {
195 {"dlinefile", &ConfigFileEntry.dlinefile,
196 STRING, "File to use for dline.conf"},
197 {"configfile", &ConfigFileEntry.configfile,
198 STRING, "File to use for ircd.conf"},
199 {"klinefile", &ConfigFileEntry.klinefile,
200 STRING, "File to use for kline.conf"},
201 {"xlinefile", &ConfigFileEntry.xlinefile,
202 STRING, "File to use for xline.conf"},
203 {"logfile", &logFileName,
204 STRING, "File to use for ircd.log"},
205 {"pidfile", &pidFileName,
206 STRING, "File to use for process ID"},
207 {"foreground", &server_state.foreground,
208 YESNO, "Run in foreground (don't detach)"},
209 {"version", &printVersion,
210 YESNO, "Print version and exit"},
211 {"help", NULL, USAGE, "Print this text"},
212 {NULL, NULL, STRING, NULL},
213 };
214
215 void
216 set_time(void)
217 {
218 static char to_send[200];
219 struct timeval newtime;
220 #ifdef _WIN32
221 FILETIME ft;
222
223 GetSystemTimeAsFileTime(&ft);
224 if (ft.dwLowDateTime < 0xd53e8000)
225 ft.dwHighDateTime--;
226 ft.dwLowDateTime -= 0xd53e8000;
227 ft.dwHighDateTime -= 0x19db1de;
228
229 newtime.tv_sec = (*(uint64_t *) &ft) / 10000000;
230 newtime.tv_usec = (*(uint64_t *) &ft) / 10 % 1000000;
231 #else
232 newtime.tv_sec = 0;
233 newtime.tv_usec = 0;
234
235 if (gettimeofday(&newtime, NULL) == -1)
236 {
237 ilog(L_ERROR, "Clock Failure (%s), TS can be corrupted",
238 strerror(errno));
239 sendto_realops_flags(UMODE_ALL, L_ALL,
240 "Clock Failure (%s), TS can be corrupted",
241 strerror(errno));
242 restart("Clock Failure");
243 }
244 #endif
245
246 if (newtime.tv_sec < CurrentTime)
247 {
248 ircsprintf(to_send, "System clock is running backwards - (%lu < %lu)",
249 (unsigned long)newtime.tv_sec, (unsigned long)CurrentTime);
250 report_error(L_ALL, to_send, me.name, 0);
251 set_back_events(CurrentTime - newtime.tv_sec);
252 }
253
254 SystemTime.tv_sec = newtime.tv_sec;
255 SystemTime.tv_usec = newtime.tv_usec;
256 }
257
258 static void
259 io_loop(void)
260 {
261 while (1 == 1)
262 {
263 /*
264 * Maybe we want a flags word?
265 * ie. if (REHASHED_KLINES(global_flags))
266 * SET_REHASHED_KLINES(global_flags)
267 * CLEAR_REHASHED_KLINES(global_flags)
268 *
269 * - Dianora
270 */
271 if (rehashed_klines)
272 {
273 check_conf_klines();
274 rehashed_klines = 0;
275 }
276
277 if (listing_client_list.head)
278 {
279 dlink_node *ptr = NULL, *ptr_next = NULL;
280 DLINK_FOREACH_SAFE(ptr, ptr_next, listing_client_list.head)
281 {
282 struct Client *client_p = ptr->data;
283 assert(client_p->localClient->list_task);
284 safe_list_channels(client_p, client_p->localClient->list_task, 0, 0);
285 }
286 }
287
288 /* Run pending events, then get the number of seconds to the next
289 * event
290 */
291 while (eventNextTime() <= CurrentTime)
292 eventRun();
293
294 comm_select();
295 exit_aborted_clients();
296 free_exited_clients();
297 send_queued_all();
298
299 /* Check to see whether we have to rehash the configuration .. */
300 if (dorehash)
301 {
302 rehash(1);
303 dorehash = 0;
304 }
305 if (doremotd)
306 {
307 read_message_file(&ConfigFileEntry.motd);
308 sendto_realops_flags(UMODE_ALL, L_ALL,
309 "Got signal SIGUSR1, reloading ircd motd file");
310 doremotd = 0;
311 }
312 }
313 }
314
315 /* initalialize_global_set_options()
316 *
317 * inputs - none
318 * output - none
319 * side effects - This sets all global set options needed
320 */
321 static void
322 initialize_global_set_options(void)
323 {
324 memset(&GlobalSetOptions, 0, sizeof(GlobalSetOptions));
325
326 GlobalSetOptions.autoconn = 1;
327 GlobalSetOptions.spam_time = MIN_JOIN_LEAVE_TIME;
328 GlobalSetOptions.spam_num = MAX_JOIN_LEAVE_COUNT;
329
330 if (ConfigFileEntry.default_floodcount)
331 GlobalSetOptions.floodcount = ConfigFileEntry.default_floodcount;
332 else
333 GlobalSetOptions.floodcount = 10;
334
335 /* XXX I have no idea what to try here - Dianora */
336 GlobalSetOptions.joinfloodcount = 16;
337 GlobalSetOptions.joinfloodtime = 8;
338
339 split_servers = ConfigChannel.default_split_server_count;
340 split_users = ConfigChannel.default_split_user_count;
341
342 if (split_users && split_servers && (ConfigChannel.no_create_on_split ||
343 ConfigChannel.no_join_on_split))
344 {
345 splitmode = 1;
346 splitchecking = 1;
347 }
348
349 GlobalSetOptions.ident_timeout = IDENT_TIMEOUT;
350 GlobalSetOptions.idletime = ConfigFileEntry.idletime;
351 /* End of global set options */
352 }
353
354 /* initialize_message_files()
355 *
356 * inputs - none
357 * output - none
358 * side effects - Set up all message files needed, motd etc.
359 */
360 static void
361 initialize_message_files(void)
362 {
363 init_message_file(USER_MOTD, MPATH, &ConfigFileEntry.motd);
364 init_message_file(OPER_MOTD, OPATH, &ConfigFileEntry.opermotd);
365 init_message_file(USER_LINKS, LIPATH, &ConfigFileEntry.linksfile);
366
367 read_message_file(&ConfigFileEntry.motd);
368 read_message_file(&ConfigFileEntry.opermotd);
369 read_message_file(&ConfigFileEntry.linksfile);
370
371 init_isupport();
372 }
373
374 /* initialize_server_capabs()
375 *
376 * inputs - none
377 * output - none
378 */
379 static void
380 initialize_server_capabs(void)
381 {
382 add_capability("QS", CAP_QS, 1);
383 add_capability("LL", CAP_LL, 1);
384 add_capability("EOB", CAP_EOB, 1);
385 if (ServerInfo.sid != NULL) /* only enable TS6 if we have an SID */
386 add_capability("TS6", CAP_TS6, 0);
387 add_capability("ZIP", CAP_ZIP, 0);
388 add_capability("CLUSTER", CAP_CLUSTER, 1);
389 #ifdef HALFOPS
390 add_capability("HOPS", CAP_HOPS, 1);
391 #endif
392 }
393
394 /* write_pidfile()
395 *
396 * inputs - filename+path of pid file
397 * output - NONE
398 * side effects - write the pid of the ircd to filename
399 */
400 static void
401 write_pidfile(const char *filename)
402 {
403 FBFILE *fb;
404
405 if ((fb = fbopen(filename, "w")))
406 {
407 char buff[32];
408 unsigned int pid = (unsigned int)getpid();
409 size_t nbytes = ircsprintf(buff, "%u\n", pid);
410
411 if ((fbputs(buff, fb, nbytes) == -1))
412 ilog(L_ERROR, "Error writing %u to pid file %s (%s)",
413 pid, filename, strerror(errno));
414
415 fbclose(fb);
416 return;
417 }
418 else
419 {
420 ilog(L_ERROR, "Error opening pid file %s", filename);
421 }
422 }
423
424 /* check_pidfile()
425 *
426 * inputs - filename+path of pid file
427 * output - none
428 * side effects - reads pid from pidfile and checks if ircd is in process
429 * list. if it is, gracefully exits
430 * -kre
431 */
432 static void
433 check_pidfile(const char *filename)
434 {
435 #ifndef _WIN32
436 FBFILE *fb;
437 char buff[32];
438 pid_t pidfromfile;
439
440 /* Don't do logging here, since we don't have log() initialised */
441 if ((fb = fbopen(filename, "r")))
442 {
443 if (fbgets(buff, 20, fb) == NULL)
444 {
445 /* log(L_ERROR, "Error reading from pid file %s (%s)", filename,
446 * strerror(errno));
447 */
448 }
449 else
450 {
451 pidfromfile = atoi(buff);
452
453 if (!kill(pidfromfile, 0))
454 {
455 /* log(L_ERROR, "Server is already running"); */
456 printf("ircd: daemon is already running\n");
457 exit(-1);
458 }
459 }
460
461 fbclose(fb);
462 }
463 else if (errno != ENOENT)
464 {
465 /* log(L_ERROR, "Error opening pid file %s", filename); */
466 }
467 #endif
468 }
469
470 /* setup_corefile()
471 *
472 * inputs - nothing
473 * output - nothing
474 * side effects - setups corefile to system limits.
475 * -kre
476 */
477 static void
478 setup_corefile(void)
479 {
480 #ifdef HAVE_SYS_RESOURCE_H
481 struct rlimit rlim; /* resource limits */
482
483 /* Set corefilesize to maximum */
484 if (!getrlimit(RLIMIT_CORE, &rlim))
485 {
486 rlim.rlim_cur = rlim.rlim_max;
487 setrlimit(RLIMIT_CORE, &rlim);
488 }
489 #endif
490 }
491
492 /* init_ssl()
493 *
494 * inputs - nothing
495 * output - nothing
496 * side effects - setups SSL context.
497 */
498 static void
499 init_ssl(void)
500 {
501 #ifdef HAVE_LIBCRYPTO
502 SSL_load_error_strings();
503 SSLeay_add_ssl_algorithms();
504
505 ServerInfo.ctx = SSL_CTX_new(SSLv23_server_method());
506 if (!ServerInfo.ctx)
507 {
508 const char *s;
509
510 fprintf(stderr, "ERROR: Could not initialize the SSL context -- %s\n",
511 s = ERR_lib_error_string(ERR_get_error()));
512 ilog(L_CRIT, "ERROR: Could not initialize the SSL context -- %s\n", s);
513 }
514
515 SSL_CTX_set_options(ServerInfo.ctx, SSL_OP_NO_SSLv2);
516 SSL_CTX_set_options(ServerInfo.ctx, SSL_OP_TLS_ROLLBACK_BUG|SSL_OP_ALL);
517 SSL_CTX_set_verify(ServerInfo.ctx, SSL_VERIFY_NONE, NULL);
518
519 bio_spare_fd = save_spare_fd("SSL private key validation");
520 #endif /* HAVE_LIBCRYPTO */
521 }
522
523 /* init_callbacks()
524 *
525 * inputs - nothing
526 * output - nothing
527 * side effects - setups standard hook points
528 */
529 static void
530 init_callbacks(void)
531 {
532 iorecv_cb = register_callback("iorecv", iorecv_default);
533 iosend_cb = register_callback("iosend", iosend_default);
534 iorecvctrl_cb = register_callback("iorecvctrl", NULL);
535 iosendctrl_cb = register_callback("iosendctrl", NULL);
536 }
537
538 int
539 main(int argc, char *argv[])
540 {
541 /* Check to see if the user is running
542 * us as root, which is a nono
543 */
544 #ifndef _WIN32
545 if (geteuid() == 0)
546 {
547 fprintf(stderr, "Don't run ircd as root!!!\n");
548 return(-1);
549 }
550
551 /* Setup corefile size immediately after boot -kre */
552 setup_corefile();
553
554 /* set initialVMTop before we allocate any memory */
555 initialVMTop = get_vm_top();
556 #endif
557
558 /* save server boot time right away, so getrusage works correctly */
559 set_time();
560
561 /* It ain't random, but it ought to be a little harder to guess */
562 srand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20)));
563 memset(&me, 0, sizeof(me));
564 memset(&meLocalUser, 0, sizeof(meLocalUser));
565 me.localClient = &meLocalUser;
566 dlinkAdd(&me, &me.node, &global_client_list); /* Pointer to beginning
567 of Client list */
568
569 memset(&ServerInfo, 0, sizeof(ServerInfo));
570
571 /* Initialise the channel capability usage counts... */
572 init_chcap_usage_counts();
573
574 ConfigFileEntry.dpath = DPATH;
575 ConfigFileEntry.configfile = CPATH; /* Server configuration file */
576 ConfigFileEntry.klinefile = KPATH; /* Server kline file */
577 ConfigFileEntry.xlinefile = XPATH; /* Server xline file */
578 ConfigFileEntry.rxlinefile = RXPATH; /* Server regex xline file */
579 ConfigFileEntry.rklinefile = RKPATH; /* Server regex kline file */
580 ConfigFileEntry.dlinefile = DLPATH; /* dline file */
581 ConfigFileEntry.glinefile = GPATH; /* gline log file */
582 ConfigFileEntry.cresvfile = CRESVPATH; /* channel resv file */
583 ConfigFileEntry.nresvfile = NRESVPATH; /* nick resv file */
584 myargv = argv;
585 umask(077); /* better safe than sorry --SRB */
586
587 parseargs(&argc, &argv, myopts);
588
589 if (printVersion)
590 {
591 printf("ircd: version %s\n", ircd_version);
592 exit(EXIT_SUCCESS);
593 }
594
595 if (chdir(ConfigFileEntry.dpath))
596 {
597 perror("chdir");
598 exit(EXIT_FAILURE);
599 }
600
601 init_ssl();
602
603 #ifndef _WIN32
604 if (!server_state.foreground)
605 {
606 make_daemon();
607 close_standard_fds(); /* this needs to be before init_netio()! */
608 }
609 else
610 print_startup(getpid());
611
612 setup_signals();
613 #endif
614
615 get_ircd_platform(ircd_platform);
616
617 /* Init the event subsystem */
618 eventInit();
619 /* We need this to initialise the fd array before anything else */
620 fdlist_init();
621 init_log(logFileName);
622 check_can_use_v6();
623 init_comm(); /* This needs to be setup early ! -- adrian */
624 /* Check if there is pidfile and daemon already running */
625 check_pidfile(pidFileName);
626
627 #ifndef NOBALLOC
628 initBlockHeap();
629 #endif
630 init_dlink_nodes();
631 init_callbacks();
632 initialize_message_files();
633 dbuf_init();
634 init_hash();
635 init_ip_hash_table(); /* client host ip hash table */
636 init_host_hash(); /* Host-hashtable. */
637 clear_tree_parse();
638 init_client();
639 init_class();
640 init_whowas();
641 init_stats();
642 read_conf_files(1); /* cold start init conf files */
643 initServerMask();
644 me.id[0] = '\0';
645 init_uid();
646 init_auth(); /* Initialise the auth code */
647 #ifndef _WIN32
648 init_resolver(); /* Needs to be setup before the io loop */
649 #endif
650 initialize_server_capabs(); /* Set up default_server_capabs */
651 initialize_global_set_options();
652 init_channels();
653
654 if (ServerInfo.name == NULL)
655 {
656 ilog(L_CRIT, "No server name specified in serverinfo block.");
657 exit(EXIT_FAILURE);
658 }
659 strlcpy(me.name, ServerInfo.name, sizeof(me.name));
660
661 /* serverinfo{} description must exist. If not, error out.*/
662 if (ServerInfo.description == NULL)
663 {
664 ilog(L_CRIT,
665 "ERROR: No server description specified in serverinfo block.");
666 exit(EXIT_FAILURE);
667 }
668 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
669
670 me.from = &me;
671 me.servptr = &me;
672
673 SetMe(&me);
674 make_server(&me);
675
676 me.lasttime = me.since = me.firsttime = CurrentTime;
677 hash_add_client(&me);
678
679 /* add ourselves to global_serv_list */
680 dlinkAdd(&me, make_dlink_node(), &global_serv_list);
681
682 check_class();
683
684 #ifndef STATIC_MODULES
685 if (chdir(MODPATH))
686 {
687 ilog (L_CRIT, "Could not load core modules. Terminating!");
688 exit(EXIT_FAILURE);
689 }
690
691 load_all_modules(1);
692 load_conf_modules();
693 load_core_modules(1);
694 /* Go back to DPATH after checking to see if we can chdir to MODPATH */
695 chdir(ConfigFileEntry.dpath);
696 #else
697 load_all_modules(1);
698 #endif
699 /*
700 * assemble_umode_buffer() has to be called after
701 * reading conf/loading modules.
702 */
703 assemble_umode_buffer();
704
705 write_pidfile(pidFileName);
706
707 ilog(L_NOTICE, "Server Ready");
708
709 eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME);
710 eventAddIsh("cleanup_tklines", cleanup_tklines, NULL, CLEANUP_TKLINES_TIME);
711
712 /* We want try_connections to be called as soon as possible now! -- adrian */
713 /* No, 'cause after a restart it would cause all sorts of nick collides */
714 eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME);
715
716 eventAddIsh("collect_zipstats", collect_zipstats, NULL, ZIPSTATS_TIME);
717
718 /* Setup the timeout check. I'll shift it later :) -- adrian */
719 eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1);
720
721 if (ConfigServerHide.links_delay > 0)
722 eventAddIsh("write_links_file", write_links_file, NULL, ConfigServerHide.links_delay);
723 else
724 ConfigServerHide.links_disabled = 1;
725
726 if (splitmode)
727 eventAddIsh("check_splitmode", check_splitmode, NULL, 60);
728
729 io_loop();
730 return(0);
731 }

Properties

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