unsigned char *arg,
unsigned int arg_len);
static void silc_server_command_free(SilcServerCommandContext cmd);
+void silc_server_command_send_names(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel);
/* Server command list. */
SilcServerCommand silc_command_list[] =
{ NULL, 0 },
};
-/* List of pending commands. */
-SilcDList silc_command_pending;
-
/* Returns TRUE if the connection is registered. Unregistered connections
usually cannot send commands hence the check. */
the `callback' will be executed when received reply with command
identifier `ident'. */
-void silc_server_command_pending(SilcCommand reply_cmd,
+void silc_server_command_pending(SilcServer server,
+ SilcCommand reply_cmd,
unsigned short ident,
SilcCommandCb callback,
void *context)
reply->ident = ident;
reply->context = context;
reply->callback = callback;
- silc_dlist_add(silc_command_pending, reply);
+ silc_dlist_add(server->pending_commands, reply);
}
/* Deletes pending command by reply command type. */
-void silc_server_command_pending_del(SilcCommand reply_cmd,
+void silc_server_command_pending_del(SilcServer server,
+ SilcCommand reply_cmd,
unsigned short ident)
{
SilcServerCommandPending *r;
- while ((r = silc_dlist_get(silc_command_pending)) != SILC_LIST_END) {
+ silc_dlist_start(server->pending_commands);
+ while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
if (r->reply_cmd == reply_cmd && r->ident == ident) {
- silc_dlist_del(silc_command_pending, r);
+ silc_dlist_del(server->pending_commands, r);
break;
}
}
/* Checks for pending commands and marks callbacks to be called from
the command reply function. Returns TRUE if there were pending command. */
-int silc_server_command_pending_check(SilcServerCommandReplyContext ctx,
+int silc_server_command_pending_check(SilcServer server,
+ SilcServerCommandReplyContext ctx,
SilcCommand command,
unsigned short ident)
{
SilcServerCommandPending *r;
- while ((r = silc_dlist_get(silc_command_pending)) != SILC_LIST_END) {
+ silc_dlist_start(server->pending_commands);
+ while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
if (r->reply_cmd == command && r->ident == ident) {
ctx->context = r->context;
ctx->callback = r->callback;
SILC_NOTIFY_TYPE_JOIN, 1,
clidp->data, clidp->len);
+ /* Send NAMES command reply to the joined channel so the user sees who
+ is currently on the channel. */
+ silc_server_command_send_names(ctx->server, ctx->client->connection,
+ ctx->channel);
+
silc_buffer_free(clidp);
silc_free(ctx);
} else {
silc_task_register(ctx->server->timeout_queue, fd,
silc_server_command_join_notify, context,
- 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
}
}
silc_free(idp);
}
-/* Server side of command JOIN. Joins client into requested channel. If
- the channel does not exist it will be created. */
+/* Internal routine to join channel. The channel sent to this function
+ has been either created or resolved from ID lists. This joins the sent
+ client to the channel. */
-SILC_SERVER_CMD_FUNC(join)
+static void
+silc_server_command_join_channel(SilcServer server,
+ SilcServerCommandContext cmd,
+ SilcChannelEntry channel,
+ unsigned int umode)
{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock;
- SilcBuffer buffer = cmd->packet->buffer;
- int argc, i, k, tmp_len;
- char *tmp, *channel_name = NULL, *cipher = NULL;
+ unsigned char *tmp;
+ unsigned int tmp_len;
unsigned char *passphrase = NULL, mode[4];
- unsigned int umode = 0;
- SilcChannelEntry channel;
+ SilcClientEntry client;
SilcChannelClientEntry chl;
- SilcServerID *router_id;
SilcBuffer packet, idp;
- SilcClientEntry client;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Check number of parameters */
- argc = silc_argument_get_arg_num(cmd->args);
- if (argc < 1) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- if (argc > 3) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_TOO_MANY_PARAMS);
- goto out;
- }
-
- /* Get channel name */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- channel_name = tmp;
- if (silc_server_command_bad_chars(channel_name) == TRUE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_BAD_CHANNEL);
- silc_free(channel_name);
- goto out;
- }
+ if (!channel)
+ return;
/* Get passphrase */
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
memcpy(passphrase, tmp, tmp_len);
}
- /* Get cipher name */
- cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
-
- /* See if the channel exists */
- channel =
- silc_idlist_find_channel_by_name(server->local_list, channel_name);
- if (!channel) {
- /* Channel not found */
-
- /* If we are standalone server we don't have a router, we just create
- the channel by ourselves. */
- if (server->standalone) {
- router_id = server->id;
- channel = silc_server_new_channel(server, router_id, cipher,
- channel_name);
- umode |= SILC_CHANNEL_UMODE_CHANOP;
- umode |= SILC_CHANNEL_UMODE_CHANFO;
- if (!channel)
- goto out;
-
- goto join_channel;
- }
-
- /* No channel ID found, the channel does not exist on our server.
- We send JOIN command to our router which will handle the joining
- procedure (either creates the channel if it doesn't exist or
- joins the client to it) - if we are normal server. */
- if (server->server_type == SILC_SERVER) {
-
- /* Forward the original JOIN command to the router */
- silc_buffer_push(buffer, buffer->data - buffer->head);
- silc_server_packet_forward(server, (SilcSocketConnection)
- server->id_entry->router->connection,
- buffer->data, buffer->len, TRUE);
-
- /* Add the command to be pending. It will be re-executed after
- router has replied back to us. */
- cmd->pending = TRUE;
- silc_server_command_pending(SILC_COMMAND_JOIN, 0,
- silc_server_command_join, context);
- return;
- }
- }
-
- /* If we are router and the channel does not exist we will check our
- global list for the channel. */
- if (!channel && server->server_type == SILC_ROUTER) {
-
- /* Notify all routers about the new channel in SILC network. */
- if (!server->standalone) {
-#if 0
- silc_server_send_new_id(server, server->id_entry->router->connection,
- TRUE,
- xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
-#endif
- }
-
- }
-
- join_channel:
-
/*
* Check channel modes
*/
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
SILC_STATUS_OK, 0, 3,
- 2, channel_name,
- strlen(channel_name),
+ 2, channel->channel_name,
+ strlen(channel->channel_name),
3, idp->data, idp->len,
4, mode, 4);
else
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
SILC_STATUS_OK, 0, 4,
- 2, channel_name,
- strlen(channel_name),
+ 2, channel->channel_name,
+ strlen(channel->channel_name),
3, idp->data, idp->len,
4, mode, 4,
5, channel->topic,
/* This is pending command request. Send the notify after we have
received the key for the channel from the router. */
JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
- ctx->channel_name = channel_name;
+ ctx->channel_name = channel->channel_name;
ctx->nickname = client->nickname;
ctx->username = client->username;
ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
silc_server_command_join_notify, ctx,
0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
}
+
+ /* Send NAMES command reply to the joined channel so the user sees who
+ is currently on the channel. */
+ silc_server_command_send_names(server, sock, channel);
+ }
+
+ out:
+ if (passphrase)
+ silc_free(passphrase);
+}
+
+/* Server side of command JOIN. Joins client into requested channel. If
+ the channel does not exist it will be created. */
+
+SILC_SERVER_CMD_FUNC(join)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ int argc, tmp_len;
+ char *tmp, *channel_name = NULL, *cipher = NULL;
+ SilcChannelEntry channel;
+ unsigned int umode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Check number of parameters */
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 1) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 3) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get channel name */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ channel_name = tmp;
+
+ if (silc_server_command_bad_chars(channel_name) == TRUE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_CHANNEL);
+ silc_free(channel_name);
+ goto out;
+ }
+
+ /* Get cipher name */
+ cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
+
+ /* See if the channel exists */
+ channel = silc_idlist_find_channel_by_name(server->local_list, channel_name);
+ if (!channel) {
+ /* Channel not found */
+
+ /* If we are standalone server we don't have a router, we just create
+ the channel by ourselves. */
+ if (server->standalone) {
+ channel = silc_server_new_channel(server, server->id, cipher,
+ channel_name);
+ } else {
+
+ /* The channel does not exist on our server. We send JOIN command to
+ our router which will handle the joining procedure (either creates
+ the channel if it doesn't exist or joins the client to it) - if we
+ are normal server. */
+ if (server->server_type == SILC_SERVER) {
+ SilcBuffer buffer = cmd->packet->buffer;
+
+ /* Forward the original JOIN command to the router */
+ silc_buffer_push(buffer, buffer->data - buffer->head);
+ silc_server_packet_forward(server, (SilcSocketConnection)
+ server->id_entry->router->connection,
+ buffer->data, buffer->len, TRUE);
+
+ /* Add the command to be pending. It will be re-executed after
+ router has replied back to us. */
+ cmd->pending = TRUE;
+ silc_server_command_pending(server, SILC_COMMAND_JOIN, 0,
+ silc_server_command_join, context);
+ return;
+ }
+
+ /* We are router and the channel does not seem exist so we will check
+ our global list as well for the channel. */
+ channel = silc_idlist_find_channel_by_name(server->global_list,
+ channel_name);
+ if (!channel) {
+ /* Channel really does not exist, create it */
+ channel = silc_server_new_channel(server, server->id, cipher,
+ channel_name);
+ umode |= SILC_CHANNEL_UMODE_CHANOP;
+ umode |= SILC_CHANNEL_UMODE_CHANFO;
+ }
+ }
}
- /* Send NAMES command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_names(server, sock, channel);
+ /* Join to the channel */
+ silc_server_command_join_channel(server, cmd, channel, umode);
out:
silc_server_command_free(cmd);
/* XXX Send names command */
cmd->pending = TRUE;
- silc_server_command_pending(SILC_COMMAND_NAMES, 0,
+ silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
silc_server_command_names, context);
return;
}
server->standalone = TRUE;
server->local_list = silc_calloc(1, sizeof(*server->local_list));
server->global_list = silc_calloc(1, sizeof(*server->global_list));
+ server->pending_commands = silc_dlist_init();
#ifdef SILC_SIM
server->sim = silc_dlist_init();
#endif
if (server->params)
silc_free(server->params);
+ if (server->pending_commands)
+ silc_dlist_uninit(server->pending_commands);
+
silc_math_primegen_uninit(); /* XXX */
silc_free(server);
}
/* Prepare outgoing data buffer for packet sending */
silc_packet_send_prepare(sock, 0, 0, data_len);
- /* Mungle the packet flags and add the FORWARDED flag */
- if (data)
- data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
-
/* Put the data to the buffer */
if (data && data_len)
silc_buffer_put(sock->outbuf, data, data_len);
+ /* Add the FORWARDED flag to packet flags */
+ sock->outbuf->data[2] |= (unsigned char)SILC_PACKET_FLAG_FORWARDED;
+
if (idata) {
cipher = idata->send_key;
hmac = idata->hmac;
SilcServerID *router_id,
char *cipher, char *channel_name)
{
- int i, channel_len, key_len;
+ int i, key_len;
SilcChannelID *channel_id;
SilcChannelEntry entry;
SilcCipher key;
- unsigned char channel_key[32], *id_string;
- SilcBuffer packet;
+ unsigned char channel_key[32];
SILC_LOG_DEBUG(("Creating new channel"));
/* Notify other routers about the new channel. We send the packet
to our primary route. */
if (server->standalone == FALSE) {
- channel_len = strlen(channel_name);
- id_string = silc_id_id2str(entry->id, SILC_ID_CHANNEL);
- packet = silc_buffer_alloc(2 + SILC_ID_CHANNEL_LEN);
-
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(channel_len),
- SILC_STR_UI_XNSTRING(channel_name, channel_len),
- SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_CHANNEL_LEN),
- SILC_STR_END);
-
- /* Send the packet to our router. */
- silc_server_packet_send(server, (SilcSocketConnection)
- server->id_entry->router->connection,
- SILC_PACKET_NEW_CHANNEL_USER, 0,
- packet->data, packet->len, TRUE);
-
- silc_free(id_string);
- silc_buffer_free(packet);
+ silc_server_send_new_id(server, server->id_entry->router->connection,
+ server->server_type == SILC_SERVER ? FALSE : TRUE,
+ entry->id, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
}
return entry;