X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient.c;h=3ab7ba17b4aa96fc872496dce38c17ae078227d7;hp=c7e4e6d8cacb1807739d68c48ed94231efdd3b22;hb=90e14dc985628e0b0f86e604d511039d302dc956;hpb=124293f6809a8200f041c276d1846cb5de4dedf2 diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index c7e4e6d8..3ab7ba17 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,9 +22,6 @@ #include "silcclient.h" #include "client_internal.h" -/************************** Types and definitions ***************************/ - - /************************ Static utility functions **************************/ /* Connection machine FSM destructor. This will finish the thread where @@ -42,7 +39,8 @@ static void silc_client_connection_destructor(SilcFSM fsm, /* Delete connection */ silc_client_del_connection(conn->client, conn); - /* Finish the thread were this machine was running */ + /* Finish the thread were this machine was running. Its destructor is the + silc_client_connection_finished. */ silc_fsm_finish(thread); } @@ -57,14 +55,13 @@ static void silc_client_connection_finished(SilcFSMThread fsm, SilcClient client = silc_fsm_get_state_context(fsm); /* Signal client that we have finished */ - silc_atomic_sub_int16(&client->internal->conns, 1); + silc_atomic_sub_int32(&client->internal->conns, 1); client->internal->connection_closed = TRUE; - SILC_FSM_SEMA_POST(&client->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); silc_fsm_free(fsm); } - /* Packet FSM thread destructor */ static void silc_client_packet_destructor(SilcFSMThread thread, @@ -101,7 +98,6 @@ static SilcBool silc_client_packet_receive(SilcPacketEngine engine, case SILC_PACKET_KEY_EXCHANGE_2: case SILC_PACKET_REKEY_DONE: case SILC_PACKET_CONNECTION_AUTH: - case SILC_PACKET_CONNECTION_AUTH_REQUEST: return FALSE; break; } @@ -134,20 +130,14 @@ static void silc_client_packet_eos(SilcPacketEngine engine, void *stream_context) { SilcClientConnection conn = stream_context; - SilcClient client = conn->client; SILC_LOG_DEBUG(("Remote disconnected connection")); - /* Call connection callback */ - if (!conn->internal->callback_called) - conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, 0, NULL, - conn->callback_context); - conn->internal->callback_called = TRUE; - /* Signal to close connection */ + conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED; if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } } @@ -186,10 +176,18 @@ static void silc_client_connect_abort(SilcAsyncOperation op, void *context) SILC_LOG_DEBUG(("Connection %p aborted by application", conn)); + /* Connection callback will not be called after user aborted connecting */ + conn->callback = NULL; + conn->internal->cop = NULL; + /* Signal to close connection */ if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + + /* If user aborts before connection machine is even up yet, then don't + send signal yet. It will process this event when it comes up. */ + if (silc_fsm_is_started(&conn->internal->fsm)) + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } } @@ -210,14 +208,16 @@ SILC_FSM_STATE(silc_client_connection_st_start) connfsm = &conn->internal->fsm; silc_fsm_init(connfsm, conn, silc_client_connection_destructor, fsm, conn->internal->schedule); - silc_fsm_sema_init(&conn->internal->wait_event, connfsm, 0); + silc_fsm_event_init(&conn->internal->wait_event, connfsm); silc_fsm_start_sync(connfsm, silc_client_connection_st_run); - /* Schedule any events set in initialization */ + /* Schedule any events possibly set in initialization */ + if (conn->internal->disconnected) + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); if (conn->internal->connect) - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); if (conn->internal->key_exchange) - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); /* Wait until this thread is terminated from the machine destructor */ return SILC_FSM_WAIT; @@ -233,14 +233,22 @@ SILC_FSM_STATE(silc_client_connection_st_run) SilcFSMThread thread; /* Wait for events */ - SILC_FSM_SEMA_WAIT(&conn->internal->wait_event); + SILC_FSM_EVENT_WAIT(&conn->internal->wait_event); /* Process events */ thread = &conn->internal->event_thread; + if (conn->internal->disconnected) { + /** Event: disconnected */ + SILC_LOG_DEBUG(("Event: disconnected")); + silc_fsm_next(fsm, silc_client_connection_st_close); + return SILC_FSM_YIELD; + } + if (conn->internal->connect) { SILC_LOG_DEBUG(("Event: connect")); conn->internal->connect = FALSE; + SILC_ASSERT(silc_fsm_is_started(thread) == FALSE); /*** Event: connect */ silc_fsm_thread_init(thread, &conn->internal->fsm, conn, @@ -252,6 +260,7 @@ SILC_FSM_STATE(silc_client_connection_st_run) if (conn->internal->key_exchange) { SILC_LOG_DEBUG(("Event: key exchange")); conn->internal->key_exchange = FALSE; + SILC_ASSERT(silc_fsm_is_started(thread) == FALSE); /*** Event: key exchange */ silc_fsm_thread_init(thread, &conn->internal->fsm, conn, @@ -263,6 +272,7 @@ SILC_FSM_STATE(silc_client_connection_st_run) if (conn->internal->rekeying) { SILC_LOG_DEBUG(("Event: rekey")); conn->internal->rekeying = FALSE; + SILC_ASSERT(silc_fsm_is_started(thread) == FALSE); /*** Event: rekey */ silc_fsm_thread_init(thread, &conn->internal->fsm, conn, @@ -271,13 +281,6 @@ SILC_FSM_STATE(silc_client_connection_st_run) return SILC_FSM_CONTINUE; } - if (conn->internal->disconnected) { - /** Event: disconnected */ - SILC_LOG_DEBUG(("Event: disconnected")); - silc_fsm_next(fsm, silc_client_connection_st_close); - return SILC_FSM_YIELD; - } - /* NOT REACHED */ SILC_ASSERT(FALSE); return SILC_FSM_CONTINUE; @@ -307,7 +310,7 @@ SILC_FSM_STATE(silc_client_connection_st_packet) case SILC_PACKET_FTP: /* File transfer packet */ - // silc_client_ftp(client, conn, packet); + silc_fsm_next(fsm, silc_client_ftp); break; case SILC_PACKET_CHANNEL_KEY: @@ -356,16 +359,15 @@ SILC_FSM_STATE(silc_client_connection_st_packet) break; case SILC_PACKET_CONNECTION_AUTH_REQUEST: - /* Reply to connection authentication request to resolve authentication - method from server. */ - // silc_client_connection_auth_request(client, conn, packet); + /** Connection auth resolve reply */ + silc_fsm_next(fsm, silc_client_connect_auth_request); 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_FSM_EVENT_SIGNAL(&conn->internal->wait_event); silc_packet_free(packet); return SILC_FSM_FINISH; @@ -382,8 +384,8 @@ SILC_FSM_STATE(silc_client_connection_st_packet) /* Disconnection event to close remote connection. We close the connection and finish the connection machine in this state. The connection context - is deleted in the machine destructor. The connection callback must be - already called back to application before getting here. */ + is deleted in the machine destructor. The connection callback is called + in this state if it is set. */ SILC_FSM_STATE(silc_client_connection_st_close) { @@ -421,13 +423,20 @@ SILC_FSM_STATE(silc_client_connection_st_close) return SILC_FSM_YIELD; } + /* Call the connection callback */ + if (conn->callback) + conn->callback(conn->client, conn, conn->internal->status, + conn->internal->error, conn->internal->disconnect_message, + conn->callback_context); + silc_free(conn->internal->disconnect_message); + SILC_LOG_DEBUG(("Closing remote connection")); - /* Close connection */ - silc_packet_stream_destroy(conn->stream); + /* Close connection. */ + if (conn->stream) + silc_packet_stream_destroy(conn->stream); SILC_LOG_DEBUG(("Finishing connection machine")); - return SILC_FSM_FINISH; } @@ -457,7 +466,6 @@ SILC_FSM_STATE(silc_client_error) SILC_FSM_STATE(silc_client_disconnect) { SilcClientConnection conn = fsm_context; - SilcClient client = conn->client; SilcPacket packet = state_context; SilcStatus status; char *message = NULL; @@ -479,20 +487,18 @@ SILC_FSM_STATE(silc_client_disconnect) silc_buffer_len(&packet->buffer)); /* Call connection callback */ - if (!conn->internal->callback_called) - conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, status, - message, conn->callback_context); - conn->internal->callback_called = TRUE; - - silc_free(message); - silc_packet_free(packet); + conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED; + conn->internal->error = status; + conn->internal->disconnect_message = message; /* Signal to close connection */ if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } + silc_packet_free(packet); + return SILC_FSM_FINISH; } @@ -505,15 +511,17 @@ SILC_FSM_STATE(silc_client_st_run) SilcClient client = fsm_context; /* Wait for events */ - SILC_FSM_SEMA_WAIT(&client->internal->wait_event); + SILC_FSM_EVENT_WAIT(&client->internal->wait_event); /* Process events */ - if (client->internal->run_callback && client->internal->running) { + if (client->internal->run_callback) { /* Call running callbcak back to application */ - SILC_LOG_DEBUG(("We are up, call running callback")); client->internal->run_callback = FALSE; - client->internal->running(client, client->internal->running_context); + if (client->internal->running) { + SILC_LOG_DEBUG(("We are up, call running callback")); + client->internal->running(client, client->internal->running_context); + } return SILC_FSM_CONTINUE; } @@ -521,18 +529,19 @@ SILC_FSM_STATE(silc_client_st_run) /* A connection finished */ SILC_LOG_DEBUG(("Event: connection closed")); client->internal->connection_closed = FALSE; - if (silc_atomic_get_int16(&client->internal->conns) == 0 && + if (silc_atomic_get_int32(&client->internal->conns) == 0 && client->internal->stop) - SILC_FSM_SEMA_POST(&client->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); return SILC_FSM_CONTINUE; } if (client->internal->stop) { /* Stop client libarry. If we have running connections, wait until they finish first. */ - SILC_LOG_DEBUG(("Event: stop")); - if (silc_atomic_get_int16(&client->internal->conns) == 0) + if (silc_atomic_get_int32(&client->internal->conns) == 0) { + SILC_LOG_DEBUG(("Event: stop")); silc_fsm_next(fsm, silc_client_st_stop); + } return SILC_FSM_CONTINUE; } @@ -564,9 +573,10 @@ SILC_FSM_STATE(silc_client_st_stop) /* Adds new connection. Creates the connection context and returns it. */ -static SilcClientConnection +SilcClientConnection silc_client_add_connection(SilcClient client, SilcConnectionType conn_type, + SilcBool connect, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, @@ -626,31 +636,33 @@ silc_client_add_connection(SilcClient client, silc_list_init(conn->internal->thread_pool, SilcFSMThreadStruct, next); /* Allocate client, channel and serve caches */ - conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, - NULL, NULL); - conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, - NULL, NULL); - conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, - NULL, NULL); - if (!conn->internal->client_cache || !conn->internal->channel_cache || - !conn->internal->server_cache) { - silc_client_del_connection(client, conn); - return NULL; + if (conn_type != SILC_CONN_CLIENT) { + conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, + NULL, NULL); + conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, + NULL, NULL); + conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, + NULL, NULL); + if (!conn->internal->client_cache || !conn->internal->channel_cache || + !conn->internal->server_cache) { + silc_client_del_connection(client, conn); + return NULL; + } } - conn->internal->ftp_sessions = silc_dlist_init(); - - /* Initialize our async operation so that application may abort us - while we're connecting. */ - conn->internal->cop = silc_async_alloc(silc_client_connect_abort, - NULL, conn); - if (!conn->internal->cop) { - silc_client_del_connection(client, conn); - return NULL; + if (connect) { + /* Initialize our async operation so that application may abort us + while we're connecting. */ + conn->internal->cop = silc_async_alloc(silc_client_connect_abort, + NULL, conn); + if (!conn->internal->cop) { + silc_client_del_connection(client, conn); + return NULL; + } } - /* Run the connection state machine. If threads are in use the machine - is always run in a real thread. */ + /* Run the connection state machine. If threads are in use the connection + machine is always run in a real thread. */ thread = silc_fsm_thread_alloc(&client->internal->fsm, conn, silc_client_connection_finished, NULL, client->internal->params->threads); @@ -662,7 +674,7 @@ silc_client_add_connection(SilcClient client, silc_fsm_start(thread, silc_client_connection_st_start); SILC_LOG_DEBUG(("New connection %p", conn)); - silc_atomic_add_int16(&client->internal->conns, 1); + silc_atomic_add_int32(&client->internal->conns, 1); return conn; } @@ -681,22 +693,28 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn) silc_schedule_task_del_by_context(conn->internal->schedule, conn); /* Free all cache entries */ - if (silc_idcache_get_all(conn->internal->server_cache, &list)) { - silc_list_start(list); - while ((entry = silc_list_get(list))) - silc_client_del_server(client, conn, entry->context); + if (conn->internal->server_cache) { + if (silc_idcache_get_all(conn->internal->server_cache, &list)) { + silc_list_start(list); + while ((entry = silc_list_get(list))) + 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))) { - silc_client_empty_channel(client, conn, entry->context); - silc_client_del_channel(client, conn, entry->context); + if (conn->internal->channel_cache) { + if (silc_idcache_get_all(conn->internal->channel_cache, &list)) { + silc_list_start(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->client_cache, &list)) { - silc_list_start(list); - while ((entry = silc_list_get(list))) - silc_client_del_client(client, conn, entry->context); + if (conn->internal->client_cache) { + if (silc_idcache_get_all(conn->internal->client_cache, &list)) { + silc_list_start(list); + while ((entry = silc_list_get(list))) + silc_client_del_client(client, conn, entry->context); + } } /* Free ID caches */ @@ -721,6 +739,11 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn) if (conn->internal->sha1hash) silc_hash_free(conn->internal->sha1hash); silc_atomic_uninit16(&conn->internal->cmd_ident); + silc_free(conn->internal->away_message); + if (conn->internal->rekey) + silc_ske_free_rekey_material(conn->internal->rekey); + if (conn->internal->cop) + silc_async_free(conn->internal->cop); silc_free(conn->internal); memset(conn, 'F', sizeof(*conn)); @@ -749,8 +772,14 @@ silc_client_connect_to_server(SilcClient client, if (!client || !remote_host) return NULL; + if (client->internal->run_callback) { + SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " + "callback has not been called yet.")); + return NULL; + } + /* Add new connection */ - conn = silc_client_add_connection(client, SILC_CONN_SERVER, params, + conn = silc_client_add_connection(client, SILC_CONN_SERVER, TRUE, params, public_key, private_key, remote_host, port, callback, context); if (!conn) { @@ -786,8 +815,17 @@ silc_client_connect_to_client(SilcClient client, if (!client || !remote_host) return NULL; + if (client->internal->run_callback) { + SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " + "callback has not been called yet.")); + return NULL; + } + + if (params) + params->no_authentication = TRUE; + /* Add new connection */ - conn = silc_client_add_connection(client, SILC_CONN_CLIENT, params, + conn = silc_client_add_connection(client, SILC_CONN_CLIENT, TRUE, params, public_key, private_key, remote_host, port, callback, context); if (!conn) { @@ -822,6 +860,12 @@ silc_client_key_exchange(SilcClient client, if (!client || !stream) return NULL; + if (client->internal->run_callback) { + SILC_LOG_ERROR(("Client library is not started yet. SilcClientRunning " + "callback has not been called yet.")); + return NULL; + } + if (!silc_socket_stream_get_info(stream, NULL, &host, NULL, &port)) { SILC_LOG_ERROR(("Socket stream does not have remote host name set")); callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); @@ -829,14 +873,14 @@ silc_client_key_exchange(SilcClient client, } /* Add new connection */ - conn = silc_client_add_connection(client, conn_type, params, + conn = silc_client_add_connection(client, conn_type, TRUE, params, public_key, private_key, (char *)host, port, callback, context); if (!conn) { callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context); return NULL; } - conn->stream = (void *)stream; + conn->internal->user_stream = stream; /* Signal connection to start key exchange */ conn->internal->key_exchange = TRUE; @@ -851,120 +895,13 @@ void silc_client_close_connection(SilcClient client, SILC_LOG_DEBUG(("Closing connection %p", conn)); /* Signal to close connection */ + conn->internal->status = SILC_CLIENT_CONN_DISCONNECTED; if (!conn->internal->disconnected) { conn->internal->disconnected = TRUE; - SILC_FSM_SEMA_POST(&conn->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&conn->internal->wait_event); } } -#if 0 -/* Processes incoming connection authentication method request packet. - It is a reply to our previously sent request. The packet can be used - to resolve the authentication method for the current session if the - client does not know it beforehand. */ - -void silc_client_connection_auth_request(SilcClient client, - SilcClientConnection conn, - SilcPacketContext *packet) -{ - SilcClientConnection conn = (SilcClientConnection)sock->user_data; - SilcUInt16 conn_type, auth_meth; - int ret; - - /* If we haven't send our request then ignore this one. */ - if (!conn->internal->connauth) - return; - - /* Parse the payload */ - ret = silc_buffer_unformat(packet->buffer, - SILC_STR_UI_SHORT(&conn_type), - SILC_STR_UI_SHORT(&auth_meth), - SILC_STR_END); - if (ret == -1) - auth_meth = SILC_AUTH_NONE; - - /* Call the request callback to notify application for received - authentication method information. */ - if (conn->internal->connauth->callback) - (*conn->internal->connauth->callback)(client, conn, auth_meth, - conn->internal->connauth->context); - - silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout); - - silc_free(conn->internal->connauth); - conn->internal->connauth = NULL; -} - -/* Timeout task callback called if the server does not reply to our - connection authentication method request in the specified time interval. */ - -SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout) -{ - SilcClientConnection conn = (SilcClientConnection)context; - SilcClient client = conn->client; - - if (!conn->internal->connauth) - return; - - /* Call the request callback to notify application */ - if (conn->internal->connauth->callback) - (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE, - conn->internal->connauth->context); - - silc_free(conn->internal->connauth); - conn->internal->connauth = NULL; -} - -/* This function can be used to request the current authentication method - from the server. This may be called when connecting to the server - and the client library requests the authentication data from the - application. If the application does not know the current authentication - method it can request it from the server using this function. - The `callback' with `context' will be called after the server has - replied back with the current authentication method. */ - -void -silc_client_request_authentication_method(SilcClient client, - SilcClientConnection conn, - SilcConnectionAuthRequest callback, - void *context) -{ - SilcClientConnAuthRequest connauth; - SilcBuffer packet; - - assert(client && conn); - connauth = silc_calloc(1, sizeof(*connauth)); - connauth->callback = callback; - connauth->context = context; - - if (conn->internal->connauth) - silc_free(conn->internal->connauth); - - conn->internal->connauth = connauth; - - /* Assemble the request packet and send it to the server */ - packet = silc_buffer_alloc(4); - silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); - silc_buffer_format(packet, - SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT), - SILC_STR_UI_SHORT(SILC_AUTH_NONE), - SILC_STR_END); - silc_client_packet_send(client, conn->sock, - SILC_PACKET_CONNECTION_AUTH_REQUEST, - NULL, 0, NULL, NULL, - packet->data, packet->len, FALSE); - silc_buffer_free(packet); - - /* Register a timeout in case server does not reply anything back. */ - connauth->timeout = - silc_schedule_task_add(client->schedule, conn->sock->sock, - silc_client_request_authentication_method_timeout, - conn, - client->internal->params->connauth_request_secs, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); -} -#endif /* 0 */ - /* Allocates new client object. This has to be done before client may work. After calling this one must call silc_client_init to initialize the client. The `application' is application specific user data pointer @@ -997,14 +934,11 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, if (params) memcpy(new_client->internal->params, params, sizeof(*params)); - if (!new_client->internal->params->connauth_request_secs) - new_client->internal->params->connauth_request_secs = 2; - new_client->internal->params-> nickname_format[sizeof(new_client->internal-> params->nickname_format) - 1] = 0; - silc_atomic_init16(&new_client->internal->conns, 0); + silc_atomic_init32(&new_client->internal->conns, 0); return new_client; } @@ -1013,7 +947,8 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, void silc_client_free(SilcClient client) { - silc_schedule_uninit(client->schedule); + if (client->schedule) + silc_schedule_uninit(client->schedule); if (client->rng) silc_rng_free(client->rng); @@ -1025,7 +960,13 @@ void silc_client_free(SilcClient client) silc_hmac_unregister_all(); } - silc_atomic_uninit16(&client->internal->conns); + if (client->internal->packet_engine) + silc_packet_engine_stop(client->internal->packet_engine); + if (client->internal->ftp_sessions) + silc_dlist_uninit(client->internal->ftp_sessions); + if (client->internal->lock) + silc_mutex_free(client->internal->lock); + silc_atomic_uninit32(&client->internal->conns); silc_free(client->username); silc_free(client->hostname); silc_free(client->realname); @@ -1082,6 +1023,10 @@ SilcBool silc_client_init(SilcClient client, const char *username, if (!username || !hostname || !realname) return FALSE; + client->internal->ftp_sessions = silc_dlist_init(); + if (!client->internal->ftp_sessions) + return FALSE; + if (!client->internal->params->dont_register_crypto_library) { /* Initialize the crypto library. If application has done this already this has no effect. Also, we will not be overriding something @@ -1121,12 +1066,12 @@ SilcBool silc_client_init(SilcClient client, const char *username, client->internal->running = running; client->internal->running_context = context; silc_fsm_init(&client->internal->fsm, client, NULL, NULL, client->schedule); - silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0); + silc_fsm_event_init(&client->internal->wait_event, &client->internal->fsm); silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run); /* Signal the application when we are running */ client->internal->run_callback = TRUE; - SILC_FSM_SEMA_POST(&client->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); return TRUE; } @@ -1158,10 +1103,16 @@ void silc_client_stop(SilcClient client, SilcClientStopped stopped, { SILC_LOG_DEBUG(("Stopping client")); + if (!silc_fsm_is_started(&client->internal->fsm)) { + SILC_LOG_WARNING(("Attempting to stop client library before it has been " + "started (silc_client_init not called)")); + return; + } + client->internal->running = (SilcClientRunning)stopped; client->internal->running_context = context; /* Signal to stop */ client->internal->stop = TRUE; - SILC_FSM_SEMA_POST(&client->internal->wait_event); + SILC_FSM_EVENT_SIGNAL(&client->internal->wait_event); }