#include "silcclient.h"
#include "client_internal.h"
-/************************** Types and definitions ***************************/
-
-
/************************ Static utility functions **************************/
/* Connection machine FSM destructor. This will finish the thread where
/* 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);
}
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_EVENT_SIGNAL(&client->internal->wait_event);
/* 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_EVENT_SIGNAL(&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);
}
}
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_EVENT_SIGNAL(&conn->internal->wait_event);
if (conn->internal->key_exchange)
/* 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,
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,
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,
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;
case SILC_PACKET_FTP:
/* File transfer packet */
-// silc_fsm_next(fsm, silc_client_ftp);
+ silc_fsm_next(fsm, silc_client_ftp);
break;
case SILC_PACKET_CHANNEL_KEY:
/* 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 is called
- in this state if it set. */
+ in this state if it is set. */
SILC_FSM_STATE(silc_client_connection_st_close)
{
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;
/* 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;
}
/* 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_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;
}
/* 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,
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);
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;
}
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 */
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));
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) {
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) {
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);
}
/* 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;
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_EVENT_SIGNAL(&conn->internal->wait_event);
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;
}
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);
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);
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
{
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;