X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=apps%2Fsilcd%2Fserver.c;h=46fccfc085d68ca3bb47b682dd69c7026be39a14;hp=16d2298881a375e8e088cd4ed047529175e3df1e;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hpb=ae1482a76c29db9fdcd6ed6cf63d312a37a5cb01 diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 16d22988..46fccfc0 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2005, 2007 Pekka Riikonen + Copyright (C) 1997 - 2007 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 @@ -24,6 +24,7 @@ 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, @@ -79,6 +80,9 @@ static SilcBool silc_server_packet_receive(SilcPacketEngine engine, SilcServer server = callback_context; SilcIDListData idata = stream_context; + if (!idata) + return FALSE; + /* Packets we do not handle */ switch (packet->type) { case SILC_PACKET_HEARTBEAT: @@ -211,6 +215,33 @@ static void silc_server_packet_eos(SilcPacketEngine engine, 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; + + if (server->router_conn && server->router_conn->sock == stream && + !server->router && server->standalone) { + silc_server_create_connections(server); + } 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); +} + /* Packet engine callback to indicate error */ static void silc_server_packet_error(SilcPacketEngine engine, @@ -219,6 +250,7 @@ static void silc_server_packet_error(SilcPacketEngine engine, 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; @@ -230,9 +262,13 @@ static void silc_server_packet_error(SilcPacketEngine engine, 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))); + + silc_schedule_task_add_timeout(server->schedule, + silc_server_packet_error_timeout, + stream, 0, 0); } /* Packet stream callbacks */ @@ -337,11 +373,13 @@ static void silc_server_packet_parse_type(SilcServer server, 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, @@ -354,21 +392,18 @@ static void silc_server_packet_parse_type(SilcServer server, 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; @@ -497,9 +532,7 @@ static void silc_server_packet_parse_type(SilcServer server, router resuming protocol. */ if (packet->flags & SILC_PACKET_FLAG_LIST) break; -#if 0 silc_server_backup_resume_router(server, sock, packet); -#endif break; default: @@ -560,6 +593,9 @@ void silc_server_free(SilcServer server) { SilcList list; SilcIDCacheEntry cache; + SilcIDListData idata; + + SILC_LOG_DEBUG(("Free server %p", server)); if (!server) return; @@ -574,8 +610,12 @@ void silc_server_free(SilcServer server) 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)) { @@ -592,24 +632,38 @@ void silc_server_free(SilcServer server) /* 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_idcache_free(server->local_list->clients); @@ -629,11 +683,13 @@ void silc_server_free(SilcServer server) silc_skr_free(server->repository); silc_packet_engine_stop(server->packet_engine); + silc_schedule_task_del_by_context(server->schedule, server); + silc_schedule_uninit(server->schedule); + server->schedule = NULL; + 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(); @@ -667,60 +723,19 @@ silc_server_listen(SilcServer server, const char *server_ip, SilcUInt16 port) 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 @@ -734,7 +749,6 @@ SilcBool silc_server_init(SilcServer server) { SilcServerID *id; SilcServerEntry id_entry; - SilcIDListPurge purge; SilcNetListener listener; SilcUInt16 *port; char **ip; @@ -836,13 +850,14 @@ SilcBool silc_server_init(SilcServer server) 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; @@ -862,12 +877,16 @@ SilcBool silc_server_init(SilcServer server) 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 */ @@ -896,23 +915,6 @@ SilcBool silc_server_init(SilcServer server) } } - /* 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 we are normal server we'll retrieve network statisticial information once in a while from the router. */ if (server->server_type != SILC_ROUTER) @@ -932,7 +934,7 @@ SilcBool silc_server_init(SilcServer server) /* 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); @@ -947,32 +949,28 @@ SilcBool silc_server_init(SilcServer 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 @@ -981,7 +979,6 @@ SILC_TASK_CALLBACK(silc_server_rehash_close_connection) SilcBool silc_server_rehash(SilcServer server) { -#if 0 SilcServerConfig newconfig; SILC_LOG_INFO(("Rehashing server")); @@ -997,12 +994,6 @@ SilcBool silc_server_rehash(SilcServer 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); @@ -1021,13 +1012,10 @@ SilcBool silc_server_rehash(SilcServer server) /* 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 */ @@ -1043,13 +1031,6 @@ SilcBool silc_server_rehash(SilcServer server) 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 @@ -1078,11 +1059,10 @@ SilcBool silc_server_rehash(SilcServer server) 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); } } } @@ -1108,11 +1088,10 @@ SilcBool silc_server_rehash(SilcServer server) 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); } } } @@ -1139,10 +1118,9 @@ SilcBool silc_server_rehash(SilcServer server) 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); } } } @@ -1185,7 +1163,6 @@ SilcBool silc_server_rehash(SilcServer server) #endif /* SILC_DEBUG */ SILC_LOG_DEBUG(("Server rehashed")); -#endif /* 0 */ return TRUE; } @@ -1233,7 +1210,7 @@ void silc_server_stop(SilcServer server) 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 */ @@ -1245,9 +1222,13 @@ void silc_server_stop(SilcServer server) 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_stop(server->schedule); - silc_schedule_uninit(server->schedule); - server->schedule = NULL; SILC_LOG_DEBUG(("Server stopped")); } @@ -1259,6 +1240,7 @@ SILC_TASK_CALLBACK(silc_server_purge_expired_clients) SilcServer server = context; SilcClientEntry client; SilcIDList id_list; + SilcUInt64 curtime = silc_time(); SILC_LOG_DEBUG(("Expire timeout")); @@ -1267,6 +1249,12 @@ SILC_TASK_CALLBACK(silc_server_purge_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) + continue; + id_list = (client->data.status & SILC_IDLIST_STATUS_LOCAL ? server->local_list : server->global_list); @@ -1277,7 +1265,7 @@ SILC_TASK_CALLBACK(silc_server_purge_expired_clients) silc_schedule_task_add_timeout(server->schedule, silc_server_purge_expired_clients, server, - 600, 0); + 120, 0); } @@ -1285,8 +1273,9 @@ SILC_TASK_CALLBACK(silc_server_purge_expired_clients) /* Free connection context */ -static void silc_server_connection_free(SilcServerConnection sconn) +void silc_server_connection_free(SilcServerConnection sconn) { + 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); @@ -1298,6 +1287,7 @@ static void silc_server_connection_free(SilcServerConnection sconn) void silc_server_create_connection(SilcServer server, SilcBool reconnect, + SilcBool dynamic, const char *remote_host, SilcUInt32 port, SilcServerConnectCallback callback, void *context) @@ -1313,6 +1303,10 @@ void silc_server_create_connection(SilcServer server, 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); @@ -1330,22 +1324,31 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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 authentication completed")); + sconn->op = NULL; + if (success == FALSE) { /* Authentication failed */ /* XXX retry connecting */ 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); 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)); @@ -1363,6 +1366,8 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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); return; @@ -1385,6 +1390,8 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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); return; @@ -1415,11 +1422,15 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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) { 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); return; @@ -1427,9 +1438,10 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, /* 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; if (!sconn->backup) { /* Mark this router our primary router if we're still standalone */ @@ -1459,12 +1471,27 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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); + 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); + return; #endif /* 0 */ } } else { @@ -1479,11 +1506,15 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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); return; } + SILC_LOG_DEBUG(("Connection established, sock %p", sconn->sock)); + conn = sconn->conn.ref_ptr; param = &server->config->param; if (conn && conn->param) @@ -1494,11 +1525,8 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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 @@ -1506,16 +1534,8 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, 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); } @@ -1528,8 +1548,9 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, 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 = silc_ske_get_context(ske); SilcServer server = entry->server; SilcServerConfigRouter *conn = sconn->conn.ref_ptr; SilcAuthMethod auth_meth = SILC_AUTH_NONE; @@ -1540,6 +1561,8 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, SilcHmac hmac_send, hmac_receive; SilcHash hash; + sconn->op = NULL; + if (status != SILC_SKE_STATUS_OK) { /* SKE failed */ SILC_LOG_ERROR(("Error (%s) during Key Exchange protocol with %s (%s)", @@ -1549,6 +1572,8 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, 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); return; } @@ -1565,6 +1590,8 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, 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); return; } @@ -1582,6 +1609,8 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, 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); return; } @@ -1603,11 +1632,14 @@ static void silc_server_ke_completed(SilcSKE ske, SilcSKEStatus status, } } + 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); + sconn->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 @@ -1631,6 +1663,8 @@ void silc_server_start_key_exchange(SilcServerConnection sconn) 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; } @@ -1640,6 +1674,8 @@ void silc_server_start_key_exchange(SilcServerConnection sconn) if (!silc_packet_set_ids(sconn->sock, SILC_ID_SERVER, server->id, 0, NULL)) { silc_packet_stream_destroy(sconn->sock); + if (sconn->callback) + (*sconn->callback)(server, NULL, sconn->callback_context); silc_server_connection_free(sconn); return; } @@ -1664,10 +1700,12 @@ void silc_server_start_key_exchange(SilcServerConnection sconn) /* Start SILC Key Exchange protocol */ SILC_LOG_DEBUG(("Starting key exchange protocol")); 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); silc_packet_stream_destroy(sconn->sock); + if (sconn->callback) + (*sconn->callback)(server, NULL, sconn->callback_context); silc_server_connection_free(sconn); return; } @@ -1677,7 +1715,7 @@ void silc_server_start_key_exchange(SilcServerConnection sconn) /* 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); + sconn->op = silc_ske_initiator(ske, sconn->sock, ¶ms, NULL); } /* Timeout callback that will be called to retry connecting to remote @@ -1712,6 +1750,9 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_retry) 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; } @@ -1754,6 +1795,9 @@ static void silc_server_connection_established(SilcNetStatus status, 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; @@ -1765,7 +1809,10 @@ static void silc_server_connection_established(SilcNetStatus status, 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; @@ -1784,6 +1831,8 @@ SILC_TASK_CALLBACK(silc_server_connect_router) /* 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; } @@ -1792,7 +1841,7 @@ SILC_TASK_CALLBACK(silc_server_connect_router) (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); @@ -1844,7 +1893,6 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) "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. */ @@ -1853,6 +1901,12 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) 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) { @@ -1868,13 +1922,16 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) 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)); @@ -1892,11 +1949,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) 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 { @@ -1908,6 +1962,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router) 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; @@ -1916,7 +1971,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_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; @@ -1972,7 +2028,13 @@ silc_server_accept_get_auth(SilcConnAuth connauth, /* 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; @@ -2016,11 +2078,12 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, 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 */ @@ -2140,7 +2203,7 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, 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 @@ -2199,14 +2262,14 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, if (!silc_server_connection_allowed(server, sock, entry->data.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; @@ -2220,14 +2283,13 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, } } - 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; @@ -2252,7 +2314,6 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, goto out; } } -#endif /* 0 */ SILC_LOG_DEBUG(("Remote host is %s", entry->data.conn_type == SILC_CONN_SERVER ? @@ -2313,9 +2374,11 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, 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 @@ -2357,15 +2420,7 @@ silc_server_accept_auth_compl(SilcConnAuth connauth, SilcBool success, 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) @@ -2400,6 +2455,10 @@ silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status, 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 */ @@ -2427,6 +2486,8 @@ silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status, 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_LOG_DEBUG(("Starting connection authentication")); server->stat.auth_attempts++; @@ -2442,8 +2503,9 @@ silc_server_accept_completed(SilcSKE ske, SilcSKEStatus status, } /* 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 */ @@ -2548,6 +2610,7 @@ static void silc_server_accept_new_connection(SilcNetStatus status, entry->ip = ip; entry->port = port; entry->server = server; + entry->data.conn_type = SILC_CONN_UNKNOWN; silc_packet_set_context(packet_stream, entry); silc_server_config_ref(&entry->cconfig, server->config, cconfig); @@ -2584,7 +2647,7 @@ static void silc_server_accept_new_connection(SilcNetStatus status, /* 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); } @@ -2631,6 +2694,8 @@ SILC_TASK_CALLBACK(silc_server_do_rekey) 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; @@ -2648,8 +2713,8 @@ SILC_TASK_CALLBACK(silc_server_do_rekey) 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; @@ -2701,8 +2766,8 @@ static void silc_server_rekey(SilcServer server, SilcPacketStream sock, 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) { silc_packet_free(packet); return; @@ -2736,20 +2801,6 @@ void silc_server_close_connection(SilcServer server, 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; - return; - } -#endif - memset(tmp, 0, sizeof(tmp)); // silc_socket_get_error(sock, tmp, sizeof(tmp)); silc_socket_stream_get_info(silc_packet_stream_get_stream(sock), @@ -2760,8 +2811,15 @@ void silc_server_close_connection(SilcServer server, // silc_socket_set_qos(sock, 0, 0, 0, 0, NULL); + if (idata && idata->sconn) { + silc_server_connection_free(idata->sconn); + idata->sconn = NULL; + } + /* 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); @@ -2799,16 +2857,6 @@ void silc_server_disconnect_remote(SilcServer server, 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, @@ -2817,7 +2865,7 @@ 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 */ @@ -2859,20 +2907,22 @@ void silc_server_free_client_data(SilcServer server, 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); + /* 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_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); } @@ -2887,10 +2937,29 @@ void silc_server_free_sock_user_data(SilcServer server, const char *signoff_message) { SilcIDListData idata = silc_packet_get_context(sock); + const char *ip; + SilcUInt16 port; + + SILC_LOG_DEBUG(("Start")); if (!idata) return; + silc_schedule_task_del_by_context(server->schedule, 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: { @@ -2907,7 +2976,7 @@ void silc_server_free_sock_user_data(SilcServer server, 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); @@ -2920,6 +2989,9 @@ void silc_server_free_sock_user_data(SilcServer server, 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) { @@ -2956,17 +3028,15 @@ void silc_server_free_sock_user_data(SilcServer server, /* 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, @@ -3058,22 +3128,29 @@ void silc_server_free_sock_user_data(SilcServer server, } 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); + + /* 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. */ @@ -3098,6 +3175,8 @@ void silc_server_free_sock_user_data(SilcServer server, SILC_LOG_DEBUG(("Freeing unknown connection data")); + if (idata->sconn) + silc_server_connection_free(idata->sconn); silc_idlist_del_data(idata); silc_free(entry); silc_packet_set_context(sock, NULL); @@ -3878,6 +3957,9 @@ static void silc_server_announce_get_clients(SilcServer server, if (!client->connection && !client->router) continue; + SILC_LOG_DEBUG(("Announce Client ID %s", + silc_id_render(client->id, SILC_ID_CLIENT))); + idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT); *clients = silc_buffer_realloc(*clients, @@ -4105,6 +4187,9 @@ void silc_server_announce_get_channel_users(SilcServer server, 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, @@ -4198,6 +4283,9 @@ void silc_server_announce_get_channels(SilcServer server, 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); @@ -4502,10 +4590,10 @@ void silc_server_announce_watches(SilcServer server, /* 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; @@ -4919,15 +5007,17 @@ SILC_TASK_CALLBACK(silc_server_get_stats) 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,