/*
- server.c
+ server.c
Author: Pekka Riikonen <priikone@silcnet.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
void silc_server_free(SilcServer server)
{
+ SilcIDCacheList list;
+ SilcIDCacheEntry cache;
+
if (!server)
return;
}
#endif
+ silc_server_backup_free(server);
silc_server_config_unref(&server->config_ref);
if (server->rng)
silc_rng_free(server->rng);
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" :
void silc_server_stop(SilcServer server)
{
- SILC_LOG_DEBUG(("Stopping server"));
+ SILC_LOG_INFO(("SILC Server shutting down"));
if (server->schedule) {
int 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) {
if (!sconn->backup) {
/* Mark this router our primary router if we're still standalone */
if (server->standalone) {
+ SILC_LOG_DEBUG(("This connection is our primary router"));
server->id_entry->router = id_entry;
server->router = id_entry;
server->standalone = FALSE;
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 */
if (conn->param) {
if (conn->param->keepalive_secs)
hearbeat_timeout = conn->param->keepalive_secs;
+
+ /* Check if to be anonymous connection */
+ if (conn->param->anonymous)
+ client->mode |= SILC_UMODE_ANONYMOUS;
}
id_entry = (void *)client;
ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
/* If entry is disabled ignore what we got. */
- if (ret != SILC_PACKET_RESUME_ROUTER &&
- idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
- SILC_LOG_DEBUG(("Connection is disabled"));
- goto out;
- }
- if (ret != SILC_PACKET_HEARTBEAT &&
- idata && idata->status & SILC_IDLIST_STATUS_DISABLED) {
+ if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
+ ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
+ ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) {
SILC_LOG_DEBUG(("Connection is disabled"));
goto out;
}
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 (server->server_shutdown)
+ backup_router = NULL;
+
/* If this was our primary router connection then we're lost to
the outside world. */
if (server->router == user_data) {
("%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",
if (!channel) {
SILC_LOG_ERROR(("Received key for non-existent channel %s",
silc_id_render(id, SILC_ID_CHANNEL)));
- assert(FALSE);
goto out;
}
}
{
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);
SilcClientEntry client;
SilcIDCacheEntry cache;
SilcChannelClientEntry chl;
- bool global;
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Saving %d users on %s channel", user_count,
+ channel->channel_name));
for (i = 0; i < user_count; i++) {
/* Client ID */
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);