/* 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)
{
}
/* 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),
SilcServer server = callback_context;
SilcIDListData idata = stream_context;
+ if (!idata)
+ return FALSE;
+
/* Packets we do not handle */
switch (packet->type) {
case SILC_PACKET_HEARTBEAT:
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,
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 */
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 */
/* 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;
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. */
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;
}
}
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);
backup_router->connection);
}
- if (idata->sconn)
- silc_server_connection_free(idata->sconn);
silc_packet_set_context(sock, NULL);
break;
}
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;
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,
(!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;
}
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;
}
}
/* Now parse the request */
- silc_server_query_parse(server, query);
+ silc_server_query_parse(server, query, FALSE);
return TRUE;
}
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;
}
/* 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);
SILC_LOG_DEBUG(("Parsing %s query",
silc_get_command_name(query->querycmd)));
+ if (query->parsed)
+ goto parsed;
+
switch (query->querycmd) {
case SILC_COMMAND_WHOIS:
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 */
silc_server_query_send_error(server, query,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
silc_server_query_free(query);
- return;
+ return FALSE;
}
/* Check nickname */
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));
silc_free(query->ids);
query->ids = NULL;
query->ids_count = 0;
- return;
+ return FALSE;
}
}
}
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 */
silc_server_query_send_error(server, query,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
silc_server_query_free(query);
- return;
+ return FALSE;
}
/* Check nickname */
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_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_server_query_send_error(server, query,
SILC_STATUS_ERR_BAD_SERVER, 0);
silc_server_query_free(query);
- return;
+ return FALSE;
}
query->server_name = tmp;
}
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;
}
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 {
silc_free(query->ids);
query->ids = NULL;
query->ids_count = 0;
- return;
+ return FALSE;
}
}
} else {
silc_free(query->ids);
query->ids = NULL;
query->ids_count = 0;
- return;
+ return FALSE;
}
}
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. */