5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
25 /* Static task callback prototypes */
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
28 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
29 SILC_TASK_CALLBACK(silc_client_packet_parse_real);
30 SILC_TASK_CALLBACK(silc_client_rekey_callback);
31 SILC_TASK_CALLBACK(silc_client_rekey_final);
33 static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
34 static void silc_client_packet_parse_type(SilcClient client,
35 SilcSocketConnection sock,
36 SilcPacketContext *packet);
38 /* Allocates new client object. This has to be done before client may
39 work. After calling this one must call silc_client_init to initialize
40 the client. The `application' is application specific user data pointer
41 and caller must free it. */
43 SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
45 SilcClient new_client;
47 new_client = silc_calloc(1, sizeof(*new_client));
48 new_client->application = application;
49 new_client->ops = ops;
54 /* Frees client object and its internals. */
56 void silc_client_free(SilcClient client)
60 silc_rng_free(client->rng);
66 /* Initializes the client. This makes all the necessary steps to make
67 the client ready to be run. One must call silc_client_run to run the
68 client. Returns FALSE if error occured, TRUE otherwise. */
70 int silc_client_init(SilcClient client)
72 SILC_LOG_DEBUG(("Initializing client"));
74 /* Initialize hash functions for client to use */
75 silc_hash_alloc("md5", &client->md5hash);
76 silc_hash_alloc("sha1", &client->sha1hash);
78 /* Initialize none cipher */
79 silc_cipher_alloc("none", &client->none_cipher);
81 /* Initialize random number generator */
82 client->rng = silc_rng_alloc();
83 silc_rng_init(client->rng);
84 silc_rng_global_init(client->rng);
86 /* Register protocols */
87 silc_client_protocols_register();
89 /* Initialize the scheduler */
90 silc_schedule_init(&client->io_queue, &client->timeout_queue,
91 &client->generic_queue, 5000);
96 /* Stops the client. This is called to stop the client and thus to stop
99 void silc_client_stop(SilcClient client)
101 SILC_LOG_DEBUG(("Stopping client"));
103 /* Stop the scheduler, although it might be already stopped. This
104 doesn't hurt anyone. This removes all the tasks and task queues,
106 silc_schedule_stop();
107 silc_schedule_uninit();
109 silc_client_protocols_unregister();
111 SILC_LOG_DEBUG(("Client stopped"));
114 /* Runs the client. This starts the scheduler from the utility library.
115 When this functions returns the execution of the appliation is over. */
117 void silc_client_run(SilcClient client)
119 SILC_LOG_DEBUG(("Running client"));
121 /* Start the scheduler, the heart of the SILC client. When this returns
122 the program will be terminated. */
126 /* Allocates and adds new connection to the client. This adds the allocated
127 connection to the connection table and returns a pointer to it. A client
128 can have multiple connections to multiple servers. Every connection must
129 be added to the client using this function. User data `context' may
130 be sent as argument. This function is normally used only if the
131 application performed the connecting outside the library. The library
132 however may use this internally. */
134 SilcClientConnection silc_client_add_connection(SilcClient client,
139 SilcClientConnection conn;
142 conn = silc_calloc(1, sizeof(*conn));
144 /* Initialize ID caches */
145 conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, NULL);
146 conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
147 conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
148 conn->client = client;
149 conn->remote_host = strdup(hostname);
150 conn->remote_port = port;
151 conn->context = context;
152 conn->pending_commands = silc_dlist_init();
154 /* Add the connection to connections table */
155 for (i = 0; i < client->conns_count; i++)
156 if (client->conns && !client->conns[i]) {
157 client->conns[i] = conn;
161 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
162 * (client->conns_count + 1));
163 client->conns[client->conns_count] = conn;
164 client->conns_count++;
169 /* Removes connection from client. Frees all memory. */
171 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
175 for (i = 0; i < client->conns_count; i++)
176 if (client->conns[i] == conn) {
177 if (conn->pending_commands)
178 silc_dlist_uninit(conn->pending_commands);
180 client->conns[i] = NULL;
184 /* Adds listener socket to the listener sockets table. This function is
185 used to add socket objects that are listeners to the client. This should
186 not be used to add other connection objects. */
188 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
192 if (!client->sockets) {
193 client->sockets = silc_calloc(1, sizeof(*client->sockets));
194 client->sockets[0] = silc_socket_dup(sock);
195 client->sockets_count = 1;
199 for (i = 0; i < client->sockets_count; i++) {
200 if (client->sockets[i] == NULL) {
201 client->sockets[i] = silc_socket_dup(sock);
206 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
207 (client->sockets_count + 1));
208 client->sockets[client->sockets_count] = silc_socket_dup(sock);
209 client->sockets_count++;
212 /* Deletes listener socket from the listener sockets table. */
214 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
218 if (!client->sockets)
221 for (i = 0; i < client->sockets_count; i++) {
222 if (client->sockets[i] == sock) {
223 silc_socket_free(sock);
224 client->sockets[i] = NULL;
231 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
235 /* XXX In the future we should give up this non-blocking connect all
236 together and use threads instead. */
237 /* Create connection to server asynchronously */
238 sock = silc_net_create_connection_async(ctx->port, ctx->host);
242 /* Register task that will receive the async connect and will
244 ctx->task = silc_task_register(ctx->client->io_queue, sock,
245 silc_client_connect_to_server_start,
248 SILC_TASK_PRI_NORMAL);
249 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
250 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
257 /* Connects to remote server. This is the main routine used to connect
258 to SILC server. Returns -1 on error and the created socket otherwise.
259 The `context' is user context that is saved into the SilcClientConnection
260 that is created after the connection is created. Note that application
261 may handle the connecting process outside the library. If this is the
262 case then this function is not used at all. When the connecting is
263 done the `connect' client operation is called. */
265 int silc_client_connect_to_server(SilcClient client, int port,
266 char *host, void *context)
268 SilcClientInternalConnectContext *ctx;
269 SilcClientConnection conn;
272 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
275 conn = silc_client_add_connection(client, host, port, context);
277 client->ops->say(client, conn,
278 "Connecting to port %d of server %s", port, host);
280 /* Allocate internal context for connection process. This is
281 needed as we are doing async connecting. */
282 ctx = silc_calloc(1, sizeof(*ctx));
283 ctx->client = client;
285 ctx->host = strdup(host);
289 /* Do the actual connecting process */
290 sock = silc_client_connect_to_server_internal(ctx);
292 silc_client_del_connection(client, conn);
296 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
297 key material between client and server. This function can be called
298 directly if application is performing its own connecting and does not
299 use the connecting provided by this library. This function is normally
300 used only if the application performed the connecting outside the library.
301 The library however may use this internally. */
303 int silc_client_start_key_exchange(SilcClient client,
304 SilcClientConnection conn,
307 SilcProtocol protocol;
308 SilcClientKEInternalContext *proto_ctx;
311 /* Allocate new socket connection object */
312 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
314 conn->nickname = strdup(client->username);
315 conn->sock->hostname = conn->remote_host;
316 conn->sock->ip = strdup(conn->remote_host);
317 conn->sock->port = conn->remote_port;
319 /* Allocate internal Key Exchange context. This is sent to the
320 protocol as context. */
321 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
322 proto_ctx->client = (void *)client;
323 proto_ctx->sock = silc_socket_dup(conn->sock);
324 proto_ctx->rng = client->rng;
325 proto_ctx->responder = FALSE;
326 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
327 proto_ctx->verify = silc_client_protocol_ke_verify_key;
329 /* Perform key exchange protocol. silc_client_connect_to_server_final
330 will be called after the protocol is finished. */
331 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
332 &protocol, (void *)proto_ctx,
333 silc_client_connect_to_server_second);
335 client->ops->say(client, conn,
336 "Error: Could not start authentication protocol");
339 conn->sock->protocol = protocol;
341 /* Register the connection for network input and output. This sets
342 that scheduler will listen for incoming packets for this connection
343 and sets that outgoing packets may be sent to this connection as well.
344 However, this doesn't set the scheduler for outgoing traffic, it will
345 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
346 later when outgoing data is available. */
347 context = (void *)client;
348 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
350 /* Execute the protocol */
351 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
355 /* Start of the connection to the remote server. This is called after
356 succesful TCP/IP connection has been established to the remote host. */
358 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
360 SilcClientInternalConnectContext *ctx =
361 (SilcClientInternalConnectContext *)context;
362 SilcClient client = ctx->client;
363 SilcClientConnection conn = ctx->conn;
364 int opt, opt_len = sizeof(opt);
366 SILC_LOG_DEBUG(("Start"));
368 /* Check the socket status as it might be in error */
369 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
371 if (ctx->tries < 2) {
372 /* Connection failed but lets try again */
373 client->ops->say(client, conn, "Could not connect to server %s: %s",
374 ctx->host, strerror(opt));
375 client->ops->say(client, conn,
376 "Connecting to port %d of server %s resumed",
377 ctx->port, ctx->host);
379 /* Unregister old connection try */
380 silc_schedule_unset_listen_fd(fd);
381 silc_net_close_connection(fd);
382 silc_task_unregister(client->io_queue, ctx->task);
385 silc_client_connect_to_server_internal(ctx);
388 /* Connection failed and we won't try anymore */
389 client->ops->say(client, conn, "Could not connect to server %s: %s",
390 ctx->host, strerror(opt));
391 silc_schedule_unset_listen_fd(fd);
392 silc_net_close_connection(fd);
393 silc_task_unregister(client->io_queue, ctx->task);
396 /* Notify application of failure */
397 client->ops->connect(client, conn, FALSE);
398 silc_client_del_connection(client, conn);
403 silc_schedule_unset_listen_fd(fd);
404 silc_task_unregister(client->io_queue, ctx->task);
407 if (!silc_client_start_key_exchange(client, conn, fd)) {
408 silc_net_close_connection(fd);
409 client->ops->connect(client, conn, FALSE);
413 /* Second part of the connecting to the server. This executed
414 authentication protocol. */
416 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
418 SilcProtocol protocol = (SilcProtocol)context;
419 SilcClientKEInternalContext *ctx =
420 (SilcClientKEInternalContext *)protocol->context;
421 SilcClient client = (SilcClient)ctx->client;
422 SilcSocketConnection sock = NULL;
423 SilcClientConnAuthInternalContext *proto_ctx;
425 SILC_LOG_DEBUG(("Start"));
427 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
428 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
429 /* Error occured during protocol */
430 SILC_LOG_DEBUG(("Error during KE protocol"));
431 silc_protocol_free(protocol);
432 silc_ske_free_key_material(ctx->keymat);
434 silc_ske_free(ctx->ske);
436 silc_free(ctx->dest_id);
437 ctx->sock->protocol = NULL;
438 silc_socket_free(ctx->sock);
440 /* Notify application of failure */
441 client->ops->connect(client, ctx->sock->user_data, FALSE);
446 /* We now have the key material as the result of the key exchange
447 protocol. Take the key material into use. Free the raw key material
448 as soon as we've set them into use. */
449 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
450 ctx->ske->prop->cipher,
451 ctx->ske->prop->pkcs,
452 ctx->ske->prop->hash,
453 ctx->ske->prop->hmac,
454 ctx->ske->prop->group);
455 silc_ske_free_key_material(ctx->keymat);
457 /* Allocate internal context for the authentication protocol. This
458 is sent as context for the protocol. */
459 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
460 proto_ctx->client = (void *)client;
461 proto_ctx->sock = sock = ctx->sock;
462 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
463 proto_ctx->dest_id_type = ctx->dest_id_type;
464 proto_ctx->dest_id = ctx->dest_id;
466 /* Resolve the authentication method to be used in this connection */
467 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
468 sock->port, &proto_ctx->auth_meth,
469 &proto_ctx->auth_data,
470 &proto_ctx->auth_data_len)) {
471 client->ops->say(client, ctx->sock->user_data,
472 "Could not resolve authentication method to use, "
473 "assume no authentication");
474 proto_ctx->auth_meth = SILC_AUTH_NONE;
477 /* Free old protocol as it is finished now */
478 silc_protocol_free(protocol);
480 silc_packet_context_free(ctx->packet);
482 sock->protocol = NULL;
484 /* Allocate the authenteication protocol and execute it. */
485 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
486 &sock->protocol, (void *)proto_ctx,
487 silc_client_connect_to_server_final);
489 /* Execute the protocol */
490 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
493 /* Finalizes the connection to the remote SILC server. This is called
494 after authentication protocol has been completed. This send our
495 user information to the server to receive our client ID from
498 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
500 SilcProtocol protocol = (SilcProtocol)context;
501 SilcClientConnAuthInternalContext *ctx =
502 (SilcClientConnAuthInternalContext *)protocol->context;
503 SilcClient client = (SilcClient)ctx->client;
504 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
507 SILC_LOG_DEBUG(("Start"));
509 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
510 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
511 /* Error occured during protocol */
512 SILC_LOG_DEBUG(("Error during authentication protocol"));
513 silc_protocol_free(protocol);
515 silc_free(ctx->auth_data);
517 silc_ske_free(ctx->ske);
519 silc_free(ctx->dest_id);
520 conn->sock->protocol = NULL;
521 silc_socket_free(ctx->sock);
523 /* Notify application of failure */
524 client->ops->connect(client, ctx->sock->user_data, FALSE);
529 /* Send NEW_CLIENT packet to the server. We will become registered
530 to the SILC network after sending this packet and we will receive
531 client ID from the server. */
532 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
533 strlen(client->realname));
534 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
535 silc_buffer_format(packet,
536 SILC_STR_UI_SHORT(strlen(client->username)),
537 SILC_STR_UI_XNSTRING(client->username,
538 strlen(client->username)),
539 SILC_STR_UI_SHORT(strlen(client->realname)),
540 SILC_STR_UI_XNSTRING(client->realname,
541 strlen(client->realname)),
544 /* Send the packet */
545 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
547 packet->data, packet->len, TRUE);
548 silc_buffer_free(packet);
550 /* Save remote ID. */
551 conn->remote_id = ctx->dest_id;
552 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
553 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
555 /* Register re-key timeout */
556 conn->rekey->timeout = 3600; /* XXX hardcoded */
557 conn->rekey->context = (void *)client;
558 silc_task_register(client->timeout_queue, conn->sock->sock,
559 silc_client_rekey_callback,
560 (void *)conn->sock, conn->rekey->timeout, 0,
561 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
563 silc_protocol_free(protocol);
565 silc_free(ctx->auth_data);
567 silc_ske_free(ctx->ske);
568 silc_socket_free(ctx->sock);
570 conn->sock->protocol = NULL;
573 /* Internal routine that sends packet or marks packet to be sent. This
574 is used directly only in special cases. Normal cases should use
575 silc_server_packet_send. Returns < 0 on error. */
577 int silc_client_packet_send_real(SilcClient client,
578 SilcSocketConnection sock,
584 /* If rekey protocol is active we must assure that all packets are
585 sent through packet queue. */
586 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
589 /* Send the packet */
590 ret = silc_packet_send(sock, force_send);
594 /* Mark that there is some outgoing data available for this connection.
595 This call sets the connection both for input and output (the input
596 is set always and this call keeps the input setting, actually).
597 Actual data sending is performed by silc_client_packet_process. */
598 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
600 /* Mark to socket that data is pending in outgoing buffer. This flag
601 is needed if new data is added to the buffer before the earlier
602 put data is sent to the network. */
603 SILC_SET_OUTBUF_PENDING(sock);
608 /* Packet processing callback. This is used to send and receive packets
609 from network. This is generic task. */
611 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
613 SilcClient client = (SilcClient)context;
614 SilcSocketConnection sock = NULL;
615 SilcClientConnection conn;
618 SILC_LOG_DEBUG(("Processing packet"));
620 SILC_CLIENT_GET_SOCK(client, fd, sock);
624 conn = (SilcClientConnection)sock->user_data;
627 if (type == SILC_TASK_WRITE) {
628 SILC_LOG_DEBUG(("Writing data to connection"));
630 if (sock->outbuf->data - sock->outbuf->head)
631 silc_buffer_push(sock->outbuf,
632 sock->outbuf->data - sock->outbuf->head);
634 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
636 /* If returned -2 could not write to connection now, will do
641 /* The packet has been sent and now it is time to set the connection
642 back to only for input. When there is again some outgoing data
643 available for this connection it will be set for output as well.
644 This call clears the output setting and sets it only for input. */
645 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
646 SILC_UNSET_OUTBUF_PENDING(sock);
648 silc_buffer_clear(sock->outbuf);
652 /* Packet receiving */
653 if (type == SILC_TASK_READ) {
654 SILC_LOG_DEBUG(("Reading data from connection"));
656 /* Read data from network */
657 ret = silc_packet_receive(sock);
663 SILC_LOG_DEBUG(("Read EOF"));
665 /* If connection is disconnecting already we will finally
666 close the connection */
667 if (SILC_IS_DISCONNECTING(sock)) {
668 if (sock == conn->sock)
669 client->ops->disconnect(client, conn);
670 silc_client_close_connection(client, sock, conn);
674 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
675 if (sock == conn->sock)
676 client->ops->disconnect(client, conn);
677 silc_client_close_connection(client, sock, conn);
681 /* Process the packet. This will call the parser that will then
682 decrypt and parse the packet. */
683 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
684 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
685 silc_client_packet_parse, client);
687 silc_packet_receive_process(sock, NULL, NULL,
688 silc_client_packet_parse, client);
692 /* Callback function that the silc_packet_decrypt will call to make the
693 decision whether the packet is normal or special packet. We will
694 return TRUE if it is normal and FALSE if it is special */
696 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
698 SilcPacketContext *packet,
702 /* Packet is normal packet, if:
704 1) packet is private message packet and does not have private key set
705 2) is other packet than channel message packet
707 all other packets are special packets
710 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
711 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
714 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
720 /* Parses whole packet, received earlier. */
722 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
724 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
725 SilcClient client = (SilcClient)parse_ctx->context;
726 SilcPacketContext *packet = parse_ctx->packet;
727 SilcBuffer buffer = packet->buffer;
728 SilcSocketConnection sock = parse_ctx->sock;
729 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
732 SILC_LOG_DEBUG(("Start"));
734 /* Decrypt the received packet */
735 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
736 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
738 silc_client_packet_decrypt_check, parse_ctx);
740 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
741 silc_client_packet_decrypt_check, parse_ctx);
747 /* Parse the packet. Packet type is returned. */
748 ret = silc_packet_parse(packet);
750 /* Parse the packet header in special way as this is "special"
752 ret = silc_packet_parse_special(packet);
755 if (ret == SILC_PACKET_NONE)
758 /* Parse the incoming packet type */
759 silc_client_packet_parse_type(client, sock, packet);
762 /* silc_buffer_clear(sock->inbuf); */
763 silc_packet_context_free(packet);
764 silc_free(parse_ctx);
767 /* Parser callback called by silc_packet_receive_process. Thie merely
768 registers timeout that will handle the actual parsing when appropriate. */
770 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
772 SilcClient client = (SilcClient)parser_context->context;
774 /* Parse the packet */
775 silc_task_register(client->timeout_queue, parser_context->sock->sock,
776 silc_client_packet_parse_real,
777 (void *)parser_context, 0, 1,
779 SILC_TASK_PRI_NORMAL);
782 /* Parses the packet type and calls what ever routines the packet type
783 requires. This is done for all incoming packets. */
785 void silc_client_packet_parse_type(SilcClient client,
786 SilcSocketConnection sock,
787 SilcPacketContext *packet)
789 SilcBuffer buffer = packet->buffer;
790 SilcPacketType type = packet->type;
792 SILC_LOG_DEBUG(("Parsing packet type %d", type));
794 /* Parse the packet type */
796 case SILC_PACKET_DISCONNECT:
797 silc_client_disconnected_by_server(client, sock, buffer);
799 case SILC_PACKET_SUCCESS:
801 * Success received for something. For now we can have only
802 * one protocol for connection executing at once hence this
803 * success message is for whatever protocol is executing currently.
805 if (sock->protocol) {
806 sock->protocol->execute(client->timeout_queue, 0,
807 sock->protocol, sock->sock, 0, 0);
810 case SILC_PACKET_FAILURE:
812 * Failure received for some protocol. Set the protocol state to
813 * error and call the protocol callback. This fill cause error on
814 * protocol and it will call the final callback.
816 silc_client_process_failure(client, sock, packet);
818 case SILC_PACKET_REJECT:
821 case SILC_PACKET_NOTIFY:
823 * Received notify message
825 silc_client_notify_by_server(client, sock, packet);
828 case SILC_PACKET_ERROR:
830 * Received error message
832 silc_client_error_by_server(client, sock, buffer);
835 case SILC_PACKET_CHANNEL_MESSAGE:
837 * Received message to (from, actually) a channel
839 silc_client_channel_message(client, sock, packet);
841 case SILC_PACKET_CHANNEL_KEY:
843 * Received key for a channel. By receiving this key the client will be
844 * able to talk to the channel it has just joined. This can also be
845 * a new key for existing channel as keys expire peridiocally.
847 silc_client_receive_channel_key(client, sock, buffer);
850 case SILC_PACKET_PRIVATE_MESSAGE:
852 * Received private message
854 silc_client_private_message(client, sock, packet);
856 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
858 * Received private message key
862 case SILC_PACKET_COMMAND_REPLY:
864 * Recived reply for a command
866 silc_client_command_reply_process(client, sock, packet);
869 case SILC_PACKET_KEY_EXCHANGE:
870 if (sock->protocol && sock->protocol->protocol &&
871 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
872 SilcClientKEInternalContext *proto_ctx =
873 (SilcClientKEInternalContext *)sock->protocol->context;
875 proto_ctx->packet = silc_packet_context_dup(packet);
876 proto_ctx->dest_id_type = packet->src_id_type;
877 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
878 packet->src_id_type);
879 if (!proto_ctx->dest_id)
882 /* Let the protocol handle the packet */
883 sock->protocol->execute(client->timeout_queue, 0,
884 sock->protocol, sock->sock, 0, 0);
886 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
887 "protocol active, packet dropped."));
891 case SILC_PACKET_KEY_EXCHANGE_1:
892 if (sock->protocol && sock->protocol->protocol &&
893 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
894 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
896 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
897 SilcClientRekeyInternalContext *proto_ctx =
898 (SilcClientRekeyInternalContext *)sock->protocol->context;
900 if (proto_ctx->packet)
901 silc_packet_context_free(proto_ctx->packet);
903 proto_ctx->packet = silc_packet_context_dup(packet);
905 /* Let the protocol handle the packet */
906 sock->protocol->execute(client->timeout_queue, 0,
907 sock->protocol, sock->sock, 0, 0);
909 SilcClientKEInternalContext *proto_ctx =
910 (SilcClientKEInternalContext *)sock->protocol->context;
912 if (proto_ctx->packet)
913 silc_packet_context_free(proto_ctx->packet);
915 proto_ctx->packet = silc_packet_context_dup(packet);
916 proto_ctx->dest_id_type = packet->src_id_type;
917 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
918 packet->src_id_type);
919 if (!proto_ctx->dest_id)
922 /* Let the protocol handle the packet */
923 sock->protocol->execute(client->timeout_queue, 0,
924 sock->protocol, sock->sock, 0, 0);
927 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
928 "protocol active, packet dropped."));
931 case SILC_PACKET_KEY_EXCHANGE_2:
932 if (sock->protocol && sock->protocol->protocol &&
933 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
934 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
936 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
937 SilcClientRekeyInternalContext *proto_ctx =
938 (SilcClientRekeyInternalContext *)sock->protocol->context;
940 if (proto_ctx->packet)
941 silc_packet_context_free(proto_ctx->packet);
943 proto_ctx->packet = silc_packet_context_dup(packet);
945 /* Let the protocol handle the packet */
946 sock->protocol->execute(client->timeout_queue, 0,
947 sock->protocol, sock->sock, 0, 0);
949 SilcClientKEInternalContext *proto_ctx =
950 (SilcClientKEInternalContext *)sock->protocol->context;
952 if (proto_ctx->packet)
953 silc_packet_context_free(proto_ctx->packet);
955 proto_ctx->packet = silc_packet_context_dup(packet);
956 proto_ctx->dest_id_type = packet->src_id_type;
957 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
958 packet->src_id_type);
959 if (!proto_ctx->dest_id)
962 /* Let the protocol handle the packet */
963 sock->protocol->execute(client->timeout_queue, 0,
964 sock->protocol, sock->sock, 0, 0);
967 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
968 "protocol active, packet dropped."));
972 case SILC_PACKET_NEW_ID:
975 * Received new ID from server. This packet is received at
976 * the connection to the server. New ID is also received when
977 * user changes nickname but in that case the new ID is received
978 * as command reply and not as this packet type.
982 idp = silc_id_payload_parse(buffer);
985 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
988 silc_client_receive_new_id(client, sock, idp);
989 silc_id_payload_free(idp);
993 case SILC_PACKET_HEARTBEAT:
995 * Received heartbeat packet
997 SILC_LOG_DEBUG(("Heartbeat packet"));
1000 case SILC_PACKET_KEY_AGREEMENT:
1002 * Received key agreement packet
1004 SILC_LOG_DEBUG(("Key agreement packet"));
1005 silc_client_key_agreement(client, sock, packet);
1008 case SILC_PACKET_REKEY:
1009 SILC_LOG_DEBUG(("Re-key packet"));
1010 /* We ignore this for now */
1013 case SILC_PACKET_REKEY_DONE:
1014 SILC_LOG_DEBUG(("Re-key done packet"));
1016 if (sock->protocol && sock->protocol->protocol &&
1017 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1019 SilcClientRekeyInternalContext *proto_ctx =
1020 (SilcClientRekeyInternalContext *)sock->protocol->context;
1022 if (proto_ctx->packet)
1023 silc_packet_context_free(proto_ctx->packet);
1025 proto_ctx->packet = silc_packet_context_dup(packet);
1027 /* Let the protocol handle the packet */
1028 if (proto_ctx->responder == FALSE)
1029 sock->protocol->execute(client->timeout_queue, 0,
1030 sock->protocol, sock->sock, 0, 0);
1032 /* Let the protocol handle the packet */
1033 sock->protocol->execute(client->timeout_queue, 0,
1034 sock->protocol, sock->sock, 0, 100000);
1036 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1037 "protocol active, packet dropped."));
1042 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1047 /* Sends packet. This doesn't actually send the packet instead it assembles
1048 it and marks it to be sent. However, if force_send is TRUE the packet
1049 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1050 will be derived from sock argument. Otherwise the valid arguments sent
1053 void silc_client_packet_send(SilcClient client,
1054 SilcSocketConnection sock,
1055 SilcPacketType type,
1057 SilcIdType dst_id_type,
1060 unsigned char *data,
1064 SilcPacketContext packetdata;
1066 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1068 /* Get data used in the packet sending, keys and stuff */
1069 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1070 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1071 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1073 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1074 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1076 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1077 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1078 dst_id_type = SILC_ID_SERVER;
1082 /* Set the packet context pointers */
1083 packetdata.flags = 0;
1084 packetdata.type = type;
1085 if (sock->user_data &&
1086 ((SilcClientConnection)sock->user_data)->local_id_data) {
1087 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1088 packetdata.src_id_len =
1089 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1092 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1093 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1095 packetdata.src_id_type = SILC_ID_CLIENT;
1097 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1098 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1099 packetdata.dst_id_type = dst_id_type;
1101 packetdata.dst_id = NULL;
1102 packetdata.dst_id_len = 0;
1103 packetdata.dst_id_type = SILC_ID_NONE;
1105 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1106 packetdata.src_id_len + packetdata.dst_id_len;
1107 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1109 /* Prepare outgoing data buffer for packet sending */
1110 silc_packet_send_prepare(sock,
1111 SILC_PACKET_HEADER_LEN +
1112 packetdata.src_id_len +
1113 packetdata.dst_id_len,
1117 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1119 packetdata.buffer = sock->outbuf;
1121 /* Put the data to the buffer */
1122 if (data && data_len)
1123 silc_buffer_put(sock->outbuf, data, data_len);
1125 /* Create the outgoing packet */
1126 silc_packet_assemble(&packetdata);
1128 /* Encrypt the packet */
1130 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1132 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1133 sock->outbuf->data, sock->outbuf->len);
1135 /* Now actually send the packet */
1136 silc_client_packet_send_real(client, sock, force_send, FALSE);
1139 /* Closes connection to remote end. Free's all allocated data except
1140 for some information such as nickname etc. that are valid at all time.
1141 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1142 provided it will be checked whether the sock and `conn->sock' are the
1143 same (they can be different, ie. a socket can use `conn' as its
1144 connection but `conn->sock' might be actually a different connection
1145 than the `sock'). */
1147 void silc_client_close_connection(SilcClient client,
1148 SilcSocketConnection sock,
1149 SilcClientConnection conn)
1153 if (!sock || (sock && conn->sock == sock))
1158 /* We won't listen for this connection anymore */
1159 silc_schedule_unset_listen_fd(sock->sock);
1161 /* Unregister all tasks */
1162 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1163 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1165 /* Close the actual connection */
1166 silc_net_close_connection(sock->sock);
1168 /* Free everything */
1169 if (del && sock->user_data) {
1170 /* XXX Free all client entries and channel entries. */
1172 client->ops->say(client, sock->user_data,
1173 "Closed connection to host %s", sock->hostname);
1175 /* Clear ID caches */
1176 silc_idcache_del_all(conn->client_cache);
1177 silc_idcache_del_all(conn->channel_cache);
1180 if (conn->remote_host)
1181 silc_free(conn->remote_host);
1183 silc_free(conn->local_id);
1184 if (conn->local_id_data)
1185 silc_free(conn->local_id_data);
1187 silc_cipher_free(conn->send_key);
1188 if (conn->receive_key)
1189 silc_cipher_free(conn->receive_key);
1190 if (conn->hmac_send) /* conn->hmac_receive is same */
1191 silc_hmac_free(conn->hmac_send);
1192 if (conn->pending_commands)
1193 silc_dlist_uninit(conn->pending_commands);
1195 silc_free(conn->rekey);
1198 conn->remote_port = 0;
1199 conn->remote_type = 0;
1200 conn->send_key = NULL;
1201 conn->receive_key = NULL;
1202 conn->hmac_send = NULL;
1203 conn->hmac_receive = NULL;
1204 conn->local_id = NULL;
1205 conn->local_id_data = NULL;
1206 conn->remote_host = NULL;
1207 conn->current_channel = NULL;
1208 conn->pending_commands = NULL;
1211 silc_client_del_connection(client, conn);
1214 if (sock->protocol) {
1215 silc_protocol_free(sock->protocol);
1216 sock->protocol = NULL;
1218 silc_socket_free(sock);
1221 /* Called when we receive disconnection packet from server. This
1222 closes our end properly and displays the reason of the disconnection
1225 void silc_client_disconnected_by_server(SilcClient client,
1226 SilcSocketConnection sock,
1231 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1233 msg = silc_calloc(message->len + 1, sizeof(char));
1234 memcpy(msg, message->data, message->len);
1235 client->ops->say(client, sock->user_data, msg);
1238 SILC_SET_DISCONNECTED(sock);
1239 silc_client_close_connection(client, sock, sock->user_data);
1242 /* Received error message from server. Display it on the screen.
1243 We don't take any action what so ever of the error message. */
1245 void silc_client_error_by_server(SilcClient client,
1246 SilcSocketConnection sock,
1251 msg = silc_calloc(message->len + 1, sizeof(char));
1252 memcpy(msg, message->data, message->len);
1253 client->ops->say(client, sock->user_data, msg);
1257 /* Processes the received new Client ID from server. Old Client ID is
1258 deleted from cache and new one is added. */
1260 void silc_client_receive_new_id(SilcClient client,
1261 SilcSocketConnection sock,
1264 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1265 int connecting = FALSE;
1267 if (!conn->local_entry)
1270 /* Delete old ID from ID cache */
1271 if (conn->local_id) {
1272 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1273 silc_free(conn->local_id);
1276 /* Save the new ID */
1278 if (conn->local_id_data)
1279 silc_free(conn->local_id_data);
1281 conn->local_id = silc_id_payload_get_id(idp);
1282 conn->local_id_data = silc_id_payload_get_data(idp);
1283 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1285 if (!conn->local_entry)
1286 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1288 conn->local_entry->nickname = conn->nickname;
1289 if (!conn->local_entry->username) {
1290 conn->local_entry->username =
1291 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1292 sizeof(conn->local_entry->username));
1293 sprintf(conn->local_entry->username, "%s@%s", client->username,
1296 conn->local_entry->server = strdup(conn->remote_host);
1297 conn->local_entry->id = conn->local_id;
1299 /* Put it to the ID cache */
1300 silc_idcache_add(conn->client_cache, conn->nickname, conn->local_id,
1301 (void *)conn->local_entry, FALSE);
1303 /* Notify application of successful connection. We do it here now that
1304 we've received the Client ID and are allowed to send traffic. */
1306 client->ops->connect(client, conn, TRUE);
1309 /* Processed received Channel ID for a channel. This is called when client
1310 joins to channel and server replies with channel ID. The ID is cached.
1311 Returns the created channel entry. */
1313 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1314 SilcSocketConnection sock,
1319 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1320 SilcChannelEntry channel;
1322 SILC_LOG_DEBUG(("New channel ID"));
1324 channel = silc_calloc(1, sizeof(*channel));
1325 channel->channel_name = channel_name;
1326 channel->id = silc_id_payload_get_id(idp);
1327 channel->mode = mode;
1328 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1330 conn->current_channel = channel;
1332 /* Put it to the ID cache */
1333 silc_idcache_add(conn->channel_cache, channel_name, (void *)channel->id,
1334 (void *)channel, FALSE);
1339 /* Removes a client entry from all channel it has joined. This really is
1340 a performance killer (client_entry should have pointers to channel
1343 void silc_client_remove_from_channels(SilcClient client,
1344 SilcClientConnection conn,
1345 SilcClientEntry client_entry)
1347 SilcIDCacheEntry id_cache;
1348 SilcIDCacheList list;
1349 SilcChannelEntry channel;
1350 SilcChannelUser chu;
1352 if (!silc_idcache_get_all(conn->channel_cache, &list))
1355 silc_idcache_list_first(list, &id_cache);
1356 channel = (SilcChannelEntry)id_cache->context;
1360 /* Remove client from channel */
1361 silc_list_start(channel->clients);
1362 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1363 if (chu->client == client_entry) {
1364 silc_list_del(channel->clients, chu);
1370 if (!silc_idcache_list_next(list, &id_cache))
1373 channel = (SilcChannelEntry)id_cache->context;
1376 silc_idcache_list_free(list);
1379 /* Replaces `old' client entries from all channels to `new' client entry.
1380 This can be called for example when nickname changes and old ID entry
1381 is replaced from ID cache with the new one. If the old ID entry is only
1382 updated, then this fucntion needs not to be called. */
1384 void silc_client_replace_from_channels(SilcClient client,
1385 SilcClientConnection conn,
1386 SilcClientEntry old,
1387 SilcClientEntry new)
1389 SilcIDCacheEntry id_cache;
1390 SilcIDCacheList list;
1391 SilcChannelEntry channel;
1392 SilcChannelUser chu;
1394 if (!silc_idcache_get_all(conn->channel_cache, &list))
1397 silc_idcache_list_first(list, &id_cache);
1398 channel = (SilcChannelEntry)id_cache->context;
1402 /* Replace client entry */
1403 silc_list_start(channel->clients);
1404 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1405 if (chu->client == old) {
1411 if (!silc_idcache_list_next(list, &id_cache))
1414 channel = (SilcChannelEntry)id_cache->context;
1417 silc_idcache_list_free(list);
1420 /* Parses mode mask and returns the mode as string. */
1422 char *silc_client_chmode(uint32 mode, SilcChannelEntry channel)
1429 memset(string, 0, sizeof(string));
1431 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1432 strncat(string, "p", 1);
1434 if (mode & SILC_CHANNEL_MODE_SECRET)
1435 strncat(string, "s", 1);
1437 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1438 strncat(string, "k", 1);
1440 if (mode & SILC_CHANNEL_MODE_INVITE)
1441 strncat(string, "i", 1);
1443 if (mode & SILC_CHANNEL_MODE_TOPIC)
1444 strncat(string, "t", 1);
1446 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1447 strncat(string, "l", 1);
1449 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1450 strncat(string, "a", 1);
1452 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
1453 strncat(string, "f", 1);
1455 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1457 memset(cipher, 0, sizeof(cipher));
1458 snprintf(cipher, sizeof(cipher), " c (%s)",
1459 channel->channel_key->cipher->name);
1460 strncat(string, cipher, strlen(cipher));
1463 if (mode & SILC_CHANNEL_MODE_HMAC) {
1465 memset(hmac, 0, sizeof(hmac));
1466 snprintf(hmac, sizeof(hmac), " h (%s)",
1467 channel->hmac->hmac->name);
1468 strncat(string, hmac, strlen(hmac));
1471 /* Rest of mode is ignored */
1473 return strdup(string);
1476 /* Parses channel user mode mask and returns te mode as string */
1478 char *silc_client_chumode(uint32 mode)
1485 memset(string, 0, sizeof(string));
1487 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1488 strncat(string, "f", 1);
1490 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1491 strncat(string, "o", 1);
1493 return strdup(string);
1496 /* Parses channel user mode and returns it as special mode character. */
1498 char *silc_client_chumode_char(uint32 mode)
1505 memset(string, 0, sizeof(string));
1507 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1508 strncat(string, "*", 1);
1510 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1511 strncat(string, "@", 1);
1513 return strdup(string);
1516 /* Registers failure timeout to process the received failure packet
1519 void silc_client_process_failure(SilcClient client,
1520 SilcSocketConnection sock,
1521 SilcPacketContext *packet)
1525 if (sock->protocol) {
1526 if (packet->buffer->len >= 4)
1527 SILC_GET32_MSB(failure, packet->buffer->data);
1529 /* Notify application */
1530 client->ops->failure(client, sock->user_data, sock->protocol,
1535 /* A timeout callback for the re-key. We will be the initiator of the
1538 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1540 SilcSocketConnection sock = (SilcSocketConnection)context;
1541 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1542 SilcClient client = (SilcClient)conn->rekey->context;
1543 SilcProtocol protocol;
1544 SilcClientRekeyInternalContext *proto_ctx;
1546 SILC_LOG_DEBUG(("Start"));
1548 /* Allocate internal protocol context. This is sent as context
1550 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1551 proto_ctx->client = (void *)client;
1552 proto_ctx->sock = silc_socket_dup(sock);
1553 proto_ctx->responder = FALSE;
1554 proto_ctx->pfs = conn->rekey->pfs;
1556 /* Perform rekey protocol. Will call the final callback after the
1557 protocol is over. */
1558 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1559 &protocol, proto_ctx, silc_client_rekey_final);
1560 sock->protocol = protocol;
1562 /* Run the protocol */
1563 protocol->execute(client->timeout_queue, 0, protocol,
1566 /* Re-register re-key timeout */
1567 silc_task_register(client->timeout_queue, sock->sock,
1568 silc_client_rekey_callback,
1569 context, conn->rekey->timeout, 0,
1570 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1573 /* The final callback for the REKEY protocol. This will actually take the
1574 new key material into use. */
1576 SILC_TASK_CALLBACK(silc_client_rekey_final)
1578 SilcProtocol protocol = (SilcProtocol)context;
1579 SilcClientRekeyInternalContext *ctx =
1580 (SilcClientRekeyInternalContext *)protocol->context;
1581 SilcClient client = (SilcClient)ctx->client;
1582 SilcSocketConnection sock = ctx->sock;
1584 SILC_LOG_DEBUG(("Start"));
1586 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1587 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1588 /* Error occured during protocol */
1589 silc_protocol_cancel(client->timeout_queue, protocol);
1590 silc_protocol_free(protocol);
1591 sock->protocol = NULL;
1593 silc_packet_context_free(ctx->packet);
1595 silc_ske_free(ctx->ske);
1596 silc_socket_free(ctx->sock);
1602 silc_protocol_free(protocol);
1603 sock->protocol = NULL;
1605 silc_packet_context_free(ctx->packet);
1607 silc_ske_free(ctx->ske);
1608 silc_socket_free(ctx->sock);