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();
/* Initialize ID caches */
server->local_list->clients =
- silc_idcache_alloc(0, silc_idlist_client_destructor);
- server->local_list->servers = silc_idcache_alloc(0, NULL);
- server->local_list->channels = silc_idcache_alloc(0, NULL);
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+ server->local_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+ server->local_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
/* These are allocated for normal server as well as these hold some
global information that the server has fetched from its router. For
router these are used as they are supposed to be used on router. */
server->global_list->clients =
- silc_idcache_alloc(0, silc_idlist_client_destructor);
- server->global_list->servers = silc_idcache_alloc(0, NULL);
- server->global_list->channels = silc_idcache_alloc(0, NULL);
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor);
+ server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+ server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
/* Allocate the entire socket list that is used in server. Eventually
all connections will have entry in this table (it is a table of
server->id = id;
server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
- server->id_string_len = silc_id_get_len(SILC_ID_SERVER);
+ server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
server->id_type = SILC_ID_SERVER;
server->server_name = server->config->server_info->server_name;
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
SilcBuffer packet;
SilcServerHBContext hb_context;
unsigned char *id_string;
+ uint32 id_len;
SilcIDListData idata;
SILC_LOG_DEBUG(("Start"));
/* Send NEW_SERVER packet to the router. We will become registered
to the SILC network after sending this packet. */
id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
- packet = silc_buffer_alloc(2 + 2 + SILC_ID_SERVER_LEN +
- strlen(server->server_name));
+ id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+ packet = silc_buffer_alloc(2 + 2 + id_len + strlen(server->server_name));
silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
silc_buffer_format(packet,
- SILC_STR_UI_SHORT(SILC_ID_SERVER_LEN),
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_SERVER_LEN),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(id_string, id_len),
SILC_STR_UI_SHORT(strlen(server->server_name)),
SILC_STR_UI_XNSTRING(server->server_name,
strlen(server->server_name)),
SilcSocketConnection newsocket;
SilcServerKEInternalContext *proto_ctx;
int sock, port;
- void *config;
+ void *cconfig, *sconfig, *rconfig;
+ SilcServerConfigSectionDenyConnection *deny;
SILC_LOG_DEBUG(("Accepting new connection"));
later when outgoing data is available. */
SILC_REGISTER_CONNECTION_FOR_IO(sock);
+ SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
+ newsocket->ip));
+
+ port = server->sockets[fd]->port; /* Listenning port */
+
+ /* Check whether this connection is denied to connect to us. */
+ deny = silc_server_config_denied_conn(server->config, newsocket->ip, port);
+ if (!deny)
+ deny = silc_server_config_denied_conn(server->config, newsocket->hostname,
+ port);
+ if (deny) {
+ /* The connection is denied */
+ SILC_LOG_INFO(("Connection %s (%s) is denied",
+ newsocket->hostname, newsocket->ip));
+ silc_server_disconnect_remote(server, newsocket, deny->comment ?
+ deny->comment :
+ "Server closed connection: "
+ "Connection refused");
+ server->stat.conn_failures++;
+ return;
+ }
+
/* Check whether we have configred this sort of connection at all. We
have to check all configurations since we don't know what type of
connection this is. */
- port = server->sockets[fd]->port; /* Listenning port */
- if (!(config = silc_server_config_find_client_conn(server->config,
+ if (!(cconfig = silc_server_config_find_client_conn(server->config,
+ newsocket->ip, port)))
+ cconfig = silc_server_config_find_client_conn(server->config,
+ newsocket->hostname,
+ port);
+ if (!(sconfig = silc_server_config_find_server_conn(server->config,
+ newsocket->ip,
+ port)))
+ sconfig = silc_server_config_find_server_conn(server->config,
+ newsocket->hostname,
+ port);
+ if (!(rconfig = silc_server_config_find_router_conn(server->config,
newsocket->ip, port)))
- if (!(config = silc_server_config_find_client_conn(server->config,
- newsocket->hostname,
- port)))
- if (!(config = silc_server_config_find_server_conn(server->config,
- newsocket->ip,
- port)))
- if (!(config = silc_server_config_find_server_conn(server->config,
- newsocket->hostname,
- port)))
- if (!(config =
- silc_server_config_find_router_conn(server->config,
- newsocket->ip, port)))
- if (!(config =
- silc_server_config_find_router_conn(server->config,
- newsocket->hostname,
- port))) {
- silc_server_disconnect_remote(server, newsocket,
- "Server closed connection: "
- "Connection refused");
- server->stat.conn_failures++;
- return;
- }
+ rconfig = silc_server_config_find_router_conn(server->config,
+ newsocket->hostname,
+ port);
+ if (!cconfig && !sconfig && !rconfig) {
+ silc_server_disconnect_remote(server, newsocket,
+ "Server closed connection: "
+ "Connection refused");
+ server->stat.conn_failures++;
+ return;
+ }
/* 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->sock = newsocket;
proto_ctx->rng = server->rng;
proto_ctx->responder = TRUE;
- proto_ctx->config = config;
+ proto_ctx->cconfig = cconfig;
+ proto_ctx->sconfig = sconfig;
+ proto_ctx->rconfig = rconfig;
/* Prepare the connection for key exchange protocol. We allocate the
protocol but will not start it yet. The connector will be the
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"));
proto_ctx->responder = TRUE;
proto_ctx->dest_id_type = ctx->dest_id_type;
proto_ctx->dest_id = ctx->dest_id;
- proto_ctx->config = ctx->config;
+ proto_ctx->cconfig = ctx->cconfig;
+ proto_ctx->sconfig = ctx->sconfig;
+ proto_ctx->rconfig = ctx->rconfig;
/* Free old protocol as it is finished now */
silc_protocol_free(protocol);
and other information is created after we have received NEW_CLIENT
packet from client. */
client = silc_idlist_add_client(server->local_list,
- NULL, 0, NULL, NULL, NULL, NULL, sock);
+ NULL, NULL, NULL, NULL, NULL, sock);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to cache"));
silc_free(sock->user_data);
case SILC_SOCKET_TYPE_ROUTER:
{
SilcServerEntry new_server;
- SilcServerConfigSectionServerConnection *conn = ctx->config;
+ SilcServerConfigSectionServerConnection *conn =
+ sock->type == SILC_SOCKET_TYPE_SERVER ? ctx->sconfig : ctx->rconfig;
SILC_LOG_DEBUG(("Remote host is %s",
sock->type == SILC_SOCKET_TYPE_SERVER ?
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);
if (client && client->id) {
void *id = silc_id_str2id(packet->src_id, packet->src_id_len,
packet->src_id_type);
- if (SILC_ID_CLIENT_COMPARE(client->id, id)) {
+ if (!id || !SILC_ID_CLIENT_COMPARE(client->id, id)) {
silc_free(id);
goto out;
}
if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
packet->dst_id_type == SILC_ID_SERVER &&
sock->type != SILC_SOCKET_TYPE_CLIENT &&
- SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+ memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
/* Route the packet to fastest route for the destination ID */
void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
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."));
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);
}
if (notify && !server->standalone && server->router)
silc_server_send_notify_signoff(server, server->router->connection,
server->server_type == SILC_SERVER ?
- FALSE : TRUE, client->id,
- SILC_ID_CLIENT_LEN, signoff);
+ FALSE : TRUE, client->id, signoff);
/* Remove client from all channels */
if (notify)
/* Free all client entries that this server owns as they will
become invalid now as well. */
- silc_server_remove_clients_by_server(server, user_data, TRUE);
+ if (user_data->id)
+ silc_server_remove_clients_by_server(server, user_data, TRUE);
/* If this was our primary router connection then we're lost to
the outside world. */
silc_buffer_free(idp);
}
- if (silc_idcache_find_by_id(server->local_list->clients,
- SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
+ if (silc_idcache_get_all(server->local_list->clients, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
silc_idcache_list_free(list);
}
- if (silc_idcache_find_by_id(server->global_list->clients,
- SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
+ if (silc_idcache_get_all(server->global_list->clients, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
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,
int silc_server_channel_has_global(SilcChannelEntry channel)
{
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
if (chl->client->router)
return TRUE;
}
int silc_server_channel_has_local(SilcChannelEntry channel)
{
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
if (!chl->client->router)
return TRUE;
}
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
SilcBuffer clidp;
SILC_LOG_DEBUG(("Start"));
/* Remove the client from all channels. The client is removed from
the channels' user list. */
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+ 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_list_del(client->channels, chl);
+ silc_hash_table_del(client->channels, channel);
/* Remove channel if there is no users anymore */
if (server->server_type == SILC_ROUTER &&
- silc_list_count(channel->user_list) < 2) {
- server->stat.my_channels--;
-
+ 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;
-
- channel->id = NULL;
-
- silc_list_start(channel->user_list);
- while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- silc_list_del(chl2->client->channels, chl2);
- silc_list_del(channel->user_list, chl2);
- silc_free(chl2);
- }
- continue;
- }
-
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_list_del(channel->user_list, chl);
+ silc_hash_table_del(channel->user_list, chl->client);
silc_free(chl);
server->stat.my_chanclients--;
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
- server->stat.my_channels--;
-
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_list_start(channel->user_list);
- while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- silc_list_del(chl2->client->channels, chl2);
- silc_list_del(channel->user_list, chl2);
+ 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;
}
SilcClientEntry client,
int notify)
{
- SilcChannelEntry ch;
SilcChannelClientEntry chl;
SilcBuffer clidp;
SILC_LOG_DEBUG(("Start"));
- clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ /* Get the entry to the channel, if this client is not on the channel
+ then return Ok. */
+ if (!silc_hash_table_find(client->channels, channel, NULL, (void *)&chl))
+ return TRUE;
/* Remove the client from the channel. The client is removed from
the channel's user list. */
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
- if (chl->channel != channel)
- continue;
-
- ch = chl->channel;
- /* Remove channel from client's channel list */
- silc_list_del(client->channels, chl);
-
- /* Remove channel if there is no users anymore */
- if (server->server_type == SILC_ROUTER &&
- silc_list_count(channel->user_list) < 2) {
- if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
- silc_buffer_free(clidp);
- server->stat.my_channels--;
- return FALSE;
- }
-
- /* Remove client from channel's client list */
- silc_list_del(channel->user_list, chl);
- silc_free(chl);
- 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))
- 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)) {
- /* Notify about leaving client if this channel has global users. */
- if (notify && channel->global_users)
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_LEAVE, 1,
- clidp->data, clidp->len);
-
- server->stat.my_channels--;
- silc_buffer_free(clidp);
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- if (channel->rekey)
- silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+ /* Remove channel from client's channel list */
+ silc_hash_table_del(client->channels, chl->channel);
- if (channel->founder_key) {
- /* The founder auth data exists, do not remove the channel entry */
- SilcChannelClientEntry chl2;
+ /* 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 (!silc_idlist_del_channel(server->local_list, channel))
+ silc_idlist_del_channel(server->global_list, channel);
+ silc_buffer_free(clidp);
+ server->stat.my_channels--;
+ return FALSE;
+ }
- channel->id = NULL;
+ /* 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. */
+ if (server->server_type == SILC_SERVER &&
+ !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)) {
+ /* Notify about leaving client if this channel has global users. */
+ if (notify && channel->global_users)
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_LEAVE, 1,
+ clidp->data, clidp->len);
+
+ silc_buffer_free(clidp);
+
+ if (channel->rekey)
+ silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
- silc_list_start(channel->user_list);
- while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- silc_list_del(chl2->client->channels, chl2);
- silc_list_del(channel->user_list, chl2);
- silc_free(chl2);
- }
- return FALSE;
+ 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);
}
-
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
return FALSE;
}
- /* Send notify to channel about client leaving the channel */
- if (notify)
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_LEAVE, 1,
- clidp->data, clidp->len);
- break;
+ /* 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--;
+ return FALSE;
}
+ /* Send notify to channel about client leaving the channel */
+ if (notify)
+ silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+ SILC_NOTIFY_TYPE_LEAVE, 1,
+ clidp->data, clidp->len);
+
silc_buffer_free(clidp);
return TRUE;
}
int silc_server_client_on_channel(SilcClientEntry client,
SilcChannelEntry channel)
{
- SilcChannelClientEntry chl;
-
if (!client || !channel)
return FALSE;
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END)
- if (chl->channel == channel)
- return TRUE;
+ if (silc_hash_table_find(client->channels, channel, NULL, NULL))
+ return TRUE;
return FALSE;
}
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;
}
to our primary route. */
if (broadcast && server->standalone == FALSE)
silc_server_send_new_channel(server, server->router->connection, TRUE,
- channel_name, entry->id, SILC_ID_CHANNEL_LEN,
+ channel_name, entry->id,
+ silc_id_get_len(entry->id, SILC_ID_CHANNEL),
entry->mode);
server->stat.my_channels++;
to our primary route. */
if (broadcast && server->standalone == FALSE)
silc_server_send_new_channel(server, server->router->connection, TRUE,
- channel_name, entry->id, SILC_ID_CHANNEL_LEN,
+ channel_name, entry->id,
+ silc_id_get_len(entry->id, SILC_ID_CHANNEL),
entry->mode);
server->stat.my_channels++;
SilcBuffer idp;
/* Go through all clients in the list */
- if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
- SILC_ID_SERVER, &list)) {
+ if (silc_idcache_get_all(id_list->servers, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
entry = (SilcServerEntry)id_cache->context;
SilcBuffer idp;
/* Go through all clients in the list */
- if (silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
- SILC_ID_CLIENT, &list)) {
+ if (silc_idcache_get_all(id_list->clients, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
}
static SilcBuffer
-silc_server_announce_encode_join(uint32 argc, ...)
+silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
{
va_list ap;
va_start(ap, argc);
- return silc_notify_payload_encode(SILC_NOTIFY_TYPE_JOIN, argc, ap);
+ return silc_notify_payload_encode(notify, argc, ap);
}
/* Returns assembled packets for channel users of the `channel'. */
void silc_server_announce_get_channel_users(SilcServer server,
SilcChannelEntry channel,
- SilcBuffer *channel_users)
+ SilcBuffer *channel_users,
+ SilcBuffer *channel_users_modes)
{
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
SilcBuffer chidp, clidp;
SilcBuffer tmp;
int len;
+ unsigned char mode[4];
SILC_LOG_DEBUG(("Start"));
/* Now find all users on the channel */
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
- tmp = silc_server_announce_encode_join(2, clidp->data, clidp->len,
- chidp->data, chidp->len);
+
+ /* JOIN Notify */
+ tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2,
+ clidp->data, clidp->len,
+ chidp->data, chidp->len);
len = tmp->len;
*channel_users =
silc_buffer_realloc(*channel_users,
silc_buffer_put(*channel_users, tmp->data, tmp->len);
silc_buffer_pull(*channel_users, len);
- silc_buffer_free(clidp);
silc_buffer_free(tmp);
+
+ /* CUMODE notify for mode change on the channel */
+ SILC_PUT32_MSB(chl->mode, mode);
+ tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CUMODE_CHANGE,
+ 3, clidp->data, clidp->len,
+ mode, 4,
+ clidp->data, clidp->len);
+ len = tmp->len;
+ *channel_users_modes =
+ silc_buffer_realloc(*channel_users_modes,
+ (*channel_users_modes ?
+ (*channel_users_modes)->truelen + len : len));
+ silc_buffer_pull_tail(*channel_users_modes,
+ ((*channel_users_modes)->end -
+ (*channel_users_modes)->data));
+
+ silc_buffer_put(*channel_users_modes, tmp->data, tmp->len);
+ silc_buffer_pull(*channel_users_modes, len);
+ silc_buffer_free(tmp);
+
+ silc_buffer_free(clidp);
}
silc_buffer_free(chidp);
}
void silc_server_announce_get_channels(SilcServer server,
SilcIDList id_list,
SilcBuffer *channels,
- SilcBuffer *channel_users)
+ SilcBuffer *channel_users,
+ SilcBuffer **channel_users_modes,
+ uint32 *channel_users_modes_c,
+ SilcChannelID ***channel_ids)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
SilcChannelEntry channel;
unsigned char *cid;
+ uint32 id_len;
uint16 name_len;
int len;
+ int i = *channel_users_modes_c;
SILC_LOG_DEBUG(("Start"));
/* Go through all channels in the list */
- if (silc_idcache_find_by_id(id_list->channels, SILC_ID_CACHE_ANY,
- SILC_ID_CHANNEL, &list)) {
+ if (silc_idcache_get_all(id_list->channels, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
channel = (SilcChannelEntry)id_cache->context;
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 + SILC_ID_CHANNEL_LEN + 4;
+ len = 4 + name_len + id_len + 4;
*channels =
silc_buffer_realloc(*channels,
(*channels ? (*channels)->truelen + len : len));
SILC_STR_UI_SHORT(name_len),
SILC_STR_UI_XNSTRING(channel->channel_name,
name_len),
- SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_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) *
+ (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);
-
- silc_free(cid);
+ channel_users,
+ 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;
+ 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);
+ &channels, &channel_users,
+ &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);
+ &channels, &channel_users,
+ &channel_users_modes,
+ &channel_users_modes_c,
+ &channel_ids);
if (channels) {
silc_buffer_push(channels, channels->data - channels->head);
silc_buffer_free(channel_users);
}
+
+ if (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);
+ }
}
/* Failure timeout callback. If this is called then we will immediately
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);
uint32 *user_count)
{
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
SilcBuffer idp;
uint32 list_count = 0;
- client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
- silc_list_count(channel->user_list));
- client_mode_list = silc_buffer_alloc(4 *
- silc_list_count(channel->user_list));
+ /* XXX rewrite - this does not support IPv6 based Client ID's. */
+
+ client_id_list =
+ silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
+ silc_hash_table_count(channel->user_list));
+ 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_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
/* Client ID */
idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
silc_buffer_put(client_id_list, idp->data, idp->len);
SILC_GET32_MSB(mode, mode_list->data);
silc_buffer_pull(mode_list, 4);
- if (noadd && !SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
+ if (noadd && SILC_ID_CLIENT_COMPARE(client_id, noadd)) {
silc_free(client_id);
continue;
}
/* We don't have that client anywhere, add it. The client is added
to global list since server didn't have it in the lists so it must be
global. */
- client = silc_idlist_add_client(server->global_list, NULL, 0, NULL,
- NULL,
+ client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
chl->client = client;
chl->mode = mode;
chl->channel = channel;
- silc_list_add(channel->user_list, chl);
- silc_list_add(client->channels, chl);
+ silc_hash_table_add(channel->user_list, chl->client, chl);
+ silc_hash_table_add(client->channels, chl->channel, chl);
}
}
}
SilcBuffer buffer = NULL;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
+ SilcHashTableList htl;
unsigned char *cid;
+ uint32 id_len;
uint16 name_len;
int len;
- silc_list_start(client->channels);
- while ((chl = silc_list_get(client->channels)) != SILC_LIST_END) {
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
channel = chl->channel;
if (channel->mode & SILC_CHANNEL_MODE_SECRET)
continue;
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 + SILC_ID_CHANNEL_LEN + 4;
+ len = 4 + name_len + id_len + 4;
buffer = silc_buffer_realloc(buffer,
(buffer ? (buffer)->truelen + len : len));
silc_buffer_pull_tail(buffer, ((buffer)->end - (buffer)->data));
SILC_STR_UI_SHORT(name_len),
SILC_STR_UI_XNSTRING(channel->channel_name,
name_len),
- SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(cid, id_len),
SILC_STR_UI_INT(chl->mode), /* Client's mode */
SILC_STR_END);
silc_buffer_pull(buffer, len);
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)