ske->sock->user_data = tmp;
}
+/* Timeout callback that is called to close the connection and free the
+ socket connection data. */
+
+SILC_TASK_CALLBACK(silc_client_key_agreement_close)
+{
+ SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
+
+ silc_schedule_unset_listen_fd(ke->sock->sock);
+ silc_schedule_unset_listen_fd(ke->fd);
+ silc_net_close_connection(ke->sock->sock);
+ silc_net_close_connection(ke->fd);
+ silc_socket_free(ke->sock);
+ silc_free(ke);
+}
+
/* This callback is called after the key agreement protocol has been
performed. This calls the final completion callback for the application. */
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
silc_ske_free_key_material(ctx->keymat);
goto out;
}
/* Pass the negotiated key material to the application. The application
is responsible of freeing the key material. */
ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry, ctx->keymat,
- ke->context);
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_OK, ctx->keymat, ke->context);
out:
silc_protocol_free(protocol);
silc_task_unregister_by_callback(client->timeout_queue,
silc_client_failure_callback);
silc_task_unregister_by_fd(client->io_queue, ke->fd);
+ silc_schedule_unset_listen_fd(ke->fd);
+ silc_net_close_connection(ke->fd);
if (ke->timeout)
silc_task_unregister(client->timeout_queue, ke->timeout);
- silc_socket_free(ke->sock);
- silc_free(ke);
+ silc_client_del_socket(ke->client, ke->sock);
+
+ silc_task_register(client->timeout_queue, 0,
+ silc_client_key_agreement_close,
+ (void *)ke, 0, 1,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
silc_free(ctx);
}
"Could not accept key agreement connection: ",
strerror(errno));
ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
silc_task_unregister_by_fd(client->io_queue, ke->fd);
+ silc_schedule_unset_listen_fd(ke->fd);
+ silc_net_close_connection(ke->fd);
if (ke->timeout)
silc_task_unregister(client->timeout_queue, ke->timeout);
silc_free(ke);
client->ops->say(client, conn,
"Could not resolve the remote IP or hostname");
ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_ERROR, NULL, ke->context);
silc_task_unregister_by_fd(client->io_queue, ke->fd);
+ silc_schedule_unset_listen_fd(ke->fd);
+ silc_net_close_connection(ke->fd);
if (ke->timeout)
silc_task_unregister(client->timeout_queue, ke->timeout);
silc_free(ke);
if (!newsocket->hostname)
newsocket->hostname = strdup(newsocket->ip);
newsocket->port = silc_net_get_remote_port(sock);
+ silc_client_add_socket(client, newsocket);
/* Allocate internal context for key exchange protocol. This is
sent as context for the protocol. */
proto_ctx->responder = TRUE;
proto_ctx->context = context;
proto_ctx->send_packet = silc_client_key_agreement_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
/* Prepare the connection for key exchange protocol. We allocate the
protocol but will not start it yet. The connector will be the
However, this doesn't set the scheduler for outgoing traffic, it
will be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
later when outgoing data is available. */
+ context = (void *)client;
SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(sock);
}
SilcClientKeyAgreement ke = (SilcClientKeyAgreement)context;
ke->client_entry->ke = NULL;
- ke->completion(ke->client, ke->conn, ke->client_entry, NULL, ke->context);
+ ke->completion(ke->client, ke->conn, ke->client_entry,
+ SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
- if (ke->sock)
+ if (ke->sock) {
+ silc_client_del_socket(ke->client, ke->sock);
silc_socket_free(ke->sock);
+ }
ke->client_entry->ke = NULL;
- silc_free(ke);
silc_task_unregister_by_callback(ke->client->timeout_queue,
silc_client_failure_callback);
- silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
+ if (ke->fd)
+ silc_task_unregister_by_fd(ke->client->io_queue, ke->fd);
+ silc_schedule_unset_listen_fd(ke->fd);
+ silc_net_close_connection(ke->fd);
+ silc_free(ke);
}
/* Sends key agreement request to the remote client indicated by the
that port for the key agreement protocol. It also sends the `hostname'
and the `port' in the key agreement packet to the remote client. This
would indicate that the remote client may initiate the key agreement
- protocol to the `hostname' on the `port'.
+ protocol to the `hostname' on the `port'. If port is zero then the
+ bound port is undefined (the operating system defines it).
If the `hostname' and `port' is not provided then empty key agreement
packet is sent to the remote client. The remote client may reply with
SilcClientEntry client_entry,
char *hostname,
int port,
- unsigned long timeout_secs,
+ uint32 timeout_secs,
SilcKeyAgreementCallback completion,
void *context)
{
SilcSocketConnection sock = conn->sock;
- SilcClientKeyAgreement ke;
+ SilcClientKeyAgreement ke = NULL;
SilcBuffer buffer;
assert(client_entry);
return;
/* Create the listener if hostname and port was provided */
- if (hostname && port) {
+ if (hostname) {
ke = silc_calloc(1, sizeof(*ke));
ke->fd = silc_net_create_server(port, hostname);
client->ops->say(client, conn,
"Cannot create listener on %s on port %d: %s",
hostname, port, strerror(errno));
- completion(client, conn, client_entry, NULL, context);
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+ NULL, context);
silc_free(ke);
return;
}
/* Register a timeout task that will be executed if the connector
will not start the key exchange protocol within the specified
timeout. */
- ke->timeout =
- silc_task_register(client->timeout_queue, 0,
- silc_client_key_agreement_timeout,
- (void *)ke, timeout_secs, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ ke->timeout = silc_task_register(client->timeout_queue, 0,
+ silc_client_key_agreement_timeout,
+ (void *)ke, timeout_secs, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
}
/* Encode the key agreement payload */
- buffer = silc_key_agreement_payload_encode(hostname, port);
+ buffer = silc_key_agreement_payload_encode(hostname,
+ !ke ? port :
+ silc_net_get_local_port(ke->fd));
/* Send the key agreement packet to the client */
silc_client_packet_send(client, sock, SILC_PACKET_KEY_AGREEMENT,
silc_schedule_unset_listen_fd(fd);
silc_net_close_connection(fd);
silc_task_unregister(client->io_queue, ctx->task);
+ silc_free(ctx->host);
silc_free(ctx);
/* Call the completion callback */
ke->completion(ke->client, ke->conn, ke->client_entry,
- NULL, ke->context);
+ SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
silc_free(ke);
}
return;
silc_schedule_unset_listen_fd(fd);
silc_task_unregister(client->io_queue, ctx->task);
- silc_free(ctx);
ke->fd = fd;
/* Now actually perform the key agreement protocol */
silc_client_perform_key_agreement_fd(ke->client, ke->conn,
- ke->client_entry, ke->fd,
+ ke->client_entry, ke->fd, ctx->host,
ke->completion, ke->context);
silc_free(ke);
+ silc_free(ctx->host);
+ silc_free(ctx);
}
/* Performs the actual key agreement protocol. Application may use this
{
SilcClientKeyAgreement ke;
+ SILC_LOG_DEBUG(("Start"));
+
assert(client_entry && hostname && port);
ke = silc_calloc(1, sizeof(*ke));
/* Connect to the remote client */
ke->fd = silc_client_connect_to_client(client, conn, port, hostname, ke);
if (ke->fd < 0) {
- completion(client, conn, client_entry, NULL, context);
+ completion(client, conn, client_entry, SILC_KEY_AGREEMENT_FAILURE,
+ NULL, context);
silc_free(ke);
return;
}
SilcClientConnection conn,
SilcClientEntry client_entry,
int sock,
+ char *hostname,
SilcKeyAgreementCallback completion,
void *context)
{
SilcClientKEInternalContext *proto_ctx;
SilcProtocol protocol;
+ SILC_LOG_DEBUG(("Start"));
+
assert(client_entry);
ke = silc_calloc(1, sizeof(*ke));
/* Allocate new socket connection object */
silc_socket_alloc(sock, SILC_SOCKET_TYPE_UNKNOWN, (void *)conn, &ke->sock);
+ silc_client_add_socket(client, ke->sock);
+ ke->sock->hostname = strdup(hostname);
+ ke->sock->port = silc_net_get_remote_port(sock);
/* Allocate internal context for key exchange protocol. This is
sent as context for the protocol. */
proto_ctx->responder = FALSE;
proto_ctx->context = ke;
proto_ctx->send_packet = silc_client_key_agreement_send_packet;
+ proto_ctx->verify = silc_client_protocol_ke_verify_key;
/* Perform key exchange protocol. */
silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
assert(client_entry);
if (client_entry->ke) {
- if (client_entry->ke->sock)
+ if (client_entry->ke->sock) {
+ silc_client_del_socket(client_entry->ke->client, client_entry->ke->sock);
silc_socket_free(client_entry->ke->sock);
+ }
client_entry->ke = NULL;
silc_task_unregister_by_fd(client->io_queue, client_entry->ke->fd);
if (client_entry->ke->timeout)
silc_client_key_agreement_resolve_cb(SilcClient client,
SilcClientConnection conn,
SilcClientEntry *clients,
- unsigned int clients_count,
+ uint32 clients_count,
void *context)
{
SilcPacketContext *packet = (SilcPacketContext *)context;