SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
SILC_TASK_CALLBACK(silc_server_failure_callback);
SILC_TASK_CALLBACK(silc_server_rekey_callback);
+SILC_TASK_CALLBACK(silc_server_get_stats);
/* Allocates a new SILC server object. This has to be done before the server
can be used. After allocation one must call silc_server_init to initialize
silc_dlist_uninit(server->sim);
#endif
+ silc_server_config_unref(&server->config_ref);
if (server->rng)
silc_rng_free(server->rng);
if (server->pkcs)
SilcSocketConnection newsocket = NULL;
SILC_LOG_DEBUG(("Initializing server"));
- assert(server);
- assert(server->config);
-
- /* Set public and private keys */
- if (!server->config->server_info ||
- !server->config->server_info->public_key ||
- !server->config->server_info->private_key) {
- SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
- return FALSE;
- }
+
+ server->starttime = time(NULL);
+
+ /* Take config object for us */
+ silc_server_config_ref(&server->config_ref, server->config,
+ server->config);
/* Steal public and private key from the config object */
server->public_key = server->config->server_info->public_key;
goto err;
}
id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
-
+
/* Put the allocated socket pointer also to the entry allocated above
for fast back-referencing to the socket list. */
newsocket->user_data = (void *)id_entry;
timeout. It expires as soon as the caller calls silc_server_run. This
task performs authentication protocol and key exchange with our
primary router. */
- silc_schedule_task_add(server->schedule, sock,
+ silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router,
(void *)server, 0, 1,
SILC_TASK_TIMEOUT,
(void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ /* If we are normal server we'll retrieve network statisticial information
+ once in a while from the router. */
+ if (server->server_type == SILC_SERVER)
+ silc_schedule_task_add(purge->schedule, 0, silc_server_get_stats,
+ server, 10, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
SILC_LOG_DEBUG(("Server initialized"));
/* We are done here, return succesfully */
return TRUE;
err:
+ silc_server_config_unref(&server->config_ref);
silc_net_close_server(sock);
return FALSE;
}
{
SilcServerConfig newconfig;
+ SILC_LOG_INFO(("Rehashing server"));
+
/* Reset the logging system */
silc_log_quick = TRUE;
silc_log_flush_all();
/* Start the main rehash phase (read again the config file) */
- SILC_LOG_INFO(("Rehashing server"));
- newconfig = silc_server_config_alloc(server, server->config_file);
+ newconfig = silc_server_config_alloc(server->config_file);
if (!newconfig) {
SILC_LOG_ERROR(("Rehash FAILED."));
return FALSE;
}
- /* Destroy old config context. This is destroyed if no one is referencing
- it at the moment. */
- silc_server_config_destroy(server->config);
- server->config = newconfig;
-
- /* Set public and private keys */
- if (!server->config->server_info ||
- !server->config->server_info->public_key ||
- !server->config->server_info->private_key) {
- SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
- return FALSE;
- }
+ /* Reinit scheduler if necessary */
+ if (newconfig->param.connections_max > server->config->param.connections_max)
+ if (!silc_schedule_reinit(server->schedule,
+ newconfig->param.connections_max))
+ return FALSE;
/* Fix the server_name field */
- if (!strcmp(server->server_name, newconfig->server_info->server_name)) {
- /* We don't need any update */
- silc_free(newconfig->server_info->server_name);
- newconfig->server_info->server_name = NULL;
- } else {
+ if (strcmp(server->server_name, newconfig->server_info->server_name)) {
silc_free(server->server_name);
server->server_name = newconfig->server_info->server_name;
newconfig->server_info->server_name = NULL;
/* Update the idcache list with a fresh pointer */
silc_free(server->id_entry->server_name);
server->id_entry->server_name = strdup(server->server_name);
- silc_idcache_del_by_context(server->local_list->servers, server->id_entry);
- silc_idcache_add(server->local_list->servers,
- server->id_entry->server_name,
- server->id_entry->id, server->id_entry, 0, NULL);
+ if (!silc_idcache_del_by_context(server->local_list->servers,
+ server->id_entry))
+ return FALSE;
+ if (!silc_idcache_add(server->local_list->servers,
+ server->id_entry->server_name,
+ server->id_entry->id, server->id_entry, 0, NULL))
+ return FALSE;
}
+ /* Set logging */
silc_server_config_setlogfiles(server);
/* Change new key pair if necessary */
- if (server->config->server_info->public_key &&
+ if (newconfig->server_info->public_key &&
!silc_pkcs_public_key_compare(server->public_key,
- server->config->server_info->public_key)) {
+ newconfig->server_info->public_key)) {
silc_pkcs_public_key_free(server->public_key);
silc_pkcs_private_key_free(server->private_key);
- server->public_key = server->config->server_info->public_key;
- server->private_key = server->config->server_info->private_key;
- server->config->server_info->public_key = NULL;
- server->config->server_info->private_key = NULL;
+ server->public_key = newconfig->server_info->public_key;
+ server->private_key = newconfig->server_info->private_key;
+ newconfig->server_info->public_key = NULL;
+ newconfig->server_info->private_key = NULL;
/* Allocate PKCS context for local public and private keys */
silc_pkcs_free(server->pkcs);
silc_pkcs_private_key_set(server->pkcs, server->private_key);
}
- return TRUE;
-}
-
-/* Drop root privileges. If some system call fails, die. */
-
-void silc_server_drop(SilcServer server)
-{
- /* Are we executing silcd as root or a regular user? */
- if (geteuid()) {
- SILC_LOG_DEBUG(("Server started as user"));
- }
- else {
- struct passwd *pw;
- struct group *gr;
- char *user, *group;
-
- SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
-
- /* Get the values given for user and group in configuration file */
- user = server->config->server_info->user;
- group = server->config->server_info->group;
-
- if (!user || !group) {
- fprintf(stderr, "Error:"
- "\tSILC server must not be run as root. For the security of your\n"
- "\tsystem it is strongly suggested that you run SILC under dedicated\n"
- "\tuser account. Modify the ServerInfo configuration section to run\n"
- "\tthe server as non-root user.\n");
- exit(1);
- }
-
- /* Check whether the user/group does not begin with a number */
- if (isdigit(user[0]) || isdigit(group[0])) {
- SILC_LOG_DEBUG(("User and/or group starts with a number"));
- fprintf(stderr, "Invalid user and/or group information\n");
- fprintf(stderr, "Please assign them as names, not numbers\n");
- exit(1);
- }
-
- if (!(pw = getpwnam(user))) {
- fprintf(stderr, "Error: No such user %s found.\n", user);
- exit(1);
- }
- if (!(gr = getgrnam(group))) {
- fprintf(stderr, "Error: No such group %s found.\n", group);
- exit(1);
- }
+ /* Go through all configured routers after rehash */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router,
+ (void *)server, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
- /* Check whether user and/or group is set to root. If yes, exit
- immediately. Otherwise, setgid and setuid server to user.group */
- if ((gr->gr_gid == 0) || (pw->pw_uid == 0)) {
- fprintf(stderr, "Error:"
- "\tSILC server must not be run as root. For the security of your\n"
- "\tsystem it is strongly suggested that you run SILC under dedicated\n"
- "\tuser account. Modify the ServerInfo configuration section to run\n"
- "\tthe server as non-root user.\n");
- exit(1);
- }
+ /* Check whether our router status has changed */
+ if (newconfig->servers) {
+ SilcServerConfigServer *ptr = newconfig->servers;
- SILC_LOG_DEBUG(("Changing to group %s (gid=%u)", group, gr->gr_gid));
- if (setgid(gr->gr_gid) != 0) {
- fprintf(stderr, "Error: Failed setgid() to %s (gid=%u). Exiting.\n",
- group, gr->gr_gid);
- exit(1);
- }
-#if defined HAVE_SETGROUPS && defined HAVE_INITGROUPS
- SILC_LOG_DEBUG(("Removing supplementary groups"));
- if (setgroups(0, NULL) != 0) {
- fprintf(stderr, "Error: Failed setgroups() to NULL. Exiting.\n");
- exit(1);
- }
- SILC_LOG_DEBUG(("Setting supplementary groups for user %s", user));
- if (initgroups(user, gr->gr_gid) != 0) {
- fprintf(stderr, "Error: Failed initgroups() for user %s (gid=%u). "
- "Exiting.\n", user, gr->gr_gid);
- exit(1);
- }
-#endif
- SILC_LOG_DEBUG(("Changing to user %s (uid=%u)", user, pw->pw_uid));
- if (setuid(pw->pw_uid) != 0) {
- fprintf(stderr, "Error: Failed to setuid() to %s (gid=%u). Exiting.\n",
- user, pw->pw_uid);
- exit(1);
+ server->server_type = SILC_ROUTER;
+ while (ptr) {
+ if (ptr->backup_router) {
+ server->server_type = SILC_BACKUP_ROUTER;
+ server->backup_router = TRUE;
+ server->id_entry->server_type = SILC_BACKUP_ROUTER;
+ break;
+ }
+ ptr = ptr->next;
}
}
-}
-
-/* Fork server to background */
-
-void silc_server_daemonise(SilcServer server)
-{
- int i;
-
- SILC_LOG_DEBUG(("Forking SILC server to background"));
- if ((i = fork()) < 0) {
- fprintf(stderr, "Error: fork() failed: %s\n", strerror(errno));
- exit(1);
- }
+ /* Our old config is gone now. We'll unreference our reference made in
+ silc_server_init and then destroy it since we are destroying it
+ underneath the application (layer which called silc_server_init). */
+ silc_server_config_unref(&server->config_ref);
+ silc_server_config_destroy(server->config);
- if (i) /* Kill the parent */
- exit(0);
+ /* Take new config context */
+ server->config = newconfig;
+ silc_server_config_ref(&server->config_ref, server->config, server->config);
- server->background = TRUE;
- setsid();
+ SILC_LOG_DEBUG(("Server rehashed"));
- /* XXX close stdin, stdout, stderr -- before this, check that all writes
- to stderr are changed to SILC_SERVER_LOG_ERROR() */
+ return TRUE;
}
/* The heart of the server. This runs the scheduler thus runs the server.
return;
}
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_router);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_to_router_retry);
+
/* Create the connections to all our routes */
for (ptr = server->config->routers; ptr; ptr = ptr->next) {
ptr->host, ptr->port));
if (ptr->initiator) {
+ /* Check whether we are connected to this host already */
+ if (silc_server_num_sockets_by_remote(server,
+ silc_net_is_ip(ptr->host) ?
+ ptr->host : NULL,
+ silc_net_is_ip(ptr->host) ?
+ NULL : ptr->host, ptr->port,
+ SILC_SOCKET_TYPE_ROUTER)) {
+ SILC_LOG_DEBUG(("We are already connected to this router"));
+ continue;
+ }
+
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
sconn->server = server;
if (!server->router_conn && !sconn->backup)
server->router_conn = sconn;
- silc_schedule_task_add(server->schedule, fd,
+ silc_schedule_task_add(server->schedule, 0,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
/* Statistics */
server->stat.my_clients++;
server->stat.clients++;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients++;
+ server->stat.cell_clients++;
/* Get connection parameters */
if (conn->param) {
/* Update statistics */
server->stat.my_clients--;
server->stat.clients--;
- if (server->server_type == SILC_ROUTER)
+ if (server->stat.cell_clients)
server->stat.cell_clients--;
SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
silc_ske_free(ctx->ske);
silc_free(ctx);
}
+
+/* Task callback used to retrieve network statistical information from
+ router server once in a while. */
+
+SILC_TASK_CALLBACK(silc_server_get_stats)
+{
+ SilcServer server = (SilcServer)context;
+ SilcBuffer idp, packet;
+
+ SILC_LOG_DEBUG(("Retrieving stats from router"));
+
+ if (!server->standalone) {
+ idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+ packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
+ ++server->cmd_ident, 1,
+ 1, idp->data, idp->len);
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
+
+ silc_schedule_task_add(server->schedule, 0, silc_server_get_stats,
+ server, 120, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+}