Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2006 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
/************************** Types and definitions ***************************/
/* Calls error command reply callback back to command sender. */
-#define ERROR_CALLBACK(error) \
+#define ERROR_CALLBACK(err) \
do { \
void *arg1 = NULL, *arg2 = NULL; \
if (cmd->status != SILC_STATUS_OK) \
silc_status_get_args(cmd->status, args, &arg1, &arg2); \
else \
- cmd->status = error; \
- silc_client_command_callback(cmd, arg1, arg2); \
+ cmd->status = cmd->error = err; \
+ SILC_LOG_DEBUG(("Error in command reply: %s", \
+ silc_get_status_message(cmd->status))); \
+ silc_client_command_callback(cmd, arg1, arg2); \
} while(0)
/* Check for error */
#define CHECK_STATUS(msg) \
- SILC_LOG_DEBUG(("Start")); \
+ SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \
if (cmd->error != SILC_STATUS_OK) { \
if (cmd->verbose) \
- SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \
+ SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \
msg "%s", silc_get_status_message(cmd->error)); \
ERROR_CALLBACK(cmd->error); \
silc_client_command_process_error(cmd, state_context, cmd->error); \
- silc_fsm_next(fsm, silc_client_command_reply_process); \
- return SILC_FSM_YIELD; \
+ silc_fsm_next(fsm, silc_client_command_reply_processed); \
+ return SILC_FSM_CONTINUE; \
}
/* Check for correct arguments */
if (silc_argument_get_arg_num(args) < min || \
silc_argument_get_arg_num(args) > max) { \
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
- silc_fsm_next(fsm, silc_client_command_reply_process); \
- return SILC_FSM_YIELD; \
+ silc_fsm_next(fsm, silc_client_command_reply_processed); \
+ return SILC_FSM_CONTINUE; \
}
#define SAY cmd->conn->client->internal->ops->say
silc_client_command_callback(SilcClientCommandContext cmd, ...)
{
SilcClientCommandReplyCallback cb;
+ SilcList list;
va_list ap, cp;
va_start(ap, cmd);
}
/* Reply callback */
- silc_list_start(cmd->reply_callbacks);
- while ((cb = silc_list_get(cmd->reply_callbacks)))
+ list = cmd->reply_callbacks;
+ silc_list_start(list);
+ while ((cb = silc_list_get(list)))
if (!cb->do_not_call) {
silc_va_copy(cp, ap);
- cb->do_not_call = cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
- cmd->status, cmd->error, cb->context, cp);
+ cb->do_not_call = !cb->reply(cmd->conn->client, cmd->conn, cmd->cmd,
+ cmd->status, cmd->error, cb->context, cp);
va_end(cp);
}
SilcClient client = cmd->conn->client;
SilcClientConnection conn = cmd->conn;
SilcArgumentPayload args = silc_command_get_args(payload);
- SilcClientEntry client_entry;
SilcID id;
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+ SilcClientEntry client_entry;
+
/* Remove unknown client entry from cache */
if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
return;
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry)
+ if (client_entry) {
+ silc_client_remove_from_channels(client, conn, client_entry);
silc_client_del_client(client, conn, client_entry);
+ silc_client_unref_client(client, conn, client_entry);
+ }
+ return;
+ }
+
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
+ SilcChannelEntry channel;
+
+ /* Remove unknown channel entry from cache */
+ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+ return;
+
+ channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
+ if (channel) {
+ silc_client_empty_channel(client, conn, channel);
+ silc_client_del_channel(client, conn, channel);
+ silc_client_unref_channel(client, conn, channel);
+ }
+ return;
+ }
+
+ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
+ SilcServerEntry server_entry;
+
+ /* Remove unknown server entry from cache */
+ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
+ return;
+
+ server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
+ if (server_entry) {
+ silc_client_del_server(client, conn, server_entry);
+ silc_client_unref_server(client, conn, server_entry);
+ }
+ return;
}
}
payload = silc_command_payload_parse(silc_buffer_datalen(&packet->buffer));
silc_packet_free(packet);
if (!payload) {
- /** Bad reply payload */
SILC_LOG_DEBUG(("Bad command reply packet"));
- silc_fsm_next(fsm, silc_client_connection_st_packet);
- return SILC_FSM_CONTINUE;
+ return SILC_FSM_FINISH;
}
cmd_ident = silc_command_get_ident(payload);
/* Find the command pending reply */
silc_mutex_lock(conn->internal->lock);
silc_list_start(conn->internal->pending_commands);
- while ((cmd = silc_list_get(conn->internal->pending_commands)))
- if (cmd->cmd == command && cmd->cmd_ident == cmd_ident)
+ while ((cmd = silc_list_get(conn->internal->pending_commands))) {
+ if ((cmd->cmd == command || cmd->cmd == SILC_COMMAND_NONE)
+ && cmd->cmd_ident == cmd_ident) {
+ silc_list_del(conn->internal->pending_commands, cmd);
break;
+ }
+ }
silc_mutex_unlock(conn->internal->lock);
if (!cmd) {
- /** Unknown command reply */
- SILC_LOG_DEBUG(("Unknown command reply"));
+ SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
+ silc_get_command_name(command), cmd_ident));
silc_command_payload_free(payload);
- silc_fsm_next(fsm, silc_client_connection_st_packet);
- return SILC_FSM_CONTINUE;
+ return SILC_FSM_FINISH;
}
- /* Signal command thread that command reply has arrived */
+ /* Signal command thread that command reply has arrived. We continue
+ command reply processing synchronously because we save the command
+ payload into state context. No other reply may arrive to this command
+ while we're processing this reply. */
silc_fsm_set_state_context(&cmd->thread, payload);
silc_fsm_next(&cmd->thread, silc_client_command_reply_process);
silc_fsm_continue_sync(&cmd->thread);
- /** Packet processed */
- silc_fsm_next(fsm, silc_client_connection_st_packet);
- return SILC_FSM_CONTINUE;
+ return SILC_FSM_FINISH;
}
/* Wait here for command reply to arrive from remote host */
SILC_LOG_DEBUG(("Wait for command reply"));
/** Wait for command reply */
- cmd->processed = FALSE;
silc_fsm_set_state_context(fsm, NULL);
- silc_fsm_next_later(fsm, silc_client_command_reply_process, 20, 0);
+ silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
+ cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
return SILC_FSM_WAIT;
}
-/* Process received command reply payload */
+/* Timeout occurred while waiting command reply */
-SILC_FSM_STATE(silc_client_command_reply_process)
+SILC_FSM_STATE(silc_client_command_reply_timeout)
{
SilcClientCommandContext cmd = fsm_context;
- SilcCommandPayload payload = state_context;
+ SilcClientConnection conn = cmd->conn;
+ SilcArgumentPayload args = NULL;
- if (!payload) {
- /* Timeout, reply not received in timely fashion */
- SilcArgumentPayload args = NULL;
- ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
+ if (conn->internal->disconnected) {
+ SILC_LOG_DEBUG(("Command %s canceled", silc_get_command_name(cmd->cmd)));
+ silc_list_del(conn->internal->pending_commands, cmd);
+ if (!cmd->called)
+ ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
return SILC_FSM_FINISH;
}
- if (cmd->processed) {
- /* Command reply processed */
- silc_command_payload_free(payload);
+ SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
- if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
- SILC_STATUS_IS_ERROR(cmd->status))
- return SILC_FSM_FINISH;
+ /* Timeout, reply not received in timely fashion */
+ silc_list_del(conn->internal->pending_commands, cmd);
+ ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
+ return SILC_FSM_FINISH;
+}
- /** Wait more command payloads */
- silc_fsm_next(fsm, silc_client_command_reply_wait);
- return SILC_FSM_CONTINUE;
- }
+/* Process received command reply payload */
+
+SILC_FSM_STATE(silc_client_command_reply_process)
+{
+ SilcClientCommandContext cmd = fsm_context;
+ SilcCommandPayload payload = state_context;
silc_command_get_status(payload, &cmd->status, &cmd->error);
- silc_fsm_set_state_context(fsm, payload);
- cmd->processed = TRUE;
switch (cmd->cmd) {
case SILC_COMMAND_WHOIS:
silc_fsm_next(fsm, silc_client_command_reply_cumode);
break;
case SILC_COMMAND_KICK:
- /** kick */
+ /** KICK */
silc_fsm_next(fsm, silc_client_command_reply_kick);
break;
case SILC_COMMAND_BAN:
return SILC_FSM_CONTINUE;
}
+/* Completes command reply processing */
+
+SILC_FSM_STATE(silc_client_command_reply_processed)
+{
+ SilcClientCommandContext cmd = fsm_context;
+ SilcClientConnection conn = cmd->conn;
+ SilcCommandPayload payload = state_context;
+
+ silc_command_payload_free(payload);
+
+ if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
+ SILC_STATUS_IS_ERROR(cmd->status))
+ return SILC_FSM_FINISH;
+
+ /* Add back to pending command reply list */
+ silc_mutex_lock(conn->internal->lock);
+ cmd->resolved = FALSE;
+ silc_list_add(conn->internal->pending_commands, cmd);
+ silc_mutex_unlock(conn->internal->lock);
+
+ /** Wait more command payloads */
+ silc_fsm_next(fsm, silc_client_command_reply_wait);
+ return SILC_FSM_CONTINUE;
+}
+
/******************************** WHOIS *************************************/
/* Received reply for WHOIS command. */
silc_client_add_client(client, conn, nickname, username, realname,
&id.u.client_id, mode);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
goto out;
}
+ silc_client_ref_client(client, conn, client_entry);
} else {
silc_client_update_client(client, conn, client_entry,
nickname, username, realname, mode);
}
+ silc_rwlock_wrlock(client_entry->internal.lock);
+
if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint))
memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
client_entry->attrs = silc_attribute_payload_parse(tmp, len);
}
+ silc_rwlock_unlock(client_entry->internal.lock);
+
/* Parse channel and channel user mode list */
if (has_channels) {
channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels),
realname, channel_list, mode, idle, fingerprint,
umodes, client_entry->attrs);
+ silc_client_unref_client(client, conn, client_entry);
if (has_channels) {
- silc_dlist_uninit(channel_list);
+ silc_channel_payload_list_free(channel_list);
silc_free(umodes);
}
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcClient client = conn->client;
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
- SilcClientEntry client_entry;
+ SilcClientEntry client_entry = NULL;
SilcID id;
char *nickname, *username;
char *realname = NULL;
realname);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_client(client, conn, client_entry);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
silc_client_add_client(client, conn, name, info, NULL,
&id.u.client_id, 0);
if (!client_entry) {
- ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
goto out;
}
+ silc_client_ref_client(client, conn, client_entry);
} else {
silc_client_update_client(client, conn, client_entry,
name, info, NULL, 0);
/* Notify application */
silc_client_command_callback(cmd, client_entry, name, info);
+ silc_client_unref_client(client, conn, client_entry);
break;
case SILC_ID_SERVER:
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_client_ref_server(client, conn, server_entry);
} else {
silc_client_update_server(client, conn, server_entry, name, info);
}
- server_entry->resolve_cmd_ident = 0;
+ server_entry->internal.resolve_cmd_ident = 0;
/* Notify application */
silc_client_command_callback(cmd, server_entry, name, info);
+ silc_client_unref_server(client, conn, server_entry);
break;
case SILC_ID_CHANNEL:
channel_entry = silc_client_get_channel_by_id(client, conn,
&id.u.channel_id);
if (!channel_entry) {
- SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY"));
+ SILC_LOG_DEBUG(("Adding new channel entry (IDENTIFY)"));
if (!name) {
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_client_ref_channel(client, conn, channel_entry);
}
/* Notify application */
- silc_client_command_callback(cmd, channel_entry, name, info);
+ silc_client_command_callback(cmd, channel_entry,
+ channel_entry->channel_name, info);
+ silc_client_unref_channel(client, conn, channel_entry);
break;
}
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcClient client = conn->client;
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
- unsigned char *tmp, *nick, *idp;
+ unsigned char *nick, *idp;
SilcUInt32 len, idp_len;
SilcClientID old_client_id;
SilcID id;
CHECK_STATUS("Cannot set nickname: ");
CHECK_ARGS(2, 3);
- old_client_id = *conn->local_id;
-
/* Take received Client ID */
idp = silc_argument_get_arg_type(args, 2, &idp_len);
if (!idp) {
goto out;
}
- /* Normalize nickname */
- tmp = silc_identifier_check(nick, len, SILC_STRING_UTF8, 128, NULL);
- if (!tmp) {
- ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
- goto out;
- }
+ silc_rwlock_wrlock(conn->local_entry->internal.lock);
- /* Update the client entry */
- if (!silc_idcache_update(conn->internal->client_cache,
- conn->internal->local_entry,
- &conn->local_entry->id,
- &id.u.client_id,
- conn->local_entry->nickname_normalized,
- tmp, TRUE)) {
- silc_free(tmp);
+ /* Change the nickname */
+ old_client_id = *conn->local_id;
+ if (!silc_client_change_nickname(client, conn, conn->local_entry,
+ nick, &id.u.client_id, idp, idp_len)) {
ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME);
+ silc_rwlock_unlock(conn->local_entry->internal.lock);
goto out;
}
- memcpy(conn->local_entry->nickname, nick, strlen(nick));
- conn->local_entry->nickname_normalized = tmp;
- silc_buffer_enlarge(conn->local_idp, idp_len);
- silc_buffer_put(conn->local_idp, idp, idp_len);
- silc_client_nickname_format(client, conn, conn->local_entry);
+
+ silc_rwlock_unlock(conn->local_entry->internal.lock);
/* Notify application */
silc_client_command_callback(cmd, conn->local_entry,
conn->local_entry->nickname, &old_client_id);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcArgumentPayload args = silc_command_get_args(payload);
unsigned char *tmp, *name, *topic;
SilcUInt32 usercount = 0;
- SilcChannelEntry channel_entry;
+ SilcChannelEntry channel_entry = NULL;
SilcID id;
/* Sanity checks */
if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) {
/* There were no channels in the network. */
silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_client_ref_channel(client, conn, channel_entry);
}
/* Notify application */
- silc_client_command_callback(cmd, channel_entry, name, topic, usercount);
+ silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name,
+ topic, usercount);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel_entry);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcClient client = conn->client;
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
char *topic;
SilcUInt32 len;
SilcID id;
goto out;
}
+ silc_rwlock_wrlock(channel->internal.lock);
+
/* Take topic */
topic = silc_argument_get_arg_type(args, 3, &len);
if (topic) {
channel->topic = silc_memdup(topic, len);
}
+ silc_rwlock_unlock(channel->internal.lock);
+
/* Notify application */
silc_client_command_callback(cmd, channel, channel->topic);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcClient client = conn->client;
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
unsigned char *tmp;
SilcUInt32 len;
- SilcBufferStruct buf;
+ SilcArgumentPayload invite_args = NULL;
SilcID id;
/* Sanity checks */
/* Get the invite list */
tmp = silc_argument_get_arg_type(args, 3, &len);
if (tmp)
- silc_buffer_set(&buf, tmp, len);
+ invite_args = silc_argument_list_parse(tmp, len);
/* Notify application */
- silc_client_command_callback(cmd, channel, tmp ? &buf : NULL);
+ silc_client_command_callback(cmd, channel, invite_args);
+
+ if (invite_args)
+ silc_argument_payload_free(invite_args);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/* Notify application */
silc_client_command_callback(cmd, client_entry);
- /* Remove the client from all channels and free it */
- if (client_entry)
+ /* Remove the client */
+ if (client_entry) {
+ silc_client_remove_from_channels(client, conn, client_entry);
silc_client_del_client(client, conn, client_entry);
+ silc_client_unref_client(client, conn, client_entry);
+ }
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/* See whether we have this server cached. If not create it. */
server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
if (!server) {
- SILC_LOG_DEBUG(("New server entry"));
+ SILC_LOG_DEBUG(("Add new server entry (INFO)"));
server = silc_client_add_server(client, conn, server_name,
server_info, &id.u.server_id);
if (!server)
goto out;
+ silc_client_ref_server(client, conn, server);
}
/* Notify application */
silc_client_command_callback(cmd, server, server->server_name,
server->server_info);
+ silc_client_unref_server(client, conn, server);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
silc_client_command_callback(cmd, &stats);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcInt64 diff;
diff = silc_time() - SILC_PTR_TO_64(cmd->context);
- SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Ping reply from %s: %d second%s", conn->remote_host,
- (int)diff, diff == 1 ? "" : "s");
+ if (cmd->verbose)
+ SAY(client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Ping reply from %s: %d second%s", conn->remote_host,
+ (int)diff, diff == 1 ? "" : "s");
/* Notify application */
silc_client_command_callback(cmd);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/********************************** JOIN ************************************/
+/* Continue JOIN command reply processing after resolving unknown users */
+
+static void
+silc_client_command_reply_join_resolved(SilcClient client,
+ SilcClientConnection conn,
+ SilcStatus status,
+ SilcDList clients,
+ void *context)
+{
+ SilcClientCommandContext cmd = context;
+ SilcChannelEntry channel = cmd->context;
+ SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
+ SilcArgumentPayload args = silc_command_get_args(payload);
+ SilcUInt32 list_count;
+ unsigned char *tmp;
+ char msg[512];
+
+ if (!clients) {
+ silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list",
+ channel->channel_name);
+ SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg);
+ } else {
+ tmp = silc_argument_get_arg_type(args, 12, NULL);
+ if (tmp) {
+ SILC_GET32_MSB(list_count, tmp);
+ if (list_count - silc_dlist_count(clients) > 5) {
+ silc_snprintf(msg, sizeof(msg),
+ "Channel %s user list was not fully resolved. "
+ "The channel may not be fully synced.",
+ channel->channel_name);
+ SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg);
+ }
+ }
+ }
+
+ channel->internal.resolve_cmd_ident = 0;
+ silc_client_unref_channel(client, conn, channel);
+
+ SILC_FSM_CALL_CONTINUE(&cmd->thread);
+}
+
+
/* Received reply for JOIN command. */
SILC_FSM_STATE(silc_client_command_reply_join)
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
SilcChannelEntry channel;
- SilcChannelUser chu;
SilcUInt32 mode = 0, len, list_count;
char *topic, *tmp, *channel_name = NULL, *hmac;
- SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
- SilcBufferStruct chpklist;
+ const char *cipher;
+ SilcBufferStruct client_id_list, client_mode_list, keyp;
+ SilcHashTableList htl;
SilcID id;
int i;
goto out;
}
- /* Get channel mode */
- tmp = silc_argument_get_arg_type(args, 5, NULL);
- if (tmp)
- SILC_GET32_MSB(mode, tmp);
-
- /* Get channel key */
- tmp = silc_argument_get_arg_type(args, 7, &len);
- if (tmp) {
- keyp = silc_buffer_alloc_size(len);
- if (keyp)
- silc_buffer_put(keyp, tmp, len);
- }
-
- /* Get topic */
- topic = silc_argument_get_arg_type(args, 10, NULL);
-
/* Check whether we have this channel entry already. */
channel = silc_client_get_channel(client, conn, channel_name);
if (channel) {
- if (!SILC_ID_CHANNEL_COMPARE(channel->id, &id.u.channel_id))
+ if (!SILC_ID_CHANNEL_COMPARE(&channel->id, &id.u.channel_id))
silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id);
} else {
/* Create new channel entry */
ERROR_CALLBACK(SILC_STATUS_ERR_BAD_CHANNEL);
goto out;
}
- }
-
- conn->current_channel = channel;
- channel->mode = mode;
-
- /* Get hmac */
- hmac = silc_argument_get_arg_type(args, 11, NULL);
- if (hmac) {
- if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
- if (cmd->verbose)
- SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Cannot join channel: Unsupported HMAC `%s'", hmac);
- ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
- goto out;
- }
+ silc_client_ref_channel(client, conn, channel);
}
/* Get the list count */
tmp = silc_argument_get_arg_type(args, 12, &len);
- if (!tmp) {
+ if (!tmp || len != 4) {
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_buffer_set(&client_id_list, tmp, len);
- client_id_list = silc_buffer_alloc_size(len);
- if (client_id_list)
- silc_buffer_put(client_id_list, tmp, len);
+ /* Resolve users we do not know about */
+ if (!cmd->resolved) {
+ cmd->resolved = TRUE;
+ cmd->context = channel;
+ SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
+ silc_client_get_clients_by_list(
+ client, conn, list_count, &client_id_list,
+ silc_client_command_reply_join_resolved, cmd));
+ /* NOT REACHED */
+ }
/* Get client mode list */
tmp = silc_argument_get_arg_type(args, 14, &len);
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
+ silc_buffer_set(&client_mode_list, tmp, len);
- client_mode_list = silc_buffer_alloc_size(len);
- if (client_mode_list)
- silc_buffer_put(client_mode_list, tmp, len);
+ silc_rwlock_wrlock(channel->internal.lock);
/* Add clients we received in the reply to the channel */
for (i = 0; i < list_count; i++) {
SilcUInt16 idp_len;
- SilcUInt32 mode;
SilcID id;
SilcClientEntry client_entry;
/* Client ID */
- SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+ SILC_GET16_MSB(idp_len, client_id_list.data + 2);
idp_len += 4;
- if (!silc_id_payload_parse_id(client_id_list->data, idp_len, &id))
- goto out;
+ if (!silc_id_payload_parse_id(client_id_list.data, idp_len, &id))
+ continue;
/* Mode */
- SILC_GET32_MSB(mode, client_mode_list->data);
+ SILC_GET32_MSB(mode, client_mode_list.data);
- /* Check if we have this client cached already. */
+ /* Get client entry */
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry) {
- /* No, we don't have it, add entry for it. */
- client_entry =
- silc_client_add_client(client, conn, NULL, NULL, NULL,
- &id.u.client_id, 0);
- if (!client_entry)
- goto out;
+ if (client_entry && client_entry->internal.valid) {
+ /* Join client to the channel */
+ silc_rwlock_wrlock(client_entry->internal.lock);
+ silc_client_add_to_channel(client, conn, channel, client_entry, mode);
+ silc_rwlock_unlock(client_entry->internal.lock);
}
+ silc_client_unref_client(client, conn, client_entry);
- /* Join client to the channel */
- if (!silc_client_on_channel(channel, client_entry)) {
- chu = silc_calloc(1, sizeof(*chu));
- if (!chu)
- goto out;
- chu->client = client_entry;
- chu->channel = channel;
- chu->mode = mode;
- silc_hash_table_add(channel->user_list, client_entry, chu);
- silc_hash_table_add(client_entry->channels, channel, chu);
+ if (!silc_buffer_pull(&client_id_list, idp_len)) {
+ silc_rwlock_unlock(channel->internal.lock);
+ goto out;
}
+ if (!silc_buffer_pull(&client_mode_list, 4)) {
+ silc_rwlock_unlock(channel->internal.lock);
+ goto out;
+ }
+ }
+
+ /* Get hmac */
+ hmac = silc_argument_get_arg_type(args, 11, NULL);
+ if (hmac) {
+ if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
+ if (cmd->verbose)
+ SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+ "Cannot join channel: Unsupported HMAC `%s'", hmac);
+ ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+ silc_rwlock_unlock(channel->internal.lock);
+ goto out;
+ }
+ }
+
+ /* Get channel mode */
+ tmp = silc_argument_get_arg_type(args, 5, &len);
+ if (tmp && len == 4)
+ SILC_GET32_MSB(mode, tmp);
+ channel->mode = mode;
- silc_buffer_pull(client_id_list, idp_len);
- silc_buffer_pull(client_mode_list, 4);
+ /* Get channel key and save it */
+ tmp = silc_argument_get_arg_type(args, 7, &len);
+ if (tmp) {
+ silc_buffer_set(&keyp, tmp, len);
+ silc_client_save_channel_key(client, conn, &keyp, channel);
}
- silc_buffer_start(client_id_list);
- silc_buffer_start(client_mode_list);
- /* Save channel key */
-#if 0
- if (keyp)
- silc_client_save_channel_key(client, conn, keyp, channel);
-#endif /* 0 */
+ /* Get topic */
+ topic = silc_argument_get_arg_type(args, 10, NULL);
+ if (topic) {
+ silc_free(channel->topic);
+ channel->topic = silc_memdup(topic, strlen(topic));
+ }
/* Get founder key */
tmp = silc_argument_get_arg_type(args, 15, &len);
/* Get channel public key list */
tmp = silc_argument_get_arg_type(args, 16, &len);
if (tmp)
- silc_buffer_set(&chpklist, tmp, len);
+ silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
- if (topic) {
- silc_free(channel->topic);
- channel->topic = silc_memdup(topic, strlen(topic));
- }
+ /* Set current channel */
+ conn->current_channel = channel;
+
+ silc_rwlock_unlock(channel->internal.lock);
+
+ cipher = (channel->internal.send_key ?
+ silc_cipher_get_name(channel->internal.send_key) : NULL);
+ silc_hash_table_list(channel->user_list, &htl);
/* Notify application */
- silc_client_command_callback(cmd, channel_name, channel, mode, 0,
- keyp ? keyp->head : NULL, NULL,
- NULL, topic, hmac, list_count, client_id_list,
- client_mode_list, channel->founder_key,
- tmp ? &chpklist : NULL, channel->user_limit);
+ silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
+ topic, cipher, hmac, channel->founder_key,
+ channel->channel_pubkeys, channel->user_limit);
+
+ silc_hash_table_list_reset(&htl);
+ silc_client_unref_channel(client, conn, channel);
out:
- silc_buffer_free(keyp);
- silc_buffer_free(client_id_list);
- silc_buffer_free(client_mode_list);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
silc_client_command_callback(cmd, motd);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/********************************** UMODE ***********************************/
-/* Received reply tot he UMODE command. Save the current user mode */
+/* Received reply to the UMODE command. Save the current user mode */
SILC_FSM_STATE(silc_client_command_reply_umode)
{
}
SILC_GET32_MSB(mode, tmp);
+ silc_rwlock_wrlock(conn->local_entry->internal.lock);
conn->local_entry->mode = mode;
+ silc_rwlock_unlock(conn->local_entry->internal.lock);
/* Notify application */
silc_client_command_callback(cmd, mode);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcArgumentPayload args = silc_command_get_args(payload);
unsigned char *tmp;
SilcUInt32 mode;
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
SilcUInt32 len;
SilcPublicKey public_key = NULL;
- SilcBufferStruct channel_pubkeys;
SilcID id;
/* Sanity checks */
goto out;
}
+ /* Get founder public key */
+ tmp = silc_argument_get_arg_type(args, 4, &len);
+ if (tmp)
+ silc_public_key_payload_decode(tmp, len, &public_key);
+
/* Get channel mode */
tmp = silc_argument_get_arg_type(args, 3, &len);
if (!tmp || len != 4) {
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
-
- /* Save the mode */
SILC_GET32_MSB(mode, tmp);
- channel->mode = mode;
- /* Get founder public key */
- tmp = silc_argument_get_arg_type(args, 4, &len);
- if (tmp)
- silc_public_key_payload_decode(tmp, len, &public_key);
+ silc_rwlock_wrlock(channel->internal.lock);
/* Get user limit */
tmp = silc_argument_get_arg_type(args, 6, &len);
/* Get channel public key(s) */
tmp = silc_argument_get_arg_type(args, 5, &len);
if (tmp)
- silc_buffer_set(&channel_pubkeys, tmp, len);
+ silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
+ else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
+ silc_client_channel_save_public_keys(channel, NULL, 0, TRUE);
+
+ /* Save the mode */
+ channel->mode = mode;
+
+ silc_rwlock_unlock(channel->internal.lock);
/* Notify application */
silc_client_command_callback(cmd, channel, mode, public_key,
- tmp ? &channel_pubkeys : NULL,
- channel->user_limit);
+ channel->channel_pubkeys, channel->user_limit);
+
+ silc_rwlock_wrlock(channel->internal.lock);
+
+ /* If founder key changed, update it */
+ if (public_key &&
+ (!channel->founder_key ||
+ !silc_pkcs_public_key_compare(public_key, channel->founder_key))) {
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = public_key;
+ public_key = NULL;
+ }
+
+ silc_rwlock_unlock(channel->internal.lock);
out:
+ silc_client_unref_channel(client, conn, channel);
if (public_key)
silc_pkcs_public_key_free(public_key);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
SilcClientEntry client_entry;
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
SilcChannelUser chu;
unsigned char *modev;
SilcUInt32 len, mode;
}
/* Save the mode */
+ silc_rwlock_wrlock(channel->internal.lock);
chu = silc_client_on_channel(channel, client_entry);
if (chu)
chu->mode = mode;
+ silc_rwlock_unlock(channel->internal.lock);
/* Notify application */
silc_client_command_callback(cmd, mode, channel, client_entry);
+ silc_client_unref_client(client, conn, client_entry);
+
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
SilcClientEntry client_entry;
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
SilcID id;
/* Sanity checks */
/* Notify application */
silc_client_command_callback(cmd, channel, client_entry);
+ silc_client_unref_client(client, conn, client_entry);
+
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
CHECK_STATUS("Cannot change mode: ");
CHECK_ARGS(1, 1);
+ /* Set user mode */
+ cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR;
+
/* Notify application */
silc_client_command_callback(cmd);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
CHECK_STATUS("Cannot change mode: ");
CHECK_ARGS(1, 1);
+ /* Set user mode */
+ cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR;
+
/* Notify application */
silc_client_command_callback(cmd);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
CHECK_STATUS("Cannot detach: ");
CHECK_ARGS(1, 1);
- /* Notify application */
- silc_client_command_callback(cmd);
-
-#if 0
- /* Generate the detachment data and deliver it to the client in the
- detach client operation */
+ /* Get detachment data */
detach = silc_client_get_detach_data(client, conn);
- if (detach) {
- client->internal->ops->detach(client, conn, silc_buffer_data(detach),
- silc_buffer_len(detach));
- silc_buffer_free(detach);
+ if (!detach) {
+ ERROR_CALLBACK(SILC_STATUS_ERR_RESOURCE_LIMIT);
+ goto out;
}
-#endif /* 0 */
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ /* Notify application */
+ silc_client_command_callback(cmd, detach);
+ silc_buffer_free(detach);
+
+ out:
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/* Notify application */
silc_client_command_callback(cmd);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcClient client = conn->client;
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
unsigned char *tmp;
SilcUInt32 len;
- SilcBufferStruct buf;
+ SilcArgumentPayload invite_args = NULL;
SilcID id;
/* Sanity checks */
goto out;
}
- /* Get the ban list */
+ /* Get the invite list */
tmp = silc_argument_get_arg_type(args, 3, &len);
if (tmp)
- silc_buffer_set(&buf, tmp, len);
+ invite_args = silc_argument_list_parse(tmp, len);
/* Notify application */
- silc_client_command_callback(cmd, channel, tmp ? &buf : NULL);
+ silc_client_command_callback(cmd, channel, invite_args);
+
+ if (invite_args)
+ silc_argument_payload_free(invite_args);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
SilcChannelEntry channel;
- SilcChannelUser chu;
SilcID id;
/* Sanity checks */
}
/* Remove us from this channel. */
- chu = silc_client_on_channel(channel, conn->local_entry);
- if (chu) {
- silc_hash_table_del(chu->client->channels, chu->channel);
- silc_hash_table_del(chu->channel->user_list, chu->client);
- silc_free(chu);
- }
+ silc_client_remove_from_channel(client, conn, channel, conn->local_entry);
/* Notify application */
silc_client_command_callback(cmd, channel);
/* Now delete the channel. */
+ silc_client_empty_channel(client, conn, channel);
silc_client_del_channel(client, conn, channel);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/********************************* USERS ************************************/
-static SilcBool
-silc_client_command_reply_users_continue(SilcClient client,
+/* Continue USERS command reply processing after resolving unknown users */
+
+static void
+silc_client_command_reply_users_resolved(SilcClient client,
SilcClientConnection conn,
- SilcCommand command,
SilcStatus status,
- SilcStatus error,
- void *context,
- va_list ap)
+ SilcDList clients,
+ void *context)
{
SilcClientCommandContext cmd = context;
-
- return TRUE;
+ SILC_FSM_CALL_CONTINUE(&cmd->thread);
}
-/* Continue USERS command after resolving unknown users */
+
+/* Continue USERS command after resolving unknown channel */
static void
-silc_client_command_reply_users_resolved(SilcClient client,
+silc_client_command_reply_users_continue(SilcClient client,
SilcClientConnection conn,
SilcStatus status,
- SilcDList clients,
+ SilcDList channels,
void *context)
{
SilcClientCommandContext cmd = context;
- SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
+
+ if (!channels) {
+ SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread);
+ SilcArgumentPayload args = silc_command_get_args(payload);
+
+ cmd->status = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
+ ERROR_CALLBACK(cmd->status);
+ silc_fsm_next(&cmd->thread, silc_client_command_reply_processed);
+ }
+
+ SILC_FSM_CALL_CONTINUE(&cmd->thread);
}
/* Reply to USERS command. Received list of client ID's and theirs modes
SilcCommandPayload payload = state_context;
SilcArgumentPayload args = silc_command_get_args(payload);
unsigned char *tmp;
- SilcUInt32 tmp_len, list_count;
- SilcUInt16 idp_len, mode;
+ SilcUInt32 tmp_len, list_count, mode;
+ SilcUInt16 idp_len;
SilcHashTableList htl;
SilcBufferStruct client_id_list, client_mode_list;
- SilcChannelEntry channel;
+ SilcChannelEntry channel = NULL;
SilcClientEntry client_entry;
- SilcChannelUser chu;
SilcID id;
int i;
channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
if (!channel) {
/* Resolve the channel from server */
-#if 0
SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
client, conn, &id.u.channel_id,
silc_client_command_reply_users_continue, cmd));
-#endif /* 0 */
/* NOT REACHED */
}
/* Resolve users we do not know about */
if (!cmd->resolved) {
cmd->resolved = TRUE;
+ silc_client_unref_channel(client, conn, channel);
SILC_FSM_CALL(silc_client_get_clients_by_list(
client, conn, list_count, &client_id_list,
silc_client_command_reply_users_resolved, cmd));
SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
+ silc_rwlock_wrlock(channel->internal.lock);
+
/* Cache the received Client ID's and modes. */
for (i = 0; i < list_count; i++) {
SILC_GET16_MSB(idp_len, client_id_list.data + 2);
/* Save the client on this channel. Unknown clients are ignored as they
clearly do not exist since the resolving didn't find them. */
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (client_entry && !silc_client_on_channel(channel, client_entry)) {
- chu = silc_calloc(1, sizeof(*chu));
- if (!chu)
- goto out;
- chu->client = client_entry;
- chu->mode = mode;
- chu->channel = channel;
- silc_hash_table_add(channel->user_list, client_entry, chu);
- silc_hash_table_add(client_entry->channels, channel, chu);
+ if (client_entry && client_entry->internal.valid) {
+ silc_rwlock_wrlock(client_entry->internal.lock);
+ silc_client_add_to_channel(client, conn, channel, client_entry, mode);
+ silc_rwlock_unlock(client_entry->internal.lock);
}
+ silc_client_unref_client(client, conn, client_entry);
- if (!silc_buffer_pull(&client_id_list, idp_len))
+ if (!silc_buffer_pull(&client_id_list, idp_len)) {
+ silc_rwlock_unlock(channel->internal.lock);
goto out;
- if (!silc_buffer_pull(&client_mode_list, 4))
+ }
+ if (!silc_buffer_pull(&client_mode_list, 4)) {
+ silc_rwlock_unlock(channel->internal.lock);
goto out;
+ }
}
+ silc_rwlock_unlock(channel->internal.lock);
+
/* Notify application */
silc_hash_table_list(channel->user_list, &htl);
silc_client_command_callback(cmd, channel, &htl);
silc_hash_table_list_reset(&htl);
out:
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_client_unref_channel(client, conn, channel);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
goto out;
}
if (!silc_public_key_payload_decode(tmp, len, &public_key)) {
+ SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+ "Cannot decode public key: malformed/unsupported public key");
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
goto out;
}
+ silc_rwlock_wrlock(client_entry->internal.lock);
+
/* Save fingerprint */
if (!client_entry->fingerprint)
- silc_hash_make(client->sha1hash, tmp + 4, len - 4,
+ silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
client_entry->fingerprint);
if (!client_entry->public_key) {
client_entry->public_key = public_key;
public_key = NULL;
}
+ silc_rwlock_unlock(client_entry->internal.lock);
+
/* Notify application */
silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry,
client_entry->public_key);
+ silc_client_unref_client(client, conn, client_entry);
} else if (id.type == SILC_ID_SERVER) {
/* Received server's public key */
server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
goto out;
}
+ silc_rwlock_wrlock(server_entry->internal.lock);
+
+ if (!server_entry->public_key) {
+ server_entry->public_key = public_key;
+ public_key = NULL;
+ }
+
+ silc_rwlock_unlock(server_entry->internal.lock);
+
/* Notify application */
silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry,
- public_key);
+ server_entry->public_key);
+ silc_client_unref_server(client, conn, server_entry);
}
out:
if (public_key)
silc_pkcs_public_key_free(public_key);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
/* Notify application */
silc_client_command_callback(cmd, service_list, name);
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}
SILC_FSM_STATE(silc_client_command_reply_quit)
{
- silc_fsm_next(fsm, silc_client_command_reply_process);
+ silc_fsm_next(fsm, silc_client_command_reply_processed);
return SILC_FSM_CONTINUE;
}