From 8e164669b363452ae89fd48b5ddeee3446636217 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 10 Jun 2007 19:32:58 +0000 Subject: [PATCH] Added preliminary support for dynamic connection during joining. --- apps/silcd/command.c | 102 ++++++++++++++++------- apps/silcd/command_reply.c | 3 +- apps/silcd/packet_receive.c | 3 +- apps/silcd/server.c | 78 +++++++++++++----- apps/silcd/server_query.c | 158 +++++++++++++++++------------------- 5 files changed, 206 insertions(+), 138 deletions(-) diff --git a/apps/silcd/command.c b/apps/silcd/command.c index f2211f50..e52244a3 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -2294,36 +2294,37 @@ static void silc_server_command_join_channel(SilcServer server, /* Server side of command JOIN. Joins client into requested channel. If the channel does not exist it will be created. */ -/* Ways of creating channel with dynamic connections: - - 1. If channels are not local (no local_channels in silcd.conf) then - /join silc, will create connection to default router if it is - specified in the silcd.conf. If it isn't, it creates local channel. - - 2. If channels are not local then /join silc@silcnet.org, will create - connection to default if it is specified in the silcd.conf and if it - isn't or join fails it creates connection to silcnet.org and sends - the JOIN command to that server/router. - - 3. If channels are local (local_channels set in silcd.conf) then - /join silc, will create local channel. No connections are created - to anywhere. - - 4. If channels are local then /join silc@silcnet.org will create - connection to default router if it is specified in the silcd.conf and - if it isn't, or join fails it creates connection to silcnet.org and - send the JOIN command to that server/router. - - 5. If we create connection to a remote that already has a channel that - we also have as a local channel, should we merge those channels? - Should I announce my local channels when I connect to router? Should - I keep local channels local, unless I say /join localch@silcnet.org - in which case the local channel 'localch' becomes global? - - 6. After we have connection established to router, depending on the - local_channels setting /join silc will join locally or globally. - /join silc@silcnet.org would always join globally. -*/ +void silc_server_command_join_connected(SilcServer server, + SilcServerEntry server_entry, + void *context) +{ + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + + if (!server_entry) { + SilcUInt32 tmp_len; + unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len); + char serv[256 + 1]; + + SILC_LOG_DEBUG(("Connecting to router failed")); + silc_parse_userfqdn(tmp, NULL, 0, serv, sizeof(serv)); + + if (serv[0]) { + silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN, + SILC_STATUS_ERR_NO_SUCH_SERVER, 0, + 2, serv, strlen(serv)); + } else { + silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN, + SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0, + 2, tmp, tmp_len); + } + silc_server_command_free(cmd); + return; + } + + /* Reprocess command */ + SILC_LOG_DEBUG(("Reprocess JOIN after connecting to router")); + silc_server_command_join(cmd, NULL); +} SILC_SERVER_CMD_FUNC(join) { @@ -2357,10 +2358,49 @@ SILC_SERVER_CMD_FUNC(join) } /* Parse server name from the channel name */ - silc_parse_userfqdn(channel_name, parsed, sizeof(parsed), serv, + silc_parse_userfqdn(tmp, parsed, sizeof(parsed), serv, sizeof(serv)); channel_name = parsed; + /* If server name is not specified but local channels is FALSE then the + channel will be global, based on our router name. */ + if (!serv[0] && !server->config->local_channels) { + if (!server->standalone) { + silc_snprintf(serv, sizeof(serv), server->router->server_name); + } else { + SilcServerConfigRouter *router; + router = silc_server_config_get_primary_router(server); + if (router) { + /* Create connection to primary router */ + SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d", + router->host, router->port)); + silc_server_create_connection(server, FALSE, TRUE, + router->host, router->port, + silc_server_command_join_connected, cmd); + return; + } + } + } + + /* If server name is ours, ignore it. */ + if (serv[0] && silc_utf8_strcasecmp(serv, server->server_name)) + memset(serv, 0, sizeof(serv)); + + /* Create connection */ + if (serv[0] && server->standalone) { + SilcServerConfigRouter *router; + router = silc_server_config_get_primary_router(server); + if (router) { + /* Create connection to primary router */ + SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d", + router->host, router->port)); + silc_server_create_connection(server, FALSE, TRUE, + router->host, router->port, + silc_server_command_join_connected, cmd); + return; + } + } + /* Check for valid channel name. This is cached, the original is saved in the channel context. */ channel_namec = silc_channel_name_check(channel_name, strlen(channel_name), diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index acf1e2dd..97aedf0e 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -1199,7 +1199,8 @@ SILC_SERVER_CMD_REPLY_FUNC(join) silc_hmac_free(hmac); silc_server_command_reply_free(cmd); - silc_pkcs_public_key_free(founder_key); + if (founder_key) + silc_pkcs_public_key_free(founder_key); if (client_id_list) silc_buffer_free(client_id_list); if (client_mode_list) diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index f17e2854..04eeb0d3 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2637,7 +2637,8 @@ static void silc_server_new_id_real(SilcServer server, global list. Cell wide information however is kept in the local list. */ entry = silc_idlist_add_client(id_list, NULL, NULL, NULL, - &id, router, NULL); + silc_id_dup(&id, SILC_ID_CLIENT), + router, NULL); if (!entry) { SILC_LOG_ERROR(("Could not add new client to the ID Cache")); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index d4770c1f..ca41f9be 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -79,6 +79,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 +214,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, @@ -235,22 +265,9 @@ static void silc_server_packet_error(SilcPacketEngine engine, SILC_CONNTYPE_STRING(idata->conn_type), silc_packet_error_string(error))); - 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); + silc_schedule_task_add_timeout(server->schedule, + silc_server_packet_error_timeout, + stream, 0, 0); } /* Packet stream callbacks */ @@ -1539,6 +1556,17 @@ silc_server_ke_auth_compl(SilcConnAuth connauth, SilcBool success, silc_server_backup_add(server, server->id_entry, sock->ip, sconn->remote_port, TRUE); #endif /* 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; } } else { /* Add this server to be our backup router */ @@ -2084,7 +2112,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; @@ -2965,6 +2999,9 @@ 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. */ @@ -3019,8 +3056,6 @@ void silc_server_free_sock_user_data(SilcServer server, SilcClientEntry client_entry = (SilcClientEntry)idata; silc_server_free_client_data(server, sock, client_entry, TRUE, signoff_message); - if (idata->sconn) - silc_server_connection_free(idata->sconn); silc_packet_set_context(sock, NULL); break; } @@ -3182,6 +3217,9 @@ void silc_server_free_sock_user_data(SilcServer server, } server->backup_noswitch = FALSE; + if (idata->sconn) + silc_server_connection_free(idata->sconn); + /* Free the server entry */ silc_server_backup_del(server, user_data); silc_server_backup_replaced_del(server, user_data); @@ -3212,8 +3250,6 @@ void silc_server_free_sock_user_data(SilcServer server, backup_router->connection); } - if (idata->sconn) - silc_server_connection_free(idata->sconn); silc_packet_set_context(sock, NULL); break; } diff --git a/apps/silcd/server_query.c b/apps/silcd/server_query.c index 634a15fa..d3a243a5 100644 --- a/apps/silcd/server_query.c +++ b/apps/silcd/server_query.c @@ -76,6 +76,7 @@ typedef struct { unsigned int dynamic_prim : 1; /* Dynamic connection attempt to primary */ unsigned int dynamic_retry : 1; /* Primary returned error, send to nick@serv server. */ + unsigned int parsed : 1; /* Set when query is parsed */ } *SilcServerQuery; @@ -94,7 +95,8 @@ void silc_server_query_add_error_id(SilcServer server, void *id, SilcIdType id_type); void silc_server_query_send_router(SilcServer server, SilcServerQuery query); void silc_server_query_send_router_reply(void *context, void *reply); -void silc_server_query_parse(SilcServer server, SilcServerQuery query); +SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query, + SilcBool parse_only); void silc_server_query_process(SilcServer server, SilcServerQuery query, SilcBool resolve); void silc_server_query_resolve(SilcServer server, SilcServerQuery query, @@ -254,6 +256,8 @@ SilcBool silc_server_query_command(SilcServer server, (!silc_argument_get_arg_type(cmd->args, 1, NULL) && !silc_argument_get_arg_type(cmd->args, 4, NULL) && silc_argument_get_arg_type(cmd->args, 3, NULL)))) { + if (!silc_server_query_parse(server, query, TRUE)) + return FALSE; silc_server_query_send_router(server, query); return TRUE; } @@ -275,6 +279,8 @@ SilcBool silc_server_query_command(SilcServer server, if (server->server_type == SILC_SERVER && !server->standalone && cmd->sock != SILC_PRIMARY_ROUTE(server) && !silc_argument_get_arg_type(cmd->args, 5, NULL)) { + if (!silc_server_query_parse(server, query, TRUE)) + return FALSE; silc_server_query_send_router(server, query); return TRUE; } @@ -287,7 +293,7 @@ SilcBool silc_server_query_command(SilcServer server, } /* Now parse the request */ - silc_server_query_parse(server, query); + silc_server_query_parse(server, query, FALSE); return TRUE; } @@ -387,11 +393,11 @@ void silc_server_query_send_router_reply(void *context, void *reply) returned error. */ if (query->nick_server[0] && !query->dynamic_retry && !silc_server_num_sockets_by_remote(server, query->nick_server, - query->nick_server, 706)) { + query->nick_server, 1334)) { SILC_LOG_DEBUG(("Retry query by connecting to %s:%d", query->nick_server, 706)); silc_server_create_connection(server, FALSE, TRUE, query->nick_server, - 706, silc_server_query_connected, + 1334, silc_server_query_connected, query); query->dynamic_retry = TRUE; query->resolved = FALSE; @@ -417,12 +423,13 @@ void silc_server_query_send_router_reply(void *context, void *reply) } /* Continue with parsing */ - silc_server_query_parse(server, query); + silc_server_query_parse(server, query, FALSE); } /* Parse the command query and start processing the queries in detail. */ -void silc_server_query_parse(SilcServer server, SilcServerQuery query) +SilcBool silc_server_query_parse(SilcServer server, SilcServerQuery query, + SilcBool parse_only) { SilcServerCommandContext cmd = query->cmd; SilcIDListData idata = silc_packet_get_context(cmd->sock); @@ -434,6 +441,9 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) SILC_LOG_DEBUG(("Parsing %s query", silc_get_command_name(query->querycmd))); + if (query->parsed) + goto parsed; + switch (query->querycmd) { case SILC_COMMAND_WHOIS: @@ -460,7 +470,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); silc_server_query_free(query); - return; + return FALSE; } /* Get the nickname@server string and parse it */ @@ -472,7 +482,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_NICKNAME, 0); silc_server_query_free(query); - return; + return FALSE; } /* Check nickname */ @@ -483,45 +493,13 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_NICKNAME, 0); silc_server_query_free(query); - return; + return FALSE; } memset(query->nickname, 0, sizeof(query->nickname)); silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp); silc_free(tmp); } - /* Check server name. If we are open server and don't yet have - connection to remote router, create it now. */ - if (query->nick_server[0] && server->config->open_server && - !query->resolved) { - /* If primary router is specified, use that. Otherwise connect - to the server in nick@server string. */ - SilcServerConfigRouter *router; - - router = silc_server_config_get_primary_router(server); - if (router && server->standalone) { - /* Create connection to primary router */ - SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d", - router->host, router->port)); - query->dynamic_prim = TRUE; - silc_server_create_connection(server, FALSE, TRUE, - router->host, router->port, - silc_server_query_connected, query); - return; - } else if (!silc_server_num_sockets_by_remote(server, - query->nick_server, - query->nick_server, - 706)) { - /* Create connection and handle the query after connection */ - SILC_LOG_DEBUG(("Create dynamic connection to %s:%d", - query->nick_server, 706)); - silc_server_create_connection(server, FALSE, TRUE, - query->nick_server, 706, - silc_server_query_connected, query); - return; - } - } - } else { /* Parse the IDs included in the query */ query->ids = silc_calloc(argc, sizeof(*query->ids)); @@ -552,7 +530,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_free(query->ids); query->ids = NULL; query->ids_count = 0; - return; + return FALSE; } } } @@ -577,7 +555,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); silc_server_query_free(query); - return; + return FALSE; } /* Get the nickname@server string and parse it */ @@ -587,7 +565,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_NICKNAME, 0); silc_server_query_free(query); - return; + return FALSE; } /* Check nickname */ @@ -597,7 +575,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_NICKNAME, 0); silc_server_query_free(query); - return; + return FALSE; } memset(query->nickname, 0, sizeof(query->nickname)); silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp); @@ -633,7 +611,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_NICKNAME, 0); silc_server_query_free(query); - return; + return FALSE; } memset(query->nickname, 0, sizeof(query->nickname)); silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp); @@ -650,7 +628,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_SERVER, 0); silc_server_query_free(query); - return; + return FALSE; } query->server_name = tmp; } @@ -665,7 +643,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_BAD_CHANNEL, 0); silc_server_query_free(query); - return; + return FALSE; } query->channel_name = tmp; } @@ -674,39 +652,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_server_query_send_error(server, query, SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); silc_server_query_free(query); - return; - } - - /* Check server name. If we are open server and don't yet have - connection to remote router, create it now. */ - if (query->nick_server[0] && server->config->open_server && - !query->resolved) { - /* If primary router is specified, use that. Otherwise connect - to the server in nick@server string. */ - SilcServerConfigRouter *router; - - router = silc_server_config_get_primary_router(server); - if (router && server->standalone) { - /* Create connection to primary router */ - SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d", - router->host, router->port)); - query->dynamic_prim = TRUE; - silc_server_create_connection(server, FALSE, TRUE, - router->host, router->port, - silc_server_query_connected, query); - return; - } else if (!silc_server_num_sockets_by_remote(server, - query->nick_server, - query->nick_server, - 706)) { - /* Create connection and handle the query after connection */ - SILC_LOG_DEBUG(("Create dynamic connection to %s:%d", - query->nick_server, 706)); - silc_server_create_connection(server, FALSE, TRUE, - query->nick_server, 706, - silc_server_query_connected, query); - return; - } + return FALSE; } } else { @@ -740,7 +686,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_free(query->ids); query->ids = NULL; query->ids_count = 0; - return; + return FALSE; } } } else { @@ -752,7 +698,7 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) silc_free(query->ids); query->ids = NULL; query->ids_count = 0; - return; + return FALSE; } } @@ -777,8 +723,52 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) break; } + query->parsed = TRUE; + + parsed: + if (!parse_only && query->nickname) { + switch (query->querycmd) { + case SILC_COMMAND_WHOIS: + case SILC_COMMAND_IDENTIFY: + /* Check server name. If we are open server and don't yet have + connection to remote router, create it now. */ + if (query->nick_server[0] && server->config->dynamic_server && + !query->resolved) { + /* If primary router is specified, use that. Otherwise connect + to the server in nick@server string. */ + SilcServerConfigRouter *router; + + router = silc_server_config_get_primary_router(server); + if (router && server->standalone) { + /* Create connection to primary router */ + SILC_LOG_DEBUG(("Create dynamic connection to primary router %s:%d", + router->host, router->port)); + query->dynamic_prim = TRUE; + silc_server_create_connection(server, FALSE, TRUE, + router->host, router->port, + silc_server_query_connected, query); + return FALSE; + } else if (!silc_server_num_sockets_by_remote(server, + query->nick_server, + query->nick_server, + 706)) { + /* Create connection and handle the query after connection */ + SILC_LOG_DEBUG(("Create dynamic connection to %s:%d", + query->nick_server, 706)); + silc_server_create_connection(server, FALSE, TRUE, + query->nick_server, 706, + silc_server_query_connected, query); + return FALSE; + } + } + } + } + /* Start processing the query information */ - silc_server_query_process(server, query, TRUE); + if (!parse_only) + silc_server_query_process(server, query, TRUE); + + return TRUE; } /* Context for holding clients searched by public key. */ -- 2.24.0