X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_register.c;h=efbeaa24d9cae4534d01d65ad53e221b9ec83fb7;hp=2901210288d95dfa50e8f8c41706131b17e3f998;hb=805fddcf6431e784f9f77114782a90c9d12f9cbe;hpb=03df183a5ada5bad0eed82b78d93ca6f4fd51213 diff --git a/lib/silcclient/client_register.c b/lib/silcclient/client_register.c index 29012102..efbeaa24 100644 --- a/lib/silcclient/client_register.c +++ b/lib/silcclient/client_register.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2006 Pekka Riikonen + Copyright (C) 2006 - 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 @@ -28,26 +28,15 @@ typedef struct { SilcClient client; SilcClientConnection conn; SilcBufferStruct detach; + SilcBuffer auth; char *nickname; + unsigned char *id; + SilcUInt32 id_len; SilcUInt32 channel_count; } *SilcClientResumeSession; /************************ Static utility functions **************************/ -/* Command callback. Nothing interesting to do here. */ - -static SilcBool -silc_client_register_command_called(SilcClient client, - SilcClientConnection conn, - SilcCommand command, - SilcStatus status, - SilcStatus error, - void *context, - va_list ap) -{ - return FALSE; -} - /* Continues resuming after resolving. Continue after last reply. */ static SilcBool @@ -82,6 +71,23 @@ silc_client_resume_command_callback(SilcClient client, va_end(ap); } +/* Resume authentication data generation callback */ + +static void silc_client_resume_auth_generated(const SilcBuffer data, + void *context) +{ + SilcClientConnection conn = context; + SilcClientResumeSession resume = + silc_fsm_get_state_context(&conn->internal->event_thread); + + if (!data) + silc_fsm_next(&conn->internal->event_thread, silc_client_st_resume_error); + else + resume->auth = silc_buffer_copy(data); + + SILC_FSM_CALL_CONTINUE_SYNC(&conn->internal->event_thread); +} + /****************************** NEW_ID packet *******************************/ @@ -92,6 +98,7 @@ SILC_FSM_STATE(silc_client_new_id) SilcClientConnection conn = fsm_context; SilcClient client = conn->client; SilcPacket packet = state_context; + char *nick; SilcID id; if (conn->local_id) @@ -106,9 +113,15 @@ SILC_FSM_STATE(silc_client_new_id) SILC_LOG_DEBUG(("New ID %s", silc_id_render(&id.u.client_id, SILC_ID_CLIENT))); + /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */ + if (conn->internal->remote_version >= 13) + nick = (conn->internal->params.nickname ? + conn->internal->params.nickname : client->username); + else + nick = client->username; + /* Create local client entry */ - conn->local_entry = silc_client_add_client(client, conn, - client->username, + conn->local_entry = silc_client_add_client(client, conn, nick, client->username, client->realname, &id.u.client_id, 0); @@ -144,7 +157,7 @@ SILC_FSM_STATE(silc_client_new_id) out: /** Packet processed */ silc_packet_free(packet); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } @@ -156,9 +169,15 @@ SILC_FSM_STATE(silc_client_st_register) { SilcClientConnection conn = fsm_context; SilcClient client = conn->client; + char *nick = NULL; SILC_LOG_DEBUG(("Register to network")); + /* From SILC protocol version 1.3, nickname is in NEW_CLIENT packet */ + if (conn->internal->remote_version >= 13) + nick = (conn->internal->params.nickname ? + conn->internal->params.nickname : client->username); + /* Send NEW_CLIENT packet to register to network */ if (!silc_packet_send_va(conn->stream, SILC_PACKET_NEW_CLIENT, 0, SILC_STR_UI_SHORT(strlen(client->username)), @@ -167,17 +186,19 @@ SILC_FSM_STATE(silc_client_st_register) SILC_STR_UI_SHORT(strlen(client->realname)), SILC_STR_DATA(client->realname, strlen(client->realname)), + SILC_STR_UI_SHORT(nick ? strlen(nick) : 0), + SILC_STR_DATA(nick, nick ? strlen(nick) : 0), SILC_STR_END)) { /** Error sending packet */ silc_fsm_next(fsm, silc_client_st_register_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /** Wait for new ID */ conn->internal->registering = TRUE; silc_fsm_next_later(fsm, silc_client_st_register_complete, conn->internal->retry_timer, 0); - SILC_FSM_WAIT; + return SILC_FSM_WAIT; } /* Wait for NEW_ID packet to arrive */ @@ -190,7 +211,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) if (conn->internal->disconnected) { /** Disconnected */ silc_fsm_next(fsm, silc_client_st_register_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } if (!conn->local_id) { @@ -200,7 +221,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) conn->internal->retry_count = 0; conn->internal->retry_timer = SILC_CLIENT_RETRY_MIN; silc_fsm_next(fsm, silc_client_st_register_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /** Resend registering packet */ @@ -209,7 +230,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) SILC_CLIENT_RETRY_MUL) + (silc_rng_get_rn16(client->rng) % SILC_CLIENT_RETRY_RAND)); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } SILC_LOG_DEBUG(("Registered to network")); @@ -217,13 +238,13 @@ SILC_FSM_STATE(silc_client_st_register_complete) /* Issue IDENTIFY command for itself to get resolved hostname correctly from server. */ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, - silc_client_register_command_called, NULL, + silc_client_command_called_dummy, NULL, 1, 5, silc_buffer_data(conn->internal->local_idp), silc_buffer_len(conn->internal->local_idp)); - /* Call NICK command if the nickname was set by the application (and is - not same as the username). */ - if (conn->internal->params.nickname && + /* With SILC protocol version 1.2 call NICK command if the nickname was + set by the application. */ + if (conn->internal->params.nickname && conn->internal->remote_version < 13 && !silc_utf8_strcasecmp(conn->internal->params.nickname, client->username)) silc_client_command_call(client, conn, NULL, "NICK", conn->internal->params.nickname, NULL); @@ -231,7 +252,7 @@ SILC_FSM_STATE(silc_client_st_register_complete) /* Issue INFO command to fetch the real server name and server information and other stuff. */ silc_client_command_send(client, conn, SILC_COMMAND_INFO, - silc_client_register_command_called, NULL, + silc_client_command_called_dummy, NULL, 1, 2, silc_buffer_data(conn->internal->remote_idp), silc_buffer_len(conn->internal->remote_idp)); @@ -242,8 +263,10 @@ SILC_FSM_STATE(silc_client_st_register_complete) conn->internal->registering = FALSE; silc_schedule_task_del_by_all(conn->internal->schedule, 0, silc_client_connect_timeout, conn); + silc_async_free(conn->internal->cop); + conn->internal->cop = NULL; - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /* Error registering to network */ @@ -251,26 +274,20 @@ SILC_FSM_STATE(silc_client_st_register_complete) SILC_FSM_STATE(silc_client_st_register_error) { SilcClientConnection conn = fsm_context; - SilcClient client = conn->client; SILC_LOG_DEBUG(("Error registering to network")); /* Signal to close connection */ + conn->internal->status = SILC_CLIENT_CONN_ERROR; if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } - /* Call connect callback */ - if (conn->internal->callback_called) - conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, - conn->callback_context); - conn->internal->callback_called = TRUE; - silc_schedule_task_del_by_all(conn->internal->schedule, 0, silc_client_connect_timeout, conn); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /************************* Resume detached session **************************/ @@ -282,7 +299,6 @@ SILC_FSM_STATE(silc_client_st_resume) SilcClientConnection conn = fsm_context; SilcClient client = conn->client; SilcClientResumeSession resume; - SilcBuffer auth; unsigned char *id; SilcUInt16 id_len; SilcClientID client_id; @@ -294,7 +310,7 @@ SILC_FSM_STATE(silc_client_st_resume) if (!resume) { /** Out of memory */ silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } silc_fsm_set_state_context(fsm, resume); @@ -316,7 +332,7 @@ SILC_FSM_STATE(silc_client_st_resume) /** Malformed detach data */ SILC_LOG_DEBUG(("Malformed detachment data")); silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } if (!silc_id_str2id(id, id_len, SILC_ID_CLIENT, &client_id, @@ -324,38 +340,47 @@ SILC_FSM_STATE(silc_client_st_resume) /** Malformed ID */ SILC_LOG_DEBUG(("Malformed ID")); silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } + resume->id = id; + resume->id_len = id_len; /* Generate authentication data that server will verify */ - auth = silc_auth_public_key_auth_generate(conn->public_key, - conn->private_key, - client->rng, - conn->internal->hash, - &client_id, SILC_ID_CLIENT); - if (!auth) { - /** Out of memory */ - silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; - } + silc_fsm_next(fsm, silc_client_st_resume_send); + SILC_FSM_CALL(silc_auth_public_key_auth_generate( + conn->public_key, conn->private_key, + client->rng, conn->internal->hash, + &client_id, SILC_ID_CLIENT, + silc_client_resume_auth_generated, conn)); + /* NOT REACHED */ +} + +/* Send RESUME_CLIENT packet */ + +SILC_FSM_STATE(silc_client_st_resume_send) +{ + SilcClientConnection conn = fsm_context; + SilcClientResumeSession resume = state_context; + + SILC_LOG_DEBUG(("Send RESUME_CLIENT packet")); /* 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_DATA(id, id_len), - SILC_STR_DATA(silc_buffer_data(auth), - silc_buffer_len(auth)), + SILC_STR_UI_SHORT(resume->id_len), + SILC_STR_DATA(resume->id, resume->id_len), + SILC_STR_DATA(silc_buffer_data(resume->auth), + silc_buffer_len(resume->auth)), SILC_STR_END)) { /** Error sending packet */ SILC_LOG_DEBUG(("Error sending packet")); silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /** Wait for new ID */ conn->internal->registering = TRUE; silc_fsm_next_later(fsm, silc_client_st_resume_resolve_channels, 15, 0); - SILC_FSM_WAIT; + return SILC_FSM_WAIT; } /* Resolve the old session information, user mode and joined channels. */ @@ -372,14 +397,14 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels) if (conn->internal->disconnected) { /** Disconnected */ silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } if (!conn->local_id) { /** Timeout, ID not received */ conn->internal->registering = FALSE; silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /** Wait for channels */ @@ -392,12 +417,12 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels) /* 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, + silc_client_command_called_dummy, NULL, 1, 1, silc_buffer_data(conn->internal->local_idp), silc_buffer_len(conn->internal->local_idp)); if (!resume->channel_count) - SILC_FSM_YIELD; + return SILC_FSM_YIELD; /* Send IDENTIFY command for all channels we know about. These are the channels we've joined to according our detachment data. */ @@ -428,6 +453,8 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels) channel = silc_client_get_channel_by_id(client, conn, &channel_id); if (!channel) silc_client_add_channel(client, conn, name, 0, &channel_id); + else + silc_client_unref_channel(client, conn, channel); res_argv = silc_realloc(res_argv, sizeof(*res_argv) * (res_argc + 1)); res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) * @@ -453,7 +480,7 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_channels) silc_free(res_argv_lens); silc_free(res_argv_types); - SILC_FSM_WAIT; + return SILC_FSM_WAIT; } /* Resolve joined channel modes, users and topics. */ @@ -471,7 +498,7 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes) if (conn->internal->disconnected) { /** Disconnected */ silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } SILC_LOG_DEBUG(("Resolving channel details")); @@ -480,7 +507,7 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes) silc_fsm_next(fsm, silc_client_st_resume_completed); if (!silc_idcache_get_all(conn->internal->channel_cache, &channels)) - SILC_FSM_YIELD; + return SILC_FSM_YIELD; /* Resolve channels' mode, users and topic */ resume->channel_count = silc_list_count(channels) * 3; @@ -506,7 +533,7 @@ SILC_FSM_STATE(silc_client_st_resume_resolve_cmodes) silc_buffer_free(idp); } - SILC_FSM_WAIT; + return SILC_FSM_WAIT; } /* Resuming completed */ @@ -523,13 +550,13 @@ SILC_FSM_STATE(silc_client_st_resume_completed) if (conn->internal->disconnected) { /** Disconnected */ silc_fsm_next(fsm, silc_client_st_resume_error); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } if (resume->channel_count > 0) { resume->channel_count--; if (resume->channel_count) - SILC_FSM_WAIT; + return SILC_FSM_WAIT; } SILC_LOG_DEBUG(("Resuming completed")); @@ -537,14 +564,14 @@ SILC_FSM_STATE(silc_client_st_resume_completed) /* Issue IDENTIFY command for itself to get resolved hostname correctly from server. */ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, - silc_client_register_command_called, NULL, + silc_client_command_called_dummy, NULL, 1, 5, silc_buffer_data(conn->internal->local_idp), silc_buffer_len(conn->internal->local_idp)); /* Issue INFO command to fetch the real server name and server information and other stuff. */ silc_client_command_send(client, conn, SILC_COMMAND_INFO, - silc_client_register_command_called, NULL, + silc_client_command_called_dummy, NULL, 1, 2, silc_buffer_data(conn->internal->remote_idp), silc_buffer_len(conn->internal->remote_idp)); @@ -564,25 +591,26 @@ SILC_FSM_STATE(silc_client_st_resume_completed) &conn->local_entry->id); /* Call JOIN command replies for all joined channel */ - silc_idcache_get_all(conn->internal->channel_cache, &channels); - silc_list_start(channels); - while ((entry = silc_list_get(channels))) { - SilcHashTableList htl; - const char *cipher, *hmac; - - channel = entry->context; - cipher = (channel->internal.send_key ? - silc_cipher_get_name(channel->internal.send_key) : NULL); - hmac = (channel->internal.hmac ? - silc_hmac_get_name(channel->internal.hmac) : NULL); - silc_hash_table_list(channel->user_list, &htl); - silc_client_resume_command_callback(client, conn, SILC_COMMAND_JOIN, - channel->channel_name, channel, - channel->mode, &htl, channel->topic, - cipher, hmac, channel->founder_key, - channel->channel_pubkeys, - channel->user_limit); - silc_hash_table_list_reset(&htl); + if (silc_idcache_get_all(conn->internal->channel_cache, &channels)) { + silc_list_start(channels); + while ((entry = silc_list_get(channels))) { + SilcHashTableList htl; + const char *cipher, *hmac; + + channel = entry->context; + cipher = (channel->internal.send_key ? + silc_cipher_get_name(channel->internal.send_key) : NULL); + hmac = (channel->internal.hmac ? + silc_hmac_get_name(channel->internal.hmac) : NULL); + silc_hash_table_list(channel->user_list, &htl); + silc_client_resume_command_callback(client, conn, SILC_COMMAND_JOIN, + channel->channel_name, channel, + channel->mode, &htl, channel->topic, + cipher, hmac, channel->founder_key, + channel->channel_pubkeys, + channel->user_limit); + silc_hash_table_list_reset(&htl); + } } conn->internal->registering = FALSE; @@ -590,8 +618,10 @@ SILC_FSM_STATE(silc_client_st_resume_completed) silc_client_connect_timeout, conn); silc_free(resume->nickname); silc_free(resume); + silc_async_free(conn->internal->cop); + conn->internal->cop = NULL; - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /* Error resuming to network */ @@ -599,7 +629,6 @@ SILC_FSM_STATE(silc_client_st_resume_completed) SILC_FSM_STATE(silc_client_st_resume_error) { SilcClientConnection conn = fsm_context; - SilcClient client = conn->client; SilcClientResumeSession resume = state_context; if (conn->internal->disconnected) { @@ -607,23 +636,18 @@ SILC_FSM_STATE(silc_client_st_resume_error) silc_free(resume->nickname); silc_free(resume); } - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } SILC_LOG_DEBUG(("Error resuming to network")); /* Signal to close connection */ + conn->internal->status = SILC_CLIENT_CONN_ERROR; if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } - /* Call connect callback */ - if (conn->internal->callback_called) - conn->callback(client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL, - conn->callback_context); - conn->internal->callback_called = TRUE; - silc_schedule_task_del_by_all(conn->internal->schedule, 0, silc_client_connect_timeout, conn); @@ -632,7 +656,7 @@ SILC_FSM_STATE(silc_client_st_resume_error) silc_free(resume); } - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /* Generates the session detachment data. This data can be used later