SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
-SILC_TASK_CALLBACK(silc_client_packet_parse_real);
SILC_TASK_CALLBACK(silc_client_rekey_callback);
SILC_TASK_CALLBACK(silc_client_rekey_final);
new_client = silc_calloc(1, sizeof(*new_client));
new_client->application = application;
- new_client->ops = ops;
- new_client->silc_client_version = strdup(silc_version);
- new_client->params = silc_calloc(1, sizeof(*new_client->params));
+
+ new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
+ 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 (params)
- memcpy(new_client->params, params, sizeof(*params));
+ memcpy(new_client->internal->params, params, sizeof(*params));
- if (!new_client->params->task_max)
- new_client->params->task_max = 200;
+ if (!new_client->internal->params->task_max)
+ new_client->internal->params->task_max = 200;
- if (!new_client->params->rekey_secs)
- new_client->params->rekey_secs = 3600;
+ if (!new_client->internal->params->rekey_secs)
+ new_client->internal->params->rekey_secs = 3600;
- if (!new_client->params->connauth_request_secs)
- new_client->params->connauth_request_secs = 2;
+ if (!new_client->internal->params->connauth_request_secs)
+ new_client->internal->params->connauth_request_secs = 2;
- new_client->params->
- nickname_format[sizeof(new_client->params->nickname_format) - 1] = 0;
+ new_client->internal->params->
+ nickname_format[sizeof(new_client->internal->
+ params->nickname_format) - 1] = 0;
return new_client;
}
if (client->rng)
silc_rng_free(client->rng);
- silc_free(client->silc_client_version);
- silc_free(client->params);
+ silc_free(client->internal->params);
+ silc_free(client->internal->silc_client_version);
+ silc_free(client->internal);
silc_free(client);
}
}
SILC_LOG_DEBUG(("Initializing client"));
/* Initialize hash functions for client to use */
- silc_hash_alloc("md5", &client->md5hash);
- silc_hash_alloc("sha1", &client->sha1hash);
+ silc_hash_alloc("md5", &client->internal->md5hash);
+ silc_hash_alloc("sha1", &client->internal->sha1hash);
/* Initialize none cipher */
- silc_cipher_alloc("none", &client->none_cipher);
+ silc_cipher_alloc("none", &client->internal->none_cipher);
/* Initialize random number generator */
client->rng = silc_rng_alloc();
silc_client_protocols_register();
/* Initialize the scheduler */
- client->schedule = silc_schedule_init(client->params->task_max ?
- client->params->task_max : 200);
+ client->schedule =
+ silc_schedule_init(client->internal->params->task_max ?
+ client->internal->params->task_max : 200);
if (!client->schedule)
return FALSE;
+ /* Register commands */
+ silc_client_commands_register(client);
+
return TRUE;
}
silc_schedule_uninit(client->schedule);
silc_client_protocols_unregister();
+ silc_client_commands_unregister(client);
SILC_LOG_DEBUG(("Client stopped"));
}
silc_schedule(client->schedule);
}
+/* Runs the client and returns immeadiately. This function is used when
+ the SILC Client object indicated by the `client' is run under some
+ other scheduler, or event loop or main loop. On GUI applications,
+ for example this may be desired to use to run the client under the
+ GUI application's main loop. Typically the GUI application would
+ register an idle task that calls this function multiple times in
+ a second to quickly process the SILC specific data. */
+
+void silc_client_run_one(SilcClient client)
+{
+ /* Run the scheduler once. */
+ silc_schedule_one(client->schedule, 0);
+}
+
static void silc_client_entry_destructor(SilcIDCache cache,
SilcIDCacheEntry entry)
{
conn->ftp_sessions = silc_dlist_init();
/* Add the connection to connections table */
- for (i = 0; i < client->conns_count; i++)
- if (client->conns && !client->conns[i]) {
- client->conns[i] = conn;
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns && !client->internal->conns[i]) {
+ client->internal->conns[i] = conn;
return conn;
}
- client->conns = silc_realloc(client->conns, sizeof(*client->conns)
- * (client->conns_count + 1));
- client->conns[client->conns_count] = conn;
- client->conns_count++;
+ client->internal->conns =
+ silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
+ * (client->internal->conns_count + 1));
+ client->internal->conns[client->internal->conns_count] = conn;
+ client->internal->conns_count++;
return conn;
}
{
int i;
- for (i = 0; i < client->conns_count; i++)
- if (client->conns[i] == conn) {
+ for (i = 0; i < client->internal->conns_count; i++)
+ if (client->internal->conns[i] == conn) {
silc_idcache_free(conn->client_cache);
silc_idcache_free(conn->channel_cache);
silc_dlist_uninit(conn->ftp_sessions);
silc_free(conn);
- client->conns[i] = NULL;
+ client->internal->conns[i] = NULL;
}
}
{
int i;
- if (!client->sockets) {
- client->sockets = silc_calloc(1, sizeof(*client->sockets));
- client->sockets[0] = silc_socket_dup(sock);
- client->sockets_count = 1;
+ if (!client->internal->sockets) {
+ client->internal->sockets =
+ silc_calloc(1, sizeof(*client->internal->sockets));
+ client->internal->sockets[0] = silc_socket_dup(sock);
+ client->internal->sockets_count = 1;
return;
}
- for (i = 0; i < client->sockets_count; i++) {
- if (client->sockets[i] == NULL) {
- client->sockets[i] = silc_socket_dup(sock);
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == NULL) {
+ client->internal->sockets[i] = silc_socket_dup(sock);
return;
}
}
- client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
- (client->sockets_count + 1));
- client->sockets[client->sockets_count] = silc_socket_dup(sock);
- client->sockets_count++;
+ client->internal->sockets =
+ silc_realloc(client->internal->sockets,
+ sizeof(*client->internal->sockets) *
+ (client->internal->sockets_count + 1));
+ client->internal->sockets[client->internal->sockets_count] =
+ silc_socket_dup(sock);
+ client->internal->sockets_count++;
}
/* Deletes listener socket from the listener sockets table. */
{
int i;
- if (!client->sockets)
+ if (!client->internal->sockets)
return;
- for (i = 0; i < client->sockets_count; i++) {
- if (client->sockets[i] == sock) {
+ for (i = 0; i < client->internal->sockets_count; i++) {
+ if (client->internal->sockets[i] == sock) {
silc_socket_free(sock);
- client->sockets[i] = NULL;
+ client->internal->sockets[i] = NULL;
return;
}
}
conn = silc_client_add_connection(client, host, port, context);
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of server %s", port, host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s", port, host);
/* Allocate internal context for connection process. This is
needed as we are doing async connecting. */
silc_schedule_task_del_by_fd(client->schedule, fd);
conn->nickname = strdup(client->username);
- conn->sock->hostname = conn->remote_host;
+ conn->sock->hostname = strdup(conn->remote_host);
conn->sock->ip = strdup(conn->remote_host);
conn->sock->port = conn->remote_port;
&protocol, (void *)proto_ctx,
silc_client_connect_to_server_second);
if (!protocol) {
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Error: Could not start key exchange protocol");
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Error: Could not start key exchange protocol");
return FALSE;
}
conn->sock->protocol = protocol;
return TRUE;
}
+/* Callback called when error has occurred during connecting to the server.
+ The `connect' client operation will be called. */
+
+SILC_TASK_CALLBACK(silc_client_connect_failure)
+{
+ SilcClientKEInternalContext *ctx =
+ (SilcClientKEInternalContext *)context;
+ SilcClient client = (SilcClient)ctx->client;
+
+ client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
+ silc_free(ctx);
+}
+
/* Start of the connection to the remote server. This is called after
succesful TCP/IP connection has been established to the remote host. */
if (opt != 0) {
if (ctx->tries < 2) {
/* Connection failed but lets try again */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to server %s: %s",
- ctx->host, strerror(opt));
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
- "Connecting to port %d of server %s resumed",
- ctx->port, ctx->host);
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+ "Connecting to port %d of server %s resumed",
+ ctx->port, ctx->host);
/* Unregister old connection try */
silc_schedule_unset_listen_fd(client->schedule, fd);
ctx->tries++;
} else {
/* Connection failed and we won't try anymore */
- client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "Could not connect to server %s: %s",
- ctx->host, strerror(opt));
+ client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "Could not connect to server %s: %s",
+ ctx->host, strerror(opt));
silc_schedule_unset_listen_fd(client->schedule, fd);
silc_net_close_connection(fd);
silc_schedule_task_del(client->schedule, ctx->task);
silc_free(ctx);
/* Notify application of failure */
- client->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, FALSE);
silc_client_del_connection(client, conn);
}
return;
if (!silc_client_start_key_exchange(client, conn, fd)) {
silc_net_close_connection(fd);
- client->ops->connect(client, conn, FALSE);
+ client->internal->ops->connect(client, conn, FALSE);
}
}
silc_socket_free(ctx->sock);
/* Notify application of failure */
- client->ops->connect(client, ctx->sock->user_data, FALSE);
- silc_free(ctx);
+ silc_schedule_task_add(client->schedule, ctx->sock->sock,
+ silc_client_connect_failure, ctx,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
return;
}
/* Resolve the authentication method to be used in this connection. The
completion callback is called after the application has resolved
the authentication method. */
- client->ops->get_auth_method(client, sock->user_data, sock->hostname,
- sock->port, silc_client_resolve_auth_method,
- proto_ctx);
+ client->internal->ops->get_auth_method(client, sock->user_data,
+ sock->hostname,
+ sock->port,
+ silc_client_resolve_auth_method,
+ proto_ctx);
}
/* Authentication method resolving callback. Application calls this function
- after we've called the client->ops->get_auth_method client operation
- to resolve the authentication method. We will continue the executiong
- of the protocol in this function. */
+ after we've called the client->internal->ops->get_auth_method
+ client operation to resolve the authentication method. We will continue
+ the executiong of the protocol in this function. */
void silc_client_resolve_auth_method(bool success,
SilcProtocolAuthMeth auth_meth,
silc_socket_free(ctx->sock);
/* Notify application of failure */
- client->ops->connect(client, ctx->sock->user_data, FALSE);
- silc_free(ctx);
+ silc_schedule_task_add(client->schedule, ctx->sock->sock,
+ silc_client_connect_failure, ctx,
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
return;
}
conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
/* Register re-key timeout */
- conn->rekey->timeout = client->params->rekey_secs;
+ conn->rekey->timeout = client->internal->params->rekey_secs;
conn->rekey->context = (void *)client;
silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_rekey_callback,
close the connection */
if (SILC_IS_DISCONNECTING(sock)) {
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->ops->disconnect(client, conn);
+ client->internal->ops->disconnect(client, conn);
silc_client_close_connection(client, sock, conn);
return;
}
SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
- client->ops->disconnect(client, conn);
+ client->internal->ops->disconnect(client, conn);
silc_client_close_connection(client, sock, conn);
return;
}
}
}
-/* Parses whole packet, received earlier. */
-
-SILC_TASK_CALLBACK(silc_client_packet_parse_real)
-{
- SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
- SilcClient client = (SilcClient)parse_ctx->context;
- SilcPacketContext *packet = parse_ctx->packet;
- SilcSocketConnection sock = parse_ctx->sock;
- SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- int ret;
-
- SILC_LOG_DEBUG(("Start"));
-
- /* Parse the packet */
- if (parse_ctx->normal)
- ret = silc_packet_parse(packet, conn->receive_key);
- else
- ret = silc_packet_parse_special(packet, conn->receive_key);
-
- if (ret == SILC_PACKET_NONE)
- goto out;
-
- /* Parse the incoming packet type */
- silc_client_packet_parse_type(client, sock, packet);
-
- out:
- /* silc_buffer_clear(sock->inbuf); */
- silc_packet_context_free(packet);
- silc_free(parse_ctx);
-}
-
/* Parser callback called by silc_packet_receive_process. Thie merely
registers timeout that will handle the actual parsing when appropriate. */
SilcClient client = (SilcClient)context;
SilcSocketConnection sock = parser_context->sock;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcPacketContext *packet = parser_context->packet;
+ SilcPacketType ret;
- if (conn && conn->hmac_receive)
+ if (conn && conn->hmac_receive && conn->sock == sock)
conn->psn_receive = parser_context->packet->sequence + 1;
+ /* Parse the packet immediately */
+ if (parser_context->normal)
+ ret = silc_packet_parse(packet, conn->receive_key);
+ else
+ ret = silc_packet_parse_special(packet, conn->receive_key);
+
+ if (ret == SILC_PACKET_NONE) {
+ silc_packet_context_free(packet);
+ silc_free(parser_context);
+ return FALSE;
+ }
+
/* If protocol for this connection is key exchange or rekey then we'll
process all packets synchronously, since there might be packets in
queue that we are not able to decrypt without first processing the
packets before them. */
- if (sock->protocol && sock->protocol->protocol &&
- (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
- silc_client_packet_parse_real(client->schedule, 0, sock->sock,
- parser_context);
+ if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
+ (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
+
+ /* Parse the incoming packet type */
+ silc_client_packet_parse_type(client, sock, packet);
+ 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 bu processing
+ the `conn->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,
else
silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
silc_client_packet_parse, client);
+
return FALSE;
}
- /* Parse the packet */
- silc_schedule_task_add(client->schedule, sock->sock,
- silc_client_packet_parse_real,
- (void *)parser_context, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
-
+ /* Parse the incoming packet type */
+ silc_client_packet_parse_type(client, sock, packet);
+ silc_packet_context_free(packet);
+ silc_free(parser_context);
return TRUE;
}
*/
SilcIDPayload idp;
- idp = silc_id_payload_parse(buffer);
+ idp = silc_id_payload_parse(buffer->data, buffer->len);
if (!idp)
break;
if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
{
int del = FALSE;
+ SILC_LOG_DEBUG(("Start"));
+
if (!sock || (sock && conn->sock == sock))
del = TRUE;
if (!sock)
silc_socket_free(sock);
}
+/* Called when we receive disconnection packet from server. This
+ closes our end properly and displays the reason of the disconnection
+ on the screen. */
+
+SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
+{
+ SilcClient client = (SilcClient)context;
+ SilcSocketConnection sock;
+
+ SILC_CLIENT_GET_SOCK(client, fd, sock);
+ if (sock == NULL)
+ return;
+
+ silc_client_close_connection(client, sock, sock->user_data);
+}
+
/* Called when we receive disconnection packet from server. This
closes our end properly and displays the reason of the disconnection
on the screen. */
msg = silc_calloc(message->len + 1, sizeof(char));
memcpy(msg, message->data, message->len);
- client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+ client->internal->ops->say(client, sock->user_data,
+ SILC_CLIENT_MESSAGE_AUDIT, msg);
silc_free(msg);
SILC_SET_DISCONNECTED(sock);
- silc_client_close_connection(client, sock, sock->user_data);
+
+ /* Close connection through scheduler. */
+ silc_schedule_task_add(client->schedule, sock->sock,
+ silc_client_disconnected_by_server_later,
+ client, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Received error message from server. Display it on the screen.
msg = silc_calloc(message->len + 1, sizeof(char));
memcpy(msg, message->data, message->len);
- client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
+ client->internal->ops->say(client, sock->user_data,
+ SILC_CLIENT_MESSAGE_AUDIT, msg);
silc_free(msg);
}
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
int connecting = FALSE;
+ SilcClientID *client_id = silc_id_payload_get_id(idp);
SilcBuffer sidp;
if (!conn->local_entry)
/* Delete old ID from ID cache */
if (conn->local_id) {
+ /* Check whether they are different */
+ if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
+ silc_free(client_id);
+ return;
+ }
+
silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
silc_free(conn->local_id);
}
if (conn->local_id_data)
silc_free(conn->local_id_data);
- conn->local_id = silc_id_payload_get_id(idp);
+ conn->local_id = client_id;
conn->local_id_data = silc_id_payload_get_data(idp);
conn->local_id_data_len = silc_id_payload_get_len(idp);;
/* Put it to the ID cache */
silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
- (void *)conn->local_entry, FALSE);
-
- /* Issue INFO command to fetch the real server name and server information
- and other stuff. */
- sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
- silc_client_send_command(client, conn, SILC_COMMAND_INFO,
- ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
- silc_buffer_free(sidp);
-
- /* Notify application of successful connection. We do it here now that
- we've received the Client ID and are allowed to send traffic. */
- if (connecting)
- client->ops->connect(client, conn, TRUE);
+ (void *)conn->local_entry, 0, NULL);
+
+ if (connecting) {
+ /* Issue INFO comqmand to fetch the real server name and server information
+ and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+
+ /* 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, TRUE);
+ }
}
/* Processed received Channel ID for a channel. This is called when client
/* Put it to the ID cache */
silc_idcache_add(conn->channel_cache, channel->channel_name,
- (void *)channel->id, (void *)channel, FALSE);
+ (void *)channel->id, (void *)channel, 0, NULL);
return channel;
}
SILC_GET32_MSB(failure, packet->buffer->data);
/* Notify application */
- client->ops->failure(client, sock->user_data, sock->protocol,
- (void *)failure);
+ client->internal->ops->failure(client, sock->user_data, sock->protocol,
+ (void *)failure);
}
}
connauth->timeout =
silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_request_authentication_method_timeout,
- conn, client->params->connauth_request_secs, 0,
+ conn,
+ client->internal->params->connauth_request_secs, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}