From: Pekka Riikonen Date: Mon, 11 Dec 2006 15:42:26 +0000 (+0000) Subject: More client library rewrites (added rekey) X-Git-Tag: silc.client.1.1.beta1~115 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=7c574a294504ec55bbd7e7686186832c0f4095ae More client library rewrites (added rekey) --- diff --git a/lib/silcclient/Makefile.ad b/lib/silcclient/Makefile.ad index 58912a13..da702bba 100644 --- a/lib/silcclient/Makefile.ad +++ b/lib/silcclient/Makefile.ad @@ -39,6 +39,6 @@ include_HEADERS= \ 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 diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 9354d28d..dd979744 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -78,7 +78,6 @@ static SilcBool silc_client_packet_receive(SilcPacketEngine engine, 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: @@ -113,7 +112,20 @@ static void silc_client_packet_eos(SilcPacketEngine engine, 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 */ @@ -124,7 +136,7 @@ static void silc_client_packet_error(SilcPacketEngine engine, void *callback_context, void *stream_context) { - + /* Nothing */ } /* Packet stream callbacks */ @@ -211,6 +223,17 @@ SILC_FSM_STATE(silc_client_connection_st_run) 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")); @@ -229,6 +252,7 @@ SILC_FSM_STATE(silc_client_connection_st_run) 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))); @@ -301,6 +325,16 @@ SILC_FSM_STATE(silc_client_connection_st_packet) // 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; @@ -471,8 +505,17 @@ silc_client_add_connection(SilcClient client, 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); @@ -503,6 +546,8 @@ silc_client_add_connection(SilcClient client, } silc_fsm_start(thread, silc_client_connection_st_start); + SILC_LOG_DEBUG(("New connection %p", conn)); + return conn; } @@ -518,21 +563,25 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection 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 */ @@ -801,8 +850,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) 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; @@ -812,8 +859,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) 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); @@ -993,9 +1038,6 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, 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; diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 28cc6147..c7a41446 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -763,6 +763,4 @@ void silc_client_empty_channel(SilcClient client, silc_free(chu); } silc_hash_table_list_reset(&htl); - - silc_hash_table_free(channel->user_list); } diff --git a/lib/silcclient/client_connect.c b/lib/silcclient/client_connect.c index 7c50d2b9..98b4372f 100644 --- a/lib/silcclient/client_connect.c +++ b/lib/silcclient/client_connect.c @@ -21,8 +21,6 @@ #include "silcclient.h" #include "client_internal.h" -/************************** Types and definitions ***************************/ - /************************ Static utility functions **************************/ /* Callback called after connected to remote host */ @@ -178,6 +176,8 @@ static void silc_client_ke_completion(SilcSKE ske, 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; @@ -185,7 +185,7 @@ static void silc_client_ke_completion(SilcSKE ske, 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 */ @@ -200,20 +200,82 @@ static void silc_client_ke_completion(SilcSKE ske, 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, @@ -261,6 +323,8 @@ static void silc_client_connect_auth_completion(SilcConnAuth connauth, SILC_FSM_CALL_CONTINUE(fsm); } +/*************************** Connect remote host ****************************/ + /* Connection timeout callback */ SILC_TASK_CALLBACK(silc_client_connect_timeout) @@ -277,8 +341,6 @@ 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) @@ -490,7 +552,7 @@ SILC_FSM_STATE(silc_client_st_connect_auth_start) /* 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, @@ -519,6 +581,14 @@ SILC_FSM_STATE(silc_client_st_connected) 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) { @@ -536,7 +606,8 @@ SILC_FSM_STATE(silc_client_st_connected) 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, @@ -551,13 +622,71 @@ SILC_FSM_STATE(silc_client_st_connect_error) { 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)); +} diff --git a/lib/silcclient/client_connect.h b/lib/silcclient/client_connect.h index 00d60f20..0ee3c9ca 100644 --- a/lib/silcclient/client_connect.h +++ b/lib/silcclient/client_connect.h @@ -29,5 +29,9 @@ SILC_FSM_STATE(silc_client_st_connect_auth); 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 */ diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index c68dc475..980daea6 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -841,13 +841,10 @@ SilcBool silc_client_del_client(SilcClient client, SilcClientConnection conn, 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, @@ -881,13 +878,12 @@ void silc_client_ref_client(SilcClient client, SilcClientConnection conn, 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 */ @@ -1359,6 +1355,7 @@ SilcBool silc_client_del_channel(SilcClient client, SilcClientConnection conn, 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) @@ -1420,6 +1417,9 @@ void silc_client_ref_channel(SilcClient client, SilcClientConnection conn, 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 */ @@ -1427,9 +1427,13 @@ void silc_client_ref_channel(SilcClient client, SilcClientConnection conn, 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 */ @@ -1787,9 +1791,7 @@ void silc_client_ref_server(SilcClient client, SilcClientConnection conn, 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 */ diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 8f56f357..0acee44d 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -182,10 +182,12 @@ struct SilcClientConnectionInternalStruct { 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; @@ -219,6 +221,8 @@ SilcUInt16 silc_client_command_send_argv(SilcClient client, 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); diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index fd8deeb0..068b22d5 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -496,6 +496,7 @@ SILC_FSM_STATE(silc_client_notify_signoff) 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); @@ -1136,7 +1137,6 @@ SILC_FSM_STATE(silc_client_notify_kicked) 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; @@ -1194,14 +1194,8 @@ SILC_FSM_STATE(silc_client_notify_kicked) 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); @@ -1210,6 +1204,7 @@ SILC_FSM_STATE(silc_client_notify_kicked) 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); } @@ -1307,8 +1302,10 @@ SILC_FSM_STATE(silc_client_notify_killed) 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); @@ -1341,7 +1338,7 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) SilcID id; int i; - SILC_LOG_DEBUG(("Notify: SIGNOFF")); + SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF")); clients = silc_dlist_init(); if (!clients) @@ -1364,8 +1361,10 @@ SILC_FSM_STATE(silc_client_notify_server_signoff) /* 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 */ @@ -1406,6 +1405,7 @@ SILC_FSM_STATE(silc_client_notify_error) 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); } @@ -1516,8 +1516,10 @@ SILC_FSM_STATE(silc_client_notify_watch) 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); diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 25ee5650..3b45718a 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -37,13 +37,13 @@ SilcBool silc_client_send_private_message(SilcClient client, 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, diff --git a/lib/silcclient/client_register.c b/lib/silcclient/client_register.c index b0ddc907..97711803 100644 --- a/lib/silcclient/client_register.c +++ b/lib/silcclient/client_register.c @@ -49,6 +49,26 @@ silc_client_register_command_called(SilcClient client, 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; } @@ -179,7 +199,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) /** 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; @@ -213,7 +233,8 @@ SILC_FSM_STATE(silc_client_st_register_complete) 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; } @@ -237,12 +258,12 @@ SILC_FSM_STATE(silc_client_st_register_error) 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 */ @@ -310,9 +331,9 @@ SILC_FSM_STATE(silc_client_st_resume) /* 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); @@ -321,17 +342,20 @@ SILC_FSM_STATE(silc_client_st_resume) /** 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 */ @@ -340,37 +364,77 @@ SILC_FSM_STATE(silc_client_st_resume_resolve) 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; } diff --git a/lib/silcclient/client_register.h b/lib/silcclient/client_register.h index 9343da97..dca9ff9c 100644 --- a/lib/silcclient/client_register.h +++ b/lib/silcclient/client_register.h @@ -25,7 +25,8 @@ SILC_FSM_STATE(silc_client_st_register); 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, diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index b1d233fc..7ffa52fa 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -352,6 +352,12 @@ void silc_client_command_free(SilcClientCommandContext cmd) 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); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index bbb4f2a2..ea1f74b0 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -114,8 +114,9 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd, 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); } } } @@ -175,11 +176,14 @@ SILC_FSM_STATE(silc_client_command_reply) 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; } @@ -899,6 +903,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill) /* 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); } @@ -1731,6 +1736,7 @@ SILC_FSM_STATE(silc_client_command_reply_leave) 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: diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 2426cb57..f6fdb758 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -643,10 +643,6 @@ typedef struct { 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. @@ -926,6 +922,12 @@ typedef struct { /* 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; /***/