Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005, 2007 Pekka Riikonen
+ Copyright (C) 1997 - 2008 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_get_stats);
SILC_TASK_CALLBACK(silc_server_connect_router);
+SILC_TASK_CALLBACK(silc_server_connect_to_router_retry);
SILC_TASK_CALLBACK(silc_server_do_rekey);
SILC_TASK_CALLBACK(silc_server_purge_expired_clients);
static void silc_server_accept_new_connection(SilcNetStatus status,
SilcServer server = callback_context;
SilcIDListData idata = stream_context;
+ if (!idata)
+ return FALSE;
+
/* Packets we do not handle */
switch (packet->type) {
case SILC_PACKET_HEARTBEAT:
!(idata->status & SILC_IDLIST_STATUS_REGISTERED)) &&
packet->type != SILC_PACKET_NEW_CLIENT &&
packet->type != SILC_PACKET_NEW_SERVER &&
+ packet->type != SILC_PACKET_RESUME_CLIENT &&
packet->type != SILC_PACKET_CONNECTION_AUTH_REQUEST &&
packet->type != SILC_PACKET_DISCONNECT)
return FALSE;
- /* NEW_CLIENT and NEW_SERVER are accepted only without source ID
- and for unregistered connection. */
+ /* NEW_CLIENT and NEW_SERVER are accepted only without source ID and
+ for unregistered connection. */
if (packet->src_id && (packet->type == SILC_PACKET_NEW_CLIENT ||
packet->type == SILC_PACKET_NEW_SERVER) &&
(idata->status & SILC_IDLIST_STATUS_REGISTERED))
silc_id_str2id(packet->src_id, packet->src_id_len,
packet->src_id_type, &client_id, sizeof(client_id))) {
if (!SILC_ID_CLIENT_COMPARE(client->id, &client_id)) {
- SILC_LOG_DEBUG(("Packet source is not same as sender"));
+ SILC_LOG_DEBUG(("Packet source is not same as sender, packet %s",
+ silc_get_packet_name(packet->type)));
return FALSE;
}
}
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) {
+ 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 &&
+ idata->conn_type == SILC_CONN_SERVER) {
+ SilcServerEntry server_entry = (SilcServerEntry)idata;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER)
+ server->backup_closed = TRUE;
+ }
+
+ silc_server_free_sock_user_data(server, stream, NULL);
+ }
+
+ silc_server_close_connection(server, stream);
+}
+
+SILC_TASK_CALLBACK(silc_server_packet_error_timeout)
+{
+ SilcServer server = app_context;
+ SilcPacketStream stream = context;
+ SilcIDListData idata = silc_packet_get_context(stream);
if (!idata)
return;
void *callback_context,
void *stream_context)
{
+ SilcServer server = callback_context;
SilcIDListData idata = silc_packet_get_context(stream);
SilcStream sock = silc_packet_stream_get_stream(stream);
const char *ip;
SilcUInt16 port;
+ SILC_LOG_DEBUG(("Packet error, sock %p", stream));
+
if (!idata || !sock)
return;
if (!silc_socket_stream_get_info(sock, NULL, NULL, &ip, &port))
return;
- SILC_LOG_ERROR(("Connection %s:%d [%s]: %s",
- SILC_CONNTYPE_STRING(idata->conn_type), ip, port,
+ SILC_LOG_ERROR(("Connection %s:%d [%s]: %s", ip, port,
+ SILC_CONNTYPE_STRING(idata->conn_type),
silc_packet_error_string(error)));
+
+ if (!silc_packet_stream_is_valid(stream))
+ return;
+
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_packet_error_timeout,
+ stream, 0, 0);
}
/* Packet stream callbacks */
status = (SilcStatus)packet->buffer.data[0];
if (silc_buffer_len(&packet->buffer) > 1 &&
- silc_utf8_valid(packet->buffer.data + 1, silc_buffer_len(&packet->buffer) - 1))
+ silc_utf8_valid(packet->buffer.data + 1,
+ silc_buffer_len(&packet->buffer) - 1))
message = silc_memdup(packet->buffer.data + 1,
silc_buffer_len(&packet->buffer) - 1);
- if (!silc_socket_stream_get_info(sock, NULL, &hostname, &ip, NULL))
+ if (!silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+ NULL, &hostname, &ip, NULL))
break;
SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", ip, hostname,
server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
/* If backup disconnected then mark that resuming will not be allowed */
-#if 0
if (server->server_type == SILC_ROUTER && !server->backup_router &&
- sock->type == SILC_CONN_SERVER && sock->user_data) {
- SilcServerEntry server_entry = sock->user_data;
+ idata->conn_type == SILC_CONN_SERVER) {
+ SilcServerEntry server_entry = (SilcServerEntry)idata;
if (server_entry->server_type == SILC_BACKUP_ROUTER)
server->backup_closed = TRUE;
}
/* Handle the disconnection from our end too */
- if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
+ if (SILC_IS_LOCAL(idata))
silc_server_free_sock_user_data(server, sock, NULL);
- SILC_SET_DISCONNECTING(sock);
silc_server_close_connection(server, sock);
server->backup_noswitch = FALSE;
-#endif
}
break;
router resuming protocol. */
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
-#if 0
silc_server_backup_resume_router(server, sock, packet);
-#endif
break;
default:
{
SilcList list;
SilcIDCacheEntry cache;
+ SilcIDListData idata;
+
+ SILC_LOG_DEBUG(("Free server %p", server));
if (!server)
return;
silc_pkcs_private_key_free(server->private_key);
if (server->pending_commands)
silc_dlist_uninit(server->pending_commands);
- if (server->id_entry)
+ if (server->id_entry) {
+ if (server->id_entry->data.sconn)
+ silc_schedule_task_del_by_context(server->schedule,
+ server->id_entry->data.sconn->sock);
silc_idlist_del_server(server->local_list, server->id_entry);
+ }
/* Delete all channels */
if (silc_idcache_get_all(server->local_list->channels, &list)) {
/* Delete all clients */
if (silc_idcache_get_all(server->local_list->clients, &list)) {
silc_list_start(list);
- while ((cache = silc_list_get(list)))
+ while ((cache = silc_list_get(list))) {
+ silc_schedule_task_del_by_context(server->schedule, cache->context);
silc_idlist_del_client(server->local_list, cache->context);
+ }
}
if (silc_idcache_get_all(server->global_list->clients, &list)) {
silc_list_start(list);
- while ((cache = silc_list_get(list)))
+ while ((cache = silc_list_get(list))) {
+ silc_schedule_task_del_by_context(server->schedule, cache->context);
silc_idlist_del_client(server->global_list, cache->context);
+ }
}
/* Delete all servers */
if (silc_idcache_get_all(server->local_list->servers, &list)) {
silc_list_start(list);
- while ((cache = silc_list_get(list)))
+ while ((cache = silc_list_get(list))) {
+ idata = (SilcIDListData)cache->context;
+ if (idata->sconn)
+ silc_schedule_task_del_by_context(server->schedule,
+ idata->sconn->sock);
silc_idlist_del_server(server->local_list, cache->context);
+ }
}
if (silc_idcache_get_all(server->global_list->servers, &list)) {
- while ((cache = silc_list_get(list)))
+ while ((cache = silc_list_get(list))) {
+ idata = (SilcIDListData)cache->context;
+ if (idata->sconn)
+ silc_schedule_task_del_by_context(server->schedule,
+ idata->sconn->sock);
silc_idlist_del_server(server->global_list, cache->context);
+ }
}
+ silc_schedule_task_del_by_context(server->schedule, server);
+ silc_schedule_uninit(server->schedule);
+ server->schedule = NULL;
+
silc_idcache_free(server->local_list->clients);
silc_idcache_free(server->local_list->servers);
silc_idcache_free(server->local_list->channels);
silc_free(server->local_list);
silc_free(server->global_list);
silc_free(server->server_name);
- silc_free(server->purge_i);
- silc_free(server->purge_g);
silc_free(server);
silc_hmac_unregister_all();
SilcBool silc_server_init_secondary(SilcServer server)
{
- return TRUE;
-#if 0
- int sock = 0;
- SilcPacketStream newsocket = NULL;
SilcServerConfigServerInfoInterface *interface;
+ SilcNetListener listener;
for (interface = server->config->server_info->secondary; interface;
- interface = interface->next, sock++) {
-
- if (!silc_server_listen(server,
- interface->server_ip, interface->port, &sock_list[sock]))
- goto err;
-
- /* Set socket to non-blocking mode */
- silc_net_set_socket_nonblock(sock_list[sock]);
-
- /* Add ourselves also to the socket table. The entry allocated above
- is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock_list[sock],
- SILC_CONN_SERVER, NULL, &newsocket);
- server->sockets[sock_list[sock]] = newsocket;
- SILC_SET_LISTENER(newsocket);
-
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock_list[sock], &newsocket->hostname,
- &newsocket->ip)) {
- if ((server->config->require_reverse_lookup && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
- newsocket->hostname ? newsocket->hostname :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock);
-
- newsocket->user_data = (void *)server->id_entry;
- silc_schedule_task_add(server->schedule, sock_list[sock],
- silc_server_accept_new_connection,
- (void *)server, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
+ interface = interface->next) {
+ listener = silc_server_listen(server, interface->server_ip,
+ interface->port);
+ if (!listener)
+ return FALSE;
+ silc_dlist_add(server->listeners, listener);
}
return TRUE;
-
- err:
- do silc_net_close_server(sock_list[sock--]); while (sock >= 0);
-#endif /* 0 */
- return FALSE;
}
/* Initializes the entire SILC server. This is called always before running
{
SilcServerID *id;
SilcServerEntry id_entry;
- SilcIDListPurge purge;
SilcNetListener listener;
SilcUInt16 *port;
char **ip;
server->config->server_info->primary->port);
if (!listener)
goto err;
-
silc_dlist_add(server->listeners, listener);
/* Create a Server ID for the server. */
port = silc_net_listener_get_port(listener, NULL);
ip = silc_net_listener_get_ip(listener, NULL);
- silc_id_create_server_id(ip[0], port[0], server->rng, &id);
+ silc_id_create_server_id(server->config->server_info->primary->public_ip ?
+ server->config->server_info->primary->public_ip :
+ ip[0], port[0], server->rng, &id);
if (!id)
goto err;
the ID list. */
id_entry =
silc_idlist_add_server(server->local_list, strdup(server->server_name),
- server->server_type, server->id, NULL, NULL);
+ server->server_type,
+ silc_id_dup(server->id, SILC_ID_SERVER),
+ NULL, NULL);
if (!id_entry) {
SILC_LOG_ERROR(("Could not add local server to cache"));
goto err;
}
id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ id_entry->data.conn_type = (server->server_type == SILC_SERVER ?
+ SILC_CONN_SERVER : SILC_CONN_ROUTER);
server->id_entry = id_entry;
/* Create secondary TCP listeners */
}
}
- /* Register the ID Cache purge task. This periodically purges the ID cache
- and removes the expired cache entries. */
-
- /* Clients local list */
- server->purge_i = purge = silc_calloc(1, sizeof(*purge));
- purge->cache = server->local_list->clients;
- purge->timeout = 600;
- silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
- (void *)purge, purge->timeout, 0);
-
- /* Clients global list */
- server->purge_g = purge = silc_calloc(1, sizeof(*purge));
- purge->cache = server->global_list->clients;
- purge->timeout = 300;
- silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge,
- (void *)purge, purge->timeout, 0);
+ if (server->server_type != SILC_ROUTER) {
+ server->stat.servers = 1;
+ server->stat.cell_servers = 1;
+ } else {
+ server->stat.routers = 1;
+ }
/* If we are normal server we'll retrieve network statisticial information
once in a while from the router. */
silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,
server, 10, 0);
- if (server->server_type == SILC_ROUTER)
- server->stat.routers++;
-
/* Start packet engine */
server->packet_engine =
silc_packet_engine_start(server->rng, server->server_type == SILC_ROUTER,
/* Register client entry expiration timeout */
silc_schedule_task_add_timeout(server->schedule,
silc_server_purge_expired_clients, server,
- 600, 0);
+ 120, 0);
/* Initialize HTTP server */
silc_server_http_init(server);
return FALSE;
}
-#if 0
/* Task callback to close a socket connection after rehash */
SILC_TASK_CALLBACK(silc_server_rehash_close_connection)
{
- SilcServer server = context;
- SilcPacketStream sock = server->sockets[fd];
+ SilcServer server = app_context;
+ SilcPacketStream sock = context;
+ SilcIDListData idata = silc_packet_get_context(sock);
+ const char *hostname;
+ SilcUInt16 port;
- if (!sock)
- return;
+ silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+ NULL, &hostname, NULL, &port);
SILC_LOG_INFO(("Connection %s:%d [%s] is unconfigured",
- sock->hostname, sock->port,
- (sock->type == SILC_CONN_UNKNOWN ? "Unknown" :
- sock->type == SILC_CONN_CLIENT ? "Client" :
- sock->type == SILC_CONN_SERVER ? "Server" :
- "Router")));
+ hostname, port, SILC_CONNTYPE_STRING(idata->conn_type)));
silc_schedule_task_del_by_context(server->schedule, sock);
silc_server_disconnect_remote(server, sock,
SILC_STATUS_ERR_BANNED_FROM_SERVER,
"This connection is removed from "
"configuration");
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_free_sock_user_data(server, sock, NULL);
}
-#endif /* 0 */
/* This function basically reads the config file again and switches the config
object pointed by the server object. After that, we have to fix various
SilcBool silc_server_rehash(SilcServer server)
{
-#if 0
SilcServerConfig newconfig;
SILC_LOG_INFO(("Rehashing server"));
return FALSE;
}
- /* Reinit scheduler if necessary */
- if (newconfig->param.connections_max > server->config->param.connections_max)
- if (!silc_schedule_reinit(server->schedule,
- newconfig->param.connections_max))
- return FALSE;
-
/* Fix the server_name field */
if (strcmp(server->server_name, newconfig->server_info->server_name)) {
silc_free(server->server_name);
/* Update the idcache list with a fresh pointer */
silc_free(server->id_entry->server_name);
server->id_entry->server_name = strdup(server->server_name);
- if (!silc_idcache_del_by_context(server->local_list->servers,
- server->id_entry))
- return FALSE;
- if (!silc_idcache_add(server->local_list->servers,
- strdup(server->id_entry->server_name),
- server->id_entry->id, server->id_entry, 0, NULL))
- return FALSE;
+ silc_idcache_update_by_context(server->local_list->servers,
+ server->id_entry, NULL,
+ strdup(server->id_entry->server_name),
+ TRUE);
}
/* Set logging */
server->private_key = newconfig->server_info->private_key;
newconfig->server_info->public_key = NULL;
newconfig->server_info->private_key = NULL;
-
- /* Allocate PKCS context for local public and private keys */
- silc_pkcs_free(server->pkcs);
- if (!silc_pkcs_alloc(server->public_key->name, &server->pkcs))
- return FALSE;
- silc_pkcs_public_key_set(server->pkcs, server->public_key);
- silc_pkcs_private_key_set(server->pkcs, server->private_key);
}
/* Check for unconfigured server and router connections and close
SilcPacketStream sock;
sock = silc_server_find_socket_by_host(server, SILC_CONN_ROUTER,
ptr->host, ptr->port);
- if (sock && !SILC_IS_LISTENER(sock))
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ if (sock)
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_rehash_close_connection,
+ sock, 0, 1);
}
}
}
SilcPacketStream sock;
sock = silc_server_find_socket_by_host(server, SILC_CONN_SERVER,
ptr->host, 0);
- if (sock && !SILC_IS_LISTENER(sock))
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ if (sock)
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_rehash_close_connection,
+ sock, 0, 1);
}
}
}
sock = silc_server_find_socket_by_host(server, SILC_CONN_CLIENT,
ptr->host, 0);
if (sock)
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_rehash_close_connection,
- server, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ silc_schedule_task_add_timeout(server->schedule,
+ silc_server_rehash_close_connection,
+ sock, 0, 1);
}
}
}
#endif /* SILC_DEBUG */
SILC_LOG_DEBUG(("Server rehashed"));
-#endif /* 0 */
return TRUE;
}
while ((ps = silc_dlist_get(list))) {
SilcIDListData idata = silc_packet_get_context(ps);
+ if (!silc_packet_stream_is_valid(ps))
+ continue;
+
if (idata)
idata->status &= ~SILC_IDLIST_STATUS_DISABLED;
silc_server_free_sock_user_data(server, ps,
"Server is shutting down");
}
- silc_dlist_uninit(list);
+ silc_packet_engine_free_streams_list(list);
}
/* We are not connected to network anymore */
silc_server_http_uninit(server);
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_router);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_to_router_retry);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_to_router);
+
silc_schedule_stop(server->schedule);
- silc_schedule_uninit(server->schedule);
- server->schedule = NULL;
SILC_LOG_DEBUG(("Server stopped"));
}
SilcServer server = context;
SilcClientEntry client;
SilcIDList id_list;
+ SilcUInt64 curtime = silc_time();
SILC_LOG_DEBUG(("Expire timeout"));
silc_dlist_start(server->expired_clients);
while ((client = silc_dlist_get(server->expired_clients))) {
- if (client->data.status & SILC_IDLIST_STATUS_REGISTERED)
+ /* For unregistered clients the created timestamp is actually
+ unregistered timestamp. Make sure client remains in history
+ at least 500 seconds. */
+ if (client->data.created && curtime - client->data.created < 500)
continue;
id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ?
silc_schedule_task_add_timeout(server->schedule,
silc_server_purge_expired_clients, server,
- 600, 0);
+ 120, 0);
}
/* Free connection context */
-static void silc_server_connection_free(SilcServerConnection sconn)
+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);
silc_free(sconn->remote_host);
void silc_server_create_connection(SilcServer server,
SilcBool reconnect,
+ SilcBool dynamic,
const char *remote_host, SilcUInt32 port,
SilcServerConnectCallback callback,
void *context)
sconn->no_reconnect = reconnect == FALSE;
sconn->callback = callback;
sconn->callback_context = context;
+ sconn->no_conf = dynamic;
+ sconn->server = server;
+
+ SILC_LOG_DEBUG(("Created connection %p", sconn));
silc_schedule_task_add_timeout(server->schedule, silc_server_connect_router,
sconn, 0, 0);
SilcServerConfigServer *conn;
SilcServerConfigConnParams *param;
SilcIDListData idata;
- SilcServerEntry id_entry;
+ SilcServerEntry id_entry = NULL;
unsigned char id[32];
SilcUInt32 id_len;
SilcID remote_id;
+ const char *ip;
+
+ SILC_LOG_DEBUG(("Connection %p authentication completed, entry %p",
+ sconn, entry));
- SILC_LOG_DEBUG(("Connection authentication completed"));
+ entry->op = NULL;
if (success == FALSE) {
/* Authentication failed */
/* XXX retry connecting */
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_AUTH_FAILED, NULL);
return;
}
+ /* XXX For now remote is router always */
+ entry->data.conn_type = SILC_CONN_ROUTER;
+
SILC_LOG_INFO(("Connected to %s %s",
SILC_CONNTYPE_STRING(entry->data.conn_type),
sconn->remote_host));
strdup(sconn->remote_host),
SILC_SERVER, NULL, NULL, sconn->sock);
if (!id_entry) {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
- silc_server_connection_free(sconn);
- silc_free(entry);
return;
}
+ /* Statistics */
+ server->stat.my_servers++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.servers++;
+ SILC_LOG_DEBUG(("my_servers %d", server->stat.my_servers));
+
silc_idlist_add_data(id_entry, (SilcIDListData)entry);
break;
SILC_STR_DATA(server->server_name,
strlen(server->server_name)),
SILC_STR_END)) {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
- silc_server_connection_free(sconn);
- silc_free(entry);
return;
}
as NULL since it's local to us. */
id_entry = silc_idlist_add_server(server->global_list,
strdup(sconn->remote_host),
- SILC_ROUTER, &remote_id.u.server_id,
+ SILC_ROUTER,
+ silc_id_dup(&remote_id.u.server_id,
+ SILC_ID_SERVER),
NULL, sconn->sock);
if (!id_entry) {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
- silc_server_connection_free(sconn);
- silc_free(entry);
return;
}
/* Registered */
silc_idlist_add_data(id_entry, (SilcIDListData)entry);
- idata = (SilcIDListData)entry;
+ idata = (SilcIDListData)id_entry;
idata->status |= (SILC_IDLIST_STATUS_REGISTERED |
SILC_IDLIST_STATUS_LOCAL);
+ idata->sconn = sconn;
+
+ /* Statistics */
+ server->stat.my_routers++;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.routers++;
+ SILC_LOG_DEBUG(("my_routers %d", server->stat.my_routers));
if (!sconn->backup) {
/* Mark this router our primary router if we're still standalone */
silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
}
-#if 0
/* If we are backup router then this primary router is whom we are
backing up. */
- if (server->server_type == SILC_BACKUP_ROUTER)
- silc_server_backup_add(server, server->id_entry, sock->ip,
+ if (server->server_type == SILC_BACKUP_ROUTER) {
+ silc_socket_stream_get_info(silc_packet_stream_get_stream(sconn->
+ sock),
+ NULL, NULL, &ip, NULL);
+ silc_server_backup_add(server, server->id_entry, ip,
sconn->remote_port, TRUE);
+ }
+#if 0
+ } 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);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ 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 */
}
} else {
break;
default:
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_AUTH_FAILED, NULL);
- silc_server_connection_free(sconn);
- silc_free(entry);
return;
}
+ SILC_LOG_DEBUG(("Connection established, sock %p", sconn->sock));
+
conn = sconn->conn.ref_ptr;
param = &server->config->param;
if (conn && conn->param)
silc_schedule_task_add_timeout(server->schedule, silc_server_do_rekey,
sconn->sock, sconn->rekey_timeout, 0);
-#if 0
- /* Perform keepalive. */
- silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
- silc_server_perform_heartbeat,
- server->schedule);
+ /* Set the entry as packet stream context */
+ silc_packet_set_context(sconn->sock, id_entry);
- out:
/* Call the completion callback to indicate that we've connected to
the router */
if (sconn && sconn->callback)
(*sconn->callback)(server, id_entry, sconn->callback_context);
- /* Free the temporary connection data context */
- if (sconn) {
- silc_server_config_unref(&sconn->conn);
- silc_free(sconn->remote_host);
- silc_free(sconn->backup_replace_ip);
- silc_free(sconn);
- }
if (sconn == server->router_conn)
server->router_conn = NULL;
-#endif /* 0 */
silc_free(entry);
}
SilcSKERekeyMaterial rekey,
void *context)
{
- SilcServerConnection sconn = context;
- SilcUnknownEntry entry = silc_packet_get_context(sconn->sock);
+ SilcPacketStream sock = context;
+ SilcUnknownEntry entry = silc_packet_get_context(sock);
+ SilcServerConnection sconn = entry->data.sconn;
SilcServer server = entry->server;
SilcServerConfigRouter *conn = sconn->conn.ref_ptr;
SilcAuthMethod auth_meth = SILC_AUTH_NONE;
SilcHmac hmac_send, hmac_receive;
SilcHash hash;
+ SILC_LOG_DEBUG(("Connection %p, SKE completed, entry %p", sconn, entry));
+
+ entry->op = NULL;
+
if (status != SILC_SKE_STATUS_OK) {
/* SKE failed */
SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)",
/* XXX retry connecting */
silc_ske_free(ske);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- silc_server_connection_free(sconn);
return;
}
/* Error setting keys */
silc_ske_free(ske);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
- silc_server_connection_free(sconn);
return;
}
silc_packet_set_keys(sconn->sock, send_key, receive_key, hmac_send,
/** Error allocating auth protocol */
silc_ske_free(ske);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
+ silc_server_free_sock_user_data(server, sconn->sock, NULL);
silc_server_disconnect_remote(server, sconn->sock,
SILC_STATUS_ERR_RESOURCE_LIMIT, NULL);
- silc_server_connection_free(sconn);
return;
}
}
}
+ entry->data.rekey = rekey;
+
/* Start connection authentication */
- silc_connauth_initiator(connauth, server->server_type == SILC_ROUTER ?
- SILC_CONN_ROUTER : SILC_CONN_SERVER, auth_meth,
- auth_data, auth_data_len,
- silc_server_ke_auth_compl, sconn);
+ entry->op =
+ silc_connauth_initiator(connauth, server->server_type == SILC_SERVER ?
+ SILC_CONN_SERVER : SILC_CONN_ROUTER, auth_meth,
+ auth_data, auth_data_len,
+ silc_server_ke_auth_compl, sconn);
}
/* Function that is called when the network connection to a router has
if (!sconn->sock) {
SILC_LOG_ERROR(("Cannot connect: cannot create packet stream"));
silc_stream_destroy(sconn->stream);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
/* Set source ID to packet stream */
if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, server->id,
0, NULL)) {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_packet_stream_destroy(sconn->sock);
silc_server_connection_free(sconn);
return;
return;
}
entry->server = server;
+ entry->data.sconn = sconn;
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->sock);
+ server->public_key, server->private_key, sconn);
if (!ske) {
silc_free(entry);
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_packet_stream_destroy(sconn->sock);
silc_server_connection_free(sconn);
return;
/* Start key exchange protocol */
params.version = silc_version_string;
params.timeout_secs = server->config->key_exchange_timeout;
- 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 ((sconn->retry_count > param->reconnect_count) &&
!param->reconnect_keep_trying) {
SILC_LOG_ERROR(("Could not connect, giving up"));
+
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
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);
break;
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;
/* Don't connect if we are shutting down. */
if (server->server_shutdown) {
+ if (sconn->callback)
+ (*sconn->callback)(server, NULL, sconn->callback_context);
silc_server_connection_free(sconn);
return;
}
(sconn->backup ? "backup router" : "router"),
sconn->remote_host, sconn->remote_port));
- if (!server->no_conf) {
+ if (!sconn->no_conf) {
/* Find connection configuration */
rconn = silc_server_config_find_router_conn(server, sconn->remote_host,
sconn->remote_port);
"normal server" : server->server_type == SILC_ROUTER ?
"router" : "backup router/normal server")));
- /* XXX */
if (!server->config->routers) {
/* There wasn't a configured router, we will continue but we don't
have a connection to outside world. We will be standalone server. */
return;
}
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_router);
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_to_router_retry);
+
/* Create the connections to all our routes */
for (ptr = server->config->routers; ptr; ptr = ptr->next) {
if (!ptr->initiator)
continue;
+ if (ptr->dynamic_connection)
+ continue;
/* Check whether we are connecting or connected to this host already */
if (silc_server_num_sockets_by_remote(server,
silc_net_is_ip(ptr->host) ?
ptr->host : NULL,
silc_net_is_ip(ptr->host) ?
- NULL : ptr->host, ptr->port)) {
+ NULL : ptr->host, ptr->port,
+ SILC_CONN_ROUTER)) {
SILC_LOG_DEBUG(("We are already connected to %s:%d",
ptr->host, ptr->port));
if (!sock)
continue;
server->backup_noswitch = TRUE;
-#if 0
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_free_sock_user_data(server, sock, NULL);
silc_server_disconnect_remote(server, sock, 0, NULL);
-#endif /* 0 */
server->backup_noswitch = FALSE;
SILC_LOG_DEBUG(("Reconnecting to primary router"));
} else {
sconn = silc_calloc(1, sizeof(*sconn));
if (!sconn)
continue;
+ sconn->server = server;
sconn->remote_host = strdup(ptr->host);
sconn->remote_port = ptr->port;
sconn->backup = ptr->backup_router;
sconn->backup_replace_port = ptr->backup_replace_port;
}
- /* XXX */
+ SILC_LOG_DEBUG(("Created connection %p", sconn));
+
if (!server->router_conn && !sconn->backup)
server->router_conn = sconn;
if (cconfig->publickeys)
*repository = server->repository;
- entry->data.conn_type = conn_type;
+ if (cconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
return TRUE;
}
/* Remote end is server */
if (conn_type == SILC_CONN_SERVER) {
- SilcServerConfigServer *sconfig = entry->sconfig.ref_ptr;
+ SilcServerConfigServer *sconfig;
+
+ /* If we are normal server, don't accept the connection */
+ if (server->server_type == SILC_SERVER)
+ return FALSE;
+
+ sconfig = entry->sconfig.ref_ptr;
if (!sconfig)
return FALSE;
if (sconfig->publickeys)
*repository = server->repository;
- entry->data.conn_type = conn_type;
+ if (sconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
return TRUE;
}
if (rconfig->publickeys)
*repository = server->repository;
- entry->data.conn_type = conn_type;
+ if (rconfig->publickeys) {
+ if (server->config->prefer_passphrase_auth) {
+ *repository = NULL;
+ } else {
+ *passphrase = NULL;
+ *passphrase_len = 0;
+ }
+ }
+
+ entry->conn_type = conn_type;
return TRUE;
}
SilcServerConfigConnParams *param = &server->config->param;
SilcServerConnection sconn;
void *id_entry;
- const char *hostname;
+ const char *hostname, *ip;
SilcUInt16 port;
+ entry->op = NULL;
silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
- NULL, &hostname, NULL, &port);
+ NULL, &hostname, &ip, &port);
if (success == FALSE) {
/* Authentication failed */
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_LOG_DEBUG(("Checking whether connection is allowed"));
- switch (entry->data.conn_type) {
+ switch (entry->conn_type) {
case SILC_CONN_CLIENT:
{
SilcClientEntry client;
SilcServerConfigClient *conn = entry->cconfig.ref_ptr;
/* Verify whether this connection is after all allowed to connect */
- if (!silc_server_connection_allowed(server, sock, entry->data.conn_type,
+ if (!silc_server_connection_allowed(server, sock, entry->conn_type,
&server->config->param,
conn->param,
silc_connauth_get_ske(connauth))) {
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 */
server->stat.my_clients++;
}
/* Add public key to repository */
+ SILC_LOG_DEBUG(("Add client public key to repository"));
if (!silc_server_get_public_key_by_client(server, client, NULL))
silc_skr_add_public_key_simple(server->repository,
entry->data.public_key,
SilcBool backup_router = FALSE;
char *backup_replace_ip = NULL;
SilcUInt16 backup_replace_port = 0;
- SilcServerConfigServer *sconn = entry->sconfig.ref_ptr;
+ SilcServerConfigServer *srvconn = entry->sconfig.ref_ptr;
SilcServerConfigRouter *rconn = entry->rconfig.ref_ptr;
/* If we are backup router and this is incoming server connection
and we do not have connection to primary router, do not allow
the connection. */
if (server->server_type == SILC_BACKUP_ROUTER &&
- entry->data.conn_type == SILC_CONN_SERVER &&
+ entry->conn_type == SILC_CONN_SERVER &&
!SILC_PRIMARY_ROUTE(server)) {
SILC_LOG_INFO(("Will not accept server connection because we do "
"not have primary router connection established"));
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;
}
- if (entry->data.conn_type == SILC_CONN_ROUTER) {
+ if (entry->conn_type == SILC_CONN_ROUTER) {
/* Verify whether this connection is after all allowed to connect */
if (!silc_server_connection_allowed(server, sock,
- entry->data.conn_type,
+ entry->conn_type,
&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;
}
}
}
- if (entry->data.conn_type == SILC_CONN_SERVER) {
+ if (entry->conn_type == SILC_CONN_SERVER) {
/* Verify whether this connection is after all allowed to connect */
if (!silc_server_connection_allowed(server, sock,
- entry->data.conn_type,
+ entry->conn_type,
&server->config->param,
- sconn ? sconn->param : NULL,
+ srvconn ? srvconn->param : NULL,
silc_connauth_get_ske(connauth))) {
server->stat.auth_failures++;
goto out;
}
- if (sconn) {
- if (sconn->param) {
- param = sconn->param;
+ if (srvconn) {
+ if (srvconn->param) {
+ param = srvconn->param;
if (!param->keepalive_secs)
param->keepalive_secs = server->config->param.keepalive_secs;
}
}
- backup_router = sconn->backup_router;
+ backup_router = srvconn->backup_router;
}
}
/* If we are primary router and we have backup router configured
but it has not connected to use yet, do not accept any other
connection. */
-#if 0
if (server->wait_backup && server->server_type == SILC_ROUTER &&
!server->backup_router && !backup_router) {
SilcServerConfigRouter *router;
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. */
goto out;
}
}
-#endif /* 0 */
SILC_LOG_DEBUG(("Remote host is %s",
- entry->data.conn_type == SILC_CONN_SERVER ?
+ entry->conn_type == SILC_CONN_SERVER ?
"server" : (backup_router ?
"backup router" : "router")));
SILC_LOG_INFO(("Connection %s (%s) is %s", entry->hostname,
- entry->ip, entry->data.conn_type == SILC_CONN_SERVER ?
+ entry->ip, entry->conn_type == SILC_CONN_SERVER ?
"server" : (backup_router ?
"backup router" : "router")));
server. We mark ourselves as router for this server if we really
are router. */
new_server =
- silc_idlist_add_server((entry->data.conn_type == SILC_CONN_SERVER ?
+ silc_idlist_add_server((entry->conn_type == SILC_CONN_SERVER ?
server->local_list : (backup_router ?
server->local_list :
server->global_list)),
NULL,
- (entry->data.conn_type == SILC_CONN_SERVER ?
+ (entry->conn_type == SILC_CONN_SERVER ?
SILC_SERVER : SILC_ROUTER),
NULL,
- (entry->data.conn_type == SILC_CONN_SERVER ?
+ (entry->conn_type == SILC_CONN_SERVER ?
server->id_entry : (backup_router ?
server->id_entry : NULL)),
sock);
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;
}
entry->data.status |= SILC_IDLIST_STATUS_LOCAL;
+ entry->data.conn_type = entry->conn_type;
id_entry = (void *)new_server;
if (entry->data.conn_type == SILC_CONN_SERVER) {
server->stat.my_servers++;
server->stat.servers++;
+ SILC_LOG_DEBUG(("my_servers %d", server->stat.my_servers));
} else {
server->stat.my_routers++;
server->stat.routers++;
+ SILC_LOG_DEBUG(("my_routers %d", server->stat.my_routers));
}
/* Check whether this connection is to be our primary router connection
silc_packet_set_context(sock, id_entry);
/* Connection has been fully established now. Everything is ok. */
- SILC_LOG_DEBUG(("New connection authenticated"));
-
-#if 0
- /* Perform keepalive. */
- if (param->keepalive_secs)
- silc_socket_set_heartbeat(sock, param->keepalive_secs, server,
- silc_server_perform_heartbeat,
- server->schedule);
-#endif
+ SILC_LOG_DEBUG(("New connection %p authenticated", sconn));
/* Perform Quality of Service */
if (param->qos)
SilcCipher send_key, receive_key;
SilcHmac hmac_send, hmac_receive;
SilcHash hash;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+
+ entry->op = NULL;
if (status != SILC_SKE_STATUS_OK) {
/* SKE failed */
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);
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;
}
/* Start connection authentication */
- silc_connauth_responder(connauth, silc_server_accept_get_auth,
- silc_server_accept_auth_compl, sock);
+ entry->op =
+ silc_connauth_responder(connauth, silc_server_accept_get_auth,
+ silc_server_accept_auth_compl, sock);
}
/* Accept new TCP connection */
}
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->ip = ip;
entry->port = port;
entry->server = server;
+ entry->data.conn_type = SILC_CONN_UNKNOWN;
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,
/* Start key exchange protocol */
params.version = silc_version_string;
params.timeout_secs = server->config->key_exchange_timeout;
- silc_ske_responder(ske, packet_stream, ¶ms);
+ entry->op = silc_ske_responder(ske, packet_stream, ¶ms);
}
SilcIDListData idata = silc_packet_get_context(sock);
SilcSKE ske;
+ SILC_LOG_DEBUG(("Perform rekey, sock %p", sock));
+
/* Do not execute rekey with disabled connections */
if (idata->status & SILC_IDLIST_STATUS_DISABLED)
return;
SILC_CONNTYPE_STRING(idata->conn_type)));
/* Allocate SKE */
- ske = silc_ske_alloc(server->rng, server->schedule, server->repository,
- server->public_key, server->private_key, sock);
+ ske = silc_ske_alloc(server->rng, server->schedule, NULL,
+ server->public_key, NULL, sock);
if (!ske)
return;
SilcIDListData idata = silc_packet_get_context(sock);
SilcSKE ske;
- SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+ 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, server->repository,
- server->public_key, server->private_key, sock);
+ ske = silc_ske_alloc(server->rng, server->schedule, NULL,
+ server->public_key, NULL, sock);
if (!ske) {
silc_packet_free(packet);
return;
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 0
- /* If any protocol is active cancel its execution. It will call
- the final callback which will finalize the disconnection. */
- if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
- SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
- silc_protocol_cancel(sock->protocol, server->schedule);
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute_final(sock->protocol, server->schedule);
- sock->protocol = NULL;
+ if (!silc_packet_stream_is_valid(sock))
return;
- }
-#endif
memset(tmp, 0, sizeof(tmp));
// silc_socket_get_error(sock, tmp, sizeof(tmp));
// silc_socket_set_qos(sock, 0, 0, 0, 0, NULL);
+ if (idata && idata->sconn) {
+ silc_server_connection_free(idata->sconn);
+ 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,
+ silc_server_close_connection_final, sock);
silc_schedule_task_add_timeout(server->schedule,
silc_server_close_connection_final,
sock, 0, 1);
if (!sock)
return;
- SILC_LOG_DEBUG(("Disconnecting remote host"));
+ SILC_LOG_DEBUG(("Disconnecting remote host, sock %p", sock));
va_start(ap, status);
cp = va_arg(ap, char *);
silc_server_close_connection(server, sock);
}
-SILC_TASK_CALLBACK(silc_server_free_client_data_timeout)
-{
- SilcClientEntry client = context;
-
- assert(!silc_hash_table_count(client->channels));
-
- silc_idlist_del_data(client);
- // silc_idcache_purge_by_context(server->local_list->clients, client);
-}
-
/* Frees client data and notifies about client's signoff. */
void silc_server_free_client_data(SilcServer server,
int notify,
const char *signoff)
{
- SILC_LOG_DEBUG(("Freeing client data"));
+ SILC_LOG_DEBUG(("Freeing client %p data", client));
if (client->id) {
/* Check if anyone is watching this nickname */
SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
silc_schedule_task_del_by_context(server->schedule, client);
+ 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
shutting down server. */
if (!server->server_shutdown) {
- silc_schedule_task_add_timeout(server->schedule,
- silc_server_free_client_data_timeout,
- client, 600, 0);
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
- client->data.status &= ~SILC_IDLIST_STATUS_LOCAL;
client->mode = 0;
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 */
+ SILC_LOG_DEBUG(("Delete client directly"));
silc_idlist_del_data(client);
silc_idlist_del_client(server->local_list, client);
}
SilcPacketStream sock,
const char *signoff_message)
{
- SilcIDListData idata = silc_packet_get_context(sock);
+ SilcIDListData idata;
+ const char *ip;
+ SilcUInt16 port;
+
+ if (!sock)
+ return;
+
+ SILC_LOG_DEBUG(("Start, sock %p", sock));
+ idata = silc_packet_get_context(sock);
if (!idata)
return;
+ 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);
+ }
+ if (idata->conn_type == SILC_CONN_UNKNOWN &&
+ ((SilcUnknownEntry)idata)->op) {
+ SILC_LOG_DEBUG(("Abort active protocol"));
+ silc_async_abort(((SilcUnknownEntry)idata)->op, NULL, NULL);
+ }
+ }
+
switch (idata->conn_type) {
case SILC_CONN_CLIENT:
{
SilcServerEntry user_data = (SilcServerEntry)idata;
SilcServerEntry backup_router = NULL;
- SILC_LOG_DEBUG(("Freeing server data"));
+ SILC_LOG_DEBUG(("Freeing server %p data", user_data));
if (user_data->id)
backup_router = silc_server_backup_get(server, user_data->id);
if (server->server_shutdown || server->backup_noswitch)
backup_router = NULL;
+ silc_socket_stream_get_info(silc_packet_stream_get_stream(sock),
+ NULL, NULL, &ip, &port);
+
/* If this was our primary router connection then we're lost to
the outside world. */
if (server->router == user_data) {
/* We stop here to take a breath */
sleep(2);
-#if 0
if (server->backup_router) {
server->server_type = SILC_ROUTER;
/* We'll need to constantly try to reconnect to the primary
router so that we'll see when it comes back online. */
- silc_server_backup_reconnect(server, sock->ip, sock->port,
+ silc_server_create_connection(server, FALSE, FALSE, ip, port,
silc_server_backup_connected,
NULL);
}
-#endif /* 0 */
/* Mark this connection as replaced */
silc_server_backup_replaced_add(server, user_data->id,
}
server->backup_noswitch = FALSE;
- /* Free the server entry */
- silc_server_backup_del(server, user_data);
- silc_server_backup_replaced_del(server, user_data);
- silc_idlist_del_data(user_data);
- if (!silc_idlist_del_server(server->local_list, user_data))
- silc_idlist_del_server(server->global_list, user_data);
+ if (idata->sconn) {
+ silc_server_connection_free(idata->sconn);
+ idata->sconn = NULL;
+ }
+
+ /* Statistics */
if (idata->conn_type == SILC_CONN_SERVER) {
server->stat.my_servers--;
server->stat.servers--;
- } else {
+ SILC_LOG_DEBUG(("my_servers %d", server->stat.my_servers));
+ } else if (idata->conn_type == SILC_CONN_ROUTER) {
server->stat.my_routers--;
server->stat.routers--;
+ SILC_LOG_DEBUG(("my_routers %d", server->stat.my_routers));
}
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers--;
+ /* Free the server entry */
+ silc_server_backup_del(server, user_data);
+ silc_server_backup_replaced_del(server, user_data);
+ silc_idlist_del_data(user_data);
+ if (!silc_idlist_del_server(server->local_list, user_data))
+ silc_idlist_del_server(server->global_list, user_data);
+
if (backup_router && backup_router != server->id_entry) {
/* Announce all of our stuff that was created about 5 minutes ago.
The backup router knows all the other stuff already. */
{
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;
+ }
+
+ 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)) {
if (!client->connection && !client->router)
continue;
- idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ SILC_LOG_DEBUG(("Announce Client ID %s",
+ silc_id_render(client->id, SILC_ID_CLIENT)));
- *clients = silc_buffer_realloc(*clients,
- (*clients ?
- silc_buffer_truelen((*clients)) +
- silc_buffer_len(idp) :
- silc_buffer_len(idp)));
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ if (!idp)
+ return;
+
+ 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));
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
+ SILC_LOG_DEBUG(("JOIN Client %s", silc_id_render(chl->client->id,
+ SILC_ID_CLIENT)));
+
/* JOIN Notify */
tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_JOIN, 2,
clidp->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"));
else
announce = TRUE;
+ SILC_LOG_DEBUG(("Announce Channel ID %s",
+ silc_id_render(channel->id, SILC_ID_CHANNEL)));
+
silc_id_id2str(channel->id, SILC_ID_CHANNEL, cid, sizeof(cid), &id_len);
name_len = strlen(channel->channel_name);
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],
/* Assembles user list and users mode list from the `channel'. */
SilcBool silc_server_get_users_on_channel(SilcServer server,
- SilcChannelEntry channel,
- SilcBuffer *user_list,
- SilcBuffer *mode_list,
- SilcUInt32 *user_count)
+ SilcChannelEntry channel,
+ SilcBuffer *user_list,
+ SilcBuffer *mode_list,
+ SilcUInt32 *user_count)
{
SilcChannelClientEntry chl;
SilcHashTableList htl;
SILC_LOG_DEBUG(("Retrieving stats from router"));
server->stat.commands_sent++;
idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
- packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
- ++server->cmd_ident, 1,
- 1, idp->data,
- silc_buffer_len(idp));
- silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
- SILC_PACKET_COMMAND, 0, packet->data,
- silc_buffer_len(packet));
- silc_buffer_free(packet);
- silc_buffer_free(idp);
+ if (idp) {
+ packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
+ ++server->cmd_ident, 1,
+ 1, idp->data,
+ silc_buffer_len(idp));
+ silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
+ SILC_PACKET_COMMAND, 0, packet->data,
+ silc_buffer_len(packet));
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
}
silc_schedule_task_add_timeout(server->schedule, silc_server_get_stats,