Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2003 Pekka Riikonen
+ Copyright (C) 1997 - 2005 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
SILC_TASK_CALLBACK(silc_server_timeout_remote);
SILC_TASK_CALLBACK(silc_server_channel_key_rekey);
SILC_TASK_CALLBACK(silc_server_get_stats);
+SILC_TASK_CALLBACK(silc_server_connect_router);
/* Allocates a new SILC server object. This has to be done before the server
can be used. After allocation one must call silc_server_init to initialize
if (list)
silc_idcache_list_free(list);
+ if (server->pk_hash)
+ silc_hash_table_free(server->pk_hash);
+
/* Delete all clients */
list = NULL;
if (silc_idcache_get_all(server->local_list->clients, &list) &&
if (list)
silc_idcache_list_free(list);
+
/* Delete all servers */
list = NULL;
if (silc_idcache_get_all(server->local_list->servers, &list) &&
silc_idcache_free(server->global_list->servers);
silc_idcache_free(server->global_list->channels);
silc_hash_table_free(server->watcher_list);
+ silc_hash_table_free(server->watcher_list_pk);
silc_hash_free(server->md5hash);
silc_hash_free(server->sha1hash);
/* Initialize ID caches */
server->local_list->clients =
- 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);
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+ FALSE, TRUE);
+ server->local_list->servers =
+ silc_idcache_alloc(0, SILC_ID_SERVER, NULL, FALSE, TRUE);
+ server->local_list->channels =
+ silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, FALSE, TRUE);
/* 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_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);
-
- /* Init watcher list */
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_idlist_client_destructor,
+ FALSE, TRUE);
+ server->global_list->servers =
+ silc_idcache_alloc(0, SILC_ID_SERVER, NULL, FALSE, TRUE);
+ server->global_list->channels =
+ silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL, FALSE, TRUE);
+
+ /* Init watcher lists */
server->watcher_list =
silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
NULL, NULL, TRUE);
if (!server->watcher_list)
goto err;
+ server->watcher_list_pk =
+ silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL,
+ NULL, NULL, TRUE);
+ if (!server->watcher_list_pk)
+ goto err;
+
+ /* Init public key list */
+ server->pk_hash =
+ silc_hash_table_alloc(0, silc_hash_public_key, NULL,
+ silc_hash_public_key_compare, NULL,
+ NULL, NULL, TRUE);
+
+ if (!server->pk_hash)
+ goto err;
/* Create a listening server */
if (!silc_server_listen(server,
/* Fix the server_name field */
if (strcmp(server->server_name, newconfig->server_info->server_name)) {
silc_free(server->server_name);
- server->server_name = newconfig->server_info->server_name;
- newconfig->server_info->server_name = NULL;
+
+ /* Check server name */
+ server->server_name =
+ silc_identifier_check(newconfig->server_info->server_name,
+ strlen(newconfig->server_info->server_name),
+ SILC_STRING_LOCALE, 256, NULL);
+ if (!server->server_name) {
+ SILC_LOG_ERROR(("Malformed server name string '%s'",
+ server->config->server_info->server_name));
+ return FALSE;
+ }
/* Update the idcache list with a fresh pointer */
silc_free(server->id_entry->server_name);
server->id_entry))
return FALSE;
if (!silc_idcache_add(server->local_list->servers,
- server->id_entry->server_name,
+ strdup(server->id_entry->server_name),
server->id_entry->id, server->id_entry, 0, NULL))
return FALSE;
}
if (server->config->debug_string) {
silc_debug = TRUE;
silc_log_set_debug_string(server->config->debug_string);
- } else {
- silc_debug = FALSE;
}
#endif /* SILC_DEBUG */
} else {
silc_socket_free(server->sockets[i]);
server->sockets[i] = NULL;
+ server->stat.conn_num--;
}
}
}
sconn->retry_count++;
sconn->retry_timeout = sconn->retry_timeout +
- silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER;
+ (silc_rng_get_rn32(server->rng) % SILC_SERVER_RETRY_RANDOMIZER);
/* If we've reached max retry count, give up. */
if ((sconn->retry_count > param->reconnect_count) &&
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
+/* Callback for async connection to remote router */
+
+SILC_TASK_CALLBACK(silc_server_connection_established)
+{
+ SilcServer server = app_context;
+ SilcServerConnection sconn = (SilcServerConnection)context;
+ int sock = fd;
+ int opt = EINVAL, optlen = sizeof(opt), ret;
+
+ ret = silc_net_get_socket_opt(sock, SOL_SOCKET, SO_ERROR, &opt, &optlen);
+
+ silc_schedule_task_del_by_fd(server->schedule, sock);
+ silc_schedule_unset_listen_fd(server->schedule, sock);
+
+ if (ret != 0 || opt != 0) {
+ SILC_LOG_ERROR(("Could not connect to router %s:%d: %s",
+ sconn->remote_host, sconn->remote_port, strerror(opt)));
+ silc_net_close_connection(sock);
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router_retry,
+ context, 1, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ } else {
+ silc_server_config_unref(&sconn->conn);
+ silc_free(sconn->remote_host);
+ silc_free(sconn->backup_replace_ip);
+ silc_free(sconn);
+ }
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Connection to router %s:%d established", sconn->remote_host,
+ sconn->remote_port));
+
+ /* Continue with key exchange protocol */
+ silc_server_start_key_exchange(server, sconn, sock);
+}
+
/* Generic routine to use connect to a router. */
SILC_TASK_CALLBACK(silc_server_connect_router)
silc_server_config_ref(&sconn->conn, server->config, (void *)rconn);
/* Connect to remote host */
- sock = silc_net_create_connection(
+ sock = silc_net_create_connection_async(
(!server->config->server_info->primary ? NULL :
server->config->server_info->primary->server_ip),
sconn->remote_port, sconn->remote_host);
if (sock < 0) {
SILC_LOG_ERROR(("Could not connect to router %s:%d",
sconn->remote_host, sconn->remote_port));
- if (!sconn->no_reconnect)
+ if (!sconn->no_reconnect) {
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router_retry,
- context, 0, 1, SILC_TASK_TIMEOUT,
+ context, 1, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
- else {
+ } else {
silc_server_config_unref(&sconn->conn);
silc_free(sconn->remote_host);
silc_free(sconn->backup_replace_ip);
return;
}
- /* Continue with key exchange protocol */
- silc_server_start_key_exchange(server, sconn, sock);
+ /* wait for the connection to be established */
+ silc_schedule_task_add(server->schedule, sock,
+ silc_server_connection_established,
+ context, 0, 0, SILC_TASK_FD,
+ SILC_TASK_PRI_NORMAL);
+ silc_schedule_set_listen_fd(server->schedule, sock,
+ SILC_TASK_WRITE, FALSE);
}
/* This function connects to our primary router or if we are a router this
if (!sconn->no_reconnect) {
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router_retry,
- sconn, 0, 1, SILC_TASK_TIMEOUT,
+ sconn, 1, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
return;
}
if (!sconn->no_reconnect) {
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router_retry,
- sconn, 0, 1, SILC_TASK_TIMEOUT,
+ sconn, 1, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
return;
}
if (!sconn->no_reconnect) {
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_to_router_retry,
- sconn, 0, 1, SILC_TASK_TIMEOUT,
+ sconn, 1, 0, SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
goto out2;
}
sock->ip));
/* Listenning port */
- if (!server->sockets[(SilcUInt32)proto_ctx->context]) {
+ if (!server->sockets[SILC_PTR_TO_32(proto_ctx->context)]) {
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_RESOURCE_LIMIT,
"Connection refused");
silc_free(proto_ctx);
return;
}
- port = server->sockets[(SilcUInt32)proto_ctx->context]->port;
+ port = server->sockets[SILC_PTR_TO_32(proto_ctx->context)]->port;
/* Check whether this connection is denied to connect to us. */
deny = silc_server_config_find_denied(server, sock->ip);
silc_net_close_connection(sock);
return;
}
+ server->stat.conn_num++;
/* Set socket options */
silc_net_set_socket_nonblock(sock);
is accepted further. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = server;
- proto_ctx->context = (void *)fd;
+ proto_ctx->context = SILC_32_TO_PTR(fd);
silc_socket_host_lookup(newsocket, TRUE,
silc_server_accept_new_connection_lookup,
(void *)proto_ctx, server->schedule);
silc_free(sock->user_data);
server->stat.auth_failures++;
- /* From here on, wait 10 seconds for the backup router to appear. */
+ /* From here on, wait 20 seconds for the backup router to appear. */
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_router_wait,
- (void *)server, 10, 0,
+ (void *)server, 20, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
goto out;
}
client->mode |= SILC_UMODE_ANONYMOUS;
}
+ /* Add public key to hash list (for whois using attributes) */
+ if (!silc_hash_table_find_by_context(server->pk_hash,
+ entry->data.public_key,
+ client, NULL))
+ silc_hash_table_add(server->pk_hash,
+ entry->data.public_key, client);
+
id_entry = (void *)client;
break;
}
silc_free(sock->user_data);
server->stat.auth_failures++;
- /* From here on, wait 10 seconds for the backup router to appear. */
+ /* From here on, wait 20 seconds for the backup router to appear. */
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_router_wait,
- (void *)server, 10, 0,
+ (void *)server, 20, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
goto out;
}
/* Remove the backup waiting with timeout */
silc_schedule_task_add(server->schedule, 0,
silc_server_backup_router_wait,
- (void *)server, 5, 0,
+ (void *)server, 10, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
/* Statistics */
if (ctx->conn_type == SILC_SOCKET_TYPE_SERVER) {
server->stat.my_servers++;
+ server->stat.servers++;
} else {
server->stat.my_routers++;
server->stat.routers++;
}
- server->stat.servers++;
/* Check whether this connection is to be our primary router connection
if we do not already have the primary route. */
/* Do not send data to disconnected connection */
if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
+ SILC_SET_CONNECTION_FOR_INPUT(server->schedule, fd);
+ SILC_UNSET_OUTBUF_PENDING(sock);
+ silc_buffer_clear(sock->outbuf);
return;
}
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
"Router")));
- if (sock->user_data)
+ if (sock->user_data) {
+ /* If backup then mark that resuming will not be allowed */
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ SilcServerEntry server_entry = sock->user_data;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
+
silc_server_free_sock_user_data(server, sock, NULL);
+ }
SILC_SET_DISCONNECTING(sock);
silc_server_close_connection(server, sock);
}
sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
"Router"), strerror(errno)));
- if (sock->user_data)
+ if (sock->user_data) {
+ /* If backup then mark that resuming will not be allowed */
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ SilcServerEntry server_entry = sock->user_data;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
+
silc_server_free_sock_user_data(server, sock, NULL);
+ }
SILC_SET_DISCONNECTING(sock);
silc_server_close_connection(server, sock);
}
if (sock->user_data) {
char tmp[128];
- /* If backup disconnected then mark that resuming willl not be allowed */
+ /* If backup disconnected then mark that resuming will not be allowed */
if (server->server_type == SILC_ROUTER && !server->backup_router &&
sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
SilcServerEntry server_entry = sock->user_data;
if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
server->backup_noswitch = TRUE;
- if (sock->user_data)
+ if (sock->user_data) {
+ /* If we are router and backup errorred then mark that resuming
+ will not be allowed */
+ if (server->server_type == SILC_ROUTER && !server->backup_router &&
+ sock->type == SILC_SOCKET_TYPE_SERVER) {
+ SilcServerEntry server_entry = sock->user_data;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
+
silc_server_free_sock_user_data(server, sock, NULL);
+ }
SILC_SET_DISCONNECTING(sock);
silc_server_close_connection(server, sock);
}
SilcIDListData idata = (SilcIDListData)sock->user_data;
int ret;
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Connection is disconnected"));
+ goto out;
+ }
+
server->stat.packets_received++;
/* Parse the packet */
/* If entry is disabled ignore what we got. */
if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
- ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) {
- SILC_LOG_DEBUG(("Connection is disabled"));
+ ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE &&
+ ret != SILC_PACKET_KEY_EXCHANGE_1 && ret != SILC_PACKET_KEY_EXCHANGE_2) {
+ SILC_LOG_DEBUG(("Connection is disabled (packet %s dropped)",
+ silc_get_packet_name(ret)));
goto out;
}
packet->dst_id_type == SILC_ID_SERVER &&
sock->type != SILC_SOCKET_TYPE_CLIENT &&
memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
+ SilcSocketConnection conn;
/* Route the packet to fastest route for the destination ID */
void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
packet->dst_id_type);
if (!id)
goto out;
- silc_server_packet_route(server,
- silc_server_route_get(server, id,
- packet->dst_id_type),
- packet);
+
+ conn = silc_server_route_get(server, id, packet->dst_id_type);
+ if (!conn) {
+ SILC_LOG_WARNING(("Packet to unknown server ID %s, dropped (no route)",
+ silc_id_render(id, SILC_ID_SERVER)));
+ goto out;
+ }
+
+ silc_server_packet_route(server, conn, packet);
silc_free(id);
goto out;
}
silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
parser_context);
+ if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+ SILC_LOG_DEBUG(("Connection is disconnected"));
+ return FALSE;
+ }
+
/* Reprocess data since we'll return FALSE here. This is because
the idata->receive_key might have become valid in the last packet
and we want to call this processor with valid cipher. */
silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
parser_context);
break;
- default:
- return TRUE;
}
return TRUE;
/* Do not switch to backup in case of error */
server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
- /* If backup disconnected then mark that resuming willl not be allowed */
+ /* If backup disconnected then mark that resuming will not be allowed */
if (server->server_type == SILC_ROUTER && !server->backup_router &&
sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
SilcServerEntry server_entry = sock->user_data;
/* Close the actual connection */
silc_net_close_connection(sock->sock);
server->sockets[sock->sock] = NULL;
+ server->stat.conn_num--;
/* We won't listen for this connection anymore */
silc_schedule_task_del_by_fd(server->schedule, sock->sock);
"Router"), tmp[0] ? tmp : ""));
SILC_SET_DISCONNECTED(sock);
+ silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
silc_schedule_task_add(server->schedule, sock->sock,
silc_server_close_connection_final,
(void *)sock, 0, 1, SILC_TASK_TIMEOUT,
/* Remove this client from watcher list if it is */
silc_server_del_from_watcher_list(server, client);
+ /* Remove this client from the public key hash list */
+ if (client->data.public_key)
+ silc_hash_table_del_by_context(server->pk_hash,
+ client->data.public_key, client);
+
/* Update statistics */
server->stat.my_clients--;
server->stat.clients--;
if (!server->server_shutdown) {
silc_schedule_task_add(server->schedule, 0,
silc_server_free_client_data_timeout,
- client, 300, 0,
+ client, 600, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute_final(sock->protocol, server->schedule);
sock->protocol = NULL;
+ if (!sock->user_data)
+ return;
}
switch (sock->type) {
silc_idlist_del_server(server->global_list, user_data);
if (sock->type == SILC_SOCKET_TYPE_SERVER) {
server->stat.my_servers--;
+ server->stat.servers--;
} else {
server->stat.my_routers--;
server->stat.routers--;
}
- server->stat.servers--;
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers--;
break;
continue;
}
- if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED) &&
- !client->connection && !client->router && !SILC_IS_LOCAL(client)) {
+ if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ continue;
+ }
+ if (!client->connection && !client->router) {
if (!silc_idcache_list_next(list, &id_cache))
break;
continue;
type = silc_hash_table_count(channel->invite_list);
SILC_PUT16_MSB(type, list->data);
silc_hash_table_list(channel->invite_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+ while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
type);
silc_hash_table_list_reset(&htl);
type = silc_hash_table_count(channel->ban_list);
SILC_PUT16_MSB(type, list->data);
silc_hash_table_list(channel->ban_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+ while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
type);
silc_hash_table_list_reset(&htl);
SilcBuffer chidp, clidp, csidp;
SilcBuffer tmp, fkey = NULL, chpklist;
int len;
- unsigned char mode[4];
+ unsigned char mode[4], ulimit[4];
char *hmac;
SILC_LOG_DEBUG(("Start"));
/* CMODE notify */
SILC_PUT32_MSB(channel->mode, mode);
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+ SILC_PUT32_MSB(channel->user_limit, ulimit);
hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
if (channel->founder_key)
fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
tmp =
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
- 7, csidp->data, csidp->len,
+ 8, csidp->data, csidp->len,
mode, sizeof(mode),
NULL, 0,
hmac, hmac ? strlen(hmac) : 0,
fkey ? fkey->data : NULL,
fkey ? fkey->len : 0,
chpklist ? chpklist->data : NULL,
- chpklist ? chpklist->len : 0);
+ chpklist ? chpklist->len : 0,
+ (channel->mode &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ ulimit : NULL),
+ (channel->mode &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ sizeof(ulimit) : 0));
len = tmp->len;
*channel_modes =
silc_buffer_realloc(*channel_modes,
silc_free(channel_ids);
}
+/* Announces WATCH list. */
+
+void silc_server_announce_watches(SilcServer server,
+ SilcSocketConnection remote)
+{
+ SilcHashTableList htl;
+ SilcBuffer buffer, idp, args, pkp;
+ SilcClientEntry client;
+ void *key;
+
+ SILC_LOG_DEBUG(("Announcing watch list"));
+
+ /* XXX because way we save the nicks (hash) we cannot announce them. */
+
+ /* XXX we should send all public keys in one command if client is
+ watching more than one key */
+ silc_hash_table_list(server->watcher_list_pk, &htl);
+ while (silc_hash_table_get(&htl, &key, (void *)&client)) {
+ if (!client || !client->id)
+ continue;
+
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ args = silc_buffer_alloc_size(2);
+ silc_buffer_format(args,
+ SILC_STR_UI_SHORT(1),
+ SILC_STR_END);
+ pkp = silc_pkcs_public_key_payload_encode(key);
+ args = silc_argument_payload_encode_one(args, pkp->data, pkp->len, 0x00);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
+ ++server->cmd_ident, 2,
+ 1, idp->data, idp->len,
+ 4, args->data, args->len);
+
+ /* Send command */
+ silc_server_packet_send(server, remote, SILC_PACKET_COMMAND, 0,
+ buffer->data, buffer->len, TRUE);
+
+ silc_buffer_free(pkp);
+ silc_buffer_free(args);
+ silc_buffer_free(idp);
+ silc_buffer_free(buffer);
+ }
+ silc_hash_table_list_reset(&htl);
+}
+
/* Assembles user list and users mode list from the `channel'. */
bool silc_server_get_users_on_channel(SilcServer server,
are no part of the list. */
if (ht) {
silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
if (!silc_hash_table_find(ht, chl->channel, NULL, NULL)) {
silc_hash_table_del(chl->channel->user_list, chl->client);
silc_hash_table_del(chl->client->channels, chl->channel);
silc_hash_table_free(ht);
} else {
silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
silc_hash_table_del(chl->channel->user_list, chl->client);
silc_hash_table_del(chl->client->channels, chl->channel);
silc_free(chl);
dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
silc_free(id);
- if (idata)
+ if (idata && dst_sock)
*idata = (SilcIDListData)dst_sock->user_data;
return dst_sock;
}
silc_ske_free(ctx->ske);
silc_socket_free(sock);
silc_free(ctx);
+
+ /* Disconnect since we failed to rekey, the keys are probably wrong. */
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+
+ /* Reconnect */
+ if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+ silc_server_create_connections(server);
}
/* A timeout callback for the re-key. We will be the initiator of the
silc_schedule_task_add(server->schedule, sock->sock,
silc_server_rekey_timeout,
proto_ctx,
- server->config->key_exchange_timeout, 0,
+ (idata->rekey->timeout >
+ server->config->key_exchange_timeout ?
+ idata->rekey->timeout :
+ server->config->key_exchange_timeout * 4), 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_LOW);
silc_free(ctx);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
/* Reconnect */
if (sock->type != SILC_SOCKET_TYPE_CLIENT)