/* Backup router */
typedef struct {
SilcServerEntry server;
+ SilcIDIP ip;
+ uint16 port;
bool local;
} SilcServerBackupEntry;
long start;
} *SilcServerBackupProtocolContext;
-/* Sets the `backup_server' to be one of our backup router. This can be
- called multiple times to set multiple backup routers. If `local' is
- TRUE then the `backup_server' is in the local cell, if FALSE it is
- in some other cell. */
+/* Adds the `backup_server' to be one of our backup router. This can be
+ called multiple times to set multiple backup routers. The `ip' and `port'
+ is the IP and port that the `backup_router' will replace if the `ip'
+ will become unresponsive. If `local' is TRUE then the `backup_server' is
+ in the local cell, if FALSE it is in some other cell. */
void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
- bool local)
+ const char *ip, int port, bool local)
{
int i;
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!ip)
+ return;
+
if (!server->backup)
server->backup = silc_calloc(1, sizeof(*server->backup));
if (!server->backup->servers[i].server) {
server->backup->servers[i].server = backup_server;
server->backup->servers[i].local = local;
+ memset(server->backup->servers[i].ip.data, 0,
+ sizeof(server->backup->servers[i].ip.data));
+ silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+ sizeof(server->backup->servers[i].ip.data));
+ //server->backup->servers[i].port = port;
return;
}
}
(i + 1));
server->backup->servers[i].server = backup_server;
server->backup->servers[i].local = local;
+ memset(server->backup->servers[i].ip.data, 0,
+ sizeof(server->backup->servers[i].ip.data));
+ silc_net_addr2bin(ip, server->backup->servers[i].ip.data,
+ sizeof(server->backup->servers[i].ip.data));
+ //server->backup->servers[i].port = server_id->port;
server->backup->servers_count++;
}
-/* Returns the first backup router context. Returns NULL if we do not have
- any backup servers. */
+/* Returns backup router for IP and port in `replacing' or NULL if there
+ does not exist backup router. */
-SilcServerEntry silc_server_backup_get(SilcServer server)
+SilcServerEntry silc_server_backup_get(SilcServer server,
+ SilcServerID *server_id)
{
- SilcServerEntry backup_router;
int i;
+ SILC_LOG_DEBUG(("Start"));
+
if (!server->backup)
return NULL;
for (i = 0; i < server->backup->servers_count; i++) {
- if (server->backup->servers[i].server) {
- backup_router = server->backup->servers[i].server;
- server->backup->servers[i].server = NULL;
- return backup_router;
- }
+ SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, 16);
+ SILC_LOG_HEXDUMP(("IP"), server->backup->servers[i].ip.data, 16);
+ if (server->backup->servers[i].server &&
+ !memcmp(&server->backup->servers[i].ip, &server_id->ip.data,
+ sizeof(server_id->ip.data)))
+ return server->backup->servers[i].server;
}
return NULL;
}
-/* Deletes the backup server `server_entry. */
-
-void silc_server_backup_del(SilcServer server,
- SilcServerEntry server_entry)
+/* Deletes the backup server `server_entry'. */
+void silc_server_backup_del(SilcServer server, SilcServerEntry server_entry)
{
int i;
+ SILC_LOG_DEBUG(("Start"));
+
if (!server->backup)
return ;
int i;
SilcServerBackupReplaced *r = silc_calloc(1, sizeof(*r));;
+ SILC_LOG_DEBUG(("Start"));
+
if (!server->backup)
server->backup = silc_calloc(1, sizeof(*server->backup));
if (!server->backup->replaced) {
{
int i;
- SILC_LOG_DEBUG(("***********************************************"));
+ SILC_LOG_DEBUG(("Start"));
+
+ SILC_LOG_DEBUG(("*************************************"));
if (!server->backup || !server->backup->replaced)
return FALSE;
SILC_LOG_HEXDUMP(("IP"), server_id->ip.data, server_id->ip.data_len);
SILC_LOG_HEXDUMP(("IP"), server->backup->replaced[i]->ip.data,
server->backup->replaced[i]->ip.data_len);
- if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip,
- sizeof(server_id->ip))) {
+ if (!memcmp(&server->backup->replaced[i]->ip, &server_id->ip.data,
+ sizeof(server_id->ip.data))) {
if (server_entry)
*server_entry = server->backup->replaced[i]->server;
SILC_LOG_DEBUG(("REPLACED"));
{
int i;
+ SILC_LOG_DEBUG(("Start"));
+
if (!server->backup || !server->backup->replaced)
return;
silc_packet_send_prepare(sock, 0, 0, buffer->len);
silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
- silc_packet_encrypt(idata->send_key, idata->hmac_send,
+ silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
sock->outbuf, sock->outbuf->len);
SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", sock->outbuf->len),
SilcPacketContext *packet)
{
uint8 type, session;
- int ret;
+ SilcServerBackupProtocolContext ctx;
+ int i, ret;
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
sock->type == SILC_SOCKET_TYPE_UNKNOWN)
if (ret < 0)
return;
+ /* Activate the protocol for this socket if necessary */
+ if ((type == SILC_SERVER_BACKUP_RESUMED ||
+ type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
+ sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
+ ((SilcIDListData)sock->user_data)->status &
+ SILC_IDLIST_STATUS_DISABLED) {
+ SilcServerEntry backup_router;
+
+ if (silc_server_backup_replaced_get(server,
+ ((SilcServerEntry)sock->
+ user_data)->id,
+ &backup_router)) {
+ SilcSocketConnection bsock =
+ (SilcSocketConnection)backup_router->connection;
+ if (bsock->protocol && bsock->protocol->protocol &&
+ bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
+ sock->protocol = bsock->protocol;
+ ctx = sock->protocol->context;
+ ctx->sock = sock;
+ }
+ }
+ }
+
/* If the backup resuming protocol is active then process the packet
in the protocol. */
if (sock->protocol && sock->protocol->protocol &&
sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
- SilcServerBackupProtocolContext ctx = sock->protocol->context;
- int i;
-
+ ctx = sock->protocol->context;
ctx->type = type;
SILC_LOG_DEBUG(("********************************"));
to use it at this moment. */
SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
+ "wait until backup resuming protocol is executed"));
+
SILC_LOG_DEBUG(("We are replaced by an backup router in this cell"));
idata->status |= SILC_IDLIST_STATUS_DISABLED;
return;
sconn->remote_port));
/* Connect to remote host */
- sock = silc_net_create_connection(server->config->listen_port->local_ip,
+ sock = silc_net_create_connection(server->config->server_info->server_ip,
sconn->remote_port,
sconn->remote_host);
if (sock < 0) {
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_connect_to_router,
- context, 2, 0, SILC_TASK_TIMEOUT,
+ context, 5, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
return;
}
sconn->callback_context = context;
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_connect_to_router,
- sconn, 2, 0, SILC_TASK_TIMEOUT,
+ sconn, 1, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
}
(SilcServerBackupProtocolContext)backup_router->protocol->context;
SilcBuffer buffer;
+ SILC_LOG_DEBUG(("Start"));
+
SILC_LOG_DEBUG(("********************************"));
SILC_LOG_DEBUG(("Sending CONNECTED packet, session %d", ctx->session));
backup_router->protocol = NULL;
}
+SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerBackupProtocolContext ctx = protocol->context;
+ SilcServer server = ctx->server;
+ SilcBuffer packet;
+ int i;
+
+ for (i = 0; i < ctx->sessions_count; i++)
+ if (ctx->sessions[i].server_entry == ctx->sock->user_data)
+ ctx->session = ctx->sessions[i].session;
+
+ /* We've received all the CONNECTED packets and now we'll send the
+ ENDING packet to the new primary router. */
+ packet = silc_buffer_alloc(2);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
+ SILC_STR_UI_CHAR(ctx->session),
+ SILC_STR_END);
+ silc_server_packet_send(server, ctx->sock,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+
+ protocol->state = SILC_PROTOCOL_STATE_END;
+}
+
/* Resume protocol with RESUME_ROUTER packet:
SILC_PACKET_RESUME_ROUTER:
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
server_entry = (SilcServerEntry)id_cache->context;
- if ((server_entry == server->id_entry) ||
- !server_entry->connection) {
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key ||
+ (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ ctx->sessions = silc_realloc(ctx->sessions,
+ sizeof(*ctx->sessions) *
+ (ctx->sessions_count + 1));
+ ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
+ ctx->sessions[ctx->sessions_count].connected = FALSE;
+ ctx->sessions[ctx->sessions_count].server_entry = server_entry;
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("START (local) for session %d",
+ ctx->sessions_count));
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_START;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
+ packet->data[1] = ctx->sessions_count;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+ ctx->sessions_count++;
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key ||
+ (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
if (!silc_idcache_list_next(list, &id_cache))
break;
else
ctx->sessions[ctx->sessions_count].server_entry = server_entry;
SILC_LOG_DEBUG(("********************************"));
- SILC_LOG_DEBUG(("START for session %d", ctx->sessions_count));
+ SILC_LOG_DEBUG(("START (global) for session %d",
+ ctx->sessions_count));
/* This connection is performing this protocol too now */
((SilcSocketConnection)server_entry->connection)->protocol =
silc_buffer_free(packet);
- /* If we are router then announce our possible servers. */
- if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server, FALSE, 0, ctx->sock);
+ /* Announce all of our information */
+ silc_server_announce_servers(server, TRUE, 0, ctx->sock);
silc_server_announce_clients(server, 0, ctx->sock);
silc_server_announce_channels(server, 0, ctx->sock);
protocol->state++;
} else {
/* Responder of the protocol. */
- SilcServerConfigSectionServerConnection *primary;
+ SilcServerConfigSectionRouter *primary;
/* We should have received START or START_GLOBAL packet */
if (ctx->type != SILC_SERVER_BACKUP_START &&
to be back online. We send the CONNECTED packet after we've
established the connection to the primary router. */
primary = silc_server_config_get_primary_router(server->config);
- if (primary) {
+ if (primary && server->backup_primary) {
silc_server_backup_reconnect(server,
primary->host, primary->port,
silc_server_backup_connect_primary,
ctx->sock);
- if (server->server_type == SILC_ROUTER &&
- (!server->router ||
- server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
- protocol->state++;
- else
- protocol->state = SILC_PROTOCOL_STATE_END;
-
} else {
/* Nowhere to connect just return the CONNECTED packet */
SILC_PACKET_RESUME_ROUTER, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
- protocol->state++;
}
+ if (server->server_type == SILC_ROUTER &&
+ (!server->router ||
+ server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
+ protocol->state++;
+ else
+ protocol->state = SILC_PROTOCOL_STATE_END;
+
ctx->sessions = silc_realloc(ctx->sessions,
sizeof(*ctx->sessions) *
(ctx->sessions_count + 1));
SILC_LOG_DEBUG(("********************************"));
SILC_LOG_DEBUG(("Sending ENDING packet to primary"));
- for (i = 0; i < ctx->sessions_count; i++)
- if (ctx->sessions[i].server_entry == ctx->sock->user_data)
- ctx->session = ctx->sessions[i].session;
-
- /* We've received all the CONNECTED packets and now we'll send the
- ENDING packet to the new primary router. */
- packet = silc_buffer_alloc(2);
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
- SILC_STR_UI_CHAR(ctx->session),
- SILC_STR_END);
- silc_server_packet_send(server, ctx->sock,
- SILC_PACKET_RESUME_ROUTER, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
-
- protocol->state = SILC_PROTOCOL_STATE_END;
+ /* Send with a timeout */
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_backup_send_resumed,
+ protocol, 1, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
} else {
/* Responder */
break;
}
- /* Switch announced informations to our entry instead of using the
+ /* Switch announced informations to our primary router of using the
backup router. */
+ silc_server_update_servers_by_server(server, ctx->sock->user_data,
+ server->router);
silc_server_update_clients_by_server(server, ctx->sock->user_data,
- server->id_entry, TRUE, FALSE);
+ server->router, TRUE, FALSE);
+ if (server->server_type == SILC_SERVER)
+ silc_server_update_channels_by_server(server, ctx->sock->user_data,
+ server->router);
packet = silc_buffer_alloc(2);
silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
server_entry = (SilcServerEntry)id_cache->context;
- if ((server_entry == server->id_entry) ||
- !server_entry->connection) {
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
+ SILC_LOG_DEBUG(("********************************"));
+ SILC_LOG_DEBUG(("RESUMED packet (local)"));
+
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+ /* This connection is performing this protocol too now */
+ ((SilcSocketConnection)server_entry->connection)->protocol =
+ protocol;
+
+ if (server_entry->server_type == SILC_ROUTER)
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
+ else
+ packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
+ silc_server_packet_send(server, server_entry->connection,
+ SILC_PACKET_RESUME_ROUTER, 0,
+ packet->data, packet->len, FALSE);
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ if (!server_entry || (server_entry == server->id_entry) ||
+ !server_entry->connection || !server_entry->data.send_key) {
if (!silc_idcache_list_next(list, &id_cache))
break;
else
}
SILC_LOG_DEBUG(("********************************"));
- SILC_LOG_DEBUG(("RESUMED packet"));
+ SILC_LOG_DEBUG(("RESUMED packet (global)"));
+
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
/* This connection is performing this protocol too now */
((SilcSocketConnection)server_entry->connection)->protocol =
silc_buffer_free(packet);
+ SILC_LOG_INFO(("We are now the primary router of our cell again"));
+
/* For us this is the end of this protocol. */
if (protocol->final_callback)
silc_protocol_execute_final(protocol, server->schedule);
case SILC_PROTOCOL_STATE_END:
{
SilcIDListData idata;
- SilcServerEntry primary;
- SilcServerEntry backup_router;
+ SilcServerEntry router, backup_router;
/* We should have been received RESUMED packet from our primary
router. */
if (server->backup_router)
server->server_type = SILC_BACKUP_ROUTER;
- primary = (SilcServerEntry)ctx->sock->user_data;
- if (silc_server_backup_replaced_get(server, primary->id,
+ router = (SilcServerEntry)ctx->sock->user_data;
+ if (silc_server_backup_replaced_get(server, router->id,
&backup_router)) {
if (backup_router == server->router) {
- server->id_entry->router = ctx->sock->user_data;
- server->router = ctx->sock->user_data;
+ server->id_entry->router = router;
+ server->router = router;
SILC_LOG_INFO(("Switching back to primary router %s",
server->router->server_name));
- SILC_LOG_DEBUG(("********************************"));
SILC_LOG_DEBUG(("Switching back to primary router %s",
server->router->server_name));
idata = (SilcIDListData)server->router;
idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
-
- /* Update the client entries of the backup router to the new
- primary router. */
- silc_server_update_clients_by_server(server, backup_router,
- primary, TRUE, FALSE);
- silc_server_backup_replaced_del(server, backup_router);
- silc_server_backup_add(server, backup_router,
- backup_router->server_type != SILC_ROUTER ?
- TRUE : FALSE);
+ } else {
+ SILC_LOG_INFO(("Resuming the use of router %s",
+ router->server_name));
+ SILC_LOG_DEBUG(("Resuming the use of router %s",
+ router->server_name));
+ idata = (SilcIDListData)router;
+ idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
}
- /* Announce all of our information to the new primary router. We
- announce all that was updated after the protocol was started since
- the router knows all the older stuff. */
+ /* Update the client entries of the backup router to the new
+ router */
+ silc_server_update_servers_by_server(server, backup_router, router);
+ silc_server_update_clients_by_server(server, backup_router,
+ router, TRUE, FALSE);
+ if (server->server_type == SILC_SERVER)
+ silc_server_update_channels_by_server(server, backup_router, router);
+ silc_server_backup_replaced_del(server, backup_router);
+ silc_server_backup_add(server, backup_router,
+ ctx->sock->ip, ctx->sock->port,
+ backup_router->server_type != SILC_ROUTER ?
+ TRUE : FALSE);
+
+ /* Announce all of our information to the router. */
if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server, FALSE, 0,
- server->router->connection);
-
- /* Announce our clients and channels to the router */
- silc_server_announce_clients(server, 0,
- server->router->connection);
- silc_server_announce_channels(server, 0,
- server->router->connection);
-#if 0
- if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server, FALSE, ctx->start - 60,
- server->router->connection);
-
+ silc_server_announce_servers(server, FALSE, 0, router->connection);
+
/* Announce our clients and channels to the router */
- silc_server_announce_clients(server, ctx->start - 60,
- server->router->connection);
- silc_server_announce_channels(server, ctx->start - 60,
- server->router->connection);
-#endif
+ silc_server_announce_clients(server, 0, router->connection);
+ silc_server_announce_channels(server, 0, router->connection);
}
/* Protocol has ended, call the final callback */
SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
}
+ /* Remove this protocol from all server entries that has it */
if (silc_idcache_get_all(server->local_list->servers, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
server_entry = (SilcServerEntry)id_cache->context;
sock = (SilcSocketConnection)server_entry->connection;
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP)
+ if (sock->protocol == protocol) {
sock->protocol = NULL;
+
+ if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ }
+ }
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(server->global_list->servers, &list)) {
+ if (silc_idcache_list_first(list, &id_cache)) {
+ while (id_cache) {
+ server_entry = (SilcServerEntry)id_cache->context;
+ sock = (SilcSocketConnection)server_entry->connection;
+
+ if (sock->protocol == protocol) {
+ sock->protocol = NULL;
+
+ if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+ server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+ }
if (!silc_idcache_list_next(list, &id_cache))
break;