server.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
silc_server_config_setlogfiles(server->config);
/* Register all configured ciphers, PKCS and hash functions. */
- silc_server_config_register_ciphers(server->config);
- silc_server_config_register_pkcs(server->config);
- silc_server_config_register_hashfuncs(server->config);
- silc_server_config_register_hmacs(server->config);
+ if (!silc_server_config_register_ciphers(server->config))
+ silc_cipher_register_default();
+ if (!silc_server_config_register_pkcs(server->config))
+ silc_pkcs_register_default();
+ if (!silc_server_config_register_hashfuncs(server->config))
+ silc_hash_register_default();
+ if (!silc_server_config_register_hmacs(server->config))
+ silc_hmac_register_default();
/* Initialize random number generator for the server. */
server->rng = silc_rng_alloc();
server->id_entry = id_entry;
}
- /* Register the task queues. 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. */
- silc_task_queue_alloc(&server->io_queue, TRUE);
- if (!server->io_queue) {
- goto err0;
- }
- silc_task_queue_alloc(&server->timeout_queue, TRUE);
- if (!server->timeout_queue) {
- goto err1;
- }
- silc_task_queue_alloc(&server->generic_queue, TRUE);
- if (!server->generic_queue) {
- goto err1;
- }
-
/* Register protocols */
silc_server_protocols_register();
- /* Initialize the scheduler */
- silc_schedule_init(&server->io_queue, &server->timeout_queue,
- &server->generic_queue,
- SILC_SERVER_MAX_CONNECTIONS);
+ /* 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);
+ if (!server->schedule)
+ goto err0;
/* Add the first task to the queue. This is task that is executed by
timeout. It expires as soon as the caller calls silc_server_run. This
/* We are done here, return succesfully */
return TRUE;
- silc_task_queue_free(server->timeout_queue);
- err1:
- silc_task_queue_free(server->io_queue);
err0:
for (i = 0; i < sock_count; i++)
silc_net_close_server(sock[i]);
/* 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();
- silc_schedule_uninit();
+ silc_schedule_stop(server->schedule);
+ silc_schedule_uninit(server->schedule);
silc_server_protocols_unregister();
{
SILC_LOG_DEBUG(("Running server"));
+ SILC_LOG_INFO(("SILC Server started"));
+
/* Start the scheduler, the heart of the SILC server. When this returns
the program will be terminated. */
- silc_schedule();
+ silc_schedule(server->schedule);
}
/* Timeout callback that will be called to retry connecting to remote
SILC_REGISTER_CONNECTION_FOR_IO(sock);
/* Run the protocol */
- protocol->execute(server->timeout_queue, 0, protocol, sock, 0, 0);
+ silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
}
/* This function connects to our primary router or if we are a router this
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
SilcServerConnection sconn = (SilcServerConnection)ctx->context;
- SilcSocketConnection sock = server->sockets[fd];
+ SilcSocketConnection sock = ctx->sock;
SilcServerConnAuthInternalContext *proto_ctx;
SilcServerConfigSectionServerConnection *conn = NULL;
SILC_TASK_PRI_LOW);
/* Run the protocol */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
}
/* Finalizes the connection to router. Registers a server task to the
sock->protocol = NULL;
}
-/* Accepts new connections to the server. Accepting new connections are
- done in three parts to make it async. */
+/* Host lookup callbcak that is called after the incoming connection's
+ IP and FQDN lookup is performed. This will actually check the acceptance
+ of the incoming connection and will register the key exchange protocol
+ for this connection. */
-SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+static void
+silc_server_accept_new_connection_lookup(SilcSocketConnection sock,
+ void *context)
{
SilcServer server = (SilcServer)context;
- SilcSocketConnection newsocket;
SilcServerKEInternalContext *proto_ctx;
- int sock, port;
void *cconfig, *sconfig, *rconfig;
SilcServerConfigSectionDenyConnection *deny;
+ int port;
- SILC_LOG_DEBUG(("Accepting new connection"));
-
- server->stat.conn_attempts++;
-
- sock = silc_net_accept_connection(server->sock);
- if (sock < 0) {
- SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
- server->stat.conn_failures++;
- return;
- }
+ SILC_LOG_DEBUG(("Start"));
- /* Check max connections */
- if (sock > SILC_SERVER_MAX_CONNECTIONS) {
- SILC_LOG_ERROR(("Refusing connection, server is full"));
+ /* Check whether we could resolve both IP and FQDN. */
+ if (!sock->ip || (!strcmp(sock->ip, sock->hostname) &&
+ server->params->require_reverse_mapping)) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed %s",
+ sock->hostname ? sock->hostname :
+ sock->ip ? sock->ip : ""));
server->stat.conn_failures++;
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: Unknown host");
return;
}
- /* Set socket options */
- silc_net_set_socket_nonblock(sock);
- silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
-
- /* We don't create a ID yet, since we don't know what type of connection
- this is yet. But, we do add the connection to the socket table. */
- silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
- server->sockets[sock] = newsocket;
-
- /* XXX This MUST be done async as this will block the entire server
- process. Either we have to do our own resolver stuff or in the future
- we can use threads. */
- /* Perform name and address lookups for the remote host. */
- if (!silc_net_check_host_by_sock(sock, &newsocket->hostname,
- &newsocket->ip)) {
- if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed %s",
- newsocket->hostname ? newsocket->hostname :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- return;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_remote_port(sock);
-
/* 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);
+ SILC_REGISTER_CONNECTION_FOR_IO(sock->sock);
- port = server->sockets[fd]->port; /* Listenning port */
+ SILC_LOG_INFO(("Incoming connection from %s (%s)", sock->hostname,
+ sock->ip));
+
+ port = server->sockets[server->sock]->port; /* Listenning port */
/* Check whether this connection is denied to connect to us. */
- deny = silc_server_config_denied_conn(server->config, newsocket->ip, port);
+ deny = silc_server_config_denied_conn(server->config, sock->ip, port);
if (!deny)
- deny = silc_server_config_denied_conn(server->config, newsocket->hostname,
+ deny = silc_server_config_denied_conn(server->config, sock->hostname,
port);
if (deny) {
/* The connection is denied */
- silc_server_disconnect_remote(server, newsocket, deny->comment ?
+ SILC_LOG_INFO(("Connection %s (%s) is denied",
+ sock->hostname, sock->ip));
+ silc_server_disconnect_remote(server, sock, deny->comment ?
deny->comment :
"Server closed connection: "
"Connection refused");
have to check all configurations since we don't know what type of
connection this is. */
if (!(cconfig = silc_server_config_find_client_conn(server->config,
- newsocket->ip, port)))
+ sock->ip, port)))
cconfig = silc_server_config_find_client_conn(server->config,
- newsocket->hostname,
+ sock->hostname,
port);
if (!(sconfig = silc_server_config_find_server_conn(server->config,
- newsocket->ip,
+ sock->ip,
port)))
sconfig = silc_server_config_find_server_conn(server->config,
- newsocket->hostname,
+ sock->hostname,
port);
if (!(rconfig = silc_server_config_find_router_conn(server->config,
- newsocket->ip, port)))
+ sock->ip, port)))
rconfig = silc_server_config_find_router_conn(server->config,
- newsocket->hostname,
+ sock->hostname,
port);
if (!cconfig && !sconfig && !rconfig) {
- silc_server_disconnect_remote(server, newsocket,
+ silc_server_disconnect_remote(server, sock,
"Server closed connection: "
"Connection refused");
server->stat.conn_failures++;
/* The connection is allowed */
- SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
- newsocket->ip));
-
/* Allocate internal context for key exchange protocol. This is
sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = context;
- proto_ctx->sock = newsocket;
+ proto_ctx->sock = sock;
proto_ctx->rng = server->rng;
proto_ctx->responder = TRUE;
proto_ctx->cconfig = cconfig;
there before we start the protocol. */
server->stat.auth_attempts++;
silc_protocol_alloc(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
- &newsocket->protocol, proto_ctx,
+ &sock->protocol, proto_ctx,
silc_server_accept_new_connection_second);
/* Register a timeout task that will be executed if the connector
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, newsocket->sock,
+ silc_task_register(server->timeout_queue, 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
+ done in three parts to make it async. */
+
+SILC_TASK_CALLBACK(silc_server_accept_new_connection)
+{
+ SilcServer server = (SilcServer)context;
+ SilcSocketConnection newsocket;
+ int sock;
+
+ SILC_LOG_DEBUG(("Accepting new connection"));
+
+ server->stat.conn_attempts++;
+
+ sock = silc_net_accept_connection(server->sock);
+ if (sock < 0) {
+ SILC_LOG_ERROR(("Could not accept new connection: %s", strerror(errno)));
+ server->stat.conn_failures++;
+ return;
+ }
+
+ /* Check max connections */
+ if (sock > SILC_SERVER_MAX_CONNECTIONS) {
+ SILC_LOG_ERROR(("Refusing connection, server is full"));
+ server->stat.conn_failures++;
+ return;
+ }
+
+ /* Set socket options */
+ silc_net_set_socket_nonblock(sock);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ /* We don't create a ID yet, since we don't know what type of connection
+ this is yet. But, we do add the connection to the socket table. */
+ silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, NULL, &newsocket);
+ server->sockets[sock] = newsocket;
+
+ /* Perform asynchronous host lookup. This will lookup the IP and the
+ FQDN of the remote connection. After the lookup is done the connection
+ is accepted further. */
+ silc_socket_host_lookup(newsocket, TRUE,
+ silc_server_accept_new_connection_lookup, context,
+ server->timeout_queue);
+}
+
/* Second part of accepting new connection. Key exchange protocol has been
performed and now it is time to do little connection authentication
protocol to figure out whether this connection is client or server
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = server->sockets[fd];
+ SilcSocketConnection sock = ctx->sock;
SilcServerConnAuthInternalContext *proto_ctx;
SILC_LOG_DEBUG(("Start"));
return;
}
- sock->type = ctx->conn_type;
- switch(sock->type) {
+ switch(ctx->conn_type) {
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry client;
if (!client) {
SILC_LOG_ERROR(("Could not add new client to cache"));
silc_free(sock->user_data);
- break;
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Authentication failed");
+ server->stat.auth_failures++;
+ goto out;
}
/* Statistics */
{
SilcServerEntry new_server;
SilcServerConfigSectionServerConnection *conn =
- sock->type == SILC_SOCKET_TYPE_SERVER ? ctx->sconfig : ctx->rconfig;
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
+ ctx->sconfig : ctx->rconfig;
SILC_LOG_DEBUG(("Remote host is %s",
- sock->type == SILC_SOCKET_TYPE_SERVER ?
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
"server" : "router"));
SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
- sock->ip, sock->type == SILC_SOCKET_TYPE_SERVER ?
+ sock->ip, ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
"server" : "router"));
/* Add the server into server cache. The server name and Server ID
are router. */
new_server =
silc_idlist_add_server(server->local_list, NULL,
- sock->type == SILC_SOCKET_TYPE_SERVER ?
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
SILC_SERVER : SILC_ROUTER, NULL,
- sock->type == SILC_SOCKET_TYPE_SERVER ?
+ ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
server->id_entry : NULL, sock);
if (!new_server) {
SILC_LOG_ERROR(("Could not add new server to cache"));
silc_free(sock->user_data);
- break;
+ silc_server_disconnect_remote(server, sock,
+ "Server closed connection: "
+ "Authentication failed");
+ server->stat.auth_failures++;
+ goto out;
}
/* Statistics */
- if (sock->type == SILC_SOCKET_TYPE_SERVER)
+ if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER)
server->stat.my_servers++;
else
server->stat.my_routers++;
/* Check whether this connection is to be our primary router connection
if we dont' already have the primary route. */
- if (server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER) {
+ if (server->standalone && ctx->conn_type == SILC_SOCKET_TYPE_ROUTER) {
if (silc_server_config_is_primary_route(server->config) &&
!conn->initiator)
break;
break;
}
+ sock->type = ctx->conn_type;
+
/* Add the common data structure to the ID entry. */
if (id_entry)
silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
silc_server_perform_heartbeat,
server->timeout_queue);
+ out:
silc_task_unregister_by_callback(server->timeout_queue,
silc_server_failure_callback);
silc_protocol_free(protocol);
if (ret == -2)
return;
- if (ret == -1)
+ if (ret == -1) {
+ SILC_LOG_ERROR(("Error sending packet to 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")));
return;
+ }
/* The packet has been sent and now it is time to set the connection
back to only for input. When there is again some outgoing data
available for this connection it will be set for output as well.
This call clears the output setting and sets it only for input. */
- SILC_SET_CONNECTION_FOR_INPUT(fd);
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
SILC_UNSET_OUTBUF_PENDING(sock);
silc_buffer_clear(sock->outbuf);
/* Read some data from connection */
ret = silc_packet_receive(sock);
- if (ret < 0)
+ if (ret < 0) {
+
+ if (ret == -1)
+ SILC_LOG_ERROR(("Error receiving packet from 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")));
return;
-
+ }
+
/* EOF */
if (ret == 0) {
SILC_LOG_DEBUG(("Read EOF"));
idata ? idata->hmac_receive : NULL,
packet->buffer, packet,
silc_server_packet_decrypt_check, parse_ctx);
- if (ret < 0)
+ if (ret < 0) {
+ SILC_LOG_WARNING(("Packet decryption failed for 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")));
goto out;
+ }
if (ret == 0) {
/* Parse the packet. Packet type is returned. */
SILC_LOG_DEBUG(("Success packet"));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
- if (sock->protocol) {
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
- }
+ if (sock->protocol)
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
break;
case SILC_PACKET_FAILURE:
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 100000);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 100000);
} else {
SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
"protocol active, packet dropped."));
-
- /* XXX Trigger KE protocol?? Rekey actually, maybe. */
}
break;
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
} else {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
break;
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ silc_protocol_execute(sock->protocol, server->timeout_queue,
+ 0, 100000);
}
} else {
SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
} else {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
break;
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ silc_protocol_execute(sock->protocol, server->timeout_queue,
+ 0, 100000);
}
} else {
SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
proto_ctx->packet = silc_packet_context_dup(packet);
/* Let the protocol handle the packet */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 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 */
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, server->timeout_queue, 0, 0);
} else {
SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
"protocol active, packet dropped."));
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;
+ }
+
/* We won't listen for this connection anymore */
- silc_schedule_unset_listen_fd(sock->sock);
+ silc_schedule_unset_listen_fd(server->schedule, sock->sock);
/* Unregister all tasks */
silc_task_unregister_by_fd(server->io_queue, sock->sock);
silc_packet_send(sock, TRUE);
- SILC_SET_CONNECTION_FOR_INPUT(sock->sock);
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
SILC_UNSET_OUTBUF_PENDING(sock);
silc_buffer_clear(sock->outbuf);
}
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] = idp->data;
+ 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_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);
SilcBuffer args;
/* Send SERVER_SIGNOFF notify to our primary router */
- if (!server->standalone && server->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,
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;
}
/* Remove channel if there is no users anymore */
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);
-
- 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--;
server->stat.my_chanclients--;
/* If there is no global users on the channel anymore mark the channel
- as local channel. */
- if (server->server_type == SILC_SERVER &&
- !silc_server_channel_has_global(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
server->stat.my_chanclients--;
/* If there is no global users on the channel anymore mark the channel
- as local channel. */
- if (server->server_type == SILC_SERVER &&
- !silc_server_channel_has_global(channel))
+ as local channel. Do not check if the 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
SilcServer server = (SilcServer)context;
SilcSocketConnection sock = server->sockets[fd];
+ SILC_LOG_DEBUG(("Start"));
+
if (!sock)
return;
+ /* If we have protocol active we must assure that we call the protocol's
+ 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);
+ return;
+ }
+
if (sock->user_data)
silc_server_free_sock_user_data(server, sock);
- silc_server_disconnect_remote(server, sock,
- "Server closed connection: "
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Connection timeout");
}
NULL, key, newhmac);
if (!entry) {
silc_free(channel_name);
+ silc_cipher_free(key);
+ silc_hmac_free(newhmac);
return NULL;
}
silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
{
va_list ap;
+ SilcBuffer p;
va_start(ap, argc);
- return silc_notify_payload_encode(notify, argc, ap);
+ p = silc_notify_payload_encode(notify, argc, ap);
+ va_end(ap);
+
+ return p;
}
/* Returns assembled packets for channel users of the `channel'. */
SilcIDList id_list,
SilcBuffer *channels,
SilcBuffer *channel_users,
- SilcBuffer *channel_users_modes)
+ SilcBuffer **channel_users_modes,
+ uint32 *channel_users_modes_c,
+ SilcChannelID ***channel_ids)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
uint32 id_len;
uint16 name_len;
int len;
+ int i = *channel_users_modes_c;
SILC_LOG_DEBUG(("Start"));
SILC_STR_END);
silc_buffer_pull(*channels, len);
+ *channel_users_modes = silc_realloc(*channel_users_modes,
+ sizeof(**channel_users_modes) *
+ (i + 1));
+ (*channel_users_modes)[i] = NULL;
+ *channel_ids = silc_realloc(*channel_ids,
+ sizeof(**channel_ids) * (i + 1));
+ (*channel_ids)[i] = NULL;
silc_server_announce_get_channel_users(server, channel,
channel_users,
- channel_users_modes);
-
- silc_free(cid);
+ channel_users_modes[i]);
+ (*channel_ids)[i] = channel->id;
+ i++;
if (!silc_idcache_list_next(list, &id_cache))
break;
}
+
+ *channel_users_modes_c += i;
}
silc_idcache_list_free(list);
void silc_server_announce_channels(SilcServer server)
{
- SilcBuffer channels = NULL, channel_users = NULL, channel_users_modes = NULL;
+ SilcBuffer channels = NULL, channel_users = NULL;
+ SilcBuffer *channel_users_modes = NULL;
+ uint32 channel_users_modes_c = 0;
+ SilcChannelID **channel_ids = NULL;
SILC_LOG_DEBUG(("Announcing channels and channel users"));
/* Get channels and channel users in local list */
silc_server_announce_get_channels(server, server->local_list,
&channels, &channel_users,
- &channel_users_modes);
+ &channel_users_modes,
+ &channel_users_modes_c,
+ &channel_ids);
/* 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,
+ &channel_users_modes_c,
+ &channel_ids);
if (channels) {
silc_buffer_push(channels, channels->data - channels->head);
}
if (channel_users_modes) {
- silc_buffer_push(channel_users_modes,
- channel_users_modes->data - channel_users_modes->head);
- SILC_LOG_HEXDUMP(("channel users modes"), channel_users_modes->data,
- channel_users_modes->len);
-
- /* Send the packet */
- silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
- channel_users_modes->data,
- channel_users_modes->len,
- FALSE);
-
- silc_buffer_free(channel_users_modes);
+ int i;
+
+ for (i = 0; i < channel_users_modes_c; i++) {
+ silc_buffer_push(channel_users_modes[i],
+ channel_users_modes[i]->data -
+ 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_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel_ids[i], SILC_ID_CHANNEL,
+ channel_users_modes[i]->data,
+ channel_users_modes[i]->len,
+ FALSE);
+ silc_buffer_free(channel_users_modes[i]);
+ }
+ silc_free(channel_users_modes);
+ silc_free(channel_ids);
}
}
if (f->sock->protocol) {
f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- f->sock->protocol->execute(f->server->timeout_queue, 0,
- f->sock->protocol, f->sock->sock, 0, 0);
+ silc_protocol_execute(f->sock->protocol, f->server->timeout_queue, 0, 0);
}
silc_free(f);
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
SilcBuffer idp;
- uint32 list_count = 0;
+ uint32 list_count = 0, len = 0;
- /* XXX rewrite - this does not support IPv6 based Client ID's. */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl))
+ len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
- client_id_list =
- silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
- silc_hash_table_count(channel->user_list));
+ client_id_list = silc_buffer_alloc(len);
client_mode_list =
silc_buffer_alloc(4 * silc_hash_table_count(channel->user_list));
silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+
silc_hash_table_list(channel->user_list, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
/* Client ID */
if (client) {
silc_free(id);
- if (client && client->data.registered == FALSE)
+ 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) {
- /* We are of course in this case the client's router thus the real
- "router" of the client is the server who owns the client. Thus
- we will send the packet to that server. */
+ /* We are of course in this case the client's router thus the route
+ to the client is the server who owns the client. So, we will send
+ the packet to that server. */
if (idata)
*idata = (SilcIDListData)client->router;
return client->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 */
- protocol->execute(server->timeout_queue, 0, protocol,
- sock->sock, 0, 0);
+ silc_protocol_execute(protocol, server->timeout_queue, 0, 0);
/* Re-register re-key timeout */
silc_task_register(server->timeout_queue, sock->sock,
if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
- silc_protocol_cancel(server->timeout_queue, protocol);
+ silc_protocol_cancel(protocol, server->timeout_queue);
silc_protocol_free(protocol);
sock->protocol = NULL;
if (ctx->packet)