SilcDList attrs; /* Requested Attributes in WHOIS */
/* Query session data */
+ SilcPacketStream router; /* Router to send our query */
SilcServerCommandContext cmd; /* Command context for query */
SilcServerQueryList querylist; /* Temporary query list context */
SilcServerQueryID queries; /* Ongoing queries */
SilcUInt16 queries_count; /* Number of ongoing queries */
SilcUInt16 queries_left; /* Number of ongoing queries left */
SilcUInt16 errors_count; /* number of errors */
- unsigned int querycmd : 7; /* Query command (SilcCommand) */
- unsigned int resolved : 1; /* TRUE if normal server has resolved
+ unsigned int querycmd : 7; /* Query command (SilcCommand) */
+ unsigned int resolved : 1; /* TRUE if normal server has resolved
information from router */
+ unsigned int dynamic_prim : 1; /* Dynamic connection attempt to primary */
+ unsigned int dynamic_retry : 1; /* Primary returned error, send to
+ nick@serv server. */
} *SilcServerQuery;
+
void silc_server_query_free(SilcServerQuery query);
void silc_server_query_send_error(SilcServer server,
SilcServerQuery query,
to the entity who sent this query to us automatically. Returns
TRUE if the query is being processed or FALSE on error. */
-SilcBool silc_server_query_command(SilcServer server, SilcCommand querycmd,
- SilcServerCommandContext cmd)
+SilcBool silc_server_query_command(SilcServer server,
+ SilcCommand querycmd,
+ SilcServerCommandContext cmd,
+ void *old_query)
{
SilcServerQuery query;
SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
- query = silc_calloc(1, sizeof(*query));
- query->querycmd = querycmd;
- query->cmd = silc_server_command_dup(cmd);
+ if (!old_query) {
+ query = silc_calloc(1, sizeof(*query));
+ query->querycmd = querycmd;
+ query->cmd = silc_server_command_dup(cmd);
+ query->router = SILC_PRIMARY_ROUTE(server);
+ } else
+ query = old_query;
switch (querycmd) {
return TRUE;
}
+/* Remote server connected callback. */
+
+void silc_server_query_connected(SilcServer server,
+ SilcServerEntry server_entry,
+ void *context)
+{
+ SilcServerQuery query = context;
+
+ if (!server_entry) {
+ /* Connecting failed */
+
+ if (query->dynamic_prim /* && @serv != prim.host.name */ &&
+ !silc_server_num_sockets_by_remote(server, query->nick_server,
+ query->nick_server, 706)) {
+ /* Connection attempt to primary router failed, now try to the one
+ specified in nick@server. */
+ silc_server_create_connection(server, FALSE, TRUE, query->nick_server,
+ 706, silc_server_query_connected,
+ query);
+ query->dynamic_prim = FALSE;
+ return;
+ }
+
+ /* Process the query after failed connect. This will send error back
+ because such nick was not found. */
+ SILC_LOG_DEBUG(("Process query, connecting failed"));
+ silc_server_query_process(server, query, TRUE);
+ return;
+ }
+
+ /* Reprocess the query */
+ SILC_LOG_DEBUG(("Reprocess query after creating connection to %s",
+ server_entry->server_name));
+ query->router = server_entry->data.sconn->sock;
+ silc_server_query_command(server, query->querycmd, query->cmd, query);
+}
+
/* Send the received query to our primary router since we could not
handle the query directly. We will reprocess the query after our
router replies back. */
SilcBuffer tmpbuf;
SilcUInt16 old_ident;
- SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
+ SILC_LOG_DEBUG(("Forwarding the query to router %p for processing",
+ query->router));
/* Statistics */
server->stat.commands_sent++;
old_ident = silc_command_get_ident(query->cmd->payload);
silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
- silc_server_packet_send(server,
- SILC_PRIMARY_ROUTE(server),
+ silc_server_packet_send(server, query->router,
SILC_PACKET_COMMAND, 0,
tmpbuf->data, silc_buffer_len(tmpbuf));
silc_command_set_ident(query->cmd->payload, old_ident);
if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
SilcBuffer buffer;
+ /* If this was nick@server query, retry to @serv if the primary router
+ returned error. */
+ if (query->nick_server[0] && !query->dynamic_retry &&
+ !silc_server_num_sockets_by_remote(server, query->nick_server,
+ query->nick_server, 706)) {
+ 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,
+ query);
+ query->dynamic_retry = TRUE;
+ query->resolved = FALSE;
+ return;
+ }
+
SILC_LOG_DEBUG(("Sending error to original query"));
/* Statistics */
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));
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;
+ }
+ }
+
} else {
/* Parse the IDs included in the query */
query->ids = silc_calloc(argc, sizeof(*query->ids));
if (query->nickname[0]) {
/* Get all clients matching nickname from local list */
if (!silc_idlist_get_clients_by_hash(server->local_list,
- query->nickname, server->md5hash,
+ query->nickname,
+ query->nick_server[0] ?
+ query->nick_server : NULL,
+ server->md5hash,
&clients, &clients_count))
silc_idlist_get_clients_by_nickname(server->local_list,
query->nickname,
- query->nick_server,
- /* XXX nick_server may not be set */
+ query->nick_server[0] ?
+ query->nick_server : NULL,
&clients, &clients_count);
/* Check global list as well */
if (check_global) {
if (!silc_idlist_get_clients_by_hash(server->global_list,
- query->nickname, server->md5hash,
+ query->nickname,
+ query->nick_server[0] ?
+ query->nick_server : NULL,
+ server->md5hash,
&clients, &clients_count))
silc_idlist_get_clients_by_nickname(server->global_list,
query->nickname,
- query->nick_server,
- /* XXX nick_server may not be set */
+ query->nick_server[0] ?
+ query->nick_server : NULL,
&clients, &clients_count);
}