#include "server_internal.h"
/* Static prototypes */
+SILC_TASK_CALLBACK(silc_server_connect_router);
SILC_TASK_CALLBACK(silc_server_connect_to_router);
SILC_TASK_CALLBACK(silc_server_connect_to_router_second);
SILC_TASK_CALLBACK(silc_server_connect_to_router_final);
}
silc_dlist_uninit(server->sim);
+ if (server->params)
+ silc_free(server->params);
+
silc_math_primegen_uninit(); /* XXX */
silc_free(server);
}
assert(server);
assert(server->config);
+ /* XXX After server is made as Silc Server Library this can be given
+ as argument, for now this is hard coded */
+ server->params = silc_calloc(1, sizeof(*server->params));
+ server->params->retry_count = SILC_SERVER_RETRY_COUNT;
+ server->params->retry_interval_min = SILC_SERVER_RETRY_INTERVAL_MIN;
+ server->params->retry_interval_max = SILC_SERVER_RETRY_INTERVAL_MAX;
+ server->params->retry_keep_trying = FALSE;
+ server->params->protocol_timeout = 60;
+
/* Set log files where log message should be saved. */
server->config->server = server;
silc_config_server_setlogfiles(server->config);
silc_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. */
+
+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_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);
+}
+
+/* Generic routine to use connect to a router. */
+
+SILC_TASK_CALLBACK(silc_server_connect_router)
+{
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcServer server = sconn->server;
+ SilcSocketConnection newsocket;
+ SilcProtocol protocol;
+ SilcServerKEInternalContext *proto_ctx;
+ int sock;
+
+ /* 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;
+ }
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* Create socket connection for the connection. Even though we
+ know that we are connecting to a router we will mark the socket
+ to be unknown connection until we have executed authentication
+ protocol. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+ newsocket->hostname = sconn->remote_host;
+ newsocket->port = sconn->remote_port;
+ sconn->sock = newsocket;
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->context = (void *)sconn;
+ proto_ctx->sock = newsocket;
+ proto_ctx->rng = server->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_server_connect_to_router_second
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+ &protocol, proto_ctx,
+ silc_server_connect_to_router_second);
+ newsocket->protocol = protocol;
+
+ /* 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_server_timeout_remote,
+ server, server->params->protocol_timeout,
+ server->params->protocol_timeout_usec,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_LOW);
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as
+ well. However, this doesn't set the scheduler for outgoing traffic,
+ it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
+ later when outgoing data is available. */
+ context = (void *)server;
+ SILC_REGISTER_CONNECTION_FOR_IO(sock);
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+}
+
/* This function connects to our primary router or if we are a router this
establishes all our primary routes. This is called at the start of the
server to do authentication and key exchange with our router - called
SILC_TASK_CALLBACK(silc_server_connect_to_router)
{
SilcServer server = (SilcServer)context;
- SilcSocketConnection newsocket;
- int sock;
+ SilcServerConnection sconn;
SILC_LOG_DEBUG(("Connecting to router(s)"));
- /* if we are normal SILC server we need to connect to our cell's
+ /* If we are normal SILC server we need to connect to our cell's
router. */
if (server->server_type == SILC_SERVER) {
- SilcProtocol protocol;
- SilcServerKEInternalContext *proto_ctx;
+ SILC_LOG_DEBUG(("We are normal server"));
/* Create connection to the router, if configured. */
if (server->config->routers) {
- sock = silc_net_create_connection(server->config->routers->port,
- server->config->routers->host);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not connect to router"));
- silc_schedule_stop();
- return;
- }
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* Create socket connection for the connection. Even though we
- know that we are connecting to a router we will mark the socket
- to be unknown connection until we have executed authentication
- protocol. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
- newsocket->hostname = server->config->routers->host;
- newsocket->port = server->config->routers->port;
-
- /* Allocate internal protocol context. This is sent as context
- to the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = context;
- proto_ctx->sock = newsocket;
- proto_ctx->rng = server->rng;
- proto_ctx->responder = FALSE;
-
- /* Perform key exchange protocol. silc_server_connect_to_router_second
- will be called after the protocol is finished. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- &protocol, proto_ctx,
- silc_server_connect_to_router_second);
- newsocket->protocol = protocol;
-
- /* Register a timeout task that will be executed if the protocol
- is not executed within 60 seconds. For now, this is a hard coded
- limit. After 60 secs the connection will be closed if the key
- exchange protocol has not been executed. */
- proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock,
- silc_server_timeout_remote,
- context, 60, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
-
- /* Register the connection for network input and output. This sets
- that scheduler will listen for incoming packets for this connection
- and sets that outgoing packets may be sent to this connection as
- well. However, this doesn't set the scheduler for outgoing traffic,
- it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- SILC_REGISTER_CONNECTION_FOR_IO(sock);
-
- /* Run the protocol */
- protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ sconn->server = server;
+ sconn->remote_host = 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;
}
}
-
- /* if we are a SILC router we need to establish all of our primary
+
+ /* If we are a SILC router we need to establish all of our primary
routes. */
if (server->server_type == SILC_ROUTER) {
SilcConfigServerSectionServerConnection *ptr;
+ SILC_LOG_DEBUG(("We are router"));
+
/* Create the connections to all our routes */
ptr = server->config->routers;
while (ptr) {
- SilcProtocol protocol;
- SilcServerKEInternalContext *proto_ctx;
-
- /* Create the connection to the remote end */
- sock = silc_net_create_connection(ptr->port, ptr->host);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not connect to router"));
- silc_schedule_stop();
- return;
- }
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* Create socket connection for the connection. Even though we
- know that we are connecting to a router we will mark the socket
- to be unknown connection until we have executed authentication
- protocol. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
- newsocket->hostname = ptr->host;
- newsocket->port = ptr->port;
-
- /* Allocate internal protocol context. This is sent as context
- to the protocol. */
- proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
- proto_ctx->server = context;
- proto_ctx->sock = newsocket;
- proto_ctx->rng = server->rng;
- proto_ctx->responder = FALSE;
-
- /* Perform key exchange protocol. silc_server_connect_to_router_final
- will be called after the protocol is finished. */
- silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- &protocol, proto_ctx,
- silc_server_connect_to_router_second);
- newsocket->protocol = protocol;
-
- /* Register a timeout task that will be executed if the protocol
- is not executed within 60 seconds. For now, this is a hard coded
- limit. After 60 secs the connection will be closed if the key
- exchange protocol has not been executed. */
- proto_ctx->timeout_task =
- silc_task_register(server->timeout_queue, sock,
- silc_server_timeout_remote,
- context, 60, 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
-
- /* Register the connection for network input and output. This sets
- that scheduler will listen for incoming packets for this connection
- and sets that outgoing packets may be sent to this connection as
- well. However, this doesn't set the scheduler for outgoing traffic,
- it will be set separately by calling SILC_SET_CONNECTION_FOR_OUTPUT,
- later when outgoing data is available. */
- SILC_REGISTER_CONNECTION_FOR_IO(sock);
-
- /* Run the protocol */
- protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ sconn->server = server;
+ sconn->remote_host = 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;
/* 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 (silc_task_register(server->io_queue, fd,
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL) == NULL) {
- silc_schedule_stop();
- return;
- }
+ silc_task_register(server->io_queue, fd,
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
}
/* Second part of connecting to router(s). Key exchange protocol has been
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
+ SilcServerConnection sconn = (SilcServerConnection)ctx->context;
SilcSocketConnection sock = NULL;
SilcServerConnAuthInternalContext *proto_ctx;
is sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
+ proto_ctx->context = (void *)sconn;
proto_ctx->sock = sock = server->sockets[fd];
proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
proto_ctx->dest_id_type = ctx->dest_id_type;
SilcServerConnAuthInternalContext *ctx =
(SilcServerConnAuthInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
+ SilcServerConnection sconn = (SilcServerConnection)ctx->context;
SilcSocketConnection sock = ctx->sock;
SilcServerEntry id_entry;
SilcUnknownEntry conn_data;
/* 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) {
- if (silc_task_register(server->io_queue, server->sock,
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL) == NULL) {
- silc_schedule_stop();
- return;
- } else {
- server->listenning = TRUE;
- }
+ silc_task_register(server->io_queue, server->sock,
+ silc_server_accept_new_connection,
+ (void *)server, 0, 0,
+ SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ server->listenning = TRUE;
}
/* Send NEW_SERVER packet to the router. We will become registered
/* Free the temporary connection data context from key exchange */
silc_free(conn_data);
+ if (sconn)
+ silc_free(sconn);
/* Free the protocol object */
silc_protocol_free(protocol);
SILC_TASK_CALLBACK(silc_server_timeout_remote)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ SilcSocketConnection sock = sconn->server->sockets[fd];
- silc_server_disconnect_remote(server, sock,
+ silc_server_disconnect_remote(sconn->server, sock,
"Server closed connection: "
"Connection timeout");
}