#include "server_internal.h"
/* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection);
SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
SILC_TASK_CALLBACK(silc_server_connect_router);
SILC_TASK_CALLBACK(silc_server_connect_to_router);
return FALSE;
}
+/* Task callback to close a socket connection after rehash */
+
+SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
+{
+ SilcServer server = context;
+ SilcSocketConnection sock = server->sockets[fd];
+
+ if (!sock)
+ return;
+
+ SILC_LOG_INFO(("Closing connection %s:%d [%s]: connection is unconfigured",
+ 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")));
+ silc_schedule_task_del_by_context(server->schedule, sock);
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_BANNED_FROM_SERVER,
+ "This connection is removed from "
+ "configuration");
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+}
+
/* This function basically reads the config file again and switches the config
object pointed by the server object. After that, we have to fix various
things such as the server_name and the listening ports.
silc_pkcs_private_key_set(server->pkcs, server->private_key);
}
+ /* Check for unconfigured server and router connections and close
+ connections that were unconfigured. */
+
+ if (server->config->routers) {
+ SilcServerConfigRouter *ptr;
+ SilcServerConfigRouter *newptr;
+ bool found;
+
+ for (ptr = server->config->routers; ptr; ptr = ptr->next) {
+ found = FALSE;
+
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
+ if (!strcmp(newptr->host, ptr->host) && newptr->port == ptr->port &&
+ newptr->initiator == ptr->initiator) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Remove this connection */
+ SilcSocketConnection sock;
+ sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+ ptr->host, ptr->port);
+ if (sock && !SILC_IS_LISTENER(sock))
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+ }
+ }
+
+ if (server->config->servers) {
+ SilcServerConfigServer *ptr;
+ SilcServerConfigServer *newptr;
+ bool found;
+
+ for (ptr = server->config->servers; ptr; ptr = ptr->next) {
+ found = FALSE;
+
+ /* Check whether new config has this one too */
+ for (newptr = newconfig->servers; newptr; newptr = newptr->next) {
+ if (!strcmp(newptr->host, ptr->host)) {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* Remove this connection */
+ SilcSocketConnection sock;
+ sock = silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_SERVER,
+ ptr->host, 0);
+ if (sock && !SILC_IS_LISTENER(sock))
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rehash_close_connection,
+ server, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+ }
+ }
+
/* Go through all configured routers after rehash */
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router,
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,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router_retry,
+ sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
return;
}
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,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router_retry,
+ sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
return;
}
silc_ske_free_key_material(ctx->keymat);
silc_free(ctx->dest_id);
silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
NULL);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router_retry,
+ sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ goto out2;
+ }
+
goto out;
}
silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
-#ifdef BACKUP_SINGLE_ROUTER
/* If we are backup router then this primary router is whom we are
backing up. */
if (server->server_type == SILC_BACKUP_ROUTER)
silc_server_backup_add(server, server->id_entry, sock->ip, 0, TRUE);
-#endif /* BACKUP_SINGLE_ROUTER */
}
} else {
/* Add this server to be our backup router */
if (sconn == server->router_conn)
server->router_conn = NULL;
+ out2:
/* Free the protocol object */
if (sock->protocol == protocol)
sock->protocol = NULL;
server->stat.auth_failures++;
goto out;
}
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
/* Statistics */
server->stat.my_clients++;
SilcServerConfigServer *sconn = ctx->sconfig.ref_ptr;
SilcServerConfigRouter *rconn = ctx->rconfig.ref_ptr;
+ /* If we are backup router and this is incoming server connection
+ and we do not have connection to primary router, do not allow
+ the connection. */
+ if (server->server_type == SILC_BACKUP_ROUTER &&
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER &&
+ !SILC_PRIMARY_ROUTE(server)) {
+ SILC_LOG_INFO(("Will not accept server connection because we do "
+ "not have primary router connection established"));
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_PERM_DENIED,
+ "We do not have connection to primary "
+ "router established, try later");
+ silc_free(sock->user_data);
+ server->stat.auth_failures++;
+ goto out;
+ }
+
if (ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
/* Verify whether this connection is after all allowed to connect */
if (!silc_server_connection_allowed(server, sock, ctx->conn_type,
&server->config->param,
rconn ? rconn->param : NULL,
ctx->ske)) {
+ silc_free(sock->user_data);
server->stat.auth_failures++;
goto out;
}
&server->config->param,
sconn ? sconn->param : NULL,
ctx->ske)) {
+ silc_free(sock->user_data);
server->stat.auth_failures++;
goto out;
}
server->stat.auth_failures++;
goto out;
}
-
- /* Statistics */
- if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
- server->stat.my_servers++;
- } else {
- server->stat.my_routers++;
- server->stat.routers++;
- }
- server->stat.servers++;
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
id_entry = (void *)new_server;
new_server->server_type = SILC_BACKUP_ROUTER;
}
+ /* Statistics */
+ if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
+ server->stat.my_servers++;
+ } else {
+ server->stat.my_routers++;
+ server->stat.routers++;
+ }
+ server->stat.servers++;
+
/* Check whether this connection is to be our primary router connection
if we do not already have the primary route. */
if (!backup_router &&
return;
}
- server->stat.packets_received++;
-
/* Get keys and stuff from ID entry */
idata = (SilcIDListData)sock->user_data;
if (idata) {
SilcIDListData idata = (SilcIDListData)sock->user_data;
int ret;
+ server->stat.packets_received++;
+
/* Parse the packet */
if (parse_ctx->normal)
ret = silc_packet_parse(packet, idata ? idata->receive_key : NULL);
message = silc_memdup(packet->buffer->data + 1,
packet->buffer->len - 1);
- SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s",
- sock->ip, sock->hostname,
- silc_get_status_message(status), status,
- message ? message : ""));
+ SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
+ sock->ip, sock->hostname,
+ silc_get_status_message(status), status,
+ message ? message : ""));
silc_free(message);
}
break;
SILC_TASK_CALLBACK(silc_server_close_connection_final)
{
- silc_socket_free((SilcSocketConnection)context);
+ silc_socket_free(context);
}
/* Closes connection to socket connection */
server->standalone = TRUE;
backup_router = NULL;
} else {
- SILC_LOG_INFO(("New primary router is backup router %s",
- backup_router->server_name));
- SILC_LOG_DEBUG(("New primary router is backup router %s",
- backup_router->server_name));
-#ifdef BACKUP_SINGLE_ROUTER
if (server->id_entry != backup_router) {
-#endif /* BACKUP_SINGLE_ROUTER */
+ SILC_LOG_INFO(("New primary router is backup router %s",
+ backup_router->server_name));
server->id_entry->router = backup_router;
server->router = backup_router;
server->router_connect = time(0);
server->backup_primary = TRUE;
-#ifdef BACKUP_SINGLE_ROUTER
} else {
+ SILC_LOG_INFO(("We are now new router in this cell"));
server->id_entry->router = NULL;
server->router = NULL;
server->standalone = TRUE;
}
-#endif /* BACKUP_SINGLE_ROUTER */
if (server->server_type == SILC_BACKUP_ROUTER) {
server->server_type = SILC_ROUTER;
}
if (!backup_router) {
- /* Free all client entries that this server owns as they will
- become invalid now as well. */
- if (user_data->id)
+ /* As router, remove clients and channels always. As normal server
+ remove only if it is our primary router. Other connections
+ may be backup routers and these normal server don't handle here. */
+ if (server->server_type != SILC_SERVER ||
+ server->standalone || sock == SILC_PRIMARY_ROUTE(server)) {
+ /* Free all client entries that this server owns as they will
+ become invalid now as well. */
silc_server_remove_clients_by_server(server, user_data, TRUE);
- if (server->server_type == SILC_SERVER)
- silc_server_remove_channels_by_server(server, user_data);
+ if (server->server_type == SILC_SERVER)
+ silc_server_remove_channels_by_server(server, user_data);
+ }
} else {
/* Update the client entries of this server to the new backup
router. This also removes the clients that *really* was owned
by the primary router and went down with the router. */
silc_server_update_clients_by_server(server, user_data, backup_router,
TRUE, TRUE);
- silc_server_update_servers_by_server(server, user_data, backup_router);
+ silc_server_update_servers_by_server(server, user_data, backup_router,
+ TRUE);
if (server->server_type == SILC_SERVER)
silc_server_update_channels_by_server(server, user_data,
backup_router);
+
+ /* Send notify about primary router going down to local operators */
+ if (server->backup_router)
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_NONE,
+ ("%s switched to backup router %s "
+ "(we are primary router now)",
+ server->server_name, server->server_name));
+ else
+ SILC_SERVER_SEND_OPERS(server, FALSE, TRUE,
+ SILC_NOTIFY_TYPE_NONE,
+ ("%s switched to backup router %s",
+ server->server_name,
+ server->router->server_name));
}
/* Free the server entry */
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers--;
- if (backup_router) {
+ if (backup_router && backup_router != server->id_entry) {
/* Announce all of our stuff that was created about 5 minutes ago.
The backup router knows all the other stuff already. */
if (server->server_type == SILC_ROUTER)
silc_free(chl);
/* Update statistics */
- if (client->connection)
+ if (SILC_IS_LOCAL(client))
server->stat.my_chanclients--;
if (server->server_type == SILC_ROUTER) {
server->stat.cell_chanclients--;
silc_free(chl);
/* Update statistics */
- if (client->connection)
+ if (SILC_IS_LOCAL(client))
server->stat.my_chanclients--;
if (server->server_type == SILC_ROUTER) {
server->stat.cell_chanclients--;
silc_buffer_pull(*clients, idp->len);
SILC_PUT32_MSB(client->mode, mode);
- tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
- 2, idp->data, idp->len,
- mode, 4);
+ tmp =
+ silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+ 2, idp->data, idp->len,
+ mode, 4);
*umodes = silc_buffer_realloc(*umodes,
(*umodes ?
(*umodes)->truelen + tmp->len :
silc_buffer_free(channels);
}
+ if (channel_users) {
+ silc_buffer_push(channel_users, channel_users->data - channel_users->head);
+ SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
+ channel_users->len);
+
+ /* Send the packet */
+ silc_server_packet_send(server, remote,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel_users->data, channel_users->len,
+ FALSE);
+
+ silc_buffer_free(channel_users);
+ }
+
if (channel_modes) {
int i;
silc_free(channel_modes);
}
- if (channel_users) {
- silc_buffer_push(channel_users, channel_users->data - channel_users->head);
- SILC_LOG_HEXDUMP(("channel users"), channel_users->data,
- channel_users->len);
-
- /* Send the packet */
- silc_server_packet_send(server, remote,
- SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- channel_users->data, channel_users->len,
- FALSE);
-
- silc_buffer_free(channel_users);
- }
-
if (channel_users_modes) {
int i;