SilcSimContext *sim;
#endif
- if (server->local_list)
- silc_free(server->local_list);
- if (server->global_list)
- silc_free(server->global_list);
+ silc_free(server->local_list);
+ silc_free(server->global_list);
if (server->rng)
silc_rng_free(server->rng);
+ if (server->pkcs)
+ silc_pkcs_free(server->pkcs);
+
#ifdef SILC_SIM
while ((sim = silc_dlist_get(server->sim)) != SILC_LIST_END) {
silc_dlist_del(server->sim, sim);
silc_dlist_uninit(server->sim);
#endif
- if (server->params)
- silc_free(server->params);
+ silc_free(server->params);
if (server->pending_commands)
silc_dlist_uninit(server->pending_commands);
SilcServerID *id;
SilcServerEntry id_entry;
SilcIDListPurge purge;
+ SilcServerConfigSectionListenPort *listen;
SILC_LOG_DEBUG(("Initializing server"));
assert(server);
/* Initialize none cipher */
silc_cipher_alloc("none", &server->none_cipher);
- /* Create a listening server. Note that our server can listen on
- multiple ports. All listeners are created here and now. */
- /* XXX Still check this whether to use server_info or listen_port. */
+ /* Allocate PKCS context for local public and private keys */
+ silc_pkcs_alloc(server->public_key->name, &server->pkcs);
+ silc_pkcs_public_key_set(server->pkcs, server->public_key);
+ silc_pkcs_private_key_set(server->pkcs, server->private_key);
+
+ /* Create a listening server. Note that our server can listen on multiple
+ ports. All listeners are created here and now. */
sock_count = 0;
- while(server->config->listen_port) {
+ listen = server->config->listen_port;
+ while(listen) {
int tmp;
tmp = silc_net_create_server(server->config->listen_port->port,
- server->config->listen_port->host);
+ server->config->listen_port->listener_ip);
if (tmp < 0)
goto err0;
sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
sock[sock_count] = tmp;
- server->config->listen_port = server->config->listen_port->next;
sock_count++;
+ listen = listen->next;
}
/* Initialize ID caches */
SILC_LOG_ERROR(("Could not add ourselves to cache"));
goto err0;
}
+ id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
/* Add ourselves also to the socket table. The entry allocated above
is sent as argument for fast referencing in the future. */
/* Register protocols */
silc_server_protocols_register();
- /* Initialize the scheduler. This will register the task queues as well.
- In SILC we have by default three task queues. One task queue for
- non-timeout tasks which perform different kind of I/O on file
- descriptors, timeout task queue for timeout tasks, and, generic
- non-timeout task queue whose tasks apply to all connections. */
- server->schedule = silc_schedule_init(&server->io_queue,
- &server->timeout_queue,
- &server->generic_queue,
- SILC_SERVER_MAX_CONNECTIONS);
+ /* Initialize the scheduler. */
+ server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
if (!server->schedule)
goto err0;
- /* Add the first task to the queue. This is task that is executed by
+ /* Add the first task to the scheduler. This is task that is executed by
timeout. It expires as soon as the caller calls silc_server_run. This
task performs authentication protocol and key exchange with our
primary router. */
- silc_task_register(server->timeout_queue, sock[0],
- silc_server_connect_to_router,
- (void *)server, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, sock[0],
+ silc_server_connect_to_router,
+ (void *)server, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
- /* Add listener task to the queue. This task receives new connections to the
- server. This task remains on the queue until the end of the program. */
- silc_task_register(server->io_queue, sock[0],
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
+ /* Add listener task to the scheduler. This task receives new connections
+ to the server. This task remains on the queue until the end of the
+ program. */
+ silc_schedule_task_add(server->schedule, sock[0],
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
server->listenning = TRUE;
/* If server connections has been configured then we must be router as
normal server cannot have server connections, only router connections. */
- if (server->config->servers)
+ if (server->config->servers) {
+ SilcServerConfigSectionServerConnection *ptr = server->config->servers;
+
server->server_type = SILC_ROUTER;
+ while (ptr) {
+ if (ptr->backup_router) {
+ server->server_type = SILC_BACKUP_ROUTER;
+ server->backup_router = TRUE;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ }
/* Register the ID Cache purge task. This periodically purges the ID cache
and removes the expired cache entries. */
/* Clients local list */
purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->local_list->clients;
- purge->timeout_queue = server->timeout_queue;
- silc_task_register(purge->timeout_queue, 0,
- silc_idlist_purge,
- (void *)purge, 600, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ purge->schedule = server->schedule;
+ silc_schedule_task_add(purge->schedule, 0,
+ silc_idlist_purge,
+ (void *)purge, 600, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Clients global list */
purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->global_list->clients;
- purge->timeout_queue = server->timeout_queue;
- silc_task_register(purge->timeout_queue, 0,
- silc_idlist_purge,
- (void *)purge, 300, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ purge->schedule = server->schedule;
+ silc_schedule_task_add(purge->schedule, 0,
+ silc_idlist_purge,
+ (void *)purge, 300, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
SILC_LOG_DEBUG(("Server initialized"));
}
}
-/* Stops the SILC server. This function is used to shutdown the server.
- This is usually called after the scheduler has returned. After stopping
- the server one should call silc_server_free. */
-
-void silc_server_stop(SilcServer server)
-{
- SILC_LOG_DEBUG(("Stopping server"));
-
- /* Stop the scheduler, although it might be already stopped. This
- doesn't hurt anyone. This removes all the tasks and task queues,
- as well. */
- silc_schedule_stop(server->schedule);
- silc_schedule_uninit(server->schedule);
-
- silc_server_protocols_unregister();
-
- SILC_LOG_DEBUG(("Server stopped"));
-}
-
/* The heart of the server. This runs the scheduler thus runs the server.
When this returns the server has been stopped and the program will
be terminated. */
silc_schedule(server->schedule);
}
-/* Timeout callback that will be called to retry connecting to remote
- router. This is used by both normal and router server. This will wait
- before retrying the connecting. The timeout is generated by exponential
- backoff algorithm. */
+/* Stops the SILC server. This function is used to shutdown the server.
+ This is usually called after the scheduler has returned. After stopping
+ the server one should call silc_server_free. */
-SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
+void silc_server_stop(SilcServer server)
{
- SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServer server = sconn->server;
-
- SILC_LOG_INFO(("Retrying connecting to a router"));
+ SILC_LOG_DEBUG(("Stopping server"));
- /* Calculate next timeout */
- if (sconn->retry_count >= 1) {
- sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
- if (sconn->retry_timeout > SILC_SERVER_RETRY_INTERVAL_MAX)
- sconn->retry_timeout = SILC_SERVER_RETRY_INTERVAL_MAX;
- } else {
- sconn->retry_timeout = server->params->retry_interval_min;
- }
- sconn->retry_count++;
- sconn->retry_timeout = sconn->retry_timeout +
- silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
+ silc_schedule_stop(server->schedule);
+ silc_schedule_uninit(server->schedule);
- /* If we've reached max retry count, give up. */
- if (sconn->retry_count > server->params->retry_count &&
- server->params->retry_keep_trying == FALSE) {
- SILC_LOG_ERROR(("Could not connect to router, giving up"));
- return;
- }
+ silc_server_protocols_unregister();
- /* Wait one before retrying */
- silc_task_register(server->timeout_queue, fd, silc_server_connect_router,
- context, sconn->retry_timeout,
- server->params->retry_interval_min_usec,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ SILC_LOG_DEBUG(("Server stopped"));
}
-/* Generic routine to use connect to a router. */
+/* Function that is called when the network connection to a router has
+ been established. This will continue with the key exchange protocol
+ with the remote router. */
-SILC_TASK_CALLBACK(silc_server_connect_router)
-{
- SilcServerConnection sconn = (SilcServerConnection)context;
- SilcServer server = sconn->server;
+void silc_server_start_key_exchange(SilcServer server,
+ SilcServerConnection sconn,
+ int sock)
+{
SilcSocketConnection newsocket;
SilcProtocol protocol;
SilcServerKEInternalContext *proto_ctx;
- int sock;
-
- SILC_LOG_INFO(("Connecting to the router %s on port %d",
- sconn->remote_host, sconn->remote_port));
-
- /* Connect to remote host */
- sock = silc_net_create_connection(sconn->remote_port,
- sconn->remote_host);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not connect to router"));
- silc_task_register(server->timeout_queue, fd,
- silc_server_connect_to_router_retry,
- context, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- return;
- }
+ void *context;
/* Set socket options */
silc_net_set_socket_nonblock(sock);
/* Register a timeout task that will be executed if the protocol
is not executed within set limit. */
proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock,
+ silc_schedule_task_add(server->schedule, sock,
silc_server_timeout_remote,
server, server->params->protocol_timeout,
server->params->protocol_timeout_usec,
SILC_REGISTER_CONNECTION_FOR_IO(sock);
/* Run the protocol */
- silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(protocol, server->schedule, 0, 0);
+}
+
+/* Timeout callback that will be called to retry connecting to remote
+ router. This is used by both normal and router server. This will wait
+ before retrying the connecting. The timeout is generated by exponential
+ backoff algorithm. */
+
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+
+ SILC_LOG_INFO(("Retrying connecting to a router"));
+
+ /* Calculate next timeout */
+ if (sconn->retry_count >= 1) {
+ sconn->retry_timeout = sconn->retry_timeout * SILC_SERVER_RETRY_MULTIPLIER;
+ if (sconn->retry_timeout > SILC_SERVER_RETRY_INTERVAL_MAX)
+ sconn->retry_timeout = SILC_SERVER_RETRY_INTERVAL_MAX;
+ } else {
+ sconn->retry_timeout = server->params->retry_interval_min;
+ }
+ sconn->retry_count++;
+ sconn->retry_timeout = sconn->retry_timeout +
+ silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
+
+ /* If we've reached max retry count, give up. */
+ if (sconn->retry_count > server->params->retry_count &&
+ server->params->retry_keep_trying == FALSE) {
+ SILC_LOG_ERROR(("Could not connect to router, giving up"));
+ return;
+ }
+
+ /* Wait one before retrying */
+ silc_schedule_task_add(server->schedule, fd, silc_server_connect_router,
+ context, sconn->retry_timeout,
+ server->params->retry_interval_min_usec,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
+
+/* Generic routine to use connect to a router. */
+
+SILC_TASK_CALLBACK(silc_server_connect_router)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+ int sock;
+
+ SILC_LOG_INFO(("Connecting to the %s %s on port %d",
+ (sconn->backup ? "backup router" : "router"),
+ sconn->remote_host, sconn->remote_port));
+
+ server->router_connect = time(0);
+
+ /* Connect to remote host */
+ sock = silc_net_create_connection(server->config->listen_port->local_ip,
+ sconn->remote_port,
+ sconn->remote_host);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not connect to router"));
+ silc_schedule_task_add(server->schedule, fd,
+ silc_server_connect_to_router_retry,
+ context, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ return;
+ }
+
+ /* Continue with key exchange protocol */
+ silc_server_start_key_exchange(server, sconn, sock);
}
/* This function connects to our primary router or if we are a router this
{
SilcServer server = (SilcServer)context;
SilcServerConnection sconn;
+ SilcServerConfigSectionServerConnection *ptr;
SILC_LOG_DEBUG(("Connecting to router(s)"));
- /* If we are normal SILC server we need to connect to our cell's
- router. */
if (server->server_type == SILC_SERVER) {
SILC_LOG_DEBUG(("We are normal server"));
+ } else if (server->server_type == SILC_ROUTER) {
+ SILC_LOG_DEBUG(("We are router"));
+ } else {
+ SILC_LOG_DEBUG(("We are backup router/normal server"));
+ }
- /* Create connection to the router, if configured. */
- if (server->config->routers) {
+ /* Create the connections to all our routes */
+ ptr = server->config->routers;
+ while (ptr) {
+
+ SILC_LOG_DEBUG(("%s connection [%s] %s:%d",
+ ptr->backup_router ? "Backup router" : "Router",
+ ptr->initiator ? "Initiator" : "Responder",
+ ptr->host, ptr->port));
+ if (ptr->initiator) {
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
sconn->server = server;
- sconn->remote_host = strdup(server->config->routers->host);
- sconn->remote_port = server->config->routers->port;
-
- silc_task_register(server->timeout_queue, fd,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- return;
+ sconn->remote_host = strdup(ptr->host);
+ sconn->remote_port = ptr->port;
+ sconn->backup = ptr->backup_router;
+
+ silc_schedule_task_add(server->schedule, fd,
+ silc_server_connect_router,
+ (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
- }
-
- /* If we are a SILC router we need to establish all of our primary
- routes. */
- if (server->server_type == SILC_ROUTER) {
- SilcServerConfigSectionServerConnection *ptr;
-
- SILC_LOG_DEBUG(("We are router"));
-
- /* Create the connections to all our routes */
- ptr = server->config->routers;
- while (ptr) {
- SILC_LOG_DEBUG(("Router connection [%s] %s:%d",
- ptr->initiator ? "Initiator" : "Responder",
- ptr->host, ptr->port));
-
- if (ptr->initiator) {
- /* Allocate connection object for hold connection specific stuff. */
- sconn = silc_calloc(1, sizeof(*sconn));
- sconn->server = server;
- sconn->remote_host = strdup(ptr->host);
- sconn->remote_port = ptr->port;
-
- silc_task_register(server->timeout_queue, fd,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
- }
-
- if (!ptr->next)
- return;
-
- ptr = ptr->next;
- }
+ if (!ptr->next)
+ return;
+
+ ptr = ptr->next;
}
SILC_LOG_DEBUG(("No router(s), server will be standalone"));
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
return;
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
return;
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
return;
this timelimit the connection will be terminated. Currently
this is 15 seconds and is hard coded limit (XXX). */
proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_timeout_remote,
(void *)server, 15, 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_LOW);
/* Run the protocol */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
}
/* Finalizes the connection to router. Registers a server task to the
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
goto out;
/* Add a task to the queue. This task receives new connections to the
server. This task remains on the queue until the end of the program. */
- if (!server->listenning) {
- silc_task_register(server->io_queue, server->sock,
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
+ if (!server->listenning && !sconn->backup) {
+ silc_schedule_task_add(server->schedule, server->sock,
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
server->listenning = TRUE;
}
silc_buffer_free(packet);
silc_free(id_string);
- SILC_LOG_DEBUG(("Connected to router %s", sock->hostname));
+ SILC_LOG_INFO(("Connected to router %s", sock->hostname));
/* Add the connected router to local server list */
- server->standalone = FALSE;
id_entry = silc_idlist_add_server(server->local_list, strdup(sock->hostname),
SILC_ROUTER, ctx->dest_id, NULL, sock);
if (!id_entry) {
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
goto out;
silc_free(sock->user_data);
sock->user_data = (void *)id_entry;
sock->type = SILC_SOCKET_TYPE_ROUTER;
- server->id_entry->router = id_entry;
- server->router = id_entry;
idata = (SilcIDListData)sock->user_data;
- idata->registered = TRUE;
+ idata->status |= SILC_IDLIST_STATUS_REGISTERED;
/* Perform keepalive. The `hb_context' will be freed automatically
when finally calling the silc_socket_free function. XXX hardcoded
hb_context->server = server;
silc_socket_set_heartbeat(sock, 600, hb_context,
silc_server_perform_heartbeat,
- server->timeout_queue);
+ server->schedule);
/* Register re-key timeout */
idata->rekey->timeout = 3600; /* XXX hardcoded */
idata->rekey->context = (void *)server;
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_rekey_callback,
- (void *)sock, idata->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rekey_callback,
+ (void *)sock, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- /* If we are router then announce our possible servers. */
- if (server->server_type == SILC_ROUTER)
- silc_server_announce_servers(server);
+ if (!sconn->backup) {
+ /* Mark this router our primary router if we're still standalone */
+ if (server->standalone) {
+ server->id_entry->router = id_entry;
+ server->router = id_entry;
+ server->standalone = FALSE;
+
+ /* If we are router then announce our possible servers. */
+ 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);
+ }
+ } else {
+ /* Add this server to be our backup router */
+ silc_server_backup_add(server, id_entry, FALSE);
+ }
- /* Announce our clients and channels to the router */
- silc_server_announce_clients(server);
- silc_server_announce_channels(server);
+ sock->protocol = NULL;
+
+ /* Call the completion callback to indicate that we've connected to
+ the router */
+ if (sconn->callback)
+ (*sconn->callback)(server, id_entry, sconn->callback_context);
out:
/* Free the temporary connection data context */
}
/* Free the protocol object */
+ if (sock->protocol == protocol)
+ sock->protocol = NULL;
silc_protocol_free(protocol);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
silc_free(ctx);
- sock->protocol = NULL;
}
/* Host lookup callbcak that is called after the incoming connection's
now, this is a hard coded limit. After 60 secs the connection will
be closed if the key exchange protocol has not been started. */
proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_timeout_remote,
- context, 60, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_timeout_remote,
+ context, 60, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
}
/* Accepts new connections to the server. Accepting new connections are
is accepted further. */
silc_socket_host_lookup(newsocket, TRUE,
silc_server_accept_new_connection_lookup, context,
- server->timeout_queue);
+ server->schedule);
}
/* Second part of accepting new connection. Key exchange protocol has been
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
server->stat.auth_failures++;
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
server->stat.auth_failures++;
this timelimit the connection will be terminated. Currently
this is 60 seconds and is hard coded limit (XXX). */
proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_timeout_remote,
- (void *)server, 60, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_timeout_remote,
+ (void *)server, 60, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
}
/* Final part of accepting new connection. The connection has now
SilcServer server = (SilcServer)ctx->server;
SilcSocketConnection sock = ctx->sock;
SilcServerHBContext hb_context;
+ SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
void *id_entry = NULL;
SILC_LOG_DEBUG(("Start"));
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
if (sock)
sock->protocol = NULL;
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
server->stat.auth_failures++;
return;
}
- switch(ctx->conn_type) {
+ entry->data.last_receive = time(NULL);
+
+ switch (ctx->conn_type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry client;
SILC_LOG_DEBUG(("Remote host is %s",
ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- "server" : "router"));
+ "server" : (conn->backup_router ?
+ "backup router" : "router")));
SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
- "server" : "router"));
+ "server" : (conn->backup_router ?
+ "backup router" : "router")));
/* Add the server into server cache. The server name and Server ID
is updated after we have received NEW_SERVER packet from the
id_entry = (void *)new_server;
+ /* 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 && conn->backup_router) {
+ silc_server_backup_add(server, new_server, conn->backup_local);
+
+ /* Change it back to SERVER type since that's what it really is. */
+ if (conn->backup_local) {
+ ctx->conn_type = SILC_SOCKET_TYPE_SERVER;
+ new_server->server_type = SILC_BACKUP_ROUTER;
+ }
+ }
+
+#if 0
+ /* If the incoming connection is normal server and marked as backup
+ server then it will use us as backup router. We'll disable the
+ connection until it is allowed to be used. */
+ if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER && conn->backup_router)
+ SILC_SET_DISABLED(sock);
+#endif
+
/* Check whether this connection is to be our primary router connection
- if we dont' already have the primary route. */
+ if we do not already have the primary route. */
if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
if (silc_server_config_is_primary_route(server->config) &&
!conn->initiator)
hb_context->server = server;
silc_socket_set_heartbeat(sock, 600, hb_context,
silc_server_perform_heartbeat,
- server->timeout_queue);
+ server->schedule);
out:
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_failure_callback);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_failure_callback);
silc_protocol_free(protocol);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
+ silc_free(ctx->dest_id);
silc_free(ctx);
sock->protocol = NULL;
}
SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
SILC_SET_DISCONNECTING(sock);
- /* If the closed connection was our primary router connection the
- start re-connecting phase. */
- if (!server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER &&
- sock == server->router->connection)
- silc_task_register(server->timeout_queue, 0,
- silc_server_connect_to_router,
- context, 1, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
-
if (sock->user_data)
silc_server_free_sock_user_data(server, sock);
silc_server_close_connection(server, sock);
/* Get keys and stuff from ID entry */
idata = (SilcIDListData)sock->user_data;
if (idata) {
- idata->last_receive = time(NULL);
cipher = idata->receive_key;
hmac = idata->hmac_receive;
}
ret = silc_packet_parse_special(packet);
}
+ /* If entry is disabled ignore what we got. */
+ if (ret != SILC_PACKET_RESUME_ROUTER &&
+ idata && idata->status & SILC_IDLIST_STATUS_DISABLED)
+ goto out;
+
if (ret == SILC_PACKET_NONE)
goto out;
if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
packet->flags & SILC_PACKET_FLAG_BROADCAST &&
!server->standalone) {
+ /* Broadcast to our primary route */
silc_server_packet_broadcast(server, server->router->connection, packet);
+
+ /* If we have backup routers then we need to feed all broadcast
+ data to those servers. */
+ silc_server_backup_broadcast(server, sock, packet);
}
}
out:
- /* silc_buffer_clear(sock->inbuf); */
silc_packet_context_free(packet);
silc_free(parse_ctx);
}
case SILC_SOCKET_TYPE_UNKNOWN:
case SILC_SOCKET_TYPE_CLIENT:
/* Parse the packet with timeout */
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 100000,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_packet_parse_real,
+ (void *)parser_context, 0, 100000,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
break;
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
/* Packets from servers are parsed as soon as possible */
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_packet_parse_real,
- (void *)parser_context, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_packet_parse_real,
+ (void *)parser_context, 0, 1,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
break;
default:
return;
SilcPacketContext *packet)
{
SilcPacketType type = packet->type;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
SILC_LOG_DEBUG(("Parsing packet type %d", type));
/* Parse the packet type */
- switch(type) {
+ switch (type) {
case SILC_PACKET_DISCONNECT:
SILC_LOG_DEBUG(("Disconnect packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
if (sock->protocol)
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
break;
case SILC_PACKET_FAILURE:
f->sock = sock;
/* We will wait 5 seconds to process this failure packet */
- silc_task_register(server->timeout_queue, sock->sock,
+ silc_schedule_task_add(server->schedule, sock->sock,
silc_server_failure_callback, (void *)f, 5, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
SILC_LOG_DEBUG(("Channel Message packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
+ idata->last_receive = time(NULL);
silc_server_channel_message(server, sock, packet);
break;
SILC_LOG_DEBUG(("Private Message packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
+ idata->last_receive = time(NULL);
silc_server_private_message(server, sock, packet);
break;
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 100000);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
} else {
SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
"protocol active, packet dropped."));
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
} else {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
break;
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue,
+ silc_protocol_execute(sock->protocol, server->schedule,
0, 100000);
}
} else {
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
} else {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
break;
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue,
+ silc_protocol_execute(sock->protocol, server->schedule,
0, 100000);
}
} else {
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
} else {
SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
"protocol active, packet dropped."));
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
} else {
SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
"protocol active, packet dropped."));
}
break;
+ case SILC_PACKET_FTP:
+ /* Ignored */
+ break;
+
+ case SILC_PACKET_RESUME_ROUTER:
+ /* Resume router packet received. This packet is received for backup
+ router resuming protocol. */
+ SILC_LOG_DEBUG(("Resume router packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_backup_resume_router(server, sock, packet);
+ break;
+
default:
SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
break;
sconn->remote_host = strdup(remote_host);
sconn->remote_port = port;
- silc_task_register(server->timeout_queue, 0,
- silc_server_connect_router,
- (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_router,
+ (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
SILC_TASK_CALLBACK(silc_server_close_connection_final)
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
- SILC_LOG_INFO(("Closing connection %s:%d [%s] (%d)", 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"), sock->sock));
-
- /* If any protocol is active cancel its execution */
- if (sock->protocol) {
- silc_protocol_cancel(sock->protocol, server->timeout_queue);
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute_final(sock->protocol, server->timeout_queue);
- sock->protocol = NULL;
- }
+ SILC_LOG_INFO(("Closing connection %s:%d [%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")));
/* We won't listen for this connection anymore */
silc_schedule_unset_listen_fd(server->schedule, sock->sock);
/* Unregister all tasks */
- silc_task_unregister_by_fd(server->io_queue, sock->sock);
- silc_task_unregister_by_fd(server->timeout_queue, sock->sock);
+ silc_schedule_task_del_by_fd(server->schedule, sock->sock);
/* Close the actual connection */
silc_net_close_connection(sock->sock);
server->sockets[sock->sock] = NULL;
- silc_task_register(server->timeout_queue, 0,
- silc_server_close_connection_final,
- (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ /* If sock->user_data is NULL then we'll check for active protocols
+ here since the silc_server_free_sock_user_data has not been called
+ for this connection. */
+ if (!sock->user_data) {
+ /* If any protocol is active cancel its execution. It will call
+ the final callback which will finalize the disconnection. */
+ if (sock->protocol) {
+ silc_protocol_cancel(sock->protocol, server->schedule);
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, server->schedule);
+ sock->protocol = NULL;
+ return;
+ }
+ }
+
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_close_connection_final,
+ (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Sends disconnect message to remote connection and disconnects the
SILC_LOG_DEBUG(("Disconnecting remote host"));
- SILC_LOG_INFO(("Disconnecting %s:%d [%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")));
-
/* Notify remote end that the conversation is over. The notify message
is tried to be sent immediately. */
silc_server_packet_send(server, sock, SILC_PACKET_DISCONNECT, 0,
/* If there is pending outgoing data for the client then purge it
to the network before removing the client entry. */
- if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
- (SILC_IS_DISCONNECTED(sock) == FALSE)) {
- server->stat.packets_sent++;
-
- if (sock->outbuf->data - sock->outbuf->head)
- silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
-
- silc_packet_send(sock, TRUE);
-
- SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
- SILC_UNSET_OUTBUF_PENDING(sock);
- silc_buffer_clear(sock->outbuf);
- }
+ silc_server_packet_queue_purge(server, sock);
/* Send SIGNOFF notify to routers. */
if (notify && !server->standalone && server->router)
into history (for WHOWAS command) for 5 minutes */
i->server = server;
i->client = client;
- silc_task_register(server->timeout_queue, 0,
- silc_server_free_client_data_timeout,
- (void *)i, 300, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
- client->data.registered = FALSE;
+ 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->router = NULL;
+ client->connection = NULL;
/* Free the client entry and everything in it */
server->stat.my_clients--;
{
SILC_LOG_DEBUG(("Start"));
- switch(sock->type) {
+ switch (sock->type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
case SILC_SOCKET_TYPE_ROUTER:
{
SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
-
- /* Free all client entries that this server owns as they will
- become invalid now as well. */
- if (user_data->id)
- silc_server_remove_clients_by_server(server, user_data, TRUE);
+ SilcServerEntry backup_router = NULL;
/* If this was our primary router connection then we're lost to
the outside world. */
if (server->router == user_data) {
- server->id_entry->router = NULL;
- server->router = NULL;
- server->standalone = TRUE;
+ backup_router = silc_server_backup_get(server);
+
+ /* Check whether we have a backup router connection */
+ if (!backup_router || backup_router == user_data) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router,
+ server, 1, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
+ server->id_entry->router = NULL;
+ server->router = NULL;
+ 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));
+ server->id_entry->router = backup_router;
+ server->router = backup_router;
+ server->router_connect = time(0);
+ if (server->server_type == SILC_BACKUP_ROUTER) {
+ server->server_type = SILC_ROUTER;
+
+ /* We'll need to constantly try to reconnect to the primary
+ router so that we'll see when it comes back online. */
+ silc_server_backup_reconnect(server, sock->ip, sock->port,
+ silc_server_backup_connected,
+ NULL);
+ }
+
+ /* Mark this connection as replaced */
+ silc_server_backup_replaced_add(server, user_data->id,
+ backup_router);
+ }
+ }
+
+ if (!backup_router) {
+ /* Free all client entries that this server owns as they will
+ become invalid now as well. */
+ if (user_data->id)
+ silc_server_remove_clients_by_server(server, user_data, TRUE);
+ } 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);
}
/* Free the server entry */
+ silc_server_backup_del(server, user_data);
+ silc_server_backup_replaced_del(server, user_data);
silc_idlist_del_data(user_data);
silc_idlist_del_server(server->local_list, user_data);
server->stat.my_servers--;
server->stat.servers--;
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers--;
+
+ if (backup_router) {
+ /* 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_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, time(0) - 300,
+ server->router->connection);
+
+ /* Announce our clients and channels to the router */
+ silc_server_announce_clients(server, time(0) - 300,
+ server->router->connection);
+ silc_server_announce_channels(server, time(0) - 300,
+ server->router->connection);
+#endif
+ }
break;
}
default:
}
}
- sock->user_data = NULL;
-}
-
-/* This function is used to remove all client entries by the server `entry'.
- This is called when the connection is lost to the server. In this case
- we must invalidate all the client entries owned by the server `entry'.
- If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
- distributed to our local clients. */
-
-int silc_server_remove_clients_by_server(SilcServer server,
- SilcServerEntry entry,
- int server_signoff)
-{
- SilcIDCacheList list = NULL;
- SilcIDCacheEntry id_cache = NULL;
- SilcClientEntry client = NULL;
- SilcBuffer idp;
- SilcClientEntry *clients = NULL;
- uint32 clients_c = 0;
- unsigned char **argv = NULL;
- uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
- SilcHashTable channels;
- SilcChannelClientEntry chl;
- SilcChannelEntry channel;
- SilcHashTableList htl;
- int i;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Allocate the hash table that holds the channels that require
- channel key re-generation after we've removed this server's clients
- from the channels. */
- channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
- NULL, NULL, TRUE);
-
- if (server_signoff) {
- idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
- argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
- argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
- argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
- argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
- memcpy(argv[argc], idp->data, idp->len);
- argv_lens[argc] = idp->len;
- argv_types[argc] = argc + 1;
- argc++;
- silc_buffer_free(idp);
- }
-
- if (silc_idcache_get_all(server->local_list->clients, &list)) {
-
- if (silc_idcache_list_first(list, &id_cache)) {
- while (id_cache) {
- client = (SilcClientEntry)id_cache->context;
- if (client->data.registered == FALSE) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (client->router != entry) {
- if (server_signoff && client->connection) {
- clients = silc_realloc(clients,
- sizeof(*clients) * (clients_c + 1));
- clients[clients_c] = client;
- clients_c++;
- }
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (server_signoff) {
- idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
- argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
- (argc + 1));
- argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
- (argc + 1));
- argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
- memcpy(argv[argc], idp->data, idp->len);
- argv_lens[argc] = idp->len;
- argv_types[argc] = argc + 1;
- argc++;
- silc_buffer_free(idp);
- }
-
- silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- if (silc_hash_table_find(channels, chl->channel, NULL, NULL))
- continue;
- silc_hash_table_add(channels, chl->channel, chl->channel);
- }
-
- /* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client, FALSE,
- NULL, FALSE);
- silc_idlist_del_client(server->local_list, client);
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- }
- }
- silc_idcache_list_free(list);
- }
-
- if (silc_idcache_get_all(server->global_list->clients, &list)) {
-
- if (silc_idcache_list_first(list, &id_cache)) {
- while (id_cache) {
- client = (SilcClientEntry)id_cache->context;
- if (client->data.registered == FALSE) {
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (client->router != entry) {
- if (server_signoff && client->connection) {
- clients = silc_realloc(clients,
- sizeof(*clients) * (clients_c + 1));
- clients[clients_c] = client;
- clients_c++;
- }
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- else
- continue;
- }
-
- if (server_signoff) {
- idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
- argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
- (argc + 1));
- argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
- (argc + 1));
- argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
- memcpy(argv[argc], idp->data, idp->len);
- argv_lens[argc] = idp->len;
- argv_types[argc] = argc + 1;
- argc++;
- silc_buffer_free(idp);
- }
-
- silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- if (silc_hash_table_find(channels, chl->channel, NULL, NULL))
- continue;
- silc_hash_table_add(channels, chl->channel, chl->channel);
- }
-
- /* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client, FALSE,
- NULL, FALSE);
- silc_idlist_del_client(server->global_list, client);
-
- if (!silc_idcache_list_next(list, &id_cache))
- break;
- }
- }
- silc_idcache_list_free(list);
- }
-
- /* Send the SERVER_SIGNOFF notify */
- if (server_signoff) {
- SilcBuffer args;
-
- /* Send SERVER_SIGNOFF notify to our primary router */
- if (!server->standalone && server->router &&
- server->router != entry) {
- args = silc_argument_payload_encode(1, argv, argv_lens,
- argv_types);
- silc_server_send_notify_args(server,
- server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE,
- SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
- argc, args);
- silc_buffer_free(args);
- }
-
- args = silc_argument_payload_encode(argc, argv, argv_lens,
- argv_types);
- /* Send to local clients */
- for (i = 0; i < clients_c; i++) {
- silc_server_send_notify_args(server, clients[i]->connection,
- FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
- argc, args);
- }
-
- silc_free(clients);
- silc_buffer_free(args);
- for (i = 0; i < argc; i++)
- silc_free(argv[i]);
- silc_free(argv);
- silc_free(argv_lens);
- silc_free(argv_types);
- }
-
- /* We must now re-generate the channel key for all channels that had
- this server's client(s) on the channel. As they left the channel we
- must re-generate the channel key. */
- silc_hash_table_list(channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
- silc_server_create_channel_key(server, channel, 0);
- silc_server_send_channel_key(server, NULL, channel,
- server->server_type == SILC_ROUTER ?
- FALSE : !server->standalone);
- }
- silc_hash_table_free(channels);
-
- return TRUE;
-}
-
-/* Checks whether given channel has global users. If it does this returns
- TRUE and FALSE if there is only locally connected clients on the channel. */
-
-int silc_server_channel_has_global(SilcChannelEntry channel)
-{
- SilcChannelClientEntry chl;
- SilcHashTableList htl;
-
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- if (chl->client->router)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* Checks whether given channel has locally connected users. If it does this
- returns TRUE and FALSE if there is not one locally connected client. */
-
-int silc_server_channel_has_local(SilcChannelEntry channel)
-{
- SilcChannelClientEntry chl;
- SilcHashTableList htl;
-
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- if (!chl->client->router)
- return TRUE;
+ /* If any protocol is active cancel its execution */
+ if (sock->protocol) {
+ silc_protocol_cancel(sock->protocol, server->schedule);
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, server->schedule);
+ sock->protocol = NULL;
}
- return FALSE;
+ sock->user_data = NULL;
}
/* Removes client from all channels it has joined. This is used when client
if (server->server_type == SILC_ROUTER &&
silc_hash_table_count(channel->user_list) < 2) {
if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
server->stat.my_channels--;
/* Remove client from channel's client list */
silc_hash_table_del(channel->user_list, chl->client);
- silc_free(chl);
- server->stat.my_chanclients--;
/* 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_SERVER && channel->global_users &&
+ if (server->server_type != SILC_ROUTER && channel->global_users &&
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
+ silc_free(chl);
+ server->stat.my_chanclients--;
+
/* 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. */
- if (server->server_type == SILC_SERVER &&
+ if (server->server_type != SILC_ROUTER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
if (notify && channel->global_users)
strlen(signoff_message) : 0);
if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
if (channel->founder_key) {
/* The founder auth data exists, do not remove the channel entry */
if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
- silc_server_create_channel_key(server, channel, 0);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ return;
/* Send the channel key to the channel. The key of course is not sent
to the client who was removed from the channel. */
if (server->server_type == SILC_ROUTER &&
silc_hash_table_count(channel->user_list) < 2) {
if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
silc_buffer_free(clidp);
/* Remove client from channel's client list */
silc_hash_table_del(channel->user_list, chl->client);
- silc_free(chl);
- server->stat.my_chanclients--;
/* 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_SERVER && channel->global_users &&
+ if (server->server_type != SILC_ROUTER && channel->global_users &&
chl->client->router && !silc_server_channel_has_global(channel))
channel->global_users = FALSE;
+ silc_free(chl);
+ server->stat.my_chanclients--;
+
/* 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. */
- if (server->server_type == SILC_SERVER &&
+ if (server->server_type != SILC_ROUTER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
if (notify && channel->global_users)
silc_buffer_free(clidp);
if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
if (channel->founder_key) {
/* The founder auth data exists, do not remove the channel entry */
return TRUE;
}
-/* Returns TRUE if the given client is on the channel. FALSE if not.
- This works because we assure that the user list on the channel is
- always in up to date thus we can only check the channel list from
- `client' which is faster than checking the user list from `channel'. */
-
-int silc_server_client_on_channel(SilcClientEntry client,
- SilcChannelEntry channel)
-{
- if (!client || !channel)
- return FALSE;
-
- if (silc_hash_table_find(client->channels, channel, NULL, NULL))
- return TRUE;
-
- return FALSE;
-}
-
/* Timeout callback. This is called if connection is idle or for some
other reason is not responding within some period of time. This
disconnects the remote end. */
final callback so that all the memory is freed. */
if (sock->protocol) {
sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute_final(sock->protocol, server->timeout_queue);
+ silc_protocol_execute_final(sock->protocol, server->schedule);
return;
}
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
if (!hmac)
- hmac = "hmac-sha1-96";
+ hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
if (!silc_cipher_alloc(cipher, &key))
channel_name = strdup(channel_name);
/* Create the channel */
- silc_id_create_channel_id(router_id, server->rng, &channel_id);
+ if (!silc_id_create_channel_id(server, router_id, server->rng,
+ &channel_id)) {
+ silc_free(channel_name);
+ silc_cipher_free(key);
+ silc_hmac_free(newhmac);
+ return NULL;
+ }
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
NULL, key, newhmac);
entry->hmac_name = strdup(hmac);
/* Now create the actual key material */
- silc_server_create_channel_key(server, entry,
- silc_cipher_get_key_len(key) / 8);
+ if (!silc_server_create_channel_key(server, entry,
+ silc_cipher_get_key_len(key) / 8)) {
+ silc_free(channel_name);
+ silc_cipher_free(key);
+ silc_hmac_free(newhmac);
+ silc_free(entry->cipher);
+ silc_free(entry->hmac_name);
+ return NULL;
+ }
/* Notify other routers about the new channel. We send the packet
to our primary route. */
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "aes-256-cbc";
+ cipher = SILC_DEFAULT_CIPHER;
if (!hmac)
- hmac = "hmac-sha1-96";
+ hmac = SILC_DEFAULT_HMAC;
/* Allocate cipher */
if (!silc_cipher_alloc(cipher, &key))
}
/* Now create the actual key material */
- silc_server_create_channel_key(server, entry,
- silc_cipher_get_key_len(key) / 8);
+ if (!silc_server_create_channel_key(server, entry,
+ silc_cipher_get_key_len(key) / 8)) {
+ silc_free(channel_name);
+ return NULL;
+ }
/* Notify other routers about the new channel. We send the packet
to our primary route. */
SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
SilcServer server = (SilcServer)rekey->context;
- silc_server_create_channel_key(server, rekey->channel, rekey->key_len);
- silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
+ rekey->task = NULL;
+
+ if (!silc_server_create_channel_key(server, rekey->channel, rekey->key_len))
+ return;
- silc_task_register(server->timeout_queue, 0,
- silc_server_channel_key_rekey,
- (void *)rekey, 3600, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
}
/* Generates new channel key. This is used to create the initial channel key
but also to re-generate new key for channel. If `key_len' is provided
it is the bytes of the key length. */
-void silc_server_create_channel_key(SilcServer server,
+bool silc_server_create_channel_key(SilcServer server,
SilcChannelEntry channel,
uint32 key_len)
{
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
- return;
+ return TRUE;
}
if (!channel->channel_key)
- if (!silc_cipher_alloc("aes-256-cbc", &channel->channel_key))
- return;
+ if (!silc_cipher_alloc(SILC_DEFAULT_CIPHER, &channel->channel_key))
+ return FALSE;
if (key_len)
len = key_len;
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
- silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+ silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
silc_hash_make(channel->hmac->hash, channel->key, len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
memset(hash, 0, sizeof(hash));
channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
channel->rekey->key_len = key_len;
+ if (channel->rekey->task)
+ silc_schedule_task_del(server->schedule, channel->rekey->task);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_channel_key_rekey);
- silc_task_register(server->timeout_queue, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey, 3600, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ channel->rekey->task =
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
+
+ return TRUE;
}
/* Saves the channel key found in the encoded `key_payload' buffer. This
/* Generate HMAC key from the channel key data and set it */
if (!channel->hmac)
- silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac);
+ silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac);
silc_hash_make(channel->hmac->hash, tmp, tmp_len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
channel->rekey->context = (void *)server;
channel->rekey->channel = channel;
+ if (channel->rekey->task)
+ silc_schedule_task_del(server->schedule, channel->rekey->task);
- silc_task_unregister_by_callback(server->timeout_queue,
- silc_server_channel_key_rekey);
- silc_task_register(server->timeout_queue, 0,
- silc_server_channel_key_rekey,
- (void *)channel->rekey, 3600, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ channel->rekey->task =
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
out:
- if (id)
- silc_free(id);
+ silc_free(id);
if (payload)
silc_channel_key_payload_free(payload);
form is dictated by the New ID payload. */
static void silc_server_announce_get_servers(SilcServer server,
+ SilcServerEntry remote,
SilcIDList id_list,
- SilcBuffer *servers)
+ SilcBuffer *servers,
+ unsigned long creation_time)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
while (id_cache) {
entry = (SilcServerEntry)id_cache->context;
+ /* Do not announce the one we've sending our announcements and
+ do not announce ourself. Also check the creation time if it's
+ provided. */
+ if ((entry == remote) || (entry == server->id_entry) ||
+ (creation_time && entry->data.created < creation_time)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ continue;
+ }
+
idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
*servers = silc_buffer_realloc(*servers,
}
/* This function is used by router to announce existing servers to our
- primary router when we've connected to it. */
+ primary router when we've connected to it. If `creation_time' is non-zero
+ then only the servers that has been created after the `creation_time'
+ will be announced. */
-void silc_server_announce_servers(SilcServer server)
+void silc_server_announce_servers(SilcServer server, bool global,
+ unsigned long creation_time,
+ SilcSocketConnection remote)
{
SilcBuffer servers = NULL;
SILC_LOG_DEBUG(("Announcing servers"));
/* Get servers in local list */
- silc_server_announce_get_servers(server, server->local_list, &servers);
+ silc_server_announce_get_servers(server, remote->user_data,
+ server->local_list, &servers,
+ creation_time);
- /* Get servers in global list */
- silc_server_announce_get_servers(server, server->global_list, &servers);
+ if (global)
+ /* Get servers in global list */
+ silc_server_announce_get_servers(server, remote->user_data,
+ server->global_list, &servers,
+ creation_time);
if (servers) {
silc_buffer_push(servers, servers->data - servers->head);
SILC_LOG_HEXDUMP(("servers"), servers->data, servers->len);
/* Send the packet */
- silc_server_packet_send(server, server->router->connection,
+ silc_server_packet_send(server, remote,
SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
servers->data, servers->len, TRUE);
static void silc_server_announce_get_clients(SilcServer server,
SilcIDList id_list,
- SilcBuffer *clients)
+ SilcBuffer *clients,
+ unsigned long creation_time)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
+ if (creation_time && client->data.created < creation_time) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ continue;
+ }
+
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
*clients = silc_buffer_realloc(*clients,
}
/* This function is used to announce our existing clients to our router
- when we've connected to it. */
+ when we've connected to it. If `creation_time' is non-zero then only
+ the clients that has been created after the `creation_time' will be
+ announced. */
-void silc_server_announce_clients(SilcServer server)
+void silc_server_announce_clients(SilcServer server,
+ unsigned long creation_time,
+ SilcSocketConnection remote)
{
SilcBuffer clients = NULL;
/* Get clients in local list */
silc_server_announce_get_clients(server, server->local_list,
- &clients);
+ &clients, creation_time);
/* As router we announce our global list as well */
if (server->server_type == SILC_ROUTER)
silc_server_announce_get_clients(server, server->global_list,
- &clients);
+ &clients, creation_time);
if (clients) {
silc_buffer_push(clients, clients->data - clients->head);
SILC_LOG_HEXDUMP(("clients"), clients->data, clients->len);
/* Send the packet */
- silc_server_packet_send(server, server->router->connection,
+ silc_server_packet_send(server, remote,
SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
clients->data, clients->len, TRUE);
SilcBuffer *channel_users,
SilcBuffer **channel_users_modes,
uint32 *channel_users_modes_c,
- SilcChannelID ***channel_ids)
+ SilcChannelID ***channel_ids,
+ unsigned long creation_time)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
uint16 name_len;
int len;
int i = *channel_users_modes_c;
+ bool announce;
SILC_LOG_DEBUG(("Start"));
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
channel = (SilcChannelEntry)id_cache->context;
-
+
+ if (creation_time && channel->created < creation_time)
+ announce = FALSE;
+ else
+ announce = TRUE;
+
cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
name_len = strlen(channel->channel_name);
- len = 4 + name_len + id_len + 4;
- *channels =
- silc_buffer_realloc(*channels,
- (*channels ? (*channels)->truelen + len : len));
- silc_buffer_pull_tail(*channels,
- ((*channels)->end - (*channels)->data));
- silc_buffer_format(*channels,
- SILC_STR_UI_SHORT(name_len),
- SILC_STR_UI_XNSTRING(channel->channel_name,
- name_len),
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(cid, id_len),
- SILC_STR_UI_INT(channel->mode),
- SILC_STR_END);
- silc_buffer_pull(*channels, len);
+ if (announce) {
+ len = 4 + name_len + id_len + 4;
+ *channels =
+ silc_buffer_realloc(*channels,
+ (*channels ? (*channels)->truelen +
+ len : len));
+ silc_buffer_pull_tail(*channels,
+ ((*channels)->end - (*channels)->data));
+ silc_buffer_format(*channels,
+ SILC_STR_UI_SHORT(name_len),
+ SILC_STR_UI_XNSTRING(channel->channel_name,
+ name_len),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(cid, id_len),
+ SILC_STR_UI_INT(channel->mode),
+ SILC_STR_END);
+ silc_buffer_pull(*channels, len);
+ }
*channel_users_modes = silc_realloc(*channel_users_modes,
sizeof(**channel_users_modes) *
/* This function is used to announce our existing channels to our router
when we've connected to it. This also announces the users on the
- channels to the router. */
-
-void silc_server_announce_channels(SilcServer server)
+ channels to the router. If the `creation_time' is non-zero only the
+ channels that was created after the `creation_time' are announced.
+ Note that the channel users are still announced even if the `creation_time'
+ was provided. */
+
+void silc_server_announce_channels(SilcServer server,
+ unsigned long creation_time,
+ SilcSocketConnection remote)
{
SilcBuffer channels = NULL, channel_users = NULL;
SilcBuffer *channel_users_modes = NULL;
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
- &channel_ids);
+ &channel_ids, creation_time);
/* Get channels and channel users in global list */
silc_server_announce_get_channels(server, server->global_list,
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
- &channel_ids);
+ &channel_ids, creation_time);
if (channels) {
silc_buffer_push(channels, channels->data - channels->head);
SILC_LOG_HEXDUMP(("channels"), channels->data, channels->len);
/* Send the packet */
- silc_server_packet_send(server, server->router->connection,
+ silc_server_packet_send(server, remote,
SILC_PACKET_NEW_CHANNEL, SILC_PACKET_FLAG_LIST,
channels->data, channels->len,
FALSE);
channel_users->len);
/* Send the packet */
- silc_server_packet_send(server, server->router->connection,
+ silc_server_packet_send(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_users->data, channel_users->len,
FALSE);
channel_users_modes[i]->head);
SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes[i]->data,
channel_users_modes[i]->len);
- silc_server_packet_send_dest(server, server->router->connection,
+ silc_server_packet_send_dest(server, remote,
SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_ids[i], SILC_ID_CHANNEL,
channel_users_modes[i]->data,
if (f->sock->protocol) {
f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- silc_protocol_execute(f->sock->protocol, f->server->timeout_queue, 0, 0);
+ silc_protocol_execute(f->sock->protocol, f->server->schedule, 0, 0);
}
silc_free(f);
{
int i;
- /* Cache the received Client ID's and modes. This cache expires
- whenever server sends notify message to channel. It means two things;
- some user has joined or leaved the channel. XXX TODO! */
for (i = 0; i < user_count; i++) {
uint16 idp_len;
uint32 mode;
/* Check if we have this client cached already. */
client = silc_idlist_find_client_by_id(server->local_list, client_id,
- NULL);
+ server->server_type, NULL);
if (!client)
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, server->server_type,
+ NULL);
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. */
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
+ SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
silc_free(client_id);
continue;
}
- client->data.registered = TRUE;
+ client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
}
silc_free(client_id);
/* If the destination belongs to our server we don't have to route
the packet anywhere but to send it to the local destination. */
- client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
+ client = silc_idlist_find_client_by_id(server->local_list, id, TRUE, NULL);
if (client) {
silc_free(id);
- if (client->data.registered == FALSE)
- return NULL;
-
/* If we are router and the client has router then the client is in
our cell but not directly connected to us. */
if (server->server_type == SILC_ROUTER && client->router) {
/* Destination belongs to someone not in this server. If we are normal
server our action is to send the packet to our router. */
- if (server->server_type == SILC_SERVER && !server->standalone) {
+ if (server->server_type != SILC_ROUTER && !server->standalone) {
silc_free(id);
if (idata)
*idata = (SilcIDListData)server->router;
and send the packet to fastest route. */
if (server->server_type == SILC_ROUTER && !server->standalone) {
/* Check first that the ID is valid */
- client = silc_idlist_find_client_by_id(server->global_list, id, NULL);
+ client = silc_idlist_find_client_by_id(server->global_list, id,
+ TRUE, NULL);
if (client) {
SilcSocketConnection dst_sock;
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
channel = chl->channel;
- if (channel->mode & SILC_CHANNEL_MODE_SECRET)
+ if (channel->mode & SILC_CHANNEL_MODE_SECRET ||
+ channel->mode & SILC_CHANNEL_MODE_PRIVATE)
continue;
cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
{
SilcClientEntry client;
- client = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
+ client = silc_idlist_find_client_by_id(server->local_list, client_id,
+ TRUE, NULL);
if (!client) {
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, TRUE, NULL);
if (!client && server->server_type == SILC_ROUTER)
return NULL;
}
if (!client || !client->nickname || !client->username) {
SilcBuffer buffer, idp;
+ client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ client->resolve_cmd_ident = ++server->cmd_ident;
+
idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
- ++server->cmd_ident, 1,
+ server->cmd_ident, 1,
3, idp->data, idp->len);
silc_server_packet_send(server, client ? client->router->connection :
server->router->connection,
buffer->data, buffer->len, FALSE);
silc_buffer_free(idp);
silc_buffer_free(buffer);
+ return NULL;
}
return client;
sock->protocol = protocol;
/* Run the protocol */
- silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
+ silc_protocol_execute(protocol, server->schedule, 0, 0);
/* Re-register re-key timeout */
- silc_task_register(server->timeout_queue, sock->sock,
- silc_server_rekey_callback,
- context, idata->rekey->timeout, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rekey_callback,
+ context, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/* The final callback for the REKEY protocol. This will actually take the
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
- silc_protocol_cancel(protocol, server->timeout_queue);
+ SILC_LOG_ERROR(("Error occurred during rekey protocol"));
+ silc_protocol_cancel(protocol, server->schedule);
silc_protocol_free(protocol);
sock->protocol = NULL;
if (ctx->packet)
return;
}
+ /* Purge the outgoing data queue to assure that all rekey packets really
+ go to the network before we quit the protocol. */
+ silc_server_packet_queue_purge(server, sock);
+
/* Cleanup */
silc_protocol_free(protocol);
sock->protocol = NULL;