+/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+ key material between client and server. This function can be called
+ directly if application is performing its own connecting and does not
+ use the connecting provided by this library. */
+
+int silc_client_start_key_exchange(SilcClient client,
+ SilcClientConnection conn,
+ int fd)
+{
+ SilcProtocol protocol;
+ SilcClientKEInternalContext *proto_ctx;
+ void *context;
+
+ /* Allocate new socket connection object */
+ silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
+ if (conn->sock == NULL) {
+ client->ops->say(client, conn,
+ "Error: Could not allocate connection socket");
+ return FALSE;
+ }
+
+ conn->nickname = strdup(client->username);
+ conn->sock->hostname = conn->remote_host;
+ conn->sock->port = conn->remote_port;
+
+ /* Allocate internal Key Exchange context. This is sent to the
+ protocol as context. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = conn->sock;
+ proto_ctx->rng = client->rng;
+ proto_ctx->responder = FALSE;
+
+ /* Perform key exchange protocol. silc_client_connect_to_server_final
+ will be called after the protocol is finished. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+ &protocol, (void *)proto_ctx,
+ silc_client_connect_to_server_second);
+ if (!protocol) {
+ client->ops->say(client, conn,
+ "Error: Could not start authentication protocol");
+ return FALSE;
+ }
+ conn->sock->protocol = protocol;
+
+ /* Register the connection for network input and output. This sets
+ that scheduler will listen for incoming packets for this connection
+ and sets that outgoing packets may be sent to this connection as well.
+ 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(fd);
+
+ /* Execute the protocol */
+ protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ return TRUE;
+}
+