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,
44 SilcClientParams *params,
46 const char *silc_version)
48 SilcClient new_client;
50 new_client = silc_calloc(1, sizeof(*new_client));
51 new_client->application = application;
52 new_client->ops = ops;
53 new_client->silc_client_version = strdup(silc_version);
54 new_client->params = silc_calloc(1, sizeof(*new_client->params));
57 memcpy(new_client->params, params, sizeof(*params));
59 if (!new_client->params->rekey_secs)
60 new_client->params->rekey_secs = 3600;
65 /* Frees client object and its internals. */
67 void silc_client_free(SilcClient client)
71 silc_rng_free(client->rng);
73 silc_free(client->silc_client_version);
74 silc_free(client->params);
79 /* Initializes the client. This makes all the necessary steps to make
80 the client ready to be run. One must call silc_client_run to run the
81 client. Returns FALSE if error occured, TRUE otherwise. */
83 int silc_client_init(SilcClient client)
85 SILC_LOG_DEBUG(("Initializing client"));
87 /* Initialize hash functions for client to use */
88 silc_hash_alloc("md5", &client->md5hash);
89 silc_hash_alloc("sha1", &client->sha1hash);
91 /* Initialize none cipher */
92 silc_cipher_alloc("none", &client->none_cipher);
94 /* Initialize random number generator */
95 client->rng = silc_rng_alloc();
96 silc_rng_init(client->rng);
97 silc_rng_global_init(client->rng);
99 /* Register protocols */
100 silc_client_protocols_register();
102 /* Initialize the scheduler */
103 client->schedule = silc_schedule_init(client->params->task_max ?
104 client->params->task_max : 200);
105 if (!client->schedule)
111 /* Stops the client. This is called to stop the client and thus to stop
114 void silc_client_stop(SilcClient client)
116 SILC_LOG_DEBUG(("Stopping client"));
118 silc_schedule_stop(client->schedule);
119 silc_schedule_uninit(client->schedule);
121 silc_client_protocols_unregister();
123 SILC_LOG_DEBUG(("Client stopped"));
126 /* Runs the client. This starts the scheduler from the utility library.
127 When this functions returns the execution of the appliation is over. */
129 void silc_client_run(SilcClient client)
131 SILC_LOG_DEBUG(("Running client"));
133 /* Start the scheduler, the heart of the SILC client. When this returns
134 the program will be terminated. */
135 silc_schedule(client->schedule);
138 /* Allocates and adds new connection to the client. This adds the allocated
139 connection to the connection table and returns a pointer to it. A client
140 can have multiple connections to multiple servers. Every connection must
141 be added to the client using this function. User data `context' may
142 be sent as argument. This function is normally used only if the
143 application performed the connecting outside the library. The library
144 however may use this internally. */
146 SilcClientConnection silc_client_add_connection(SilcClient client,
151 SilcClientConnection conn;
154 conn = silc_calloc(1, sizeof(*conn));
156 /* Initialize ID caches */
157 conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, NULL);
158 conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
159 conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
160 conn->client = client;
161 conn->remote_host = strdup(hostname);
162 conn->remote_port = port;
163 conn->context = context;
164 conn->pending_commands = silc_dlist_init();
166 /* Add the connection to connections table */
167 for (i = 0; i < client->conns_count; i++)
168 if (client->conns && !client->conns[i]) {
169 client->conns[i] = conn;
173 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
174 * (client->conns_count + 1));
175 client->conns[client->conns_count] = conn;
176 client->conns_count++;
181 /* Removes connection from client. Frees all memory. */
183 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
187 for (i = 0; i < client->conns_count; i++)
188 if (client->conns[i] == conn) {
189 if (conn->pending_commands)
190 silc_dlist_uninit(conn->pending_commands);
192 client->conns[i] = NULL;
196 /* Adds listener socket to the listener sockets table. This function is
197 used to add socket objects that are listeners to the client. This should
198 not be used to add other connection objects. */
200 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
204 if (!client->sockets) {
205 client->sockets = silc_calloc(1, sizeof(*client->sockets));
206 client->sockets[0] = silc_socket_dup(sock);
207 client->sockets_count = 1;
211 for (i = 0; i < client->sockets_count; i++) {
212 if (client->sockets[i] == NULL) {
213 client->sockets[i] = silc_socket_dup(sock);
218 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
219 (client->sockets_count + 1));
220 client->sockets[client->sockets_count] = silc_socket_dup(sock);
221 client->sockets_count++;
224 /* Deletes listener socket from the listener sockets table. */
226 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
230 if (!client->sockets)
233 for (i = 0; i < client->sockets_count; i++) {
234 if (client->sockets[i] == sock) {
235 silc_socket_free(sock);
236 client->sockets[i] = NULL;
243 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
247 /* XXX In the future we should give up this non-blocking connect all
248 together and use threads instead. */
249 /* Create connection to server asynchronously */
250 sock = silc_net_create_connection_async(ctx->port, ctx->host);
254 /* Register task that will receive the async connect and will
256 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
257 silc_client_connect_to_server_start,
260 SILC_TASK_PRI_NORMAL);
261 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
268 /* Connects to remote server. This is the main routine used to connect
269 to SILC server. Returns -1 on error and the created socket otherwise.
270 The `context' is user context that is saved into the SilcClientConnection
271 that is created after the connection is created. Note that application
272 may handle the connecting process outside the library. If this is the
273 case then this function is not used at all. When the connecting is
274 done the `connect' client operation is called. */
276 int silc_client_connect_to_server(SilcClient client, int port,
277 char *host, void *context)
279 SilcClientInternalConnectContext *ctx;
280 SilcClientConnection conn;
283 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
286 conn = silc_client_add_connection(client, host, port, context);
288 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
289 "Connecting to port %d of server %s", port, host);
291 /* Allocate internal context for connection process. This is
292 needed as we are doing async connecting. */
293 ctx = silc_calloc(1, sizeof(*ctx));
294 ctx->client = client;
296 ctx->host = strdup(host);
300 /* Do the actual connecting process */
301 sock = silc_client_connect_to_server_internal(ctx);
303 silc_client_del_connection(client, conn);
307 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
308 key material between client and server. This function can be called
309 directly if application is performing its own connecting and does not
310 use the connecting provided by this library. This function is normally
311 used only if the application performed the connecting outside the library.
312 The library however may use this internally. */
314 int silc_client_start_key_exchange(SilcClient client,
315 SilcClientConnection conn,
318 SilcProtocol protocol;
319 SilcClientKEInternalContext *proto_ctx;
322 /* Allocate new socket connection object */
323 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
325 /* Sometimes when doing quick reconnects the new socket may be same as
326 the old one and there might be pending stuff for the old socket.
327 If new one is same then those pending sutff might cause problems.
328 Make sure they do not do that. */
329 silc_schedule_task_del_by_fd(client->schedule, fd);
331 conn->nickname = strdup(client->username);
332 conn->sock->hostname = conn->remote_host;
333 conn->sock->ip = strdup(conn->remote_host);
334 conn->sock->port = conn->remote_port;
336 /* Allocate internal Key Exchange context. This is sent to the
337 protocol as context. */
338 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
339 proto_ctx->client = (void *)client;
340 proto_ctx->sock = silc_socket_dup(conn->sock);
341 proto_ctx->rng = client->rng;
342 proto_ctx->responder = FALSE;
343 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
344 proto_ctx->verify = silc_client_protocol_ke_verify_key;
346 /* Perform key exchange protocol. silc_client_connect_to_server_final
347 will be called after the protocol is finished. */
348 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
349 &protocol, (void *)proto_ctx,
350 silc_client_connect_to_server_second);
352 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
353 "Error: Could not start authentication protocol");
356 conn->sock->protocol = protocol;
358 /* Register the connection for network input and output. This sets
359 that scheduler will listen for incoming packets for this connection
360 and sets that outgoing packets may be sent to this connection as well.
361 However, this doesn't set the scheduler for outgoing traffic, it will
362 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
363 later when outgoing data is available. */
364 context = (void *)client;
365 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
367 /* Execute the protocol */
368 silc_protocol_execute(protocol, client->schedule, 0, 0);
372 /* Start of the connection to the remote server. This is called after
373 succesful TCP/IP connection has been established to the remote host. */
375 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
377 SilcClientInternalConnectContext *ctx =
378 (SilcClientInternalConnectContext *)context;
379 SilcClient client = ctx->client;
380 SilcClientConnection conn = ctx->conn;
381 int opt, opt_len = sizeof(opt);
383 SILC_LOG_DEBUG(("Start"));
385 /* Check the socket status as it might be in error */
386 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
388 if (ctx->tries < 2) {
389 /* Connection failed but lets try again */
390 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
391 "Could not connect to server %s: %s",
392 ctx->host, strerror(opt));
393 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
394 "Connecting to port %d of server %s resumed",
395 ctx->port, ctx->host);
397 /* Unregister old connection try */
398 silc_schedule_unset_listen_fd(client->schedule, fd);
399 silc_net_close_connection(fd);
400 silc_schedule_task_del(client->schedule, ctx->task);
403 silc_client_connect_to_server_internal(ctx);
406 /* Connection failed and we won't try anymore */
407 client->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
408 "Could not connect to server %s: %s",
409 ctx->host, strerror(opt));
410 silc_schedule_unset_listen_fd(client->schedule, fd);
411 silc_net_close_connection(fd);
412 silc_schedule_task_del(client->schedule, ctx->task);
415 /* Notify application of failure */
416 client->ops->connect(client, conn, FALSE);
417 silc_client_del_connection(client, conn);
422 silc_schedule_unset_listen_fd(client->schedule, fd);
423 silc_schedule_task_del(client->schedule, ctx->task);
426 if (!silc_client_start_key_exchange(client, conn, fd)) {
427 silc_net_close_connection(fd);
428 client->ops->connect(client, conn, FALSE);
432 /* Second part of the connecting to the server. This executed
433 authentication protocol. */
435 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
437 SilcProtocol protocol = (SilcProtocol)context;
438 SilcClientKEInternalContext *ctx =
439 (SilcClientKEInternalContext *)protocol->context;
440 SilcClient client = (SilcClient)ctx->client;
441 SilcSocketConnection sock = NULL;
442 SilcClientConnAuthInternalContext *proto_ctx;
444 SILC_LOG_DEBUG(("Start"));
446 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
447 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
448 /* Error occured during protocol */
449 SILC_LOG_DEBUG(("Error during KE protocol"));
450 silc_protocol_free(protocol);
451 silc_ske_free_key_material(ctx->keymat);
453 silc_ske_free(ctx->ske);
455 silc_free(ctx->dest_id);
456 ctx->sock->protocol = NULL;
457 silc_socket_free(ctx->sock);
459 /* Notify application of failure */
460 client->ops->connect(client, ctx->sock->user_data, FALSE);
465 /* We now have the key material as the result of the key exchange
466 protocol. Take the key material into use. Free the raw key material
467 as soon as we've set them into use. */
468 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
469 ctx->ske->prop->cipher,
470 ctx->ske->prop->pkcs,
471 ctx->ske->prop->hash,
472 ctx->ske->prop->hmac,
473 ctx->ske->prop->group);
474 silc_ske_free_key_material(ctx->keymat);
476 /* Allocate internal context for the authentication protocol. This
477 is sent as context for the protocol. */
478 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
479 proto_ctx->client = (void *)client;
480 proto_ctx->sock = sock = ctx->sock;
481 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
482 proto_ctx->dest_id_type = ctx->dest_id_type;
483 proto_ctx->dest_id = ctx->dest_id;
485 /* Resolve the authentication method to be used in this connection */
486 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
487 sock->port, &proto_ctx->auth_meth,
488 &proto_ctx->auth_data,
489 &proto_ctx->auth_data_len))
490 proto_ctx->auth_meth = SILC_AUTH_NONE;
492 /* Free old protocol as it is finished now */
493 silc_protocol_free(protocol);
495 silc_packet_context_free(ctx->packet);
497 sock->protocol = NULL;
499 /* Allocate the authenteication protocol and execute it. */
500 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
501 &sock->protocol, (void *)proto_ctx,
502 silc_client_connect_to_server_final);
504 /* Execute the protocol */
505 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
508 /* Finalizes the connection to the remote SILC server. This is called
509 after authentication protocol has been completed. This send our
510 user information to the server to receive our client ID from
513 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
515 SilcProtocol protocol = (SilcProtocol)context;
516 SilcClientConnAuthInternalContext *ctx =
517 (SilcClientConnAuthInternalContext *)protocol->context;
518 SilcClient client = (SilcClient)ctx->client;
519 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
522 SILC_LOG_DEBUG(("Start"));
524 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
525 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
526 /* Error occured during protocol */
527 SILC_LOG_DEBUG(("Error during authentication protocol"));
528 silc_protocol_free(protocol);
530 silc_free(ctx->auth_data);
532 silc_ske_free(ctx->ske);
534 silc_free(ctx->dest_id);
535 conn->sock->protocol = NULL;
536 silc_socket_free(ctx->sock);
538 /* Notify application of failure */
539 client->ops->connect(client, ctx->sock->user_data, FALSE);
544 /* Send NEW_CLIENT packet to the server. We will become registered
545 to the SILC network after sending this packet and we will receive
546 client ID from the server. */
547 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
548 strlen(client->realname));
549 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
550 silc_buffer_format(packet,
551 SILC_STR_UI_SHORT(strlen(client->username)),
552 SILC_STR_UI_XNSTRING(client->username,
553 strlen(client->username)),
554 SILC_STR_UI_SHORT(strlen(client->realname)),
555 SILC_STR_UI_XNSTRING(client->realname,
556 strlen(client->realname)),
559 /* Send the packet */
560 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
562 packet->data, packet->len, TRUE);
563 silc_buffer_free(packet);
565 /* Save remote ID. */
566 conn->remote_id = ctx->dest_id;
567 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
568 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
570 /* Register re-key timeout */
571 conn->rekey->timeout = client->params->rekey_secs;
572 conn->rekey->context = (void *)client;
573 silc_schedule_task_add(client->schedule, conn->sock->sock,
574 silc_client_rekey_callback,
575 (void *)conn->sock, conn->rekey->timeout, 0,
576 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
578 silc_protocol_free(protocol);
580 silc_free(ctx->auth_data);
582 silc_ske_free(ctx->ske);
583 silc_socket_free(ctx->sock);
585 conn->sock->protocol = NULL;
588 /* Internal routine that sends packet or marks packet to be sent. This
589 is used directly only in special cases. Normal cases should use
590 silc_server_packet_send. Returns < 0 on error. */
592 int silc_client_packet_send_real(SilcClient client,
593 SilcSocketConnection sock,
599 /* If rekey protocol is active we must assure that all packets are
600 sent through packet queue. */
601 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
604 /* Send the packet */
605 ret = silc_packet_send(sock, force_send);
609 /* Mark that there is some outgoing data available for this connection.
610 This call sets the connection both for input and output (the input
611 is set always and this call keeps the input setting, actually).
612 Actual data sending is performed by silc_client_packet_process. */
613 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
615 /* Mark to socket that data is pending in outgoing buffer. This flag
616 is needed if new data is added to the buffer before the earlier
617 put data is sent to the network. */
618 SILC_SET_OUTBUF_PENDING(sock);
623 /* Packet processing callback. This is used to send and receive packets
624 from network. This is generic task. */
626 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
628 SilcClient client = (SilcClient)context;
629 SilcSocketConnection sock = NULL;
630 SilcClientConnection conn;
633 SILC_LOG_DEBUG(("Processing packet"));
635 SILC_CLIENT_GET_SOCK(client, fd, sock);
639 conn = (SilcClientConnection)sock->user_data;
642 if (type == SILC_TASK_WRITE) {
643 SILC_LOG_DEBUG(("Writing data to connection"));
645 if (sock->outbuf->data - sock->outbuf->head)
646 silc_buffer_push(sock->outbuf,
647 sock->outbuf->data - sock->outbuf->head);
649 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
651 /* If returned -2 could not write to connection now, will do
656 /* The packet has been sent and now it is time to set the connection
657 back to only for input. When there is again some outgoing data
658 available for this connection it will be set for output as well.
659 This call clears the output setting and sets it only for input. */
660 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
661 SILC_UNSET_OUTBUF_PENDING(sock);
663 silc_buffer_clear(sock->outbuf);
667 /* Packet receiving */
668 if (type == SILC_TASK_READ) {
669 SILC_LOG_DEBUG(("Reading data from connection"));
671 /* Read data from network */
672 ret = silc_packet_receive(sock);
678 SILC_LOG_DEBUG(("Read EOF"));
680 /* If connection is disconnecting already we will finally
681 close the connection */
682 if (SILC_IS_DISCONNECTING(sock)) {
683 if (sock == conn->sock)
684 client->ops->disconnect(client, conn);
685 silc_client_close_connection(client, sock, conn);
689 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
690 if (sock == conn->sock)
691 client->ops->disconnect(client, conn);
692 silc_client_close_connection(client, sock, conn);
696 /* Process the packet. This will call the parser that will then
697 decrypt and parse the packet. */
698 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
699 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
700 silc_client_packet_parse, client);
702 silc_packet_receive_process(sock, NULL, NULL,
703 silc_client_packet_parse, client);
707 /* Callback function that the silc_packet_decrypt will call to make the
708 decision whether the packet is normal or special packet. We will
709 return TRUE if it is normal and FALSE if it is special */
711 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
713 SilcPacketContext *packet,
717 /* Packet is normal packet, if:
719 1) packet is private message packet and does not have private key set
720 2) is other packet than channel message packet
722 all other packets are special packets
725 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
726 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
729 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
735 /* Parses whole packet, received earlier. */
737 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
739 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
740 SilcClient client = (SilcClient)parse_ctx->context;
741 SilcPacketContext *packet = parse_ctx->packet;
742 SilcBuffer buffer = packet->buffer;
743 SilcSocketConnection sock = parse_ctx->sock;
744 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
747 SILC_LOG_DEBUG(("Start"));
749 /* Decrypt the received packet */
750 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
751 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
753 silc_client_packet_decrypt_check, parse_ctx);
755 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
756 silc_client_packet_decrypt_check, parse_ctx);
762 /* Parse the packet. Packet type is returned. */
763 ret = silc_packet_parse(packet);
765 /* Parse the packet header in special way as this is "special"
767 ret = silc_packet_parse_special(packet);
770 if (ret == SILC_PACKET_NONE)
773 /* Parse the incoming packet type */
774 silc_client_packet_parse_type(client, sock, packet);
777 /* silc_buffer_clear(sock->inbuf); */
778 silc_packet_context_free(packet);
779 silc_free(parse_ctx);
782 /* Parser callback called by silc_packet_receive_process. Thie merely
783 registers timeout that will handle the actual parsing when appropriate. */
785 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
787 SilcClient client = (SilcClient)parser_context->context;
789 /* Parse the packet */
790 silc_schedule_task_add(client->schedule, parser_context->sock->sock,
791 silc_client_packet_parse_real,
792 (void *)parser_context, 0, 1,
794 SILC_TASK_PRI_NORMAL);
797 /* Parses the packet type and calls what ever routines the packet type
798 requires. This is done for all incoming packets. */
800 void silc_client_packet_parse_type(SilcClient client,
801 SilcSocketConnection sock,
802 SilcPacketContext *packet)
804 SilcBuffer buffer = packet->buffer;
805 SilcPacketType type = packet->type;
807 SILC_LOG_DEBUG(("Parsing packet type %d", type));
809 /* Parse the packet type */
811 case SILC_PACKET_DISCONNECT:
812 silc_client_disconnected_by_server(client, sock, buffer);
814 case SILC_PACKET_SUCCESS:
816 * Success received for something. For now we can have only
817 * one protocol for connection executing at once hence this
818 * success message is for whatever protocol is executing currently.
821 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
823 case SILC_PACKET_FAILURE:
825 * Failure received for some protocol. Set the protocol state to
826 * error and call the protocol callback. This fill cause error on
827 * protocol and it will call the final callback.
829 silc_client_process_failure(client, sock, packet);
831 case SILC_PACKET_REJECT:
834 case SILC_PACKET_NOTIFY:
836 * Received notify message
838 silc_client_notify_by_server(client, sock, packet);
841 case SILC_PACKET_ERROR:
843 * Received error message
845 silc_client_error_by_server(client, sock, buffer);
848 case SILC_PACKET_CHANNEL_MESSAGE:
850 * Received message to (from, actually) a channel
852 silc_client_channel_message(client, sock, packet);
854 case SILC_PACKET_CHANNEL_KEY:
856 * Received key for a channel. By receiving this key the client will be
857 * able to talk to the channel it has just joined. This can also be
858 * a new key for existing channel as keys expire peridiocally.
860 silc_client_receive_channel_key(client, sock, buffer);
863 case SILC_PACKET_PRIVATE_MESSAGE:
865 * Received private message
867 silc_client_private_message(client, sock, packet);
869 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
871 * Received private message key
875 case SILC_PACKET_COMMAND_REPLY:
877 * Recived reply for a command
879 silc_client_command_reply_process(client, sock, packet);
882 case SILC_PACKET_KEY_EXCHANGE:
883 if (sock->protocol && sock->protocol->protocol &&
884 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
885 SilcClientKEInternalContext *proto_ctx =
886 (SilcClientKEInternalContext *)sock->protocol->context;
888 proto_ctx->packet = silc_packet_context_dup(packet);
889 proto_ctx->dest_id_type = packet->src_id_type;
890 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
891 packet->src_id_type);
892 if (!proto_ctx->dest_id)
895 /* Let the protocol handle the packet */
896 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
898 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
899 "protocol active, packet dropped."));
903 case SILC_PACKET_KEY_EXCHANGE_1:
904 if (sock->protocol && sock->protocol->protocol &&
905 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
906 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
908 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
909 SilcClientRekeyInternalContext *proto_ctx =
910 (SilcClientRekeyInternalContext *)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);
917 /* Let the protocol handle the packet */
918 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
920 SilcClientKEInternalContext *proto_ctx =
921 (SilcClientKEInternalContext *)sock->protocol->context;
923 if (proto_ctx->packet)
924 silc_packet_context_free(proto_ctx->packet);
926 proto_ctx->packet = silc_packet_context_dup(packet);
927 proto_ctx->dest_id_type = packet->src_id_type;
928 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
929 packet->src_id_type);
930 if (!proto_ctx->dest_id)
933 /* Let the protocol handle the packet */
934 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
937 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
938 "protocol active, packet dropped."));
941 case SILC_PACKET_KEY_EXCHANGE_2:
942 if (sock->protocol && sock->protocol->protocol &&
943 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
944 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
946 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
947 SilcClientRekeyInternalContext *proto_ctx =
948 (SilcClientRekeyInternalContext *)sock->protocol->context;
950 if (proto_ctx->packet)
951 silc_packet_context_free(proto_ctx->packet);
953 proto_ctx->packet = silc_packet_context_dup(packet);
955 /* Let the protocol handle the packet */
956 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
958 SilcClientKEInternalContext *proto_ctx =
959 (SilcClientKEInternalContext *)sock->protocol->context;
961 if (proto_ctx->packet)
962 silc_packet_context_free(proto_ctx->packet);
964 proto_ctx->packet = silc_packet_context_dup(packet);
965 proto_ctx->dest_id_type = packet->src_id_type;
966 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
967 packet->src_id_type);
968 if (!proto_ctx->dest_id)
971 /* Let the protocol handle the packet */
972 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
975 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
976 "protocol active, packet dropped."));
980 case SILC_PACKET_NEW_ID:
983 * Received new ID from server. This packet is received at
984 * the connection to the server. New ID is also received when
985 * user changes nickname but in that case the new ID is received
986 * as command reply and not as this packet type.
990 idp = silc_id_payload_parse(buffer);
993 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
996 silc_client_receive_new_id(client, sock, idp);
997 silc_id_payload_free(idp);
1001 case SILC_PACKET_HEARTBEAT:
1003 * Received heartbeat packet
1005 SILC_LOG_DEBUG(("Heartbeat packet"));
1008 case SILC_PACKET_KEY_AGREEMENT:
1010 * Received key agreement packet
1012 SILC_LOG_DEBUG(("Key agreement packet"));
1013 silc_client_key_agreement(client, sock, packet);
1016 case SILC_PACKET_REKEY:
1017 SILC_LOG_DEBUG(("Re-key packet"));
1018 /* We ignore this for now */
1021 case SILC_PACKET_REKEY_DONE:
1022 SILC_LOG_DEBUG(("Re-key done packet"));
1024 if (sock->protocol && sock->protocol->protocol &&
1025 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1027 SilcClientRekeyInternalContext *proto_ctx =
1028 (SilcClientRekeyInternalContext *)sock->protocol->context;
1030 if (proto_ctx->packet)
1031 silc_packet_context_free(proto_ctx->packet);
1033 proto_ctx->packet = silc_packet_context_dup(packet);
1035 /* Let the protocol handle the packet */
1036 if (proto_ctx->responder == FALSE)
1037 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1039 /* Let the protocol handle the packet */
1040 silc_protocol_execute(sock->protocol, client->schedule,
1043 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1044 "protocol active, packet dropped."));
1049 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1054 /* Sends packet. This doesn't actually send the packet instead it assembles
1055 it and marks it to be sent. However, if force_send is TRUE the packet
1056 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1057 will be derived from sock argument. Otherwise the valid arguments sent
1060 void silc_client_packet_send(SilcClient client,
1061 SilcSocketConnection sock,
1062 SilcPacketType type,
1064 SilcIdType dst_id_type,
1067 unsigned char *data,
1071 SilcPacketContext packetdata;
1076 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1078 /* Get data used in the packet sending, keys and stuff */
1079 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1080 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1081 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1083 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1084 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1086 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1087 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1088 dst_id_type = SILC_ID_SERVER;
1092 /* Set the packet context pointers */
1093 packetdata.flags = 0;
1094 packetdata.type = type;
1095 if (sock->user_data &&
1096 ((SilcClientConnection)sock->user_data)->local_id_data) {
1097 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1098 packetdata.src_id_len =
1099 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1102 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1103 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1105 packetdata.src_id_type = SILC_ID_CLIENT;
1107 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1108 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1109 packetdata.dst_id_type = dst_id_type;
1111 packetdata.dst_id = NULL;
1112 packetdata.dst_id_len = 0;
1113 packetdata.dst_id_type = SILC_ID_NONE;
1115 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1116 packetdata.src_id_len + packetdata.dst_id_len;
1117 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1119 /* Prepare outgoing data buffer for packet sending */
1120 silc_packet_send_prepare(sock,
1121 SILC_PACKET_HEADER_LEN +
1122 packetdata.src_id_len +
1123 packetdata.dst_id_len,
1127 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1129 packetdata.buffer = sock->outbuf;
1131 /* Put the data to the buffer */
1132 if (data && data_len)
1133 silc_buffer_put(sock->outbuf, data, data_len);
1135 /* Create the outgoing packet */
1136 silc_packet_assemble(&packetdata);
1138 /* Encrypt the packet */
1140 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1142 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1143 sock->outbuf->data, sock->outbuf->len);
1145 /* Now actually send the packet */
1146 silc_client_packet_send_real(client, sock, force_send, FALSE);
1149 /* Closes connection to remote end. Free's all allocated data except
1150 for some information such as nickname etc. that are valid at all time.
1151 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1152 provided it will be checked whether the sock and `conn->sock' are the
1153 same (they can be different, ie. a socket can use `conn' as its
1154 connection but `conn->sock' might be actually a different connection
1155 than the `sock'). */
1157 void silc_client_close_connection(SilcClient client,
1158 SilcSocketConnection sock,
1159 SilcClientConnection conn)
1163 if (!sock || (sock && conn->sock == sock))
1168 /* We won't listen for this connection anymore */
1169 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1171 /* Unregister all tasks */
1172 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1173 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1175 /* Close the actual connection */
1176 silc_net_close_connection(sock->sock);
1178 /* Cancel any active protocol */
1179 if (sock->protocol) {
1180 if (sock->protocol->protocol->type ==
1181 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1182 sock->protocol->protocol->type ==
1183 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1184 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1185 silc_protocol_execute_final(sock->protocol, client->schedule);
1186 /* The application will recall this function with these protocols
1187 (the ops->connect client operation). */
1190 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1191 silc_protocol_execute_final(sock->protocol, client->schedule);
1192 sock->protocol = NULL;
1196 /* Free everything */
1197 if (del && sock->user_data) {
1198 /* Free all cache entries */
1199 SilcIDCacheList list;
1200 SilcIDCacheEntry entry;
1203 if (silc_idcache_get_all(conn->client_cache, &list)) {
1204 ret = silc_idcache_list_first(list, &entry);
1206 silc_client_del_client(client, conn, entry->context);
1207 ret = silc_idcache_list_next(list, &entry);
1209 silc_idcache_list_free(list);
1212 if (silc_idcache_get_all(conn->channel_cache, &list)) {
1213 ret = silc_idcache_list_first(list, &entry);
1215 silc_client_del_channel(client, conn, entry->context);
1216 ret = silc_idcache_list_next(list, &entry);
1218 silc_idcache_list_free(list);
1221 if (silc_idcache_get_all(conn->server_cache, &list)) {
1222 ret = silc_idcache_list_first(list, &entry);
1224 silc_client_del_server(client, conn, entry->context);
1225 ret = silc_idcache_list_next(list, &entry);
1227 silc_idcache_list_free(list);
1230 /* Clear ID caches */
1231 if (conn->client_cache)
1232 silc_idcache_del_all(conn->client_cache);
1233 if (conn->channel_cache)
1234 silc_idcache_del_all(conn->channel_cache);
1235 if (conn->server_cache)
1236 silc_idcache_del_all(conn->server_cache);
1238 /* Free data (my ID is freed in above silc_client_del_client) */
1239 if (conn->remote_host)
1240 silc_free(conn->remote_host);
1241 if (conn->local_id_data)
1242 silc_free(conn->local_id_data);
1244 silc_cipher_free(conn->send_key);
1245 if (conn->receive_key)
1246 silc_cipher_free(conn->receive_key);
1247 if (conn->hmac_send) /* conn->hmac_receive is same */
1248 silc_hmac_free(conn->hmac_send);
1249 if (conn->pending_commands)
1250 silc_dlist_uninit(conn->pending_commands);
1252 silc_free(conn->rekey);
1254 memset(conn, 0, sizeof(*conn));
1255 silc_client_del_connection(client, conn);
1258 silc_socket_free(sock);
1261 /* Called when we receive disconnection packet from server. This
1262 closes our end properly and displays the reason of the disconnection
1265 void silc_client_disconnected_by_server(SilcClient client,
1266 SilcSocketConnection sock,
1271 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1273 msg = silc_calloc(message->len + 1, sizeof(char));
1274 memcpy(msg, message->data, message->len);
1275 client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
1278 SILC_SET_DISCONNECTED(sock);
1279 silc_client_close_connection(client, sock, sock->user_data);
1282 /* Received error message from server. Display it on the screen.
1283 We don't take any action what so ever of the error message. */
1285 void silc_client_error_by_server(SilcClient client,
1286 SilcSocketConnection sock,
1291 msg = silc_calloc(message->len + 1, sizeof(char));
1292 memcpy(msg, message->data, message->len);
1293 client->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, msg);
1297 /* Processes the received new Client ID from server. Old Client ID is
1298 deleted from cache and new one is added. */
1300 void silc_client_receive_new_id(SilcClient client,
1301 SilcSocketConnection sock,
1304 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1305 int connecting = FALSE;
1308 if (!conn->local_entry)
1311 /* Delete old ID from ID cache */
1312 if (conn->local_id) {
1313 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1314 silc_free(conn->local_id);
1317 /* Save the new ID */
1319 if (conn->local_id_data)
1320 silc_free(conn->local_id_data);
1322 conn->local_id = silc_id_payload_get_id(idp);
1323 conn->local_id_data = silc_id_payload_get_data(idp);
1324 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1326 if (!conn->local_entry)
1327 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1329 conn->local_entry->nickname = conn->nickname;
1330 if (!conn->local_entry->username) {
1331 conn->local_entry->username =
1332 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1333 sizeof(conn->local_entry->username));
1334 sprintf(conn->local_entry->username, "%s@%s", client->username,
1337 conn->local_entry->server = strdup(conn->remote_host);
1338 conn->local_entry->id = conn->local_id;
1340 /* Put it to the ID cache */
1341 silc_idcache_add(conn->client_cache, conn->nickname, conn->local_id,
1342 (void *)conn->local_entry, FALSE);
1344 /* Issue INFO command to fetch the real server name and server information
1346 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1347 silc_client_send_command(client, conn, SILC_COMMAND_INFO,
1348 ++conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1349 silc_buffer_free(sidp);
1351 /* Notify application of successful connection. We do it here now that
1352 we've received the Client ID and are allowed to send traffic. */
1354 client->ops->connect(client, conn, TRUE);
1357 /* Processed received Channel ID for a channel. This is called when client
1358 joins to channel and server replies with channel ID. The ID is cached.
1359 Returns the created channel entry. This is also called when received
1360 channel ID in for example USERS command reply that we do not have. */
1362 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1363 SilcSocketConnection sock,
1368 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1369 SilcChannelEntry channel;
1371 SILC_LOG_DEBUG(("New channel ID"));
1373 channel = silc_calloc(1, sizeof(*channel));
1374 channel->channel_name = channel_name;
1375 channel->id = silc_id_payload_get_id(idp);
1376 channel->mode = mode;
1377 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1379 /* Put it to the ID cache */
1380 silc_idcache_add(conn->channel_cache, channel->channel_name,
1381 (void *)channel->id, (void *)channel, FALSE);
1386 /* Removes a client entry from all channel it has joined. This really is
1387 a performance killer (client_entry should have pointers to channel
1390 void silc_client_remove_from_channels(SilcClient client,
1391 SilcClientConnection conn,
1392 SilcClientEntry client_entry)
1394 SilcIDCacheEntry id_cache;
1395 SilcIDCacheList list;
1396 SilcChannelEntry channel;
1397 SilcChannelUser chu;
1399 if (!silc_idcache_get_all(conn->channel_cache, &list))
1402 silc_idcache_list_first(list, &id_cache);
1403 channel = (SilcChannelEntry)id_cache->context;
1407 /* Remove client from channel */
1408 silc_list_start(channel->clients);
1409 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1410 if (chu->client == client_entry) {
1411 silc_list_del(channel->clients, chu);
1417 if (!silc_idcache_list_next(list, &id_cache))
1420 channel = (SilcChannelEntry)id_cache->context;
1423 silc_idcache_list_free(list);
1426 /* Replaces `old' client entries from all channels to `new' client entry.
1427 This can be called for example when nickname changes and old ID entry
1428 is replaced from ID cache with the new one. If the old ID entry is only
1429 updated, then this fucntion needs not to be called. */
1431 void silc_client_replace_from_channels(SilcClient client,
1432 SilcClientConnection conn,
1433 SilcClientEntry old,
1434 SilcClientEntry new)
1436 SilcIDCacheEntry id_cache;
1437 SilcIDCacheList list;
1438 SilcChannelEntry channel;
1439 SilcChannelUser chu;
1441 if (!silc_idcache_get_all(conn->channel_cache, &list))
1444 silc_idcache_list_first(list, &id_cache);
1445 channel = (SilcChannelEntry)id_cache->context;
1449 /* Replace client entry */
1450 silc_list_start(channel->clients);
1451 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1452 if (chu->client == old) {
1458 if (!silc_idcache_list_next(list, &id_cache))
1461 channel = (SilcChannelEntry)id_cache->context;
1464 silc_idcache_list_free(list);
1467 /* Registers failure timeout to process the received failure packet
1470 void silc_client_process_failure(SilcClient client,
1471 SilcSocketConnection sock,
1472 SilcPacketContext *packet)
1476 if (sock->protocol) {
1477 if (packet->buffer->len >= 4)
1478 SILC_GET32_MSB(failure, packet->buffer->data);
1480 /* Notify application */
1481 client->ops->failure(client, sock->user_data, sock->protocol,
1486 /* A timeout callback for the re-key. We will be the initiator of the
1489 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1491 SilcSocketConnection sock = (SilcSocketConnection)context;
1492 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1493 SilcClient client = (SilcClient)conn->rekey->context;
1494 SilcProtocol protocol;
1495 SilcClientRekeyInternalContext *proto_ctx;
1497 SILC_LOG_DEBUG(("Start"));
1499 /* Allocate internal protocol context. This is sent as context
1501 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1502 proto_ctx->client = (void *)client;
1503 proto_ctx->sock = silc_socket_dup(sock);
1504 proto_ctx->responder = FALSE;
1505 proto_ctx->pfs = conn->rekey->pfs;
1507 /* Perform rekey protocol. Will call the final callback after the
1508 protocol is over. */
1509 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1510 &protocol, proto_ctx, silc_client_rekey_final);
1511 sock->protocol = protocol;
1513 /* Run the protocol */
1514 silc_protocol_execute(protocol, client->schedule, 0, 0);
1516 /* Re-register re-key timeout */
1517 silc_schedule_task_add(client->schedule, sock->sock,
1518 silc_client_rekey_callback,
1519 context, conn->rekey->timeout, 0,
1520 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1523 /* The final callback for the REKEY protocol. This will actually take the
1524 new key material into use. */
1526 SILC_TASK_CALLBACK(silc_client_rekey_final)
1528 SilcProtocol protocol = (SilcProtocol)context;
1529 SilcClientRekeyInternalContext *ctx =
1530 (SilcClientRekeyInternalContext *)protocol->context;
1531 SilcClient client = (SilcClient)ctx->client;
1532 SilcSocketConnection sock = ctx->sock;
1534 SILC_LOG_DEBUG(("Start"));
1536 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1537 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1538 /* Error occured during protocol */
1539 silc_protocol_cancel(protocol, client->schedule);
1540 silc_protocol_free(protocol);
1541 sock->protocol = NULL;
1543 silc_packet_context_free(ctx->packet);
1545 silc_ske_free(ctx->ske);
1546 silc_socket_free(ctx->sock);
1552 silc_protocol_free(protocol);
1553 sock->protocol = NULL;
1555 silc_packet_context_free(ctx->packet);
1557 silc_ske_free(ctx->ske);
1558 silc_socket_free(ctx->sock);