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);
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
/* 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"));
{
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);
}
/* 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_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. */
sconn->remote_host, sconn->remote_port));
/* Connect to remote host */
- sock = silc_net_create_connection(sconn->remote_port,
+ 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_task_register(server->timeout_queue, fd,
- silc_server_connect_to_router_retry,
- context, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add(server->schedule, fd,
+ silc_server_connect_to_router_retry,
+ context, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
return;
}
/* 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);
}
/* This function connects to our primary router or if we are a router this
sconn->remote_host = strdup(server->config->routers->host);
sconn->remote_port = server->config->routers->port;
- silc_task_register(server->timeout_queue, fd,
+ silc_schedule_task_add(server->schedule, fd,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
sconn->remote_host = strdup(ptr->host);
sconn->remote_port = ptr->port;
- silc_task_register(server->timeout_queue, fd,
+ silc_schedule_task_add(server->schedule, fd,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
+ silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
+ silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
if (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
/* 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);
+ 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;
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_schedule_task_add(server->schedule, sock->sock,
silc_server_rekey_callback,
(void *)sock, idata->rekey->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
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
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
+ silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- silc_task_unregister_by_callback(server->timeout_queue,
+ silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
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_free(ctx);
if (sock)
sock->protocol = NULL;
- silc_task_unregister_by_callback(server->timeout_queue,
+ silc_schedule_task_del_by_callback(server->schedule,
silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
return;
}
- switch(ctx->conn_type) {
+ entry->data.last_receive = time(NULL);
+
+ switch (ctx->conn_type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry client;
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);
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);
+ silc_schedule_task_add(server->schedule, 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);
/* 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;
}
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."));
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,
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;
}
}
+ /* 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;
+ }
+
sock->user_data = NULL;
}
+/* Removes the client from channels and possibly removes the channels
+ as well. After removing those channels that exist, their channel
+ keys are regnerated. This is called only by the function
+ silc_server_remove_clients_by_server. */
+
+static void silc_server_remove_clients_channels(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry client,
+ SilcHashTable channels)
+{
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcHashTableList htl;
+ SilcBuffer clidp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!client || !client->id)
+ return;
+
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Remove the client from all channels. The client is removed from
+ the channels' user list. */
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ channel = chl->channel;
+
+ /* Remove channel from client's channel list */
+ silc_hash_table_del(client->channels, channel);
+
+ /* Remove channel if there is no users anymore */
+ if (server->server_type == SILC_ROUTER &&
+ silc_hash_table_count(channel->user_list) < 2) {
+
+ if (silc_hash_table_find(channels, channel, NULL, NULL))
+ silc_hash_table_del(channels, channel);
+
+ if (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--;
+ continue;
+ }
+
+ /* 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 &&
+ chl->client->router && !silc_server_channel_has_global(channel))
+ channel->global_users = FALSE;
+
+ /* 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 &&
+ !silc_server_channel_has_local(channel)) {
+
+ if (silc_hash_table_find(channels, channel, NULL, NULL))
+ silc_hash_table_del(channels, channel);
+
+ if (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 */
+ SilcChannelClientEntry chl2;
+ SilcHashTableList htl2;
+
+ channel->id = NULL;
+
+ silc_hash_table_list(channel->user_list, &htl2);
+ while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
+ silc_hash_table_del(chl2->client->channels, channel);
+ silc_hash_table_del(channel->user_list, chl2->client);
+ silc_free(chl2);
+ }
+ continue;
+ }
+
+ /* Remove the channel entry */
+ if (!silc_idlist_del_channel(server->local_list, channel))
+ silc_idlist_del_channel(server->global_list, channel);
+ server->stat.my_channels--;
+ continue;
+ }
+
+ /* Add the channel to the the channels list to regenerate the
+ channel key */
+ if (!silc_hash_table_find(channels, channel, NULL, NULL))
+ silc_hash_table_add(channels, channel, channel);
+ }
+
+ silc_buffer_free(clidp);
+}
+
/* 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'.
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;
+ SilcChannelEntry channel;
+ SilcHashTable channels;
int i;
SILC_LOG_DEBUG(("Start"));
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
- if (client->data.registered == FALSE) {
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
if (!silc_idcache_list_next(list, &id_cache))
break;
else
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_server_remove_clients_channels(server, NULL, client, channels);
silc_idlist_del_client(server->local_list, client);
if (!silc_idcache_list_next(list, &id_cache))
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
- if (client->data.registered == FALSE) {
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
if (!silc_idcache_list_next(list, &id_cache))
break;
else
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_server_remove_clients_channels(server, NULL, client, channels);
silc_idlist_del_client(server->global_list, client);
if (!silc_idcache_list_next(list, &id_cache))
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);
+ if (!silc_server_create_channel_key(server, channel, 0))
+ return FALSE;
+
+ /* Do not send the channel key if private channel key mode is set */
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+ continue;
+
silc_server_send_channel_key(server, NULL, channel,
server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
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--;
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);
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 */
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)
{
while (id_cache) {
entry = (SilcServerEntry)id_cache->context;
+ /* Do not announce the one we've sending our announcements and
+ do not announce ourself. */
+ if (entry == remote || entry == server->id_entry) {
+ 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,
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, server->router,
+ server->local_list, &servers);
/* Get servers in global list */
- silc_server_announce_get_servers(server, server->global_list, &servers);
+ silc_server_announce_get_servers(server, server->router,
+ server->global_list, &servers);
if (servers) {
silc_buffer_push(servers, servers->data - servers->head);
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) {
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;
{
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_protocol_cancel(protocol, server->schedule);
silc_protocol_free(protocol);
sock->protocol = NULL;
if (ctx->packet)