5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 * Created: Wed Mar 19 00:17:12 1997
22 * This is the main program for the SILC daemon. This parses command
23 * line arguments and creates the server object.
27 #include "serverincludes.h"
28 #include "server_internal.h"
29 #include "silcversion.h"
31 /* For now, we'll have this one server context global for this module. */
32 static SilcServer silcd;
34 static void silc_usage(void);
36 #ifdef HAVE_GETOPT_LONG
37 /* Long command line options */
38 static struct option long_opts[] =
40 { "config-file", 1, NULL, 'f' },
41 { "passphrase", 1, NULL, 'p' },
42 { "debug", 2, NULL, 'd' },
43 { "debug-level", 1, NULL, 'D' },
44 { "hexdump", 0, NULL, 'x' },
45 { "help", 0, NULL, 'h' },
46 { "foreground", 0, NULL, 'F' },
47 { "version", 0, NULL,'V' },
49 /* Key management options */
50 { "create-key-pair", 1, NULL, 'C' },
51 { "pkcs", 1, NULL, 10 },
52 { "bits", 1, NULL, 11 },
53 { "identifier", 1, NULL, 12 },
57 #endif /* HAVE_GETOPT_LONG */
59 /* Command line option variables */
60 static char *opt_keypath = NULL;
61 static char *opt_pkcs = "rsa";
62 static char *opt_identifier = NULL;
63 static int opt_bits = 2048;
65 /* Prints out the usage of silc client */
67 static void silc_usage(void)
70 "Usage: silcd [options]\n"
73 " -f --config-file=FILE Alternate configuration file\n"
74 " -d --debug=string Enable debugging (Implies --foreground)\n"
75 " -D --debug-level=level Enable debugging (Implies --foreground)\n"
76 " -x --hexdump Enable hexdumps (Implies --debug)\n"
77 " -h --help Display this message\n"
78 " -F --foreground Dont fork\n"
79 " -V --version Display version\n"
81 " Key Management Options:\n"
82 " -C, --create-key-pair=PATH Create new public key pair\n"
83 " --pkcs=PKCS Set the PKCS of the public key pair\n"
84 " --bits=VALUE Set length of the public key pair\n"
85 " --identifier=IDENTIFIER Public key identifier\n"
87 " The public key identifier may be of the following format:\n"
89 " UN=<username>, HN=<hostname or IP>, RN=<real name>, E=<email>,\n"
90 " O=<organization>, C=<country>\n"
92 " The UN and HN must be provided, the others are optional. If the\n"
93 " --identifier option is not used an identifier will be created for\n"
94 " the public key automatically.\n"
96 " Example identifier: \"UN=foobar, HN=foo.bar.com, RN=Foo T. Bar, \n"
97 " E=foo@bar.com, C=FI\"\n"
102 /* Die if a *valid* pid file exists already */
104 static void silc_server_checkpid(SilcServer silcd)
106 if (silcd->config->server_info->pid_file) {
111 SILC_LOG_DEBUG(("Checking for another silcd running"));
112 buf = silc_file_readfile(silcd->config->server_info->pid_file, &buf_len);
119 kill(oldpid, SIGCHLD); /* this signal does nothing, check if alive */
120 if (errno != ESRCH) {
121 fprintf(stderr, "\nI detected another daemon running with the "
123 fprintf(stderr, "Please change the config file, or erase the %s\n",
124 silcd->config->server_info->pid_file);
130 /* Drop root privileges. If some system call fails, die. */
132 static void silc_server_drop_privs(SilcServer server)
134 /* Are we executing silcd as root or a regular user? */
136 SILC_LOG_DEBUG(("Server started as user"));
143 SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
145 /* Get the values given for user and group in configuration file */
146 user = server->config->server_info->user;
147 group = server->config->server_info->group;
149 if (!user || !group) {
150 fprintf(stderr, "Error:"
151 "\tSILC server must not be run as root. For the security of your\n"
152 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
153 "\tuser account. Modify the ServerInfo configuration section to run\n"
154 "\tthe server as non-root user.\n");
158 /* Check whether the user/group does not begin with a number */
159 if (isdigit(user[0]) || isdigit(group[0])) {
160 SILC_LOG_DEBUG(("User and/or group starts with a number"));
161 fprintf(stderr, "Invalid user and/or group information\n");
162 fprintf(stderr, "Please assign them as names, not numbers\n");
166 if (!(pw = getpwnam(user))) {
167 fprintf(stderr, "Error: No such user %s found.\n", user);
170 if (!(gr = getgrnam(group))) {
171 fprintf(stderr, "Error: No such group %s found.\n", group);
175 /* Check whether user and/or group is set to root. If yes, exit
176 immediately. Otherwise, setgid and setuid server to user.group */
177 if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
178 fprintf(stderr, "Error:"
179 "\tSILC server must not be run as root. For the security of your\n"
180 "\tsystem it is strongly suggested that you run SILC under dedicated\n"
181 "\tuser account. Modify the ServerInfo configuration section to run\n"
182 "\tthe server as non-root user.\n");
186 SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
187 if (setgid(gr->gr_gid) != 0) {
188 fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
192 #if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
193 SILC_LOG_DEBUG(("Removing supplementary groups"));
194 if (setgroups(0, NULL) != 0) {
195 fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
198 SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
199 if (initgroups(user, gr->gr_gid) != 0) {
200 fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
201 "Exiting.\n", user, gr->gr_gid);
205 SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
206 if (setuid(pw->pw_uid) != 0) {
207 fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
214 /* Fork server to background */
216 static void silc_server_daemonise(SilcServer server)
220 SILC_LOG_DEBUG(("Forking SILC server to background"));
222 if ((i = fork()) < 0) {
223 fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
227 if (i) /* Kill the parent */
230 server->background = TRUE;
233 /* XXX close stdin, stdout, stderr -- before this, check that all writes
234 to stderr are changed to SILC_SERVER_LOG_ERROR() */
237 SILC_TASK_CALLBACK(got_hup)
239 /* First, reset all log files (they might have been deleted) */
240 silc_log_reset_all();
242 /* Rehash the configuration file */
243 silc_server_rehash(silcd);
246 SILC_TASK_CALLBACK(stop_server)
248 /* Stop scheduler, the program will stop eventually after noticing
249 that the scheduler is down. */
250 silc_schedule_stop(silcd->schedule);
253 /* Dump server statistics into a file into /tmp directory */
255 SILC_TASK_CALLBACK(dump_stats)
261 memset(filename, 0, sizeof(filename));
262 snprintf(filename, sizeof(filename) - 1, "/tmp/silcd.%d.stats-XXXXXX", getpid());
263 fild = mkstemp(filename);
267 fdd = fdopen(fild, "w");
274 #define STAT_OUTPUT(fmt, stat) fprintf(fdd, fmt "\n", (int)stat);
276 fprintf(fdd, "SILC Server %s Statistics\n\n", silcd->server_name);
277 fprintf(fdd, "Local Stats:\n");
278 STAT_OUTPUT(" My clients : %d", silcd->stat.my_clients);
279 STAT_OUTPUT(" My servers : %d", silcd->stat.my_servers);
280 STAT_OUTPUT(" My routers : %d", silcd->stat.my_routers);
281 STAT_OUTPUT(" My channels : %d", silcd->stat.my_channels);
282 STAT_OUTPUT(" My joined users : %d", silcd->stat.my_chanclients);
283 STAT_OUTPUT(" My aways : %d", silcd->stat.my_aways);
284 STAT_OUTPUT(" My detached clients : %d", silcd->stat.my_detached);
285 STAT_OUTPUT(" My server operators : %d", silcd->stat.my_server_ops);
286 STAT_OUTPUT(" My router operators : %d", silcd->stat.my_router_ops);
287 fprintf(fdd, "\nGlobal Stats:\n");
288 STAT_OUTPUT(" Cell clients : %d", silcd->stat.cell_clients);
289 STAT_OUTPUT(" Cell servers : %d", silcd->stat.cell_servers);
290 STAT_OUTPUT(" Cell channels : %d", silcd->stat.cell_channels);
291 STAT_OUTPUT(" Cell joined users : %d", silcd->stat.cell_chanclients);
292 STAT_OUTPUT(" All clients : %d", silcd->stat.clients);
293 STAT_OUTPUT(" All servers : %d", silcd->stat.servers);
294 STAT_OUTPUT(" All routers : %d", silcd->stat.routers);
295 STAT_OUTPUT(" All channels : %d", silcd->stat.channels);
296 STAT_OUTPUT(" All joined users : %d", silcd->stat.chanclients);
297 STAT_OUTPUT(" All aways : %d", silcd->stat.aways);
298 STAT_OUTPUT(" All detached clients : %d", silcd->stat.detached);
299 STAT_OUTPUT(" All server operators : %d", silcd->stat.server_ops);
300 STAT_OUTPUT(" All router operators : %d", silcd->stat.router_ops);
301 fprintf(fdd, "\nGeneral Stats:\n");
302 STAT_OUTPUT(" Connection attempts : %d", silcd->stat.conn_attempts);
303 STAT_OUTPUT(" Connection failures : %d", silcd->stat.conn_failures);
304 STAT_OUTPUT(" Authentication attempts : %d", silcd->stat.auth_attempts);
305 STAT_OUTPUT(" Authentication failures : %d", silcd->stat.auth_failures);
306 STAT_OUTPUT(" Packets sent : %d", silcd->stat.packets_sent);
307 STAT_OUTPUT(" Packets received : %d", silcd->stat.packets_received);
308 STAT_OUTPUT(" Commands sent : %d", silcd->stat.commands_sent);
309 STAT_OUTPUT(" Commands received : %d", silcd->stat.commands_received);
310 STAT_OUTPUT(" Connections : %d", silcd->stat.conn_num);
315 /* Dump internal flags */
316 fprintf(fdd, "\nDumping internal flags\n");
317 fprintf(fdd, " server_type : %d\n", silcd->server_type);
318 fprintf(fdd, " standalone : %d\n", silcd->standalone);
319 fprintf(fdd, " listenning : %d\n", silcd->listenning);
320 fprintf(fdd, " background : %d\n", silcd->background);
321 fprintf(fdd, " backup_router : %d\n", silcd->backup_router);
322 fprintf(fdd, " backup_primary : %d\n", silcd->backup_primary);
323 fprintf(fdd, " backup_noswitch : %d\n", silcd->backup_noswitch);
324 fprintf(fdd, " backup_closed : %d\n", silcd->backup_closed);
325 fprintf(fdd, " wait_backup : %d\n", silcd->wait_backup);
327 fprintf(fdd, " primary router : %s\n",
328 silcd->router->server_name ? silcd->router->server_name : "");
330 /* Dump connections */
333 SilcDList conns = silc_packet_engine_get_streams(silcd->packet_engine);
335 fprintf(fdd, "\nDumping connections\n");
336 silc_dlist_start(conns);
337 while ((s = silc_dlist_get(conns))) {
338 const char *hostname, *ip;
341 SilcIDListData idata = silc_packet_get_context(s);
342 if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(s),
343 &sock, &hostname, &ip, &port))
345 fprintf(fdd, " %d: host %s ip %s port %d type %d\n",
346 sock, hostname ? hostname : "N/A",
347 ip ? ip : "N/A", port, idata ? idata->conn_type : 0);
349 silc_dlist_uninit(conns);
355 SilcIDCacheEntry id_cache = NULL;
356 SilcServerEntry server_entry;
357 SilcClientEntry client_entry;
358 SilcChannelEntry channel_entry;
361 fprintf(fdd, "\nDumping databases\n");
363 if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
365 fprintf(fdd, "\nServers in local-list:\n");
366 while ((id_cache = silc_list_get(list))) {
367 server_entry = (SilcServerEntry)id_cache->context;
368 fprintf(fdd, " %d: name %s id %s status 0x%x\n", c,
369 server_entry->server_name ? server_entry->server_name :
370 "N/A", server_entry->id ?
371 silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
372 server_entry->data.status);
376 if (silc_idcache_get_all(silcd->global_list->servers, &list)) {
377 fprintf(fdd, "\nServers in global-list:\n");
379 while ((id_cache = silc_list_get(list))) {
380 server_entry = (SilcServerEntry)id_cache->context;
381 fprintf(fdd, " %d: name %s id %s status 0x%x\n", c,
382 server_entry->server_name ? server_entry->server_name :
383 "N/A", server_entry->id ?
384 silc_id_render(server_entry->id, SILC_ID_SERVER) : "N/A",
385 server_entry->data.status);
389 if (silc_idcache_get_all(silcd->local_list->clients, &list)) {
390 fprintf(fdd, "\nClients in local-list:\n");
392 while ((id_cache = silc_list_get(list))) {
393 client_entry = (SilcClientEntry)id_cache->context;
394 server_entry = client_entry->router;
395 fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c,
396 client_entry->nickname ? client_entry->nickname :
397 (unsigned char *)"N/A", client_entry->id ?
398 silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
399 client_entry->data.status, server_entry ?
400 server_entry->server_name ? server_entry->server_name :
405 if (silc_idcache_get_all(silcd->global_list->clients, &list)) {
406 fprintf(fdd, "\nClients in global-list:\n");
408 while ((id_cache = silc_list_get(list))) {
409 client_entry = (SilcClientEntry)id_cache->context;
410 server_entry = client_entry->router;
411 fprintf(fdd, " %d: name %s id %s status 0x%x from %s\n", c,
412 client_entry->nickname ? client_entry->nickname :
413 (unsigned char *)"N/A", client_entry->id ?
414 silc_id_render(client_entry->id, SILC_ID_CLIENT) : "N/A",
415 client_entry->data.status, server_entry ?
416 server_entry->server_name ? server_entry->server_name :
421 if (silc_idcache_get_all(silcd->local_list->channels, &list)) {
422 fprintf(fdd, "\nChannels in local-list:\n");
424 while ((id_cache = silc_list_get(list))) {
425 channel_entry = (SilcChannelEntry)id_cache->context;
426 fprintf(fdd, " %d: name %s id %s\n", c,
427 channel_entry->channel_name ? channel_entry->channel_name :
428 "N/A", channel_entry->id ?
429 silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
433 if (silc_idcache_get_all(silcd->global_list->channels, &list)) {
434 fprintf(fdd, "\nChannels in global-list:\n");
436 while ((id_cache = silc_list_get(list))) {
437 channel_entry = (SilcChannelEntry)id_cache->context;
438 fprintf(fdd, " %d: name %s id %s\n", c,
439 channel_entry->channel_name ? channel_entry->channel_name :
440 "N/A", channel_entry->id ?
441 silc_id_render(channel_entry->id, SILC_ID_CHANNEL) : "N/A");
459 static DebugLevel debug_levels[] = {
460 /* Very basic stuff from silcd/ */
461 { 3, "silcd\\.c,server\\.c" },
463 /* More stuff from silcd/ */
464 { 7, "silcd\\.c,server\\.c,command\\.c,server_backup\\.c,packet_send\\.c" },
466 /* All basic stuff from silcd/ */
467 { 10, "silc_server_*" },
469 /* All from silcd/ */
470 { 15, "*silcd*,*serverid*,silc_server_*,*idlist*" },
472 /* All from silcd/ and basic stuff from libs */
473 { 20, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,*silcske*" },
475 /* All from silcd/ and more stuff from libs */
476 { 25, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
477 "*silcpacket*,*ske*,*silcrng*" },
479 /* All from silcd/ and even more stuff from libs */
480 { 30, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
481 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*" },
483 /* All from silcd/ and even more stuff from libs + all from silccore */
484 { 35, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
485 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
486 "*silcid*,*argument*" },
488 /* All from silcd/, all from silccore, silccrypt and silcmath */
489 { 40, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
490 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
491 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*" },
493 /* All from silcd/, all from silccore, silccrypt and silcmath + stuff
495 { 45, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
496 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
497 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
500 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
502 { 50, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
503 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
504 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
505 "*sockconn*,*net*" },
507 /* All from silcd/, all from silccore, silccrypt and silcmath + more stuff
509 { 55, "*silcd*,*serverid*,silc_server_*,*idlist*,*silcconauth*,"
510 "*silcpacket*,*ske*,*silcrng*,*command*,*channel*,*private*,*notify*"
511 "*silcid*,*argument*,*pkcs*,*hmac*,*hash*,*cipher*,silc_math*,*sim*"
512 "*sockconn*,*net*,*log*,*config*" },
520 static void silc_get_debug_level(int level)
527 for (i = 0; debug_levels[i].string; i++)
528 if (level <= debug_levels[i].level) {
529 silc_log_set_debug_string(debug_levels[i].string);
533 #endif /* SILC_DEBUG */
535 /* This function should not be called directly but through the appropriate
536 wrapper macro defined in server.h */
538 void silc_server_stderr(SilcLogType type, char *message)
540 if (silcd->background) {
541 char *p, *n = message;
543 /* remove newlines if we are going to output it to a log file */
544 for (p = n; *p; p++) {
553 /* the message is freed inside the logging function */
554 silc_log_output(type, message);
557 fprintf(stderr, "%s\n", message);
562 int main(int argc, char **argv)
564 int ret, opt, option_index;
565 SilcBool foreground = FALSE;
566 SilcBool opt_create_keypair = FALSE;
567 char *silcd_config_file = NULL;
570 /* Parse command line arguments */
572 #ifdef HAVE_GETOPT_LONG
573 while ((opt = getopt_long(argc, argv, "f:p:d:D:xhFVC:",
574 long_opts, &option_index)) != EOF) {
576 while ((opt = getopt(argc, argv, "f:p:d:D:xhFVC:")) != EOF) {
577 #endif /* HAVE_GETOPT_LONG */
583 printf("SILCd Secure Internet Live Conferencing daemon, "
584 "version %s (base: SILC Toolkit %s)\n",
585 silc_dist_version, silc_version);
586 printf("(c) 1997 - 2007 Pekka Riikonen "
587 "<priikone@silcnet.org>\n");
592 silc_log_debug(TRUE);
593 silc_log_quick(TRUE);
595 silc_log_set_debug_string(optarg);
596 foreground = TRUE; /* implied */
599 "Run-time debugging is not enabled. To enable it recompile\n"
600 "the server with --enable-debug configuration option.\n");
605 silc_log_debug(TRUE);
606 silc_log_quick(TRUE);
608 silc_get_debug_level(atoi(optarg));
609 foreground = TRUE; /* implied */
612 "Run-time debugging is not enabled. To enable it recompile\n"
613 "the server with --enable-debug configuration option.\n");
618 silc_log_debug(TRUE);
619 silc_log_debug_hexdump(TRUE);
620 silc_log_quick(TRUE);
621 foreground = TRUE; /* implied */
624 "Run-time debugging is not enabled. To enable it recompile\n"
625 "the server with --enable-debug configuration option.\n");
629 silcd_config_file = strdup(optarg);
636 * Key management options
639 opt_create_keypair = TRUE;
641 opt_keypath = strdup(optarg);
645 opt_pkcs = strdup(optarg);
649 opt_bits = atoi(optarg);
653 opt_identifier = strdup(optarg);
663 if (opt_create_keypair == TRUE) {
664 /* Create new key pair and exit */
665 char pubfile[256], prvfile[256];
667 memset(pubfile, 0, sizeof(pubfile));
668 memset(prvfile, 0, sizeof(prvfile));
669 snprintf(pubfile, sizeof(pubfile) - 1, "%s/silcd.pub", opt_keypath);
670 snprintf(prvfile, sizeof(prvfile) - 1, "%s/silcd.prv", opt_keypath);
672 silc_cipher_register_default();
673 silc_pkcs_register_default();
674 silc_hash_register_default();
675 silc_hmac_register_default();
676 if (!silc_create_key_pair(opt_pkcs, opt_bits, pubfile, prvfile,
677 opt_identifier, "", NULL, NULL, FALSE))
682 /* Default configuration file */
683 if (!silcd_config_file)
684 silcd_config_file = strdup(SILC_SERVER_CONFIG_FILE);
686 /* Create SILC Server object */
687 ret = silc_server_alloc(&silcd);
691 /* Register default crypto stuff since we are going to need them
692 in the configuration file parsing phase */
693 silc_cipher_register_default();
694 silc_pkcs_register_default();
695 silc_hash_register_default();
696 silc_hmac_register_default();
698 /* Read configuration files */
699 silcd->config = silc_server_config_alloc(silcd_config_file, silcd);
700 if (silcd->config == NULL)
702 silcd->config_file = silcd_config_file;
704 /* Unregister the default crypto stuff so that configuration takes effect */
705 silc_cipher_unregister_all();
706 /* silc_pkcs_unregister_all(); MUST NOT do this anymore; SilcPublicKey
707 parsed from config file references pointers so we cannot unregister */
708 silc_hash_unregister_all();
709 silc_hmac_unregister_all();
711 /* Check for another silcd running */
712 silc_server_checkpid(silcd);
714 /* Initialize the server */
715 if (silc_server_init(silcd) == FALSE)
718 /* Ignore some signals */
719 sa.sa_handler = SIG_IGN;
721 sigemptyset(&sa.sa_mask);
723 sigaction(SIGPIPE, &sa, NULL); /* Ignore broken pipes */
726 sigaction(SIGXFSZ, &sa, NULL); /* Ignore file limit exceeds */
729 sigaction(SIGXCPU, &sa, NULL); /* Ignore CPU time limit exceeds */
732 /* Handle specificly some other signals. */
733 silc_schedule_task_add_signal(silcd->schedule, SIGHUP, got_hup, NULL);
734 silc_schedule_task_add_signal(silcd->schedule, SIGTERM, stop_server, NULL);
735 silc_schedule_task_add_signal(silcd->schedule, SIGINT, stop_server, NULL);
736 silc_schedule_task_add_signal(silcd->schedule, SIGUSR1, dump_stats, NULL);
739 /* Before running the server, fork to background. */
740 silc_server_daemonise(silcd);
742 /* If set, write pid to file */
743 if (silcd->config->server_info->pid_file) {
744 char buf[10], *pidfile = silcd->config->server_info->pid_file;
746 snprintf(buf, sizeof(buf) - 1, "%d\n", getpid());
747 silc_file_writefile(pidfile, buf, strlen(buf));
750 silc_server_drop_privs(silcd);
753 /* Run the server. When this returns the server has been stopped
755 silc_server_run(silcd);
757 /* Stop the server and free it. */
758 silc_server_stop(silcd);
759 silc_server_config_destroy(silcd->config);
760 silc_server_free(silcd);
762 /* Flush the logging system */
763 silc_log_flush_all();
765 silc_free(silcd_config_file);
766 silc_free(opt_identifier);
767 silc_free(opt_keypath);
771 silc_free(silcd_config_file);
772 silc_free(opt_identifier);
773 silc_free(opt_keypath);