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_processed); \
- SILC_FSM_CONTINUE; \
+ return SILC_FSM_CONTINUE; \
}
/* Check for correct arguments */
silc_argument_get_arg_num(args) > max) { \
ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
silc_fsm_next(fsm, silc_client_command_reply_processed); \
- SILC_FSM_CONTINUE; \
+ return SILC_FSM_CONTINUE; \
}
#define SAY cmd->conn->client->internal->ops->say
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) {
SilcChannelEntry channel;
- /* Remove unknown client entry from cache */
+ /* Remove unknown channel entry from cache */
if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
return;
if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) {
SilcServerEntry server_entry;
- /* Remove unknown client entry from cache */
+ /* Remove unknown server entry from cache */
if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
return;
silc_packet_free(packet);
if (!payload) {
SILC_LOG_DEBUG(("Bad command reply packet"));
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
cmd_ident = silc_command_get_ident(payload);
SILC_LOG_DEBUG(("Unknown command reply %s, ident %d",
silc_get_command_name(command), cmd_ident));
silc_command_payload_free(payload);
- SILC_FSM_FINISH;
+ 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);
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
/* Wait here for command reply to arrive from remote host */
/** Wait for command reply */
silc_fsm_set_state_context(fsm, NULL);
silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
- cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
- SILC_FSM_WAIT;
+ cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0);
+ return SILC_FSM_WAIT;
}
/* Timeout occurred while waiting command reply */
silc_list_del(conn->internal->pending_commands, cmd);
if (!cmd->called)
ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd)));
/* Timeout, reply not received in timely fashion */
silc_list_del(conn->internal->pending_commands, cmd);
ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT);
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
/* Process received command reply payload */
silc_fsm_next(fsm, silc_client_command_reply_service);
break;
default:
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
}
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/* Completes command reply processing */
if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END ||
SILC_STATUS_IS_ERROR(cmd->status))
- SILC_FSM_FINISH;
+ return SILC_FSM_FINISH;
/* Add back to pending command reply list */
silc_mutex_lock(conn->internal->lock);
/** Wait more command payloads */
silc_fsm_next(fsm, silc_client_command_reply_wait);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/******************************** WHOIS *************************************/
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),
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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/******************************** WHOWAS ************************************/
out:
silc_client_unref_client(client, conn, client_entry);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/******************************** IDENTIFY **********************************/
}
/* 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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** NICK ************************************/
goto out;
}
+ silc_rwlock_wrlock(conn->local_entry->internal.lock);
+
/* 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;
}
+ 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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** LIST ************************************/
/* There were no channels in the network. */
silc_client_command_callback(cmd, NULL, NULL, NULL, 0);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
CHECK_ARGS(3, 5);
}
/* 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_client_unref_channel(client, conn, channel_entry);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************* TOPIC ************************************/
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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************* INVITE ***********************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** KILL ************************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** INFO ************************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** STATS ***********************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** PING ************************************/
silc_client_command_callback(cmd);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** JOIN ************************************/
}
silc_buffer_set(&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;
/* Get client entry */
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
- if (!client_entry)
- continue;
-
- /* Join client to the channel */
- silc_client_add_to_channel(client, conn, channel, client_entry, mode);
+ 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);
- 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;
+ }
}
/* Get hmac */
if (hmac) {
if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
if (cmd->verbose)
- SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ 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, NULL);
- if (tmp)
+ tmp = silc_argument_get_arg_type(args, 5, &len);
+ if (tmp && len == 4)
SILC_GET32_MSB(mode, tmp);
channel->mode = mode;
/* Get channel public key list */
tmp = silc_argument_get_arg_type(args, 16, &len);
if (tmp)
- channel->channel_pubkeys =
- silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
+ silc_client_channel_save_public_keys(channel, tmp, len, FALSE);
/* 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, &htl,
+ silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl,
topic, cipher, hmac, channel->founder_key,
channel->channel_pubkeys, channel->user_limit);
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** MOTD ************************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** 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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** CMODE ***********************************/
SilcChannelEntry channel;
SilcUInt32 len;
SilcPublicKey public_key = NULL;
- SilcDList channel_pubkeys = NULL;
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)
- channel_pubkeys =
- silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY);
+ 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,
- channel_pubkeys, channel->user_limit);
-
- silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY);
+ channel->channel_pubkeys, channel->user_limit);
out:
if (public_key)
silc_pkcs_public_key_free(public_key);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** CUMODE **********************************/
}
/* 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);
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** KICK ************************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/******************************** SILCOPER **********************************/
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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** OPER ************************************/
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_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************* DETACH ***********************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** WATCH ***********************************/
silc_client_command_callback(cmd);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/*********************************** BAN ************************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** LEAVE ***********************************/
out:
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************* USERS ************************************/
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)
+ 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);
out:
silc_client_unref_channel(client, conn, channel);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** GETKEY **********************************/
goto out;
}
+ silc_rwlock_wrlock(client_entry->internal.lock);
+
/* Save fingerprint */
if (!client_entry->fingerprint)
silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4,
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);
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,
server_entry->public_key);
if (public_key)
silc_pkcs_public_key_free(public_key);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/********************************** SERVICE *********************************/
silc_client_command_callback(cmd, service_list, name);
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}
/*********************************** QUIT ***********************************/
SILC_FSM_STATE(silc_client_command_reply_quit)
{
silc_fsm_next(fsm, silc_client_command_reply_processed);
- SILC_FSM_CONTINUE;
+ return SILC_FSM_CONTINUE;
}