X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient.c;h=681d9e0eaf300ff1f9d88047a55ef1ce58214905;hb=017dec75a98209fbef49eb496c2269b0c49e736d;hp=20c878707604a6a23192a2bc7b5e08eb62b48cb8;hpb=afca12dad0ef6623a983bdcc10b6f7ff7364edae;p=silc.git diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 20c87870..681d9e0e 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -2,7 +2,7 @@ client.c - Author: Pekka Riikonen + Author: Pekka Riikonen Copyright (C) 1997 - 2001 Pekka Riikonen @@ -34,13 +34,19 @@ static void silc_client_packet_parse(SilcPacketParserContext *parser_context); static void silc_client_packet_parse_type(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_client_resolve_auth_method(bool success, + SilcProtocolAuthMeth auth_meth, + const unsigned char *auth_data, + uint32 auth_data_len, void *context); /* Allocates new client object. This has to be done before client may work. After calling this one must call silc_client_init to initialize the client. The `application' is application specific user data pointer and caller must free it. */ -SilcClient silc_client_alloc(SilcClientOperations *ops, void *application, +SilcClient silc_client_alloc(SilcClientOperations *ops, + SilcClientParams *params, + void *application, const char *silc_version) { SilcClient new_client; @@ -49,6 +55,22 @@ SilcClient silc_client_alloc(SilcClientOperations *ops, void *application, 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)); + + if (params) + memcpy(new_client->params, params, sizeof(*params)); + + if (!new_client->params->task_max) + new_client->params->task_max = 200; + + if (!new_client->params->rekey_secs) + new_client->params->rekey_secs = 3600; + + if (!new_client->params->connauth_request_secs) + new_client->params->connauth_request_secs = 2; + + new_client->params-> + nickname_format[sizeof(new_client->params->nickname_format) - 1] = 0; return new_client; } @@ -61,6 +83,8 @@ void silc_client_free(SilcClient client) if (client->rng) silc_rng_free(client->rng); + silc_free(client->silc_client_version); + silc_free(client->params); silc_free(client); } } @@ -89,9 +113,8 @@ int silc_client_init(SilcClient client) silc_client_protocols_register(); /* Initialize the scheduler */ - client->schedule = silc_schedule_init(&client->io_queue, - &client->timeout_queue, - &client->generic_queue, 5000); + client->schedule = silc_schedule_init(client->params->task_max ? + client->params->task_max : 200); if (!client->schedule) return FALSE; @@ -105,9 +128,6 @@ void silc_client_stop(SilcClient client) { SILC_LOG_DEBUG(("Stopping client")); - /* Stop the scheduler, although it might be already stopped. This - doesn't hurt anyone. This removes all the tasks and task queues, - as well. */ silc_schedule_stop(client->schedule); silc_schedule_uninit(client->schedule); @@ -128,6 +148,12 @@ void silc_client_run(SilcClient client) silc_schedule(client->schedule); } +static void silc_client_entry_destructor(SilcIDCache cache, + SilcIDCacheEntry entry) +{ + silc_free(entry->name); +} + /* Allocates and adds new connection to the client. This adds the allocated connection to the connection table and returns a pointer to it. A client can have multiple connections to multiple servers. Every connection must @@ -147,7 +173,8 @@ SilcClientConnection silc_client_add_connection(SilcClient client, conn = silc_calloc(1, sizeof(*conn)); /* Initialize ID caches */ - conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, NULL); + 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; @@ -240,19 +267,18 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx) /* XXX In the future we should give up this non-blocking connect all together and use threads instead. */ /* Create connection to server asynchronously */ - sock = silc_net_create_connection_async(ctx->port, ctx->host); + sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host); if (sock < 0) return -1; /* Register task that will receive the async connect and will read the result. */ - ctx->task = silc_task_register(ctx->client->io_queue, sock, - silc_client_connect_to_server_start, - (void *)ctx, 0, 0, - SILC_TASK_FD, - SILC_TASK_PRI_NORMAL); - silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE); - silc_schedule_set_listen_fd(ctx->client->schedule, sock, ctx->task->iomask); + ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, + silc_client_connect_to_server_start, + (void *)ctx, 0, 0, + SILC_TASK_FD, + SILC_TASK_PRI_NORMAL); + silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE); ctx->sock = sock; @@ -305,9 +331,9 @@ int silc_client_connect_to_server(SilcClient client, int port, used only if the application performed the connecting outside the library. The library however may use this internally. */ -int silc_client_start_key_exchange(SilcClient client, - SilcClientConnection conn, - int fd) +bool silc_client_start_key_exchange(SilcClient client, + SilcClientConnection conn, + int fd) { SilcProtocol protocol; SilcClientKEInternalContext *proto_ctx; @@ -316,6 +342,12 @@ int silc_client_start_key_exchange(SilcClient client, /* Allocate new socket connection object */ silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock); + /* Sometimes when doing quick reconnects the new socket may be same as + the old one and there might be pending stuff for the old socket. + If new one is same then those pending sutff might cause problems. + Make sure they do not do that. */ + silc_schedule_task_del_by_fd(client->schedule, fd); + conn->nickname = strdup(client->username); conn->sock->hostname = conn->remote_host; conn->sock->ip = strdup(conn->remote_host); @@ -338,7 +370,7 @@ int silc_client_start_key_exchange(SilcClient client, silc_client_connect_to_server_second); if (!protocol) { client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, - "Error: Could not start authentication protocol"); + "Error: Could not start key exchange protocol"); return FALSE; } conn->sock->protocol = protocol; @@ -353,7 +385,7 @@ int silc_client_start_key_exchange(SilcClient client, SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd); /* Execute the protocol */ - silc_protocol_execute(protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); return TRUE; } @@ -385,7 +417,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) /* Unregister old connection try */ silc_schedule_unset_listen_fd(client->schedule, fd); silc_net_close_connection(fd); - silc_task_unregister(client->io_queue, ctx->task); + silc_schedule_task_del(client->schedule, ctx->task); /* Try again */ silc_client_connect_to_server_internal(ctx); @@ -397,7 +429,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) ctx->host, strerror(opt)); silc_schedule_unset_listen_fd(client->schedule, fd); silc_net_close_connection(fd); - silc_task_unregister(client->io_queue, ctx->task); + silc_schedule_task_del(client->schedule, ctx->task); silc_free(ctx); /* Notify application of failure */ @@ -408,7 +440,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) } silc_schedule_unset_listen_fd(client->schedule, fd); - silc_task_unregister(client->io_queue, ctx->task); + silc_schedule_task_del(client->schedule, ctx->task); silc_free(ctx); if (!silc_client_start_key_exchange(client, conn, fd)) { @@ -470,13 +502,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) proto_ctx->dest_id_type = ctx->dest_id_type; proto_ctx->dest_id = ctx->dest_id; - /* Resolve the authentication method to be used in this connection */ - if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname, - sock->port, &proto_ctx->auth_meth, - &proto_ctx->auth_data, - &proto_ctx->auth_data_len)) - proto_ctx->auth_meth = SILC_AUTH_NONE; - /* Free old protocol as it is finished now */ silc_protocol_free(protocol); if (ctx->packet) @@ -484,13 +509,46 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) silc_free(ctx); sock->protocol = NULL; + /* 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); +} + +/* 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. */ + +void silc_client_resolve_auth_method(bool success, + SilcProtocolAuthMeth auth_meth, + const unsigned char *auth_data, + uint32 auth_data_len, void *context) +{ + SilcClientConnAuthInternalContext *proto_ctx = + (SilcClientConnAuthInternalContext *)context; + SilcClient client = (SilcClient)proto_ctx->client; + + if (!success) + auth_meth = SILC_AUTH_NONE; + + proto_ctx->auth_meth = auth_meth; + + if (auth_data && auth_data_len) { + proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data)); + memcpy(proto_ctx->auth_data, auth_data, auth_data_len); + proto_ctx->auth_data_len = auth_data_len; + } + /* Allocate the authenteication protocol and execute it. */ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, - &sock->protocol, (void *)proto_ctx, + &proto_ctx->sock->protocol, (void *)proto_ctx, silc_client_connect_to_server_final); /* Execute the protocol */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0); } /* Finalizes the connection to the remote SILC server. This is called @@ -556,12 +614,12 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER); /* Register re-key timeout */ - conn->rekey->timeout = 3600; /* XXX hardcoded */ + conn->rekey->timeout = client->params->rekey_secs; conn->rekey->context = (void *)client; - silc_task_register(client->timeout_queue, conn->sock->sock, - silc_client_rekey_callback, - (void *)conn->sock, conn->rekey->timeout, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(client->schedule, conn->sock->sock, + silc_client_rekey_callback, + (void *)conn->sock, conn->rekey->timeout, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); silc_protocol_free(protocol); if (ctx->auth_data) @@ -775,11 +833,11 @@ void silc_client_packet_parse(SilcPacketParserContext *parser_context) SilcClient client = (SilcClient)parser_context->context; /* Parse the packet */ - silc_task_register(client->timeout_queue, parser_context->sock->sock, - silc_client_packet_parse_real, - (void *)parser_context, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(client->schedule, parser_context->sock->sock, + silc_client_packet_parse_real, + (void *)parser_context, 0, 1, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); } /* Parses the packet type and calls what ever routines the packet type @@ -806,7 +864,7 @@ void silc_client_packet_parse_type(SilcClient client, * success message is for whatever protocol is executing currently. */ if (sock->protocol) - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); break; case SILC_PACKET_FAILURE: /* @@ -881,7 +939,7 @@ void silc_client_packet_parse_type(SilcClient client, break; /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); } else { SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange " "protocol active, packet dropped.")); @@ -903,7 +961,7 @@ void silc_client_packet_parse_type(SilcClient client, proto_ctx->packet = silc_packet_context_dup(packet); /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); } else { SilcClientKEInternalContext *proto_ctx = (SilcClientKEInternalContext *)sock->protocol->context; @@ -919,7 +977,7 @@ void silc_client_packet_parse_type(SilcClient client, break; /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); } } else { SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange " @@ -941,7 +999,7 @@ void silc_client_packet_parse_type(SilcClient client, proto_ctx->packet = silc_packet_context_dup(packet); /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); } else { SilcClientKEInternalContext *proto_ctx = (SilcClientKEInternalContext *)sock->protocol->context; @@ -957,7 +1015,7 @@ void silc_client_packet_parse_type(SilcClient client, break; /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); } } else { SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange " @@ -1022,10 +1080,10 @@ void silc_client_packet_parse_type(SilcClient client, /* Let the protocol handle the packet */ if (proto_ctx->responder == FALSE) - silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(sock->protocol, client->schedule, 0, 0); else /* Let the protocol handle the packet */ - silc_protocol_execute(sock->protocol, client->timeout_queue, + silc_protocol_execute(sock->protocol, client->schedule, 0, 100000); } else { SILC_LOG_ERROR(("Received Re-key done packet but no re-key " @@ -1033,6 +1091,15 @@ void silc_client_packet_parse_type(SilcClient client, } break; + case SILC_PACKET_CONNECTION_AUTH_REQUEST: + /* + * Reveived reply to our connection authentication method request + * packet. This is used to resolve the authentication method for the + * current session from the server if the client does not know it. + */ + silc_client_connection_auth_request(client, sock, packet); + break; + default: SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type)); break; @@ -1157,8 +1224,8 @@ void silc_client_close_connection(SilcClient client, silc_schedule_unset_listen_fd(client->schedule, sock->sock); /* Unregister all tasks */ - silc_task_unregister_by_fd(client->io_queue, sock->sock); - silc_task_unregister_by_fd(client->timeout_queue, sock->sock); + silc_schedule_task_del_by_fd(client->schedule, sock->sock); + silc_schedule_task_del_by_fd(client->schedule, sock->sock); /* Close the actual connection */ silc_net_close_connection(sock->sock); @@ -1170,33 +1237,62 @@ void silc_client_close_connection(SilcClient client, sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute_final(sock->protocol, client->timeout_queue); - sock->protocol = NULL; + silc_protocol_execute_final(sock->protocol, client->schedule); /* The application will recall this function with these protocols (the ops->connect client operation). */ return; } else { sock->protocol->state = SILC_PROTOCOL_STATE_ERROR; - silc_protocol_execute_final(sock->protocol, client->timeout_queue); + silc_protocol_execute_final(sock->protocol, client->schedule); sock->protocol = NULL; } } /* Free everything */ if (del && sock->user_data) { - /* XXX Free all client entries and channel entries. */ + /* Free all cache entries */ + SilcIDCacheList list; + SilcIDCacheEntry entry; + 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_del_all(conn->client_cache); if (conn->channel_cache) silc_idcache_del_all(conn->channel_cache); + if (conn->server_cache) + silc_idcache_del_all(conn->server_cache); - /* Free data */ + /* Free data (my ID is freed in above silc_client_del_client) */ if (conn->remote_host) silc_free(conn->remote_host); - if (conn->local_id) - silc_free(conn->local_id); if (conn->local_id_data) silc_free(conn->local_id_data); if (conn->send_key) @@ -1262,6 +1358,7 @@ void silc_client_receive_new_id(SilcClient client, { SilcClientConnection conn = (SilcClientConnection)sock->user_data; int connecting = FALSE; + SilcBuffer sidp; if (!conn->local_entry) connecting = TRUE; @@ -1285,20 +1382,24 @@ void silc_client_receive_new_id(SilcClient client, conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry)); conn->local_entry->nickname = conn->nickname; - if (!conn->local_entry->username) { - conn->local_entry->username = - silc_calloc(strlen(client->username) + strlen(client->hostname) + 1, - sizeof(conn->local_entry->username)); - sprintf(conn->local_entry->username, "%s@%s", client->username, - client->hostname); - } + if (!conn->local_entry->username) + conn->local_entry->username = strdup(client->username); + if (!conn->local_entry->hostname) + conn->local_entry->hostname = strdup(client->hostname); conn->local_entry->server = strdup(conn->remote_host); conn->local_entry->id = conn->local_id; /* Put it to the ID cache */ - silc_idcache_add(conn->client_cache, conn->nickname, conn->local_id, + 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) @@ -1307,7 +1408,8 @@ void silc_client_receive_new_id(SilcClient client, /* Processed received Channel ID for a channel. This is called when client joins to channel and server replies with channel ID. The ID is cached. - Returns the created channel entry. */ + Returns the created channel entry. This is also called when received + channel ID in for example USERS command reply that we do not have. */ SilcChannelEntry silc_client_new_channel_id(SilcClient client, SilcSocketConnection sock, @@ -1326,11 +1428,9 @@ SilcChannelEntry silc_client_new_channel_id(SilcClient client, channel->mode = mode; silc_list_init(channel->clients, struct SilcChannelUserStruct, next); - conn->current_channel = channel; - /* Put it to the ID cache */ - silc_idcache_add(conn->channel_cache, channel_name, (void *)channel->id, - (void *)channel, FALSE); + silc_idcache_add(conn->channel_cache, channel->channel_name, + (void *)channel->id, (void *)channel, FALSE); return channel; } @@ -1463,13 +1563,13 @@ SILC_TASK_CALLBACK(silc_client_rekey_callback) sock->protocol = protocol; /* Run the protocol */ - silc_protocol_execute(protocol, client->timeout_queue, 0, 0); + silc_protocol_execute(protocol, client->schedule, 0, 0); /* Re-register re-key timeout */ - silc_task_register(client->timeout_queue, sock->sock, - silc_client_rekey_callback, - context, conn->rekey->timeout, 0, - SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + silc_schedule_task_add(client->schedule, sock->sock, + silc_client_rekey_callback, + context, conn->rekey->timeout, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } /* The final callback for the REKEY protocol. This will actually take the @@ -1488,7 +1588,7 @@ SILC_TASK_CALLBACK(silc_client_rekey_final) if (protocol->state == SILC_PROTOCOL_STATE_ERROR || protocol->state == SILC_PROTOCOL_STATE_FAILURE) { /* Error occured during protocol */ - silc_protocol_cancel(protocol, client->timeout_queue); + silc_protocol_cancel(protocol, client->schedule); silc_protocol_free(protocol); sock->protocol = NULL; if (ctx->packet) @@ -1510,3 +1610,107 @@ SILC_TASK_CALLBACK(silc_client_rekey_final) silc_socket_free(ctx->sock); silc_free(ctx); } + +/* Processes incoming connection authentication method request packet. + It is a reply to our previously sent request. The packet can be used + to resolve the authentication method for the current session if the + client does not know it beforehand. */ + +void silc_client_connection_auth_request(SilcClient client, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcClientConnection conn = (SilcClientConnection)sock->user_data; + uint16 conn_type, auth_meth; + int ret; + + /* If we haven't send our request then ignore this one. */ + if (!conn->connauth) + return; + + /* Parse the payload */ + ret = silc_buffer_unformat(packet->buffer, + SILC_STR_UI_SHORT(&conn_type), + SILC_STR_UI_SHORT(&auth_meth), + SILC_STR_END); + if (ret == -1) + auth_meth = SILC_AUTH_NONE; + + /* 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); + + silc_schedule_task_del(client->schedule, conn->connauth->timeout); + + silc_free(conn->connauth); + conn->connauth = NULL; +} + +/* Timeout task callback called if the server does not reply to our + connection authentication method request in the specified time interval. */ + +SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout) +{ + SilcClientConnection conn = (SilcClientConnection)context; + SilcClient client = conn->client; + + if (!conn->connauth) + return; + + /* Call the request callback to notify application */ + if (conn->connauth->callback) + (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE, + conn->connauth->context); + + silc_free(conn->connauth); + conn->connauth = NULL; +} + +/* This function can be used to request the current authentication method + from the server. This may be called when connecting to the server + and the client library requests the authentication data from the + application. If the application does not know the current authentication + method it can request it from the server using this function. + The `callback' with `context' will be called after the server has + replied back with the current authentication method. */ + +void +silc_client_request_authentication_method(SilcClient client, + SilcClientConnection conn, + SilcConnectionAuthRequest callback, + void *context) +{ + SilcClientConnAuthRequest connauth; + SilcBuffer packet; + + connauth = silc_calloc(1, sizeof(*connauth)); + connauth->callback = callback; + connauth->context = context; + + if (conn->connauth) + silc_free(conn->connauth); + + conn->connauth = connauth; + + /* Assemble the request packet and send it to the server */ + packet = silc_buffer_alloc(4); + silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet)); + silc_buffer_format(packet, + SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT), + SILC_STR_UI_SHORT(SILC_AUTH_NONE), + SILC_STR_END); + silc_client_packet_send(client, conn->sock, + SILC_PACKET_CONNECTION_AUTH_REQUEST, + NULL, 0, NULL, NULL, + packet->data, packet->len, FALSE); + silc_buffer_free(packet); + + /* Register a timeout in case server does not reply anything back. */ + connauth->timeout = + silc_schedule_task_add(client->schedule, conn->sock->sock, + silc_client_request_authentication_method_timeout, + conn, client->params->connauth_request_secs, 0, + SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); +}