void silc_server_free(SilcServer server)
{
+ SilcIDCacheList list;
+ SilcIDCacheEntry cache;
+
if (!server)
return;
if (server->id_entry)
silc_idlist_del_server(server->local_list, server->id_entry);
+ /* Delete all channels */
+ list = NULL;
+ if (silc_idcache_get_all(server->local_list->channels, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_channel(server->local_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_channel(server->local_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+ list = NULL;
+ if (silc_idcache_get_all(server->global_list->channels, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_channel(server->global_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_channel(server->global_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+
+ /* Delete all clients */
+ list = NULL;
+ if (silc_idcache_get_all(server->local_list->clients, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_client(server->local_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_client(server->local_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+ list = NULL;
+ if (silc_idcache_get_all(server->global_list->clients, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_client(server->global_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_client(server->global_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+
+ /* Delete all servers */
+ list = NULL;
+ if (silc_idcache_get_all(server->local_list->servers, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_server(server->local_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_server(server->local_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+ list = NULL;
+ if (silc_idcache_get_all(server->global_list->servers, &list) &&
+ silc_idcache_list_first(list, &cache)) {
+ silc_idlist_del_server(server->global_list, cache->context);
+ while (silc_idcache_list_next(list, &cache))
+ silc_idlist_del_server(server->global_list, cache->context);
+ }
+ if (list)
+ silc_idcache_list_free(list);
+
silc_idcache_free(server->local_list->clients);
silc_idcache_free(server->local_list->servers);
silc_idcache_free(server->local_list->channels);
if (!sock)
return;
- SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+ SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
sock->hostname, sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
if (server->schedule) {
int i;
+ server->server_shutdown = TRUE;
+
/* Close all connections */
for (i = 0; i < server->config->param.connections_max; i++) {
if (!server->sockets[i])
continue;
if (!SILC_IS_LISTENER(server->sockets[i])) {
- SilcIDListData idata = server->sockets[i]->user_data;
+ SilcSocketConnection sock = server->sockets[i];
+ SilcIDListData idata = sock->user_data;
if (idata)
idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
silc_server_disconnect_remote(server, server->sockets[i],
SILC_STATUS_OK,
"Server is shutting down");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock,
+ "Server is shutting down");
+ silc_socket_free(sock);
} else {
silc_socket_free(server->sockets[i]);
server->sockets[i] = NULL;
SilcServerConfigConnParams *param =
(conn->param ? conn->param : &server->config->param);
+ /* Don't retry if we are shutting down. */
+ if (server->server_shutdown) {
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ return;
+ }
+
SILC_LOG_INFO(("Retrying connecting to a router"));
/* Calculate next timeout */
SilcServerConfigRouter *rconn;
int sock;
+ /* Don't connect if we are shutting down. */
+ if (server->server_shutdown) {
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ return;
+ }
+
SILC_LOG_INFO(("Connecting to the %s %s on port %d",
(sconn->backup ? "backup router" : "router"),
sconn->remote_host, sconn->remote_port));
SilcServerConnection sconn;
SilcServerConfigRouter *ptr;
+ /* Don't connect if we are shutting down. */
+ if (server->server_shutdown)
+ return;
+
SILC_LOG_DEBUG(("We are %s",
(server->server_type == SILC_SERVER ?
"normal server" : server->server_type == SILC_ROUTER ?
ptr->host, ptr->port));
if (server->server_type == SILC_ROUTER && ptr->backup_router &&
- ptr->initiator == FALSE && !server->backup_router)
+ ptr->initiator == FALSE && !server->backup_router &&
+ !silc_server_config_get_backup_router(server))
server->wait_backup = TRUE;
if (ptr->initiator) {
SILC_LOG_DEBUG(("New server id(%s)",
silc_id_render(ctx->dest_id, SILC_ID_SERVER)));
- /* Add the connected router to global server list */
+ /* Add the connected router to global server list. Router is sent
+ as NULL since it's local to us. */
id_entry = silc_idlist_add_server(server->global_list,
strdup(sock->hostname),
SILC_ROUTER, ctx->dest_id, NULL, sock);
server->router = id_entry;
server->standalone = FALSE;
- /* If we are router then announce our possible servers. */
+ /* If we are router then announce our possible servers. Backup
+ router announces also global servers. */
if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server, FALSE, 0,
- SILC_PRIMARY_ROUTE(server));
+ silc_server_announce_servers(server,
+ server->backup_router ? TRUE : FALSE,
+ 0, SILC_PRIMARY_ROUTE(server));
/* Announce our clients and channels to the router */
silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
out:
/* Call the completion callback to indicate that we've connected to
the router */
- if (sconn->callback)
+ if (sconn && sconn->callback)
(*sconn->callback)(server, id_entry, sconn->callback_context);
/* Free the temporary connection data context */
SILC_TASK_PRI_LOW);
}
-/* After this is called, server don't wait for backup router anymore */
+/* After this is called, server don't wait for backup router anymore.
+ This gets called automatically even after we have backup router
+ connection established. */
SILC_TASK_CALLBACK(silc_server_backup_router_wait)
{
/* If the incoming connection is router and marked as backup router
then add it to be one of our backups */
if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER && backup_router) {
- silc_server_backup_add(server, new_server, backup_replace_ip,
- backup_replace_port, backup_local);
-
/* Change it back to SERVER type since that's what it really is. */
if (backup_local)
ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
-
new_server->server_type = SILC_BACKUP_ROUTER;
- server->wait_backup = FALSE;
+
+ /* Remove the backup waiting with timeout */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_router_wait,
+ (void *)server, 5, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/* Statistics */
SILC_LOG_DEBUG(("Connection is disabled"));
goto out;
}
+ if (ret != SILC_PACKET_HEARTBEAT &&
+ idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+ SILC_LOG_DEBUG(("Connection is disabled"));
+ goto out;
+ }
if (ret == SILC_PACKET_NONE) {
SILC_LOG_DEBUG(("Error parsing packet"));
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
+ char tmp[128];
+
if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
silc_schedule_task_add(server->schedule, 0,
silc_server_close_connection_final,
return;
}
- SILC_LOG_INFO(("Closing connection %s:%d [%s]", sock->hostname,
+ memset(tmp, 0, sizeof(tmp));
+ silc_socket_get_error(sock, tmp, sizeof(tmp));
+ SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", sock->hostname,
sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
- "Router")));
+ "Router"), tmp[0] ? tmp : ""));
/* We won't listen for this connection anymore */
silc_schedule_unset_listen_fd(server->schedule, sock->sock);
{
FreeClientInternal i = (FreeClientInternal)context;
+ assert(!silc_hash_table_count(i->client->channels));
+
silc_idlist_del_data(i->client);
silc_idcache_purge_by_context(i->server->local_list->clients, i->client);
silc_free(i);
int notify,
const char *signoff)
{
- FreeClientInternal i = silc_calloc(1, sizeof(*i));
-
SILC_LOG_DEBUG(("Freeing client data"));
#if 1
silc_schedule_task_del_by_context(server->schedule, client);
/* We will not delete the client entry right away. We will take it
- into history (for WHOWAS command) for 5 minutes */
- i->server = server;
- i->client = client;
- silc_schedule_task_add(server->schedule, 0,
- silc_server_free_client_data_timeout,
- (void *)i, 300, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
- client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
- client->mode = 0;
- client->router = NULL;
- client->connection = NULL;
+ into history (for WHOWAS command) for 5 minutes, unless we're
+ shutting down server. */
+ if (!server->server_shutdown) {
+ FreeClientInternal i = silc_calloc(1, sizeof(*i));
+ i->server = server;
+ i->client = client;
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_free_client_data_timeout,
+ (void *)i, 300, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
+ client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
+ client->mode = 0;
+ client->router = NULL;
+ client->connection = NULL;
+ } else {
+ /* Delete directly since we're shutting down server */
+ silc_idlist_del_data(client);
+ silc_idlist_del_client(server->local_list, client);
+ }
}
/* Frees user_data pointer from socket connection object. This also sends
if (user_data->id)
backup_router = silc_server_backup_get(server, user_data->id);
+ if (!server->backup_router && server->server_type == SILC_ROUTER &&
+ backup_router == server->id_entry &&
+ sock->type != SILC_SOCKET_TYPE_ROUTER)
+ backup_router = NULL;
+
/* If this was our primary router connection then we're lost to
the outside world. */
if (server->router == user_data) {
/* Enable local server connections that may be disabled */
silc_server_local_servers_toggle_enabled(server, TRUE);
+ /* Update the client entries of this server to the new backup
+ router. If we are the backup router we also resolve the real
+ servers for the clients. After updating is over this also
+ removes the clients that this server explicitly owns. */
+ silc_server_update_clients_by_server(server, user_data,
+ backup_router, TRUE);
+
/* If we are router and just lost our primary router (now standlaone)
we remove everything that was behind it, since we don't know
any better. */
remove the clients of those servers too. */
silc_server_remove_servers_by_server(server, user_data, TRUE);
- /* Update the client entries of this server to the new backup
- router. If we are the backup router we also resolve the real
- servers for the clients. After updating is over this also
- removes the clients that this server explicitly owns. */
- silc_server_update_clients_by_server(server, user_data,
- backup_router, TRUE, TRUE);
+ /* Finally remove the clients that are explicitly owned by this
+ server. They go down with the server. */
+ silc_server_remove_clients_by_server(server, user_data,
+ user_data, TRUE);
/* Update our server cache to use the new backup router too. */
silc_server_update_servers_by_server(server, user_data, backup_router);
("%s switched to backup router %s "
"(we are primary router now)",
server->server_name, server->server_name));
- else
+ else if (server->router)
SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
SILC_NOTIFY_TYPE_NONE,
("%s switched to backup router %s",
/* Remove channel if this is last client leaving the channel, unless
the channel is permanent. */
- if (server->server_type == SILC_ROUTER &&
+ if (server->server_type != SILC_SERVER &&
silc_hash_table_count(channel->user_list) < 2) {
silc_server_channel_delete(server, channel);
continue;
/* If there is no global users on the channel anymore mark the channel
as local channel. Do not check if the removed client is local client. */
- if (server->server_type != SILC_ROUTER && channel->global_users &&
+ if (server->server_type == SILC_SERVER && channel->global_users &&
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
/* If there is not at least one local user on the channel then we don't
need the channel entry anymore, we can remove it safely, unless the
channel is permanent channel */
- if (server->server_type != SILC_ROUTER &&
+ if (server->server_type == SILC_SERVER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
if (notify && channel->global_users)
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
+ /* Don't create keys if we are shutting down */
+ if (server->server_shutdown)
+ continue;
+
/* Re-generate channel key if needed */
if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
if (!silc_server_create_channel_key(server, channel, 0))
/* Remove channel if this is last client leaving the channel, unless
the channel is permanent. */
- if (server->server_type == SILC_ROUTER &&
+ if (server->server_type != SILC_SERVER &&
silc_hash_table_count(channel->user_list) < 2) {
silc_server_channel_delete(server, channel);
return FALSE;
/* If there is no global users on the channel anymore mark the channel
as local channel. Do not check if the client is local client. */
- if (server->server_type != SILC_ROUTER && channel->global_users &&
+ if (server->server_type == SILC_SERVER && channel->global_users &&
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
/* If there is not at least one local user on the channel then we don't
need the channel entry anymore, we can remove it safely, unless the
channel is permanent channel */
- if (server->server_type != SILC_ROUTER &&
+ if (server->server_type == SILC_SERVER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
if (notify && channel->global_users)
rekey->task = NULL;
+ /* Return now if we are shutting down */
+ if (server->server_shutdown)
+ return;
+
if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
return;
unsigned char channel_key[32], hash[32];
SilcUInt32 len;
- SILC_LOG_DEBUG(("Generating channel key"));
-
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
return TRUE;
}
+ SILC_LOG_DEBUG(("Generating channel %s key", channel->channel_name));
+
if (!channel->channel_key)
if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key)) {
channel->channel_key = NULL;
SilcUInt32 tmp_len;
char *cipher;
- SILC_LOG_DEBUG(("Saving new channel key"));
-
/* Decode channel key payload */
payload = silc_channel_key_payload_parse(key_payload->data,
key_payload->len);
}
}
+ SILC_LOG_DEBUG(("Saving new channel %s key", channel->channel_name));
+
tmp = silc_channel_key_get_key(payload, &tmp_len);
if (!tmp) {
channel = NULL;
{
SilcServerHBContext hb = (SilcServerHBContext)hb_context;
- SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
+ SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname,
+ sock->port, sock->ip));
/* Send the heartbeat */
silc_server_send_heartbeat(hb->server, sock);
break;
continue;
}
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) &&
+ !client->connection && !client->router && !SILC_IS_LOCAL(client)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ continue;
+ }
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_buffer_pull(*channels, len);
}
- /* Channel user modes */
- *channel_users_modes = silc_realloc(*channel_users_modes,
- sizeof(**channel_users_modes) *
- (i + 1));
- (*channel_users_modes)[i] = NULL;
- *channel_modes = silc_realloc(*channel_modes,
- sizeof(**channel_modes) * (i + 1));
- (*channel_modes)[i] = NULL;
- *channel_ids = silc_realloc(*channel_ids,
- sizeof(**channel_ids) * (i + 1));
- (*channel_ids)[i] = NULL;
- silc_server_announce_get_channel_users(server, channel,
- &(*channel_modes)[i],
- channel_users,
- &(*channel_users_modes)[i]);
- (*channel_ids)[i] = channel->id;
-
- /* Channel's topic */
- *channel_topics = silc_realloc(*channel_topics,
- sizeof(**channel_topics) * (i + 1));
- (*channel_topics)[i] = NULL;
- silc_server_announce_get_channel_topic(server, channel,
- &(*channel_topics)[i]);
- (*channel_users_modes_c)++;
- i++;
+ if (creation_time && channel->updated < creation_time)
+ announce = FALSE;
+ else
+ announce = TRUE;
+
+ if (announce) {
+ /* Channel user modes */
+ *channel_users_modes = silc_realloc(*channel_users_modes,
+ sizeof(**channel_users_modes) *
+ (i + 1));
+ (*channel_users_modes)[i] = NULL;
+ *channel_modes = silc_realloc(*channel_modes,
+ sizeof(**channel_modes) * (i + 1));
+ (*channel_modes)[i] = NULL;
+ *channel_ids = silc_realloc(*channel_ids,
+ sizeof(**channel_ids) * (i + 1));
+ (*channel_ids)[i] = NULL;
+ silc_server_announce_get_channel_users(server, channel,
+ &(*channel_modes)[i],
+ channel_users,
+ &(*channel_users_modes)[i]);
+ (*channel_ids)[i] = channel->id;
+
+ /* Channel's topic */
+ *channel_topics = silc_realloc(*channel_topics,
+ sizeof(**channel_topics) * (i + 1));
+ (*channel_topics)[i] = NULL;
+ silc_server_announce_get_channel_topic(server, channel,
+ &(*channel_topics)[i]);
+ (*channel_users_modes_c)++;
+ i++;
+ }
if (!silc_idcache_list_next(list, &id_cache))
break;
SilcClientEntry client;
SilcIDCacheEntry cache;
SilcChannelClientEntry chl;
- bool global;
SILC_LOG_DEBUG(("Start"));
continue;
}
- global = FALSE;
+ cache = NULL;
/* Check if we have this client cached already. */
client = silc_idlist_find_client_by_id(server->local_list, client_id,
server->server_type, &cache);
- if (!client) {
+ if (!client)
client = silc_idlist_find_client_by_id(server->global_list,
client_id, server->server_type,
&cache);
- global = TRUE;
- }
if (!client) {
/* If router did not find such Client ID in its lists then this must
be bogus client or some router in the net is buggy. */
- if (server->server_type == SILC_ROUTER) {
+ if (server->server_type != SILC_SERVER) {
silc_free(client_id);
continue;
}
}
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
- } else {
- /* Found, if it is from global list we'll assure that we won't
- expire it now that the entry is on channel. */
- if (global)
- cache->expire = 0;
}
+ if (cache)
+ cache->expire = 0;
silc_free(client_id);
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+ "%s", channel->channel_name));
+ continue;
+ }
+
if (!silc_server_client_on_channel(client, channel, &chl)) {
/* Client was not on the channel, add it. */
chl = silc_calloc(1, sizeof(*chl));
char *name;
int i = 0;
- if (!channels ||!channels_user_modes)
+ if (!channels || !channels_user_modes ||
+ !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
goto out;
ch = silc_channel_payload_parse_list(channels->data, channels->len);