silc_rng_free(server->rng);
if (server->pkcs)
silc_pkcs_free(server->pkcs);
+ if (server->public_key)
+ silc_pkcs_public_key_free(server->public_key);
+ if (server->private_key)
+ silc_pkcs_private_key_free(server->private_key);
if (server->pending_commands)
silc_dlist_uninit(server->pending_commands);
if (server->id_entry)
SilcServerID *id;
SilcServerEntry id_entry;
SilcIDListPurge purge;
+ SilcSocketConnection newsocket = NULL;
SILC_LOG_DEBUG(("Initializing server"));
assert(server);
silc_hash_alloc("sha1", &server->sha1hash);
/* Allocate PKCS context for local public and private keys */
- silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+ if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+ goto err;
silc_pkcs_public_key_set(server->pkcs, server->public_key);
silc_pkcs_private_key_set(server->pkcs, server->private_key);
if (!silc_server_listen(server, &sock))
goto err;
+ /* Set socket to non-blocking mode */
+ silc_net_set_socket_nonblock(sock);
+ server->sock = sock;
+
/* Allocate the entire socket list that is used in server. Eventually
all connections will have entry in this table (it is a table of
pointers to the actual object that is allocated individually
later). */
server->sockets = silc_calloc(server->config->param.connections_max,
sizeof(*server->sockets));
+ if (!server->sockets)
+ goto err;
- do {
- SilcSocketConnection newsocket = NULL;
-
- /* Set socket to non-blocking mode */
- silc_net_set_socket_nonblock(sock);
- server->sock = sock;
-
- /* Add ourselves also to the socket table. The entry allocated above
- is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
- server->sockets[sock] = newsocket;
-
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
- &newsocket->ip)) {
- if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
- newsocket->hostname ? newsocket->hostname :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock);
-
- /* Create a Server ID for the server. */
- silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
- if (!id)
- goto err;
+ /* Add ourselves also to the socket table. The entry allocated above
+ is sent as argument for fast referencing in the future. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
- server->id = id;
- server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
- server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
- server->id_type = SILC_ID_SERVER;
- server->server_name = server->config->server_info->server_name;
- server->config->server_info->server_name = NULL;
-
- /* Add ourselves to the server list. We don't have a router yet
- beacuse we haven't established a route yet. It will be done later.
- For now, NULL is sent as router. This allocates new entry to
- the ID list. */
- id_entry =
- silc_idlist_add_server(server->local_list, strdup(server->server_name),
- server->server_type, server->id, NULL, NULL);
- if (!id_entry) {
- SILC_LOG_ERROR(("Could not add ourselves to cache"));
+ /* Perform name and address lookups to resolve the listenning address
+ and port. */
+ if (!silc_net_check_local_by_sock(sock, &newsocket->hostname,
+ &newsocket->ip)) {
+ if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
+ !newsocket->ip) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+ newsocket->hostname ? newsocket->hostname :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
goto err;
}
- id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ }
+ newsocket->port = silc_net_get_local_port(sock);
+
+ /* Create a Server ID for the server. */
+ silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+ if (!id)
+ goto err;
- /* 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;
- id_entry->connection = (void *)newsocket;
- server->id_entry = id_entry;
- } while (0);
+ server->id = id;
+ server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
+ server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
+ server->id_type = SILC_ID_SERVER;
+ server->server_name = server->config->server_info->server_name;
+ server->config->server_info->server_name = NULL;
+
+ /* Add ourselves to the server list. We don't have a router yet
+ beacuse we haven't established a route yet. It will be done later.
+ For now, NULL is sent as router. This allocates new entry to
+ the ID list. */
+ id_entry =
+ silc_idlist_add_server(server->local_list, strdup(server->server_name),
+ server->server_type, server->id, NULL, NULL);
+ if (!id_entry) {
+ SILC_LOG_ERROR(("Could not add ourselves to cache"));
+ 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;
+ id_entry->connection = (void *)newsocket;
+ server->id_entry = id_entry;
/* Register protocols */
silc_server_protocols_register();
/* Start the main rehash phase (read again the config file) */
SILC_LOG_INFO(("Rehashing server"));
- newconfig = silc_server_config_alloc(server->config_file);
-
+ newconfig = silc_server_config_alloc(server, server->config_file);
if (!newconfig) {
SILC_LOG_ERROR(("Rehash FAILED."));
return FALSE;
}
- silc_server_config_unref(&server->config_ref);
+
+ /* 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;
- silc_server_config_ref(&server->config_ref, newconfig, (void *) 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;
+ }
/* Fix the server_name field */
if (!strcmp(server->server_name, newconfig->server_info->server_name)) {
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,
+ silc_idcache_add(server->local_list->servers,
+ server->id_entry->server_name,
server->id_entry->id, server->id_entry, 0, NULL);
}
silc_server_config_setlogfiles(server);
- /* XXX There is still to implement the publickey change and modules
- adding (we can't allow modules removing since we can't know which
- one are actually in use */
+ /* Change new key pair if necessary */
+ if (server->config->server_info->public_key &&
+ !silc_pkcs_public_key_compare(server->public_key,
+ server->config->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;
+
+ /* Allocate PKCS context for local public and private keys */
+ silc_pkcs_free(server->pkcs);
+ if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
+ return FALSE;
+ silc_pkcs_public_key_set(server->pkcs, server->public_key);
+ silc_pkcs_private_key_set(server->pkcs, server->private_key);
+ }
return TRUE;
}
return;
}
- /* we will lookup a fresh pointer later */
+ /* We will lookup a fresh pointer later */
silc_server_config_unref(&sconn->conn);
/* Wait one before retrying */
rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
sconn->remote_port);
if (!rconn) {
- SILC_LOG_INFO(("Unconfigured server, giving up"));
+ SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
+ (sconn->backup ? "backup router" : "router"),
+ sconn->remote_host, sconn->remote_port));
silc_free(sconn->remote_host);
silc_free(sconn->backup_replace_ip);
silc_free(sconn);
if (ctx->ske)
silc_ske_free(ctx->ske);
silc_free(ctx->dest_id);
- silc_server_config_unref(&ctx->cconfig);
- silc_server_config_unref(&ctx->sconfig);
- silc_server_config_unref(&ctx->rconfig);
silc_free(ctx);
silc_server_config_unref(&sconn->conn);
silc_free(sconn->remote_host);
silc_ske_free(ctx->ske);
silc_free(ctx->dest_id);
silc_free(ctx);
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
/* Check for maximum allowed connections */
if (sock > server->config->param.connections_max) {
- SILC_LOG_ERROR(("Refusing connection, server is full, try again later"));
+ SILC_LOG_ERROR(("Refusing connection, server is full"));
server->stat.conn_failures++;
silc_net_close_connection(sock);
return;
* parses it. The parsed data is returned to the newly allocated
* configuration object. */
-SilcServerConfig silc_server_config_alloc(char *filename)
+SilcServerConfig silc_server_config_alloc(SilcServer server,
+ const char *filename)
{
SilcServerConfig config_new;
SilcConfigEntity ent;
SILC_LOG_DEBUG(("Loading config data from `%s'", filename));
/* alloc a config object */
- config_new = (SilcServerConfig) silc_calloc(1, sizeof(*config_new));
+ config_new = silc_calloc(1, sizeof(*config_new));
+ if (!config_new)
+ return NULL;
+
/* obtain a config file object */
file = silc_config_open(filename);
if (!file) {
- SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n", filename));
+ SILC_SERVER_LOG_ERROR(("\nError: can't open config file `%s'\n",
+ filename));
return NULL;
}
+
/* obtain a SilcConfig entity, we can use it to start the parsing */
ent = silc_config_init(file);
SILC_SERVER_LOG_ERROR(("Error while parsing config file: %s.\n",
silc_config_strerror(ret)));
linebuf = silc_config_read_line(file, line);
- SILC_SERVER_LOG_ERROR((" file %s line %lu: %s\n", filename, line, linebuf));
+ SILC_SERVER_LOG_ERROR((" file %s line %lu: %s\n", filename,
+ line, linebuf));
silc_free(linebuf);
}
silc_server_config_destroy(config_new);
return NULL;
}
+
/* close (destroy) the file object */
silc_config_close(file);
/* If config_new is incomplete, abort the object and return NULL */
if (!config_new->server_info) {
- SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block `server_info'\n"));
+ SILC_SERVER_LOG_ERROR(("\nError: Missing mandatory block "
+ "`server_info'\n"));
silc_server_config_destroy(config_new);
return NULL;
}
/* Set default to configuration parameters */
silc_server_config_set_defaults(config_new);
+ silc_server_config_ref(&server->config_ref, config_new, config_new);
return config_new;
}
config->refcount++;
ref->config = config;
ref->ref_ptr = ref_ptr;
- SILC_LOG_DEBUG(("Referencing config [%p] New Ref=%hu", config,
- config->refcount));
+ SILC_LOG_DEBUG(("Referencing config [%p] refcnt %hu->%hu", config,
+ config->refcount - 1, config->refcount));
}
}
void silc_server_config_unref(SilcServerConfigRef *ref)
{
SilcServerConfig config = ref->config;
-
- if (config) {
+ if (ref->ref_ptr) {
config->refcount--;
- SILC_LOG_DEBUG(("Unreferencing config [%p] New Ref=%hu", config,
- config->refcount));
+ SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %hu->%hu", config,
+ config->refcount + 1, config->refcount));
if (!config->refcount)
silc_server_config_destroy(config);
- memset(ref, 0, sizeof(*ref));
}
}
void silc_server_config_destroy(SilcServerConfig config)
{
void *tmp;
+
+ if (config->refcount > 0) {
+ config->refcount--;
+ SILC_LOG_DEBUG(("Unreferencing config [%p] refcnt %hu->%hu", config,
+ config->refcount + 1, config->refcount));
+ if (config->refcount > 0)
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Freeing config context"));
+
silc_free(config->module_path);
/* Destroy Logging channels */
SILC_LOG_DEBUG(("Setting configured log file names and options"));
silc_log_quick = config->logging_quick;
- silc_log_flushdelay = config->logging_flushdelay;
+ silc_log_flushdelay = (config->logging_flushdelay ?
+ config->logging_flushdelay :
+ SILC_SERVER_LOG_FLUSH_DELAY);
if ((this = config->logging_fatals))
silc_log_set_file(SILC_LOG_FATAL, this->file, this->maxsize,