SilcClient silc_client_alloc(SilcClientOperations *ops,
SilcClientParams *params,
void *application,
- const char *silc_version)
+ const char *version_string)
{
SilcClient new_client;
new_client->internal->ops = ops;
new_client->internal->params =
silc_calloc(1, sizeof(*new_client->internal->params));
- new_client->internal->silc_client_version = strdup(silc_version);
+ if (!version_string)
+ version_string = silc_version_string;
+ new_client->internal->silc_client_version = strdup(version_string);
if (params)
memcpy(new_client->internal->params, params, sizeof(*params));
{
SILC_LOG_DEBUG(("Initializing client"));
+ assert(client);
+ assert(client->username);
+ assert(client->hostname);
+ assert(client->realname);
+
+ /* Initialize the crypto library. If application has done this already
+ this has no effect. Also, we will not be overriding something
+ application might have registered earlier. */
+ silc_cipher_register_default();
+ silc_pkcs_register_default();
+ silc_hash_register_default();
+ silc_hmac_register_default();
+
/* Initialize hash functions for client to use */
silc_hash_alloc("md5", &client->md5hash);
silc_hash_alloc("sha1", &client->sha1hash);
{
SILC_LOG_DEBUG(("Running client"));
+ assert(client);
+ assert(client->pkcs);
+ assert(client->public_key);
+ assert(client->private_key);
+
/* Start the scheduler, the heart of the SILC client. When this returns
the program will be terminated. */
silc_schedule(client->schedule);
SILC_LOG_DEBUG(("Adding new connection to %s:%d", hostname, port));
conn = silc_calloc(1, sizeof(*conn));
+ conn->internal = silc_calloc(1, sizeof(*conn->internal));
/* Initialize ID caches */
- conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
- silc_client_entry_destructor);
- conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
- conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
conn->client = client;
conn->remote_host = strdup(hostname);
conn->remote_port = port;
conn->context = context;
- conn->pending_commands = silc_dlist_init();
- conn->ftp_sessions = silc_dlist_init();
+ conn->internal->client_cache =
+ silc_idcache_alloc(0, SILC_ID_CLIENT, silc_client_entry_destructor);
+ conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
+ conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
+ conn->internal->pending_commands = silc_dlist_init();
+ conn->internal->ftp_sessions = silc_dlist_init();
if (params) {
if (params->detach_data)
- conn->params.detach_data = silc_memdup(params->detach_data,
- params->detach_data_len);
- conn->params.detach_data_len = params->detach_data_len;
+ conn->internal->params.detach_data =
+ silc_memdup(params->detach_data,
+ params->detach_data_len);
+ conn->internal->params.detach_data_len = params->detach_data_len;
}
/* Add the connection to connections table */
for (i = 0; i < client->internal->conns_count; i++)
if (client->internal->conns[i] == conn) {
+ /* Free all cache entries */
+ SilcIDCacheList list;
+ SilcIDCacheEntry entry;
+ SilcClientCommandPending *r;
+ bool ret;
+
+ if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_client(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_channel(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
+
+ if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
+ ret = silc_idcache_list_first(list, &entry);
+ while (ret) {
+ silc_client_del_server(client, conn, entry->context);
+ ret = silc_idcache_list_next(list, &entry);
+ }
+ silc_idcache_list_free(list);
+ }
- silc_idcache_free(conn->client_cache);
- silc_idcache_free(conn->channel_cache);
- silc_idcache_free(conn->server_cache);
- if (conn->pending_commands)
- silc_dlist_uninit(conn->pending_commands);
+ /* Clear ID caches */
+ if (conn->internal->client_cache)
+ silc_idcache_free(conn->internal->client_cache);
+ if (conn->internal->channel_cache)
+ silc_idcache_free(conn->internal->channel_cache);
+ if (conn->internal->server_cache)
+ silc_idcache_free(conn->internal->server_cache);
+
+ /* Free data (my ID is freed in above silc_client_del_client).
+ conn->nickname is freed when freeing the local_entry->nickname. */
silc_free(conn->remote_host);
- if (conn->ftp_sessions)
- silc_dlist_uninit(conn->ftp_sessions);
+ silc_free(conn->local_id_data);
+ if (conn->internal->send_key)
+ silc_cipher_free(conn->internal->send_key);
+ if (conn->internal->receive_key)
+ silc_cipher_free(conn->internal->receive_key);
+ if (conn->internal->hmac_send)
+ silc_hmac_free(conn->internal->hmac_send);
+ if (conn->internal->hmac_receive)
+ silc_hmac_free(conn->internal->hmac_receive);
+ silc_free(conn->internal->rekey);
+
+ if (conn->internal->active_session) {
+ conn->sock->user_data = NULL;
+ silc_client_ftp_session_free(conn->internal->active_session);
+ conn->internal->active_session = NULL;
+ }
+
+ silc_client_ftp_free_sessions(client, conn);
+
+ if (conn->internal->pending_commands) {
+ silc_dlist_start(conn->internal->pending_commands);
+ while ((r = silc_dlist_get(conn->internal->pending_commands))
+ != SILC_LIST_END)
+ silc_dlist_del(conn->internal->pending_commands, r);
+ silc_dlist_uninit(conn->internal->pending_commands);
+ }
+
+ silc_free(conn->internal);
+ memset(conn, 0, sizeof(*conn));
silc_free(conn);
client->internal->conns[i] = NULL;
ctx->client = client;
ctx->conn = conn;
ctx->host = strdup(host);
- ctx->port = port;
+ ctx->port = port ? port : 706;
ctx->tries = 0;
/* Do the actual connecting process */
client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
"Error: Could not start key exchange protocol");
silc_net_close_connection(conn->sock->sock);
- client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_ERROR);
+ client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
return;
}
conn->sock->protocol = protocol;
SilcClientConnection conn,
int fd)
{
+ assert(client->pkcs);
+ assert(client->public_key);
+ assert(client->private_key);
+
/* Allocate new socket connection object */
silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
(SilcClientKEInternalContext *)context;
SilcClient client = (SilcClient)ctx->client;
- client->internal->ops->connect(client, ctx->sock->user_data,
- SILC_CLIENT_CONN_ERROR);
+ client->internal->ops->connected(client, ctx->sock->user_data,
+ SILC_CLIENT_CONN_ERROR);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
silc_free(ctx);
(SilcClientConnAuthInternalContext *)context;
SilcClient client = (SilcClient)ctx->client;
- client->internal->ops->connect(client, ctx->sock->user_data,
- SILC_CLIENT_CONN_ERROR);
+ client->internal->ops->connected(client, ctx->sock->user_data,
+ SILC_CLIENT_CONN_ERROR);
silc_free(ctx);
}
silc_free(ctx);
/* Notify application of failure */
- client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_ERROR);
+ client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
silc_client_del_connection(client, conn);
}
return;
goto err;
}
- if (conn->params.detach_data) {
+ if (conn->internal->params.detach_data) {
/* Send RESUME_CLIENT packet to the server, which is used to resume
old detached session back. */
SilcBuffer auth;
/* Generate authentication data that server will verify */
auth = silc_auth_public_key_auth_generate(client->public_key,
client->private_key,
- client->rng, conn->hash,
+ client->rng,
+ conn->internal->hash,
old_client_id, SILC_ID_CLIENT);
if (!auth) {
silc_free(old_client_id);
conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
/* Register re-key timeout */
- conn->rekey->timeout = client->internal->params->rekey_secs;
- conn->rekey->context = (void *)client;
+ conn->internal->rekey->timeout = client->internal->params->rekey_secs;
+ conn->internal->rekey->context = (void *)client;
silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_rekey_callback,
- (void *)conn->sock, conn->rekey->timeout, 0,
+ (void *)conn->sock, conn->internal->rekey->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
silc_protocol_free(protocol);
close the connection */
if (SILC_IS_DISCONNECTING(sock)) {
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->internal->ops->disconnect(client, conn, 0, NULL);
+ client->internal->ops->disconnected(client, conn, 0, NULL);
silc_client_close_connection_real(client, sock, conn);
return;
}
SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->internal->ops->disconnect(client, conn, 0, NULL);
+ client->internal->ops->disconnected(client, conn, 0, NULL);
silc_client_close_connection_real(client, sock, conn);
return;
}
/* Process the packet. This will call the parser that will then
decrypt and parse the packet. */
if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
- silc_packet_receive_process(sock, FALSE, conn->receive_key,
- conn->hmac_receive, conn->psn_receive,
+ silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
+ conn->internal->hmac_receive,
+ conn->internal->psn_receive,
silc_client_packet_parse, client);
else
silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
SilcPacketContext *packet = parser_context->packet;
SilcPacketType ret;
- if (conn && conn->hmac_receive && conn->sock == sock)
- conn->psn_receive = parser_context->packet->sequence + 1;
+ if (conn && conn->internal->hmac_receive && conn->sock == sock)
+ conn->internal->psn_receive = parser_context->packet->sequence + 1;
/* Parse the packet immediately */
if (parser_context->normal)
- ret = silc_packet_parse(packet, conn->receive_key);
+ ret = silc_packet_parse(packet, conn->internal->receive_key);
else
- ret = silc_packet_parse_special(packet, conn->receive_key);
+ ret = silc_packet_parse_special(packet, conn->internal->receive_key);
if (ret == SILC_PACKET_NONE) {
silc_packet_context_free(packet);
silc_free(parser_context);
/* Reprocess the buffer since we'll return FALSE. This is because
- the `conn->receive_key' might have become valid by processing
+ the `conn->internal->receive_key' might have become valid by processing
the previous packet */
if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
- silc_packet_receive_process(sock, FALSE, conn->receive_key,
- conn->hmac_receive, conn->psn_receive,
+ silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
+ conn->internal->hmac_receive,
+ conn->internal->psn_receive,
silc_client_packet_parse, client);
else
silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
SilcHmac hmac,
unsigned char *data,
SilcUInt32 data_len,
- int force_send)
+ bool force_send)
{
SilcPacketContext packetdata;
const SilcBufferStruct packet;
/* Get data used in the packet sending, keys and stuff */
if ((!cipher || !hmac || !dst_id) && sock->user_data) {
- if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
- cipher = ((SilcClientConnection)sock->user_data)->send_key;
+ if (!cipher && ((SilcClientConnection)sock->user_data)->internal->send_key)
+ cipher = ((SilcClientConnection)sock->user_data)->internal->send_key;
- if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
- hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
+ if (!hmac && ((SilcClientConnection)sock->user_data)->internal->hmac_send)
+ hmac = ((SilcClientConnection)sock->user_data)->internal->hmac_send;
if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
}
if (hmac)
- sequence = ((SilcClientConnection)sock->user_data)->psn_send++;
+ sequence = ((SilcClientConnection)sock->user_data)->internal->psn_send++;
}
block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute_final(sock->protocol, client->schedule);
/* The application will recall this function with these protocols
- (the ops->connect client operation). */
+ (the ops->connected client operation). */
return;
} else {
sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
}
/* Free everything */
- if (del && sock->user_data) {
- /* Free all cache entries */
- SilcIDCacheList list;
- SilcIDCacheEntry entry;
- SilcClientCommandPending *r;
- bool ret;
-
- if (silc_idcache_get_all(conn->client_cache, &list)) {
- ret = silc_idcache_list_first(list, &entry);
- while (ret) {
- silc_client_del_client(client, conn, entry->context);
- ret = silc_idcache_list_next(list, &entry);
- }
- silc_idcache_list_free(list);
- }
-
- if (silc_idcache_get_all(conn->channel_cache, &list)) {
- ret = silc_idcache_list_first(list, &entry);
- while (ret) {
- silc_client_del_channel(client, conn, entry->context);
- ret = silc_idcache_list_next(list, &entry);
- }
- silc_idcache_list_free(list);
- }
-
- if (silc_idcache_get_all(conn->server_cache, &list)) {
- ret = silc_idcache_list_first(list, &entry);
- while (ret) {
- silc_client_del_server(client, conn, entry->context);
- ret = silc_idcache_list_next(list, &entry);
- }
- silc_idcache_list_free(list);
- }
-
- /* Clear ID caches */
- if (conn->client_cache)
- silc_idcache_free(conn->client_cache);
- if (conn->channel_cache)
- silc_idcache_free(conn->channel_cache);
- if (conn->server_cache)
- silc_idcache_free(conn->server_cache);
-
- /* Free data (my ID is freed in above silc_client_del_client).
- conn->nickname is freed when freeing the local_entry->nickname. */
- if (conn->remote_host)
- silc_free(conn->remote_host);
- if (conn->local_id_data)
- silc_free(conn->local_id_data);
- if (conn->send_key)
- silc_cipher_free(conn->send_key);
- if (conn->receive_key)
- silc_cipher_free(conn->receive_key);
- if (conn->hmac_send)
- silc_hmac_free(conn->hmac_send);
- if (conn->hmac_receive)
- silc_hmac_free(conn->hmac_receive);
- if (conn->rekey)
- silc_free(conn->rekey);
-
- if (conn->active_session) {
- sock->user_data = NULL;
- silc_client_ftp_session_free(conn->active_session);
- conn->active_session = NULL;
- }
-
- silc_client_ftp_free_sessions(client, conn);
-
- silc_dlist_start(conn->pending_commands);
- while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END)
- silc_dlist_del(conn->pending_commands, r);
- if (conn->pending_commands)
- silc_dlist_uninit(conn->pending_commands);
-
- memset(conn, 0, sizeof(*conn));
+ if (del && sock->user_data)
silc_client_del_connection(client, conn);
- }
silc_socket_free(sock);
}
conn = (SilcClientConnection)sock->user_data;
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->internal->ops->disconnect(client, conn, status, message);
+ client->internal->ops->disconnected(client, conn, status, message);
silc_free(message);
SilcBuffer sidp;
/* Notify application that connection is created to server */
- client->internal->ops->connect(client, conn, success ?
- SILC_CLIENT_CONN_SUCCESS_RESUME :
- SILC_CLIENT_CONN_ERROR);
+ client->internal->ops->connected(client, conn, success ?
+ SILC_CLIENT_CONN_SUCCESS_RESUME :
+ SILC_CLIENT_CONN_ERROR);
if (success) {
/* Issue INFO command to fetch the real server name and server
return;
}
- silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
+ silc_idcache_del_by_context(conn->internal->client_cache,
+ conn->local_entry);
silc_free(conn->local_id);
}
TRUE);
/* Put it to the ID cache */
- silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
+ silc_idcache_add(conn->internal->client_cache,
+ strdup(conn->nickname), conn->local_id,
(void *)conn->local_entry, 0, NULL);
if (connecting) {
conn->cmd_ident, 1, 5, sidp->data, sidp->len);
silc_buffer_free(sidp);
- if (!conn->params.detach_data) {
+ if (!conn->internal->params.detach_data) {
/* Send NICK command if the nickname was set by the application (and is
not same as the username). Send this with little timeout. */
if (client->nickname && strcmp(client->nickname, client->username))
/* Notify application of successful connection. We do it here now that
we've received the Client ID and are allowed to send traffic. */
- client->internal->ops->connect(client, conn, SILC_CLIENT_CONN_SUCCESS);
+ client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
/* Issue INFO command to fetch the real server name and server
information and other stuff. */
{
SilcSocketConnection sock = (SilcSocketConnection)context;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcClient client = (SilcClient)conn->rekey->context;
+ SilcClient client = (SilcClient)conn->internal->rekey->context;
SilcProtocol protocol;
SilcClientRekeyInternalContext *proto_ctx;
proto_ctx->client = (void *)client;
proto_ctx->sock = silc_socket_dup(sock);
proto_ctx->responder = FALSE;
- proto_ctx->pfs = conn->rekey->pfs;
+ proto_ctx->pfs = conn->internal->rekey->pfs;
/* Perform rekey protocol. Will call the final callback after the
protocol is over. */
/* Re-register re-key timeout */
silc_schedule_task_add(client->schedule, sock->sock,
silc_client_rekey_callback,
- context, conn->rekey->timeout, 0,
+ context, conn->internal->rekey->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
int ret;
/* If we haven't send our request then ignore this one. */
- if (!conn->connauth)
+ if (!conn->internal->connauth)
return;
/* Parse the payload */
/* Call the request callback to notify application for received
authentication method information. */
- if (conn->connauth->callback)
- (*conn->connauth->callback)(client, conn, auth_meth,
- conn->connauth->context);
+ if (conn->internal->connauth->callback)
+ (*conn->internal->connauth->callback)(client, conn, auth_meth,
+ conn->internal->connauth->context);
- silc_schedule_task_del(client->schedule, conn->connauth->timeout);
+ silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
- silc_free(conn->connauth);
- conn->connauth = NULL;
+ silc_free(conn->internal->connauth);
+ conn->internal->connauth = NULL;
}
/* Timeout task callback called if the server does not reply to our
SilcClientConnection conn = (SilcClientConnection)context;
SilcClient client = conn->client;
- if (!conn->connauth)
+ if (!conn->internal->connauth)
return;
/* Call the request callback to notify application */
- if (conn->connauth->callback)
- (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
- conn->connauth->context);
+ if (conn->internal->connauth->callback)
+ (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
+ conn->internal->connauth->context);
- silc_free(conn->connauth);
- conn->connauth = NULL;
+ silc_free(conn->internal->connauth);
+ conn->internal->connauth = NULL;
}
/* This function can be used to request the current authentication method
SilcClientConnAuthRequest connauth;
SilcBuffer packet;
+ assert(client && conn);
connauth = silc_calloc(1, sizeof(*connauth));
connauth->callback = callback;
connauth->context = context;
- if (conn->connauth)
- silc_free(conn->connauth);
+ if (conn->internal->connauth)
+ silc_free(conn->internal->connauth);
- conn->connauth = connauth;
+ conn->internal->connauth = connauth;
/* Assemble the request packet and send it to the server */
packet = silc_buffer_alloc(4);