Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2009 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
SilcServer server = callback_context;
SilcIDListData idata = silc_packet_get_context(stream);
- SILC_LOG_DEBUG(("End of stream received"));
+ SILC_LOG_DEBUG(("End of stream received, sock %p", stream));
if (!idata)
return;
if (server->router_conn && server->router_conn->sock == stream &&
!server->router && server->standalone) {
+ if (idata->sconn && idata->sconn->callback)
+ (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
silc_server_create_connections(server);
+ silc_server_free_sock_user_data(server, stream, NULL);
} else {
/* If backup disconnected then mark that resuming will not be allowed */
if (server->server_type == SILC_ROUTER && !server->backup_router &&
server->backup_closed = TRUE;
}
+ if (idata->sconn && idata->sconn->callback)
+ (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
silc_server_free_sock_user_data(server, stream, NULL);
}
SilcPacketStream stream = context;
SilcIDListData idata = silc_packet_get_context(stream);
- if (!idata)
+ if (!idata || !silc_packet_stream_is_valid(stream)) {
+ silc_packet_stream_unref(stream);
return;
+ }
if (server->router_conn && server->router_conn->sock == stream &&
!server->router && server->standalone) {
+ if (idata->sconn && idata->sconn->callback)
+ (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
silc_server_create_connections(server);
+ silc_server_free_sock_user_data(server, stream, NULL);
} else {
/* If backup disconnected then mark that resuming will not be allowed */
if (server->server_type == SILC_ROUTER && !server->backup_router &&
server->backup_closed = TRUE;
}
+ if (idata->sconn && idata->sconn->callback)
+ (*idata->sconn->callback)(server, NULL, idata->sconn->callback_context);
silc_server_free_sock_user_data(server, stream, NULL);
}
silc_server_close_connection(server, stream);
+
+ /* Release our stream reference */
+ silc_packet_stream_unref(stream);
}
/* Packet engine callback to indicate error */
const char *ip;
SilcUInt16 port;
+ SILC_LOG_DEBUG(("Packet error %d, sock %p", error, stream));
+
if (!idata || !sock)
return;
SILC_CONNTYPE_STRING(idata->conn_type),
silc_packet_error_string(error)));
+ if (!silc_packet_stream_is_valid(stream))
+ return;
+
+ /* We must take reference of the stream */
+ silc_packet_stream_ref(stream);
+
+ /* In case we get here many times, register only one timeout */
+ silc_schedule_task_del_by_all(server->schedule, 0,
+ silc_server_packet_error_timeout, stream);
+
+ /* Close connection with random timeout */
silc_schedule_task_add_timeout(server->schedule,
- silc_server_packet_error_timeout,
- stream, 0, 0);
+ silc_server_packet_error_timeout, stream,
+ silc_rng_get_byte(server->rng) % 10, 0);
}
/* Packet stream callbacks */
{
SilcPacketType type = packet->type;
SilcIDListData idata = silc_packet_get_context(sock);
+#ifdef SILC_DEBUG
+ const char *ip;
+ SilcUInt16 port;
- SILC_LOG_DEBUG(("Received %s packet [flags %d]",
- silc_get_packet_name(type), packet->flags));
+ silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+ NULL, NULL, &ip, &port);
+#endif /* SILC_DEBUG */
+
+ SILC_LOG_DEBUG(("Received %s packet [flags %d] from %s:%d",
+ silc_get_packet_name(type), packet->flags, ip, port));
/* Parse the packet type */
switch (type) {
silc_free(server->local_list);
silc_free(server->global_list);
silc_free(server->server_name);
+ silc_free(server->id);
silc_free(server);
silc_hmac_unregister_all();
silc_dlist_start(server->expired_clients);
while ((client = silc_dlist_get(server->expired_clients))) {
- if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
- continue;
-
/* For unregistered clients the created timestamp is actually
unregistered timestamp. Make sure client remains in history
at least 500 seconds. */
- if (curtime - client->data.created < 500)
+ if (client->data.created && curtime - client->data.created < 500)
continue;
id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
void silc_server_connection_free(SilcServerConnection sconn)
{
+ if (!sconn)
+ return;
SILC_LOG_DEBUG(("Free connection %p", sconn));
silc_dlist_del(sconn->server->conns, sconn);
silc_server_config_unref(&sconn->conn);
sconn->no_conf = dynamic;
sconn->server = server;
- SILC_LOG_DEBUG(("Created connection %p", sconn));
+ SILC_LOG_DEBUG(("Created connection %p to %s:%d", sconn,
+ remote_host, port));
silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
sconn, 0, 0);
SilcID remote_id;
const char *ip;
- SILC_LOG_DEBUG(("Connection authentication completed"));
+ SILC_LOG_DEBUG(("Connection %p authentication completed, entry %p",
+ sconn, entry));
- sconn->op = NULL;
+ entry->op = NULL;
if (success == FALSE) {
/* Authentication failed */
- /* XXX retry connecting */
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
return;
}
strdup(sconn->remote_host),
SILC_SERVER, NULL, NULL, sconn->sock);
if (!id_entry) {
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
- silc_free(entry);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
return;
}
SILC_STR_DATA(server->server_name,
strlen(server->server_name)),
SILC_STR_END)) {
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
- silc_free(entry);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
return;
}
SILC_ID_SERVER),
NULL, sconn->sock);
if (!id_entry) {
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
- silc_free(entry);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
return;
}
idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
SILC_IDLIST_STATUS_LOCAL);
idata->sconn = sconn;
+ idata->sconn->callback = NULL;
/* Statistics */
server->stat.my_routers++;
silc_server_backup_add(server, server->id_entry, ip,
sconn->remote_port, TRUE);
}
+ }
#if 0
- } else {
+ else {
/* We already have primary router. Disconnect this connection */
SILC_LOG_DEBUG(("We already have primary router, disconnect"));
silc_idlist_del_server(server->global_list, id_entry);
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
- silc_free(entry);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
return;
-#endif /* 0 */
}
+#endif /* 0 */
} else {
/* Add this server to be our backup router */
id_entry->server_type = SILC_BACKUP_ROUTER;
break;
default:
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_AUTH_FAILED, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
- silc_free(entry);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_AUTH_FAILED, NULL);
return;
}
{
SilcPacketStream sock = context;
SilcUnknownEntry entry = silc_packet_get_context(sock);
- SilcServerConnection sconn = silc_ske_get_context(ske);
- SilcServer server = entry->server;
- SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
+ SilcServerConnection sconn;
+ SilcServer server;
+ SilcServerConfigRouter *conn;
SilcAuthMethod auth_meth = SILC_AUTH_NONE;
void *auth_data = NULL;
SilcUInt32 auth_data_len = 0;
SilcConnAuth connauth;
SilcCipher send_key, receive_key;
SilcHmac hmac_send, hmac_receive;
- SilcHash hash;
- sconn->op = NULL;
+ server = entry->server;
+ sconn = entry->data.sconn;
+ conn = sconn->conn.ref_ptr;
+ entry->op = NULL;
+
+ SILC_LOG_DEBUG(("Connection %p, SKE completed, entry %p", sconn, entry));
if (status != SILC_SKE_STATUS_OK) {
/* SKE failed */
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
silc_ske_map_status(status), entry->hostname, entry->ip));
-
- /* XXX retry connecting */
silc_ske_free(ske);
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
return;
}
/* Set the keys into use. The data will be encrypted after this. */
if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
- &hmac_send, &hmac_receive, &hash)) {
+ &hmac_send, &hmac_receive, NULL)) {
+ silc_ske_free(ske);
- /* XXX retry connecting */
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
/* Error setting keys */
- silc_ske_free(ske);
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
return;
}
silc_packet_set_keys(sconn->sock, send_key, receive_key, hmac_send,
connauth = silc_connauth_alloc(server->schedule, ske,
server->config->conn_auth_timeout);
if (!connauth) {
- /* XXX retry connecting */
+ silc_ske_free(ske);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
/** Error allocating auth protocol */
- silc_ske_free(ske);
- silc_server_disconnect_remote(server, sconn->sock,
- SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
+ silc_server_disconnect_remote(server, sconn->sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
return;
}
entry->data.rekey = rekey;
/* Start connection authentication */
- sconn->op =
+ entry->op =
silc_connauth_initiator(connauth, server->server_type == SILC_SERVER ?
SILC_CONN_SERVER : SILC_CONN_ROUTER, auth_meth,
auth_data, auth_data_len,
if (!sconn->sock) {
SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
silc_stream_destroy(sconn->stream);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, server->id,
0, NULL)) {
silc_packet_stream_destroy(sconn->sock);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
entry = silc_calloc(1, sizeof(*entry));
if (!entry) {
silc_packet_stream_destroy(sconn->sock);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
entry->server = server;
+ entry->data.sconn = sconn;
+ entry->data.conn_type = SILC_CONN_UNKNOWN;
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
silc_packet_set_context(sconn->sock, entry);
+ SILC_LOG_DEBUG(("Created unknown connection %p", entry));
+
/* Set Key Exchange flags from configuration, but fall back to global
settings too. */
memset(¶ms, 0, sizeof(params));
params.flags |= SILC_SKE_SP_FLAG_PFS;
/* Start SILC Key Exchange protocol */
- SILC_LOG_DEBUG(("Starting key exchange protocol"));
+ SILC_LOG_DEBUG(("Starting key exchange protocol, connection %p", sconn));
ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
server->public_key, server->private_key, sconn);
if (!ske) {
silc_free(entry);
silc_packet_stream_destroy(sconn->sock);
+
+ /* Try reconnecting if configuration wants it */
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ return;
+ }
+
if (sconn->callback)
(*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
/* Start key exchange protocol */
params.version = silc_version_string;
params.timeout_secs = server->config->key_exchange_timeout;
- sconn->op = silc_ske_initiator(ske, sconn->sock, ¶ms, NULL);
+ entry->op = silc_ske_initiator(ske, sconn->sock, ¶ms, NULL);
}
/* Timeout callback that will be called to retry connecting to remote
/* If we've reached max retry count, give up. */
if ((sconn->retry_count > param->reconnect_count) &&
- !param->reconnect_keep_trying) {
+ sconn->no_reconnect) {
SILC_LOG_ERROR(("Could not connect, giving up"));
if (sconn->callback)
switch (status) {
case SILC_NET_OK:
- SILC_LOG_DEBUG(("Connection to %s:%d established",
+ SILC_LOG_DEBUG(("Connection %p to %s:%d established", sconn,
sconn->remote_host, sconn->remote_port));
/* Continue with key exchange protocol */
SILC_LOG_ERROR(("Could not connect to %s:%d: %s",
sconn->remote_host, sconn->remote_port,
silc_net_get_error_string(status)));
-
- if (sconn->callback)
- (*sconn->callback)(server, NULL, sconn->callback_context);
- silc_server_connection_free(sconn);
+ if (!sconn->no_reconnect) {
+ silc_schedule_task_add_timeout(sconn->server->schedule,
+ silc_server_connect_to_router_retry,
+ sconn, 1, 0);
+ silc_dlist_del(server->conns, sconn);
+ } else {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_connection_free(sconn);
+ }
break;
default:
SILC_LOG_INFO(("Unconfigured %s connection %s:%d, cannot connect",
(sconn->backup ? "backup router" : "router"),
sconn->remote_host, sconn->remote_port));
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
if (!sconn->op) {
SILC_LOG_ERROR(("Could not connect to router %s:%d",
sconn->remote_host, sconn->remote_port));
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
SilcServer server = context;
SilcServerConnection sconn;
SilcServerConfigRouter *ptr;
+ SilcServerConfigConnParams *param;
/* Don't connect if we are shutting down. */
if (server->server_shutdown)
}
}
+ param = (ptr->param ? ptr->param : &server->config->param);
+
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
if (!sconn)
sconn->backup_replace_ip = strdup(ptr->backup_replace_ip);
sconn->backup_replace_port = ptr->backup_replace_port;
}
+ sconn->no_reconnect = param->reconnect_keep_trying == FALSE;
SILC_LOG_DEBUG(("Created connection %p", sconn));
server->stat.auth_failures++;
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
goto out;
}
SILC_STATUS_ERR_PERM_DENIED,
"We do not have connection to backup "
"router established, try later");
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
server->stat.auth_failures++;
/* From here on, wait 20 seconds for the backup router to appear. */
server->stat.auth_failures++;
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
goto out;
}
entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
entry->data.conn_type = SILC_CONN_CLIENT;
/* Statistics */
+ SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+ server->stat.clients + 1));
server->stat.my_clients++;
server->stat.clients++;
server->stat.cell_clients++;
SILC_STATUS_ERR_PERM_DENIED,
"We do not have connection to primary "
"router established, try later");
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
server->stat.auth_failures++;
goto out;
}
&server->config->param,
rconn ? rconn->param : NULL,
silc_connauth_get_ske(connauth))) {
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
server->stat.auth_failures++;
goto out;
}
SILC_STATUS_ERR_PERM_DENIED,
"We do not have connection to backup "
"router established, try later");
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
server->stat.auth_failures++;
/* From here on, wait 20 seconds for the backup router to appear. */
SILC_LOG_ERROR(("Could not add new server to cache"));
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_AUTH_FAILED, NULL);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
server->stat.auth_failures++;
goto out;
}
/* Add connection to server->conns so that we know we have connection
to this peer. */
sconn = silc_calloc(1, sizeof(*sconn));
+ if (!sconn)
+ goto out;
sconn->server = server;
sconn->sock = sock;
sconn->remote_host = strdup(hostname);
sconn->remote_port = port;
silc_dlist_add(server->conns, sconn);
idata->sconn = sconn;
+ idata->sconn->callback = NULL;
idata->last_receive = time(NULL);
/* Add the common data structure to the ID entry. */
silc_ske_free(ske);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
return;
}
silc_ske_free(ske);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
+ silc_server_free_sock_user_data(server, sock, NULL);
return;
}
silc_packet_set_keys(sock, send_key, receive_key, hmac_send,
idata->rekey = rekey;
idata->public_key = silc_pkcs_public_key_copy(prop->public_key);
pk = silc_pkcs_public_key_encode(idata->public_key, &pk_len);
- silc_hash_make(server->sha1hash, pk, pk_len, idata->fingerprint);
-
- silc_hash_alloc(silc_hash_get_name(prop->hash), &idata->hash);
+ if (pk) {
+ silc_hash_make(server->sha1hash, pk, pk_len, idata->fingerprint);
+ silc_free(pk);
+ }
+ idata->hash = hash;
SILC_LOG_DEBUG(("Starting connection authentication"));
server->stat.auth_attempts++;
silc_ske_free(ske);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_config_unref(&entry->cconfig);
+ silc_server_config_unref(&entry->sconfig);
+ silc_server_config_unref(&entry->rconfig);
+ silc_server_free_sock_user_data(server, sock, NULL);
return;
}
}
server->stat.conn_num++;
+ SILC_LOG_DEBUG(("Created packet stream %p", packet_stream));
+
/* Set source ID to packet stream */
if (!silc_packet_set_ids(packet_stream, SILC_ID_SERVER, server->id,
0, NULL)) {
silc_server_disconnect_remote(server, packet_stream,
SILC_STATUS_ERR_BANNED_FROM_SERVER,
deny->reason);
+ silc_server_free_sock_user_data(server, packet_stream, NULL);
return;
}
server->stat.conn_failures++;
silc_server_disconnect_remote(server, packet_stream,
SILC_STATUS_ERR_BANNED_FROM_SERVER, NULL);
+ silc_server_free_sock_user_data(server, packet_stream, NULL);
return;
}
server->stat.conn_failures++;
silc_server_disconnect_remote(server, packet_stream,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_free_sock_user_data(server, packet_stream, NULL);
return;
}
entry->hostname = hostname;
entry->port = port;
entry->server = server;
entry->data.conn_type = SILC_CONN_UNKNOWN;
+ entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
silc_packet_set_context(packet_stream, entry);
+ SILC_LOG_DEBUG(("Created unknown connection %p", entry));
+
silc_server_config_ref(&entry->cconfig, server->config, cconfig);
silc_server_config_ref(&entry->sconfig, server->config, sconfig);
silc_server_config_ref(&entry->rconfig, server->config, rconfig);
server->stat.conn_failures++;
silc_server_disconnect_remote(server, packet_stream,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
+ silc_server_free_sock_user_data(server, packet_stream, NULL);
return;
}
silc_ske_set_callbacks(ske, silc_server_verify_key,
sock, idata->sconn->rekey_timeout, 0);
}
+/* Helper to stop future rekeys on a link. */
+void silc_server_stop_rekey(SilcServer server, SilcClientEntry client)
+{
+ if (!client->connection)
+ return;
+
+ SILC_LOG_DEBUG(("Stopping rekey for client %p", client));
+
+ silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_rekey,
+ client->connection);
+}
+
/* Rekey callback. Start rekey as initiator */
SILC_TASK_CALLBACK(silc_server_do_rekey)
SILC_LOG_DEBUG(("Perform rekey, sock %p", sock));
/* Do not execute rekey with disabled connections */
- if (idata->status & SILC_IDLIST_STATUS_DISABLED)
+ if (idata->status & SILC_IDLIST_STATUS_DISABLED || !idata->rekey)
return;
/* If another protocol is active do not start rekey */
SilcIDListData idata = silc_packet_get_context(sock);
SilcSKE ske;
- SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+ if (!idata->rekey) {
+ silc_packet_free(packet);
+ return;
+ }
+ if (idata->conn_type == SILC_CONN_UNKNOWN) {
+ silc_packet_free(packet);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s], sock %p",
idata->sconn->remote_host, idata->sconn->remote_port,
- SILC_CONNTYPE_STRING(idata->conn_type)));
+ SILC_CONNTYPE_STRING(idata->conn_type), sock));
/* Allocate SKE */
ske = silc_ske_alloc(server->rng, server->schedule, NULL,
SILC_TASK_CALLBACK(silc_server_close_connection_final)
{
- silc_packet_stream_destroy(context);
+ silc_packet_stream_unref(context);
}
/* Closes connection to socket connection */
const char *hostname;
SilcUInt16 port;
+ if (!silc_packet_stream_is_valid(sock))
+ return;
+
memset(tmp, 0, sizeof(tmp));
// silc_socket_get_error(sock, tmp, sizeof(tmp));
silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
idata->sconn = NULL;
}
+ /* Take a reference and then destroy the stream. The last reference
+ is released later in a timeout callback. */
+ silc_packet_stream_ref(sock);
+ silc_packet_stream_destroy(sock);
+
/* Close connection with timeout */
server->stat.conn_num--;
silc_schedule_task_del_by_all(server->schedule, 0,
if (!sock)
return;
- SILC_LOG_DEBUG(("Disconnecting remote host"));
+ SILC_LOG_DEBUG(("Disconnecting remote host, sock %p, status %d", sock,
+ status));
va_start(ap, status);
cp = va_arg(ap, char *);
}
/* Update statistics */
- server->stat.my_clients--;
+
+ /* Local detached clients aren't counted. */
+ if (!client->local_detached)
+ server->stat.my_clients--;
+ SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+ server->stat.clients - 1));
+ SILC_VERIFY(server->stat.clients > 0);
server->stat.clients--;
if (server->stat.cell_clients)
server->stat.cell_clients--;
SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
silc_schedule_task_del_by_context(server->schedule, client);
- if (client->data.sconn)
+ if (client->data.sconn) {
silc_server_connection_free(client->data.sconn);
+ client->data.sconn = NULL;
+ }
/* We will not delete the client entry right away. We will take it
into history (for WHOWAS command) for 5 minutes, unless we're
client->router = NULL;
client->connection = NULL;
client->data.created = silc_time();
+ silc_dlist_del(server->expired_clients, client);
silc_dlist_add(server->expired_clients, client);
} else {
/* Delete directly since we're shutting down server */
SilcPacketStream sock,
const char *signoff_message)
{
- SilcIDListData idata = silc_packet_get_context(sock);
+ SilcIDListData idata;
const char *ip;
SilcUInt16 port;
- SILC_LOG_DEBUG(("Start"));
+ if (!sock)
+ return;
+
+ SILC_LOG_DEBUG(("Start, sock %p", sock));
+ idata = silc_packet_get_context(sock);
if (!idata)
return;
- silc_schedule_task_del_by_context(server->schedule, sock);
+ silc_schedule_task_del_by_all(server->schedule, 0, silc_server_do_rekey,
+ sock);
/* Cancel active protocols */
if (idata) {
if (idata->sconn && idata->sconn->op) {
SILC_LOG_DEBUG(("Abort active protocol"));
silc_async_abort(idata->sconn->op, NULL, NULL);
+ idata->sconn->op = NULL;
}
if (idata->conn_type == SILC_CONN_UNKNOWN &&
((SilcUnknownEntry)idata)->op) {
SILC_LOG_DEBUG(("Abort active protocol"));
silc_async_abort(((SilcUnknownEntry)idata)->op, NULL, NULL);
+ ((SilcUnknownEntry)idata)->op = NULL;
}
}
/* We'll need to constantly try to reconnect to the primary
router so that we'll see when it comes back online. */
- silc_server_create_connection(server, FALSE, FALSE, ip, port,
+ silc_server_create_connection(server, TRUE, FALSE, ip, port,
silc_server_backup_connected,
NULL);
}
}
server->backup_noswitch = FALSE;
- if (idata->sconn)
+ if (idata->sconn) {
silc_server_connection_free(idata->sconn);
+ idata->sconn = NULL;
+ }
/* Statistics */
if (idata->conn_type == SILC_CONN_SERVER) {
{
SilcUnknownEntry entry = (SilcUnknownEntry)idata;
- SILC_LOG_DEBUG(("Freeing unknown connection data"));
+ SILC_LOG_DEBUG(("Freeing unknown connection data %p", entry));
+
+ if (idata->sconn) {
+ if (server->router_conn == idata->sconn) {
+ if (!server->no_reconnect)
+ silc_server_create_connections(server);
+ server->router_conn = NULL;
+ }
- if (idata->sconn)
silc_server_connection_free(idata->sconn);
+ idata->sconn = NULL;
+ }
silc_idlist_del_data(idata);
silc_free(entry);
silc_packet_set_context(sock, NULL);
SilcIDCacheEntry id_cache;
SilcServerEntry entry;
SilcBuffer idp;
+ void *tmp;
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->servers, &list)) {
idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
- *servers = silc_buffer_realloc(*servers,
- (*servers ?
- silc_buffer_truelen((*servers)) +
- silc_buffer_len(idp) :
- silc_buffer_len(idp)));
+ tmp = silc_buffer_realloc(*servers,
+ (*servers ?
+ silc_buffer_truelen((*servers)) +
+ silc_buffer_len(idp) :
+ silc_buffer_len(idp)));
+ if (!tmp)
+ return;
+ *servers = tmp;
silc_buffer_pull_tail(*servers, ((*servers)->end - (*servers)->data));
silc_buffer_put(*servers, idp->data, silc_buffer_len(idp));
silc_buffer_pull(*servers, silc_buffer_len(idp));
SilcBuffer idp;
SilcBuffer tmp;
unsigned char mode[4];
+ void *tmp2;
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->clients, &list)) {
silc_id_render(client->id, SILC_ID_CLIENT)));
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ if (!idp)
+ return;
- *clients = silc_buffer_realloc(*clients,
- (*clients ?
- silc_buffer_truelen((*clients)) +
- silc_buffer_len(idp) :
- silc_buffer_len(idp)));
+ tmp2 = silc_buffer_realloc(*clients,
+ (*clients ?
+ silc_buffer_truelen((*clients)) +
+ silc_buffer_len(idp) :
+ silc_buffer_len(idp)));
+ if (!tmp2)
+ return;
+ *clients = tmp2;
silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
silc_buffer_put(*clients, idp->data, silc_buffer_len(idp));
silc_buffer_pull(*clients, silc_buffer_len(idp));
silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
2, idp->data, silc_buffer_len(idp),
mode, 4);
- *umodes = silc_buffer_realloc(*umodes,
- (*umodes ?
- silc_buffer_truelen((*umodes)) +
- silc_buffer_len(tmp) :
- silc_buffer_len(tmp)));
+ tmp2 = silc_buffer_realloc(*umodes,
+ (*umodes ?
+ silc_buffer_truelen((*umodes)) +
+ silc_buffer_len(tmp) :
+ silc_buffer_len(tmp)));
+ if (!tmp2)
+ return;
+ *umodes = tmp2;
silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
silc_buffer_put(*umodes, tmp->data, silc_buffer_len(tmp));
silc_buffer_pull(*umodes, silc_buffer_len(tmp));
{
SilcBuffer list, idp, idp2, tmp2;
SilcUInt32 type;
+ void *ptype;
SilcHashTableList htl;
const unsigned char a[1] = { 0x03 };
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))
- list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
- type);
+ while (silc_hash_table_get(&htl, (void *)&ptype, (void *)&tmp2))
+ list = silc_argument_payload_encode_one(list, tmp2->data,
+ silc_buffer_len(tmp2),
+ SILC_PTR_TO_32(ptype));
silc_hash_table_list_reset(&htl);
idp2 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
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))
- list = silc_argument_payload_encode_one(list, tmp2->data, silc_buffer_len(tmp2),
- type);
+ while (silc_hash_table_get(&htl, (void *)&ptype, (void *)&tmp2))
+ list = silc_argument_payload_encode_one(list, tmp2->data,
+ silc_buffer_len(tmp2),
+ SILC_PTR_TO_32(ptype));
silc_hash_table_list_reset(&htl);
*ban =
int len;
unsigned char mode[4], ulimit[4];
char *hmac;
+ void *tmp2;
SILC_LOG_DEBUG(("Start"));
SILC_CHANNEL_MODE_ULIMIT ?
sizeof(ulimit) : 0));
len = silc_buffer_len(tmp);
- *channel_modes =
+ tmp2 =
silc_buffer_realloc(*channel_modes,
(*channel_modes ?
silc_buffer_truelen((*channel_modes)) + len : len));
+ if (!tmp2)
+ return;
+ *channel_modes = tmp2;
silc_buffer_pull_tail(*channel_modes,
((*channel_modes)->end -
(*channel_modes)->data));
chidp->data,
silc_buffer_len(chidp));
len = silc_buffer_len(tmp);
- *channel_users =
+ tmp2 =
silc_buffer_realloc(*channel_users,
(*channel_users ?
silc_buffer_truelen((*channel_users)) + len : len));
+ if (!tmp2)
+ return;
+ *channel_users = tmp2;
silc_buffer_pull_tail(*channel_users,
((*channel_users)->end -
(*channel_users)->data));
fkey ? fkey->data : NULL,
fkey ? silc_buffer_len(fkey) : 0);
len = silc_buffer_len(tmp);
- *channel_users_modes =
+ tmp2 =
silc_buffer_realloc(*channel_users_modes,
(*channel_users_modes ?
silc_buffer_truelen((*channel_users_modes)) +
len : len));
+ if (!tmp2)
+ return;
+ *channel_users_modes = tmp2;
silc_buffer_pull_tail(*channel_users_modes,
((*channel_users_modes)->end -
(*channel_users_modes)->data));
SilcUInt16 name_len;
int len;
int i = *channel_users_modes_c;
+ void *tmp;
SilcBool announce;
SILC_LOG_DEBUG(("Start"));
if (announce) {
len = 4 + name_len + id_len + 4;
- *channels =
+ tmp =
silc_buffer_realloc(*channels,
(*channels ?
silc_buffer_truelen((*channels)) +
len : len));
+ if (!tmp)
+ break;
+ *channels = tmp;
+
silc_buffer_pull_tail(*channels,
((*channels)->end - (*channels)->data));
silc_buffer_format(*channels,
if (announce) {
/* Channel user modes */
- *channel_users_modes = silc_realloc(*channel_users_modes,
- sizeof(**channel_users_modes) *
- (i + 1));
+ tmp = silc_realloc(*channel_users_modes,
+ sizeof(**channel_users_modes) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_users_modes = tmp;
(*channel_users_modes)[i] = NULL;
- *channel_modes = silc_realloc(*channel_modes,
- sizeof(**channel_modes) * (i + 1));
+ tmp = silc_realloc(*channel_modes,
+ sizeof(**channel_modes) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_modes = tmp;
(*channel_modes)[i] = NULL;
- *channel_ids = silc_realloc(*channel_ids,
- sizeof(**channel_ids) * (i + 1));
+ tmp = silc_realloc(*channel_ids,
+ sizeof(**channel_ids) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_ids = tmp;
(*channel_ids)[i] = NULL;
silc_server_announce_get_channel_users(server, channel,
&(*channel_modes)[i],
(*channel_ids)[i] = channel->id;
/* Channel's topic */
- *channel_topics = silc_realloc(*channel_topics,
- sizeof(**channel_topics) * (i + 1));
+ tmp = silc_realloc(*channel_topics,
+ sizeof(**channel_topics) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_topics = tmp;
(*channel_topics)[i] = NULL;
silc_server_announce_get_channel_topic(server, channel,
&(*channel_topics)[i]);
/* Channel's invite and ban list */
- *channel_invites = silc_realloc(*channel_invites,
- sizeof(**channel_invites) * (i + 1));
+ tmp = silc_realloc(*channel_invites,
+ sizeof(**channel_invites) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_invites = tmp;
(*channel_invites)[i] = NULL;
- *channel_bans = silc_realloc(*channel_bans,
- sizeof(**channel_bans) * (i + 1));
+ tmp = silc_realloc(*channel_bans,
+ sizeof(**channel_bans) * (i + 1));
+ if (!tmp)
+ break;
+ *channel_bans = tmp;
(*channel_bans)[i] = NULL;
silc_server_announce_get_inviteban(server, channel,
&(*channel_invites)[i],
}
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+
+ SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
+ server->stat.clients + 1));
+ server->stat.clients++;
}
if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
- SILC_LOG_ERROR(("Attempting to add unregistered client to channel ",
+ SILC_LOG_ERROR(("Attempting to add unregistered client to channel "
"%s", channel->channel_name));
continue;
}