SILC_EXTRA_DIST = client_ops_example.c
#endif SILC_DIST_TOOLKIT
-EXTRA_DIST = *.h $(SILC_EXTRA_DIST)
+EXTRA_DIST = *.h tests $(SILC_EXTRA_DIST)
include $(top_srcdir)/Makefile.defines.in
case SILC_PACKET_KEY_EXCHANGE:
case SILC_PACKET_KEY_EXCHANGE_1:
case SILC_PACKET_KEY_EXCHANGE_2:
- case SILC_PACKET_REKEY:
case SILC_PACKET_REKEY_DONE:
case SILC_PACKET_CONNECTION_AUTH:
case SILC_PACKET_CONNECTION_AUTH_REQUEST:
void *callback_context,
void *stream_context)
{
- SILC_LOG_DEBUG(("End of stream received"));
+ SilcClientConnection conn = stream_context;
+ SilcClient client = conn->client;
+
+ SILC_LOG_DEBUG(("Remote disconnected connection"));
+
+ /* Call connection callback */
+ conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, 0, NULL,
+ conn->callback_context);
+
+ /* Signal to close connection */
+ if (!conn->internal->disconnected) {
+ conn->internal->disconnected = TRUE;
+ SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+ }
}
/* Packet engine callback to indicate error */
void *callback_context,
void *stream_context)
{
-
+ /* Nothing */
}
/* Packet stream callbacks */
return SILC_FSM_CONTINUE;
}
+ if (conn->internal->rekeying) {
+ SILC_LOG_DEBUG(("Event: rekey"));
+ conn->internal->rekeying = FALSE;
+
+ /*** Event: rekey */
+ silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
+ NULL, NULL, FALSE);
+ silc_fsm_start_sync(thread, silc_client_st_rekey);
+ return SILC_FSM_CONTINUE;
+ }
+
if (conn->internal->disconnected) {
/** Event: disconnected */
SILC_LOG_DEBUG(("Event: disconnected"));
SILC_FSM_STATE(silc_client_connection_st_packet)
{
+ SilcClientConnection conn = fsm_context;
SilcPacket packet = state_context;
SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
// silc_client_connection_auth_request(client, conn, packet);
break;
+ case SILC_PACKET_REKEY:
+ /* Signal to start rekey */
+ conn->internal->rekey_responder = TRUE;
+ conn->internal->rekeying = TRUE;
+ SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+
+ silc_packet_free(packet);
+ return SILC_FSM_FINISH;
+ break;
+
default:
silc_packet_free(packet);
return SILC_FSM_FINISH;
silc_free(conn->internal);
return NULL;
}
+
+ /* Set parameters */
if (params)
conn->internal->params = *params;
+ if (!conn->internal->params.rekey_secs)
+ conn->internal->params.rekey_secs = 3600;
+#ifndef SILC_DIST_INPLACE
+ if (conn->internal->params.rekey_secs < 300)
+ conn->internal->params.rekey_secs = 300;
+#endif /* SILC_DIST_INPLACE */
+
conn->internal->verbose = TRUE;
silc_list_init(conn->internal->pending_commands,
struct SilcClientCommandContextStruct, next);
}
silc_fsm_start(thread, silc_client_connection_st_start);
+ SILC_LOG_DEBUG(("New connection %p", conn));
+
return conn;
}
SILC_LOG_DEBUG(("Freeing connection %p", conn));
+ silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+
/* Free all cache entries */
- if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
+ if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
silc_list_start(list);
while ((entry = silc_list_get(list)))
- silc_client_del_client(client, conn, entry->context);
+ silc_client_del_server(client, conn, entry->context);
}
if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
silc_list_start(list);
- while ((entry = silc_list_get(list)))
+ while ((entry = silc_list_get(list))) {
+ silc_client_empty_channel(client, conn, entry->context);
silc_client_del_channel(client, conn, entry->context);
+ }
}
- if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
+ if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
silc_list_start(list);
while ((entry = silc_list_get(list)))
- silc_client_del_server(client, conn, entry->context);
+ silc_client_del_client(client, conn, entry->context);
}
/* Free ID caches */
silc_protocol_free(protocol);
silc_free(ctx->auth_data);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
silc_socket_free(ctx->sock);
silc_free(ctx);
conn->sock->protocol = NULL;
silc_protocol_free(protocol);
silc_free(ctx->auth_data);
silc_free(ctx->dest_id);
- if (ctx->ske)
- silc_ske_free(ctx->ske);
conn->sock->protocol = NULL;
silc_socket_free(ctx->sock);
if (params)
memcpy(new_client->internal->params, params, sizeof(*params));
- if (!new_client->internal->params->rekey_secs)
- new_client->internal->params->rekey_secs = 3600;
-
if (!new_client->internal->params->connauth_request_secs)
new_client->internal->params->connauth_request_secs = 2;
silc_free(chu);
}
silc_hash_table_list_reset(&htl);
-
- silc_hash_table_free(channel->user_list);
}
#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
-
/************************ Static utility functions **************************/
/* Callback called after connected to remote host */
conn->remote_host,
silc_ske_map_status(status));
+ silc_ske_free_rekey_material(rekey);
+
silc_fsm_next(fsm, silc_client_st_connect_error);
SILC_FSM_CALL_CONTINUE(fsm);
return;
SILC_LOG_DEBUG(("Setting keys into use"));
- /* Set the keys into use. Data will be encrypted after this. */
+ /* Allocate the cipher and HMAC contexts */
if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
&hmac_send, &hmac_receive, &conn->internal->hash)) {
/* Error setting keys */
conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
conn->callback_context);
+ silc_ske_free_rekey_material(rekey);
+
silc_fsm_next(fsm, silc_client_st_connect_error);
SILC_FSM_CALL_CONTINUE(fsm);
return;
}
- silc_packet_set_ciphers(conn->stream, send_key, receive_key);
- silc_packet_set_hmacs(conn->stream, hmac_send, hmac_receive);
+ /* Set the keys into the packet stream. After this call packets will be
+ encrypted with these keys. */
+ if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
+ hmac_receive, FALSE)) {
+ /* Error setting keys */
+ SILC_LOG_DEBUG(("Could not set keys into use"));
+
+ if (conn->internal->verbose)
+ client->internal->ops->say(
+ client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Error during key exchange with %s: cannot use keys",
+ conn->remote_host);
+
+ conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
+ conn->callback_context);
+
+ silc_ske_free_rekey_material(rekey);
+
+ silc_fsm_next(fsm, silc_client_st_connect_error);
+ SILC_FSM_CALL_CONTINUE(fsm);
+ return;
+ }
conn->internal->rekey = rekey;
+ SILC_LOG_DEBUG(("Key Exchange completed"));
+
/* Key exchange done */
SILC_FSM_CALL_CONTINUE(fsm);
}
+/* Rekey protocol completion callback */
+
+static void silc_client_rekey_completion(SilcSKE ske,
+ SilcSKEStatus status,
+ SilcSKESecurityProperties prop,
+ SilcSKEKeyMaterial keymat,
+ SilcSKERekeyMaterial rekey,
+ void *context)
+{
+ SilcFSMThread fsm = context;
+ SilcClientConnection conn = silc_fsm_get_context(fsm);
+ SilcClient client = conn->client;
+
+ conn->internal->op = NULL;
+ if (status != SILC_SKE_STATUS_OK) {
+ /* Rekey failed */
+ SILC_LOG_DEBUG(("Error during rekey with %s: %s (%d)",
+ conn->remote_host, silc_ske_map_status(status), status));
+
+ if (conn->internal->verbose)
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Error during rekey with %s: %s",
+ conn->remote_host,
+ silc_ske_map_status(status));
+
+ silc_fsm_finish(fsm);
+ return;
+ }
+
+ silc_ske_free_rekey_material(conn->internal->rekey);
+ conn->internal->rekey = rekey;
+
+ SILC_LOG_DEBUG(("Rekey completed"));
+
+ /* Rekey done */
+ silc_fsm_finish(fsm);
+}
+
/* Callback called by application to return authentication data */
static void silc_client_connect_auth_method(SilcBool success,
SILC_FSM_CALL_CONTINUE(fsm);
}
+/*************************** Connect remote host ****************************/
+
/* Connection timeout callback */
SILC_TASK_CALLBACK(silc_client_connect_timeout)
silc_fsm_continue_sync(&conn->internal->event_thread);
}
-/*************************** Connect remote host ****************************/
-
/* Creates a connection to remote host */
SILC_FSM_STATE(silc_client_st_connect)
/* Allocate connection authentication protocol */
connauth = silc_connauth_alloc(conn->internal->schedule,
conn->internal->ske,
- client->internal->params->rekey_secs);
+ conn->internal->params.rekey_secs);
if (!connauth) {
/** Out of memory */
conn->callback(client, conn, SILC_CLIENT_CONN_ERROR_AUTH, 0, NULL,
SILC_LOG_DEBUG(("Connection established"));
+ silc_ske_free(conn->internal->ske);
+ conn->internal->ske = NULL;
+
+ /* Install rekey timer */
+ silc_schedule_task_add_timeout(conn->internal->schedule,
+ silc_client_rekey_timer, conn,
+ conn->internal->params.rekey_secs, 0);
+
/* If we connected to server, now register to network. */
if (conn->type == SILC_CONN_SERVER &&
!conn->internal->params.no_authentication) {
return SILC_FSM_CONTINUE;
}
- silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+ silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+ silc_client_connect_timeout, conn);
/* Call connection callback */
conn->callback(client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
{
SilcClientConnection conn = fsm_context;
+ if (conn->internal->ske) {
+ silc_ske_free(conn->internal->ske);
+ conn->internal->ske = NULL;
+ }
+
/* Signal to close connection */
if (!conn->internal->disconnected) {
conn->internal->disconnected = TRUE;
SILC_FSM_SEMA_POST(&conn->internal->wait_event);
}
- silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+ silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+ silc_client_connect_timeout, conn);
return SILC_FSM_FINISH;
}
+
+/****************************** Connect rekey *******************************/
+
+/* Connection rekey timer callback */
+
+SILC_TASK_CALLBACK(silc_client_rekey_timer)
+{
+ SilcClientConnection conn = context;
+
+ /* Signal to start rekey */
+ conn->internal->rekeying = TRUE;
+ SILC_FSM_SEMA_POST(&conn->internal->wait_event);
+
+ /* Reinstall rekey timer */
+ silc_schedule_task_add_timeout(conn->internal->schedule,
+ silc_client_rekey_timer, conn,
+ conn->internal->params.rekey_secs, 0);
+}
+
+/* Performs rekey */
+
+SILC_FSM_STATE(silc_client_st_rekey)
+{
+ SilcClientConnection conn = fsm_context;
+ SilcClient client = conn->client;
+
+ SILC_LOG_DEBUG(("Rekey"));
+
+ /* Allocate SKE */
+ conn->internal->ske =
+ silc_ske_alloc(client->rng, conn->internal->schedule,
+ conn->internal->params.repository,
+ conn->public_key, conn->private_key, fsm);
+ if (!conn->internal->ske)
+ return SILC_FSM_FINISH;
+
+ /* Set SKE callbacks */
+ silc_ske_set_callbacks(conn->internal->ske, NULL,
+ silc_client_rekey_completion, fsm);
+
+ /** Perform rekey */
+ if (!conn->internal->rekey_responder)
+ SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_initiator(
+ conn->internal->ske,
+ conn->stream,
+ conn->internal->rekey));
+ else
+ SILC_FSM_CALL(conn->internal->op = silc_ske_rekey_responder(
+ conn->internal->ske,
+ conn->stream,
+ conn->internal->rekey));
+}
SILC_FSM_STATE(silc_client_st_connect_auth_start);
SILC_FSM_STATE(silc_client_st_connected);
SILC_FSM_STATE(silc_client_st_connect_error);
+SILC_FSM_STATE(silc_client_st_rekey);
+
+SILC_TASK_CALLBACK(silc_client_connect_timeout);
+SILC_TASK_CALLBACK(silc_client_rekey_timer);
#endif /* CLIENT_CONNECT_H */
if (!client_entry)
return FALSE;
- SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
- silc_atomic_get_int8(&client_entry->internal.refcnt),
- silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
if (silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) > 0)
return FALSE;
- SILC_LOG_DEBUG(("Deleting client %p"));
+ SILC_LOG_DEBUG(("Deleting client %p", client_entry));
silc_mutex_lock(conn->internal->lock);
ret = silc_idcache_del_by_context(conn->internal->client_cache,
void silc_client_unref_client(SilcClient client, SilcClientConnection conn,
SilcClientEntry client_entry)
{
- if (client_entry)
+ if (client_entry) {
SILC_LOG_DEBUG(("Client %p refcnt %d->%d", client_entry,
silc_atomic_get_int8(&client_entry->internal.refcnt),
silc_atomic_get_int8(&client_entry->internal.refcnt) - 1));
- if (client_entry &&
- silc_atomic_sub_int8(&client_entry->internal.refcnt, 1) == 0)
silc_client_del_client(client, conn, client_entry);
+ }
}
/* Free client entry list */
return FALSE;
silc_client_empty_channel(client, conn, channel);
+ silc_hash_table_free(channel->user_list);
silc_free(channel->channel_name);
silc_free(channel->topic);
if (channel->founder_key)
SilcChannelEntry channel_entry)
{
silc_atomic_add_int8(&channel_entry->internal.refcnt, 1);
+ SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
+ silc_atomic_get_int8(&channel_entry->internal.refcnt) - 1,
+ silc_atomic_get_int8(&channel_entry->internal.refcnt)));
}
/* Release reference of channel entry */
void silc_client_unref_channel(SilcClient client, SilcClientConnection conn,
SilcChannelEntry channel_entry)
{
- if (channel_entry &&
- silc_atomic_sub_int8(&channel_entry->internal.refcnt, 1) == 0)
+ if (channel_entry) {
+ SILC_LOG_DEBUG(("Channel %p refcnt %d->%d", channel_entry,
+ silc_atomic_get_int8(&channel_entry->internal.refcnt),
+ silc_atomic_get_int8(&channel_entry->internal.refcnt)
+ - 1));
silc_client_del_channel(client, conn, channel_entry);
+ }
}
/* Free channel entry list */
void silc_client_unref_server(SilcClient client, SilcClientConnection conn,
SilcServerEntry server_entry)
{
- if (server_entry &&
- silc_atomic_sub_int8(&server_entry->internal.refcnt, 1) == 0)
- silc_client_del_server(client, conn, server_entry);
+ silc_client_del_server(client, conn, server_entry);
}
/* Free server entry list */
unsigned int connect : 1; /* Connect remote host */
unsigned int disconnected : 1; /* Disconnected by remote host */
unsigned int key_exchange : 1; /* Start key exchange */
+ unsigned int rekeying : 1; /* Start rekey */
/* Flags */
unsigned int verbose : 1; /* Notify application */
unsigned int registering : 1; /* Set when registering to network */
+ unsigned int rekey_responder : 1; /* Set when rekeying as responder */
SilcClientAway *away;
SilcClientConnAuthRequest connauth;
SilcUInt32 *argv_lens,
SilcUInt32 *argv_types);
void silc_client_command_free(SilcClientCommandContext cmd);
+void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
+ void *destructor_context);
void silc_client_ftp(SilcClient client, SilcClientConnection conn,
SilcPacket packet);
NOTIFY(client, conn, type, client_entry, tmp);
/* Delete client */
+ 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);
SilcArgumentPayload args = silc_notify_get_args(payload);
SilcClientEntry client_entry, client_entry2;
SilcChannelEntry channel = NULL;
- SilcChannelUser chu;
unsigned char *tmp;
SilcUInt32 tmp_len;
SilcID id;
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
/* Remove kicked client from channel */
- if (client_entry != conn->local_entry) {
- chu = silc_client_on_channel(channel, client_entry);
- if (chu) {
- silc_hash_table_del(client_entry->channels, channel);
- silc_hash_table_del(channel->user_list, client_entry);
- silc_free(chu);
- }
- }
+ if (client_entry != conn->local_entry)
+ silc_client_remove_from_channel(client, conn, channel, client_entry);
/* Notify application. */
NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
if (client_entry == conn->local_entry) {
if (conn->current_channel == channel)
conn->current_channel = NULL;
+ silc_client_empty_channel(client, conn, channel);
silc_client_del_channel(client, conn, channel);
}
NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
/* Delete the killed client */
- if (client_entry != conn->local_entry)
+ if (client_entry != conn->local_entry) {
+ silc_client_remove_from_channels(client, conn, client_entry);
silc_client_del_client(client, conn, client_entry);
+ }
out:
silc_client_unref_client(client, conn, client_entry);
SilcID id;
int i;
- SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+ SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
clients = silc_dlist_init();
if (!clients)
/* Delete the clients */
silc_dlist_start(clients);
- while ((client_entry = silc_dlist_get(clients)))
+ while ((client_entry = silc_dlist_get(clients))) {
+ silc_client_remove_from_channels(client, conn, client_entry);
silc_client_del_client(client, conn, client_entry);
+ }
out:
/** Notify processed */
goto out;
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
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);
}
ntype == SILC_NOTIFY_TYPE_KILLED)
del_client = TRUE;
- if (del_client)
+ if (del_client) {
+ silc_client_remove_from_channels(client, conn, client_entry);
silc_client_del_client(client, conn, client_entry);
+ }
if (public_key)
silc_pkcs_public_key_free(public_key);
SilcBuffer buffer;
SilcBool ret;
- SILC_LOG_DEBUG(("Sending private message"));
-
if (!client || !conn || !client_entry)
return FALSE;
if (flags & SILC_MESSAGE_FLAG_SIGNED && !hash)
return FALSE;
+ SILC_LOG_DEBUG(("Sending private message"));
+
/* Encode private message payload */
buffer =
silc_message_payload_encode(flags, data, data_len,
void *context,
va_list ap)
{
+ return FALSE;
+}
+
+/* Continues resuming after resolving. Continue after last reply. */
+
+static SilcBool
+silc_client_resume_continue(SilcClient client,
+ SilcClientConnection conn,
+ SilcCommand command,
+ SilcStatus status,
+ SilcStatus error,
+ void *context,
+ va_list ap)
+{
+ if (status == SILC_STATUS_OK || status == SILC_STATUS_LIST_END ||
+ SILC_STATUS_IS_ERROR(status)) {
+ silc_fsm_continue(&conn->internal->event_thread);
+ return FALSE;
+ }
+
return TRUE;
}
/** Resend registering packet */
silc_fsm_next(fsm, silc_client_st_register);
conn->internal->retry_timer = ((conn->internal->retry_timer *
- SILC_CLIENT_RETRY_MUL) +
+ SILC_CLIENT_RETRY_MUL) +
(silc_rng_get_rn16(client->rng) %
SILC_CLIENT_RETRY_RAND));
return SILC_FSM_CONTINUE;
conn->callback_context);
conn->internal->registering = FALSE;
- silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+ silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+ silc_client_connect_timeout, conn);
return SILC_FSM_FINISH;
}
conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
conn->callback_context);
- silc_schedule_task_del_by_context(conn->internal->schedule, conn);
+ silc_schedule_task_del_by_all(conn->internal->schedule, 0,
+ silc_client_connect_timeout, conn);
return SILC_FSM_FINISH;
}
-
/************************* Resume detached session **************************/
/* Resume detached session */
/* Send RESUME_CLIENT packet to resume to network */
if (!silc_packet_send_va(conn->stream, SILC_PACKET_RESUME_CLIENT, 0,
SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(id, id_len),
- SILC_STR_UI_XNSTRING(silc_buffer_data(auth),
- silc_buffer_len(auth)),
+ SILC_STR_DATA(id, id_len),
+ SILC_STR_DATA(silc_buffer_data(auth),
+ silc_buffer_len(auth)),
SILC_STR_END)) {
/** Error sending packet */
silc_fsm_next(fsm, silc_client_st_resume_error);
/** Wait for new ID */
conn->internal->registering = TRUE;
- silc_fsm_next_later(fsm, silc_client_st_resume_resolve, 15, 0);
+ silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0);
return SILC_FSM_WAIT;
}
-/* Resolve the old session information */
+/* Resolve the old session information, user mode and joined channels. */
-SILC_FSM_STATE(silc_client_st_resume_resolve)
+SILC_FSM_STATE(silc_client_st_resume_resolve_channels)
{
-#if 0
SilcClientConnection conn = fsm_context;
+ SilcClient client = conn->client;
SilcClientResumeSession resume = state_context;
+ SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+ unsigned char **res_argv = NULL;
+ int i;
if (!conn->local_id) {
/** Timeout, ID not received */
return SILC_FSM_CONTINUE;
}
+ /* First, send UMODE command to get our own user mode in the network */
+ SILC_LOG_DEBUG(("Resolving user mode"));
+ silc_client_command_send(client, conn, SILC_COMMAND_UMODE,
+ silc_client_register_command_called, NULL,
+ 1, 1, silc_buffer_data(conn->internal->local_idp),
+ silc_buffer_len(conn->internal->local_idp));
- for (i = 0; i < ch_count; i++) {
- char *channel;
+ /* Second, send IDENTIFY command for all channels we know about. These
+ are the channels we've joined to according our detachment data. */
+ for (i = 0; i < resume->channel_count; i++) {
+ SilcChannelID channel_id;
unsigned char *chid;
SilcUInt16 chid_len;
- SilcUInt32 ch_mode;
- SilcChannelID *channel_id;
- SilcChannelEntry channel_entry;
-
- len = silc_buffer_unformat(&detach,
- SILC_STR_UI16_NSTRING_ALLOC(&channel, NULL),
- SILC_STR_UI16_NSTRING(&chid, &chid_len),
- SILC_STR_UI_INT(&ch_mode),
- SILC_STR_END);
- if (len == -1)
- return FALSE;
-
- /* Add new channel */
- channel_id = silc_id_str2id(chid, chid_len, SILC_ID_CHANNEL);
- channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
- if (!channel_entry) {
- channel_entry = silc_client_add_channel(client, conn, channel, ch_mode,
- channel_id);
- } else {
- silc_free(channel);
- silc_free(channel_id);
- }
+ SilcBuffer idp;
- silc_buffer_pull(&detach, len);
+ if (silc_buffer_unformat(&resume->detach,
+ SILC_STR_ADVANCE,
+ SILC_STR_UI16_NSTRING(NULL, NULL),
+ SILC_STR_UI16_NSTRING(&chid, &chid_len),
+ SILC_STR_UI_INT(NULL),
+ SILC_STR_END) < 0)
+ continue;
+
+ idp = silc_id_payload_encode_data(chid, chid_len, SILC_ID_CHANNEL);
+ if (!idp)
+ continue;
+ res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1));
+ res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+ (res_argc + 1));
+ res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+ (res_argc + 1));
+ res_argv[res_argc] = silc_buffer_steal(idp, &res_argv_lens[res_argc]);
+ res_argv_types[res_argc] = res_argc + 5;
+ res_argc++;
+ silc_buffer_free(idp);
}
-#endif /* 0 */
+
+ /* Send IDENTIFY command */
+ SILC_LOG_DEBUG(("Resolving joined channels"));
+ silc_client_command_send_argv(client, conn, SILC_COMMAND_IDENTIFY,
+ silc_client_resume_continue, conn,
+ res_argc, res_argv, res_argv_lens,
+ res_argv_types);
+
+ for (i = 0; i < resume->channel_count; i++)
+ silc_free(res_argv[i]);
+ silc_free(res_argv);
+ silc_free(res_argv_lens);
+ silc_free(res_argv_types);
+
+ /** Wait for channels */
+ silc_fsm_next(fsm, silc_client_st_resume_resolve_cmodes);
+ return SILC_FSM_WAIT;
+}
+
+/* Resolve joined channel modes. */
+
+SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes)
+{
+ SilcClientConnection conn = fsm_context;
+ SilcClientResumeSession resume = state_context;
+ SilcHashTableList htl;
+ SilcChannelUser chu;
+
+ SILC_LOG_DEBUG(("Resolving joined channel modes"));
+
+ silc_hash_table_list(conn->local_entry->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
+
+ }
+ silc_hash_table_list_reset(&htl);
return SILC_FSM_FINISH;
}
SILC_FSM_STATE(silc_client_st_register_complete);
SILC_FSM_STATE(silc_client_st_register_error);
SILC_FSM_STATE(silc_client_st_resume);
-SILC_FSM_STATE(silc_client_st_resume_resolve);
+SILC_FSM_STATE(silc_client_st_resume_resolve_channels);
+SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes);
SILC_FSM_STATE(silc_client_st_resume_error);
SilcBuffer silc_client_get_detach_data(SilcClient client,
SilcClientCommandReplyCallback cb;
int i;
+ /* If command is running, finish it. Destructor will free the context. */
+ if (silc_fsm_is_started(&cmd->thread)) {
+ silc_fsm_finish(&cmd->thread);
+ return;
+ }
+
for (i = 0; i < cmd->argc; i++)
silc_free(cmd->argv[i]);
silc_free(cmd->argv);
client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
if (client_entry) {
- silc_client_unref_client(client, conn, 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);
}
}
}
SILC_FSM_STATE(silc_client_command_reply_wait)
{
+ SilcClientCommandContext cmd = fsm_context;
+
SILC_LOG_DEBUG(("Wait for command reply"));
/** Wait for command reply */
silc_fsm_set_state_context(fsm, NULL);
- silc_fsm_next_later(fsm, silc_client_command_reply_timeout, 20, 0);
+ silc_fsm_next_later(fsm, silc_client_command_reply_timeout,
+ cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0);
return SILC_FSM_WAIT;
}
/* Remove the client from all channels and free it */
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);
}
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:
in the callbacks to protect application specific data. */
SilcBool threads;
- /* Rekey timeout in seconds. The client will perform rekey in this
- time interval. If set to zero, the default value will be used. */
- unsigned int rekey_secs;
-
/* Connection authentication method request timeout. If server does not
reply back the current authentication method when we've requested it
in this time interval we'll assume the reply will not come at all.
/* Connection timeout. If non-zero, the connection will timeout unless
the SILC connection is completed in the specified amount of time. */
SilcUInt32 timeout_secs;
+
+ /* Rekey timeout in seconds. The client will perform rekey in this
+ time interval. If set to zero, the default value will be used
+ (3600 seconds, 1 hour). */
+ unsigned int rekey_secs;
+
} SilcClientConnectionParams;
/***/