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, NULL);
146 conn->channel_cache = silc_idcache_alloc(0, NULL);
147 conn->server_cache = silc_idcache_alloc(0, 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] = 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] = sock;
206 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
207 (client->sockets_count + 1));
208 client->sockets[client->sockets_count] = 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 client->sockets[i] = NULL;
230 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
234 /* XXX In the future we should give up this non-blocking connect all
235 together and use threads instead. */
236 /* Create connection to server asynchronously */
237 sock = silc_net_create_connection_async(ctx->port, ctx->host);
241 /* Register task that will receive the async connect and will
243 ctx->task = silc_task_register(ctx->client->io_queue, sock,
244 silc_client_connect_to_server_start,
247 SILC_TASK_PRI_NORMAL);
248 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
249 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
256 /* Connects to remote server. This is the main routine used to connect
257 to SILC server. Returns -1 on error and the created socket otherwise.
258 The `context' is user context that is saved into the SilcClientConnection
259 that is created after the connection is created. Note that application
260 may handle the connecting process outside the library. If this is the
261 case then this function is not used at all. When the connecting is
262 done the `connect' client operation is called. */
264 int silc_client_connect_to_server(SilcClient client, int port,
265 char *host, void *context)
267 SilcClientInternalConnectContext *ctx;
268 SilcClientConnection conn;
271 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
274 conn = silc_client_add_connection(client, host, port, context);
276 client->ops->say(client, conn,
277 "Connecting to port %d of server %s", port, host);
279 /* Allocate internal context for connection process. This is
280 needed as we are doing async connecting. */
281 ctx = silc_calloc(1, sizeof(*ctx));
282 ctx->client = client;
284 ctx->host = strdup(host);
288 /* Do the actual connecting process */
289 sock = silc_client_connect_to_server_internal(ctx);
291 silc_client_del_connection(client, conn);
295 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
296 key material between client and server. This function can be called
297 directly if application is performing its own connecting and does not
298 use the connecting provided by this library. This function is normally
299 used only if the application performed the connecting outside the library.
300 The library however may use this internally. */
302 int silc_client_start_key_exchange(SilcClient client,
303 SilcClientConnection conn,
306 SilcProtocol protocol;
307 SilcClientKEInternalContext *proto_ctx;
310 /* Allocate new socket connection object */
311 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
313 conn->nickname = strdup(client->username);
314 conn->sock->hostname = conn->remote_host;
315 conn->sock->ip = strdup(conn->remote_host);
316 conn->sock->port = conn->remote_port;
318 /* Allocate internal Key Exchange context. This is sent to the
319 protocol as context. */
320 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
321 proto_ctx->client = (void *)client;
322 proto_ctx->sock = conn->sock;
323 proto_ctx->rng = client->rng;
324 proto_ctx->responder = FALSE;
325 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
326 proto_ctx->verify = silc_client_protocol_ke_verify_key;
328 /* Perform key exchange protocol. silc_client_connect_to_server_final
329 will be called after the protocol is finished. */
330 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
331 &protocol, (void *)proto_ctx,
332 silc_client_connect_to_server_second);
334 client->ops->say(client, conn,
335 "Error: Could not start authentication protocol");
338 conn->sock->protocol = protocol;
340 /* Register the connection for network input and output. This sets
341 that scheduler will listen for incoming packets for this connection
342 and sets that outgoing packets may be sent to this connection as well.
343 However, this doesn't set the scheduler for outgoing traffic, it will
344 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
345 later when outgoing data is available. */
346 context = (void *)client;
347 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
349 /* Execute the protocol */
350 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
354 /* Start of the connection to the remote server. This is called after
355 succesful TCP/IP connection has been established to the remote host. */
357 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
359 SilcClientInternalConnectContext *ctx =
360 (SilcClientInternalConnectContext *)context;
361 SilcClient client = ctx->client;
362 SilcClientConnection conn = ctx->conn;
363 int opt, opt_len = sizeof(opt);
365 SILC_LOG_DEBUG(("Start"));
367 /* Check the socket status as it might be in error */
368 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
370 if (ctx->tries < 2) {
371 /* Connection failed but lets try again */
372 client->ops->say(client, conn, "Could not connect to server %s: %s",
373 ctx->host, strerror(opt));
374 client->ops->say(client, conn,
375 "Connecting to port %d of server %s resumed",
376 ctx->port, ctx->host);
378 /* Unregister old connection try */
379 silc_schedule_unset_listen_fd(fd);
380 silc_net_close_connection(fd);
381 silc_task_unregister(client->io_queue, ctx->task);
384 silc_client_connect_to_server_internal(ctx);
387 /* Connection failed and we won't try anymore */
388 client->ops->say(client, conn, "Could not connect to server %s: %s",
389 ctx->host, strerror(opt));
390 silc_schedule_unset_listen_fd(fd);
391 silc_net_close_connection(fd);
392 silc_task_unregister(client->io_queue, ctx->task);
395 /* Notify application of failure */
396 client->ops->connect(client, conn, FALSE);
397 silc_client_del_connection(client, conn);
402 silc_schedule_unset_listen_fd(fd);
403 silc_task_unregister(client->io_queue, ctx->task);
406 if (!silc_client_start_key_exchange(client, conn, fd)) {
407 silc_net_close_connection(fd);
408 client->ops->connect(client, conn, FALSE);
412 /* Second part of the connecting to the server. This executed
413 authentication protocol. */
415 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
417 SilcProtocol protocol = (SilcProtocol)context;
418 SilcClientKEInternalContext *ctx =
419 (SilcClientKEInternalContext *)protocol->context;
420 SilcClient client = (SilcClient)ctx->client;
421 SilcSocketConnection sock = NULL;
422 SilcClientConnAuthInternalContext *proto_ctx;
424 SILC_LOG_DEBUG(("Start"));
426 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
427 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
428 /* Error occured during protocol */
429 SILC_LOG_DEBUG(("Error during KE protocol"));
430 silc_protocol_free(protocol);
431 silc_ske_free_key_material(ctx->keymat);
433 silc_ske_free(ctx->ske);
435 silc_free(ctx->dest_id);
436 ctx->sock->protocol = NULL;
437 silc_task_unregister_by_callback(client->timeout_queue,
438 silc_client_failure_callback);
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 authentication protocol. This is allocated here
485 but we won't start it yet. We will be receiving party of this
486 protocol thus we will wait that connecting party will make
488 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
489 &sock->protocol, (void *)proto_ctx,
490 silc_client_connect_to_server_final);
492 /* Execute the protocol */
493 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
496 /* Finalizes the connection to the remote SILC server. This is called
497 after authentication protocol has been completed. This send our
498 user information to the server to receive our client ID from
501 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
503 SilcProtocol protocol = (SilcProtocol)context;
504 SilcClientConnAuthInternalContext *ctx =
505 (SilcClientConnAuthInternalContext *)protocol->context;
506 SilcClient client = (SilcClient)ctx->client;
507 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
510 SILC_LOG_DEBUG(("Start"));
512 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
513 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
514 /* Error occured during protocol */
515 SILC_LOG_DEBUG(("Error during authentication protocol"));
516 silc_protocol_free(protocol);
518 silc_free(ctx->auth_data);
520 silc_ske_free(ctx->ske);
522 silc_free(ctx->dest_id);
523 conn->sock->protocol = NULL;
524 silc_task_unregister_by_callback(client->timeout_queue,
525 silc_client_failure_callback);
527 /* Notify application of failure */
528 client->ops->connect(client, ctx->sock->user_data, FALSE);
533 /* Send NEW_CLIENT packet to the server. We will become registered
534 to the SILC network after sending this packet and we will receive
535 client ID from the server. */
536 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
537 strlen(client->realname));
538 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
539 silc_buffer_format(packet,
540 SILC_STR_UI_SHORT(strlen(client->username)),
541 SILC_STR_UI_XNSTRING(client->username,
542 strlen(client->username)),
543 SILC_STR_UI_SHORT(strlen(client->realname)),
544 SILC_STR_UI_XNSTRING(client->realname,
545 strlen(client->realname)),
548 /* Send the packet */
549 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
551 packet->data, packet->len, TRUE);
552 silc_buffer_free(packet);
554 /* Save remote ID. */
555 conn->remote_id = ctx->dest_id;
556 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
557 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
559 /* Register re-key timeout */
560 conn->rekey->timeout = 3600; /* XXX hardcoded */
561 conn->rekey->context = (void *)client;
562 silc_task_register(client->timeout_queue, conn->sock->sock,
563 silc_client_rekey_callback,
564 (void *)conn->sock, conn->rekey->timeout, 0,
565 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
567 silc_task_unregister_by_callback(client->timeout_queue,
568 silc_client_failure_callback);
569 silc_protocol_free(protocol);
571 silc_free(ctx->auth_data);
573 silc_ske_free(ctx->ske);
575 conn->sock->protocol = NULL;
578 /* Internal routine that sends packet or marks packet to be sent. This
579 is used directly only in special cases. Normal cases should use
580 silc_server_packet_send. Returns < 0 on error. */
582 int silc_client_packet_send_real(SilcClient client,
583 SilcSocketConnection sock,
589 /* If rekey protocol is active we must assure that all packets are
590 sent through packet queue. */
591 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
594 /* Send the packet */
595 ret = silc_packet_send(sock, force_send);
599 /* Mark that there is some outgoing data available for this connection.
600 This call sets the connection both for input and output (the input
601 is set always and this call keeps the input setting, actually).
602 Actual data sending is performed by silc_client_packet_process. */
603 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
605 /* Mark to socket that data is pending in outgoing buffer. This flag
606 is needed if new data is added to the buffer before the earlier
607 put data is sent to the network. */
608 SILC_SET_OUTBUF_PENDING(sock);
613 /* Packet processing callback. This is used to send and receive packets
614 from network. This is generic task. */
616 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
618 SilcClient client = (SilcClient)context;
619 SilcSocketConnection sock = NULL;
620 SilcClientConnection conn;
623 SILC_LOG_DEBUG(("Processing packet"));
625 SILC_CLIENT_GET_SOCK(client, fd, sock);
629 conn = (SilcClientConnection)sock->user_data;
632 if (type == SILC_TASK_WRITE) {
633 SILC_LOG_DEBUG(("Writing data to connection"));
635 if (sock->outbuf->data - sock->outbuf->head)
636 silc_buffer_push(sock->outbuf,
637 sock->outbuf->data - sock->outbuf->head);
639 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
641 /* If returned -2 could not write to connection now, will do
646 /* The packet has been sent and now it is time to set the connection
647 back to only for input. When there is again some outgoing data
648 available for this connection it will be set for output as well.
649 This call clears the output setting and sets it only for input. */
650 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
651 SILC_UNSET_OUTBUF_PENDING(sock);
653 silc_buffer_clear(sock->outbuf);
657 /* Packet receiving */
658 if (type == SILC_TASK_READ) {
659 SILC_LOG_DEBUG(("Reading data from connection"));
661 /* Read data from network */
662 ret = silc_packet_receive(sock);
668 SILC_LOG_DEBUG(("Read EOF"));
670 /* If connection is disconnecting already we will finally
671 close the connection */
672 if (SILC_IS_DISCONNECTING(sock)) {
673 if (sock == conn->sock)
674 client->ops->disconnect(client, conn);
675 silc_client_close_connection(client, sock, conn);
679 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
680 if (sock == conn->sock)
681 client->ops->disconnect(client, conn);
682 silc_client_close_connection(client, sock, conn);
686 /* Process the packet. This will call the parser that will then
687 decrypt and parse the packet. */
688 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
689 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
690 silc_client_packet_parse, client);
692 silc_packet_receive_process(sock, NULL, NULL,
693 silc_client_packet_parse, client);
697 /* Callback function that the silc_packet_decrypt will call to make the
698 decision whether the packet is normal or special packet. We will
699 return TRUE if it is normal and FALSE if it is special */
701 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
703 SilcPacketContext *packet,
707 /* Packet is normal packet, if:
709 1) packet is private message packet and does not have private key set
710 2) is other packet than channel message packet
712 all other packets are special packets
715 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
716 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
719 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
725 /* Parses whole packet, received earlier. */
727 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
729 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
730 SilcClient client = (SilcClient)parse_ctx->context;
731 SilcPacketContext *packet = parse_ctx->packet;
732 SilcBuffer buffer = packet->buffer;
733 SilcSocketConnection sock = parse_ctx->sock;
734 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
737 SILC_LOG_DEBUG(("Start"));
739 /* Decrypt the received packet */
740 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
741 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
743 silc_client_packet_decrypt_check, parse_ctx);
745 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
746 silc_client_packet_decrypt_check, parse_ctx);
752 /* Parse the packet. Packet type is returned. */
753 ret = silc_packet_parse(packet);
755 /* Parse the packet header in special way as this is "special"
757 ret = silc_packet_parse_special(packet);
760 if (ret == SILC_PACKET_NONE)
763 /* Parse the incoming packet type */
764 silc_client_packet_parse_type(client, sock, packet);
767 /* silc_buffer_clear(sock->inbuf); */
768 silc_packet_context_free(packet);
769 silc_free(parse_ctx);
772 /* Parser callback called by silc_packet_receive_process. Thie merely
773 registers timeout that will handle the actual parsing when appropriate. */
775 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
777 SilcClient client = (SilcClient)parser_context->context;
779 /* Parse the packet */
782 /* If REKEY protocol is active we must proccess the packets synchronously
783 since we must assure that incoming packets that are encrypted with
784 the old key is processed before the new keys is set to use. */
785 if (SILC_CLIENT_IS_REKEY(parser_context->sock))
786 silc_client_packet_parse_real(client->timeout_queue, SILC_TASK_READ,
787 (void *)parser_context,
788 parser_context->sock->sock);
791 silc_task_register(client->timeout_queue, parser_context->sock->sock,
792 silc_client_packet_parse_real,
793 (void *)parser_context, 0, 1,
795 SILC_TASK_PRI_NORMAL);
798 /* Parses the packet type and calls what ever routines the packet type
799 requires. This is done for all incoming packets. */
801 void silc_client_packet_parse_type(SilcClient client,
802 SilcSocketConnection sock,
803 SilcPacketContext *packet)
805 SilcBuffer buffer = packet->buffer;
806 SilcPacketType type = packet->type;
808 SILC_LOG_DEBUG(("Parsing packet type %d", type));
810 /* Parse the packet type */
812 case SILC_PACKET_DISCONNECT:
813 silc_client_disconnected_by_server(client, sock, buffer);
815 case SILC_PACKET_SUCCESS:
817 * Success received for something. For now we can have only
818 * one protocol for connection executing at once hence this
819 * success message is for whatever protocol is executing currently.
821 if (sock->protocol) {
822 sock->protocol->execute(client->timeout_queue, 0,
823 sock->protocol, sock->sock, 0, 0);
826 case SILC_PACKET_FAILURE:
828 * Failure received for some protocol. Set the protocol state to
829 * error and call the protocol callback. This fill cause error on
830 * protocol and it will call the final callback.
832 silc_client_process_failure(client, sock, packet);
834 case SILC_PACKET_REJECT:
837 case SILC_PACKET_NOTIFY:
839 * Received notify message
841 silc_client_notify_by_server(client, sock, packet);
844 case SILC_PACKET_ERROR:
846 * Received error message
848 silc_client_error_by_server(client, sock, buffer);
851 case SILC_PACKET_CHANNEL_MESSAGE:
853 * Received message to (from, actually) a channel
855 silc_client_channel_message(client, sock, packet);
857 case SILC_PACKET_CHANNEL_KEY:
859 * Received key for a channel. By receiving this key the client will be
860 * able to talk to the channel it has just joined. This can also be
861 * a new key for existing channel as keys expire peridiocally.
863 silc_client_receive_channel_key(client, sock, buffer);
866 case SILC_PACKET_PRIVATE_MESSAGE:
868 * Received private message
870 silc_client_private_message(client, sock, packet);
872 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
874 * Received private message key
878 case SILC_PACKET_COMMAND_REPLY:
880 * Recived reply for a command
882 silc_client_command_reply_process(client, sock, packet);
885 case SILC_PACKET_KEY_EXCHANGE:
886 if (sock->protocol && sock->protocol->protocol &&
887 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
888 SilcClientKEInternalContext *proto_ctx =
889 (SilcClientKEInternalContext *)sock->protocol->context;
891 proto_ctx->packet = silc_packet_context_dup(packet);
892 proto_ctx->dest_id_type = packet->src_id_type;
893 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
894 packet->src_id_type);
895 if (!proto_ctx->dest_id)
898 /* Let the protocol handle the packet */
899 sock->protocol->execute(client->timeout_queue, 0,
900 sock->protocol, sock->sock, 0, 0);
902 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
903 "protocol active, packet dropped."));
905 /* XXX Trigger KE protocol?? Rekey actually! */
909 case SILC_PACKET_KEY_EXCHANGE_1:
910 if (sock->protocol && sock->protocol->protocol &&
911 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
912 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
914 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
915 SilcClientRekeyInternalContext *proto_ctx =
916 (SilcClientRekeyInternalContext *)sock->protocol->context;
918 if (proto_ctx->packet)
919 silc_packet_context_free(proto_ctx->packet);
921 proto_ctx->packet = silc_packet_context_dup(packet);
923 /* Let the protocol handle the packet */
924 sock->protocol->execute(client->timeout_queue, 0,
925 sock->protocol, sock->sock, 0, 0);
927 SilcClientKEInternalContext *proto_ctx =
928 (SilcClientKEInternalContext *)sock->protocol->context;
930 if (proto_ctx->packet)
931 silc_packet_context_free(proto_ctx->packet);
933 proto_ctx->packet = silc_packet_context_dup(packet);
934 proto_ctx->dest_id_type = packet->src_id_type;
935 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
936 packet->src_id_type);
937 if (!proto_ctx->dest_id)
940 /* Let the protocol handle the packet */
941 sock->protocol->execute(client->timeout_queue, 0,
942 sock->protocol, sock->sock, 0, 0);
945 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
946 "protocol active, packet dropped."));
949 case SILC_PACKET_KEY_EXCHANGE_2:
950 if (sock->protocol && sock->protocol->protocol &&
951 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
952 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
954 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
955 SilcClientRekeyInternalContext *proto_ctx =
956 (SilcClientRekeyInternalContext *)sock->protocol->context;
958 if (proto_ctx->packet)
959 silc_packet_context_free(proto_ctx->packet);
961 proto_ctx->packet = silc_packet_context_dup(packet);
963 /* Let the protocol handle the packet */
964 sock->protocol->execute(client->timeout_queue, 0,
965 sock->protocol, sock->sock, 0, 0);
967 SilcClientKEInternalContext *proto_ctx =
968 (SilcClientKEInternalContext *)sock->protocol->context;
970 if (proto_ctx->packet)
971 silc_packet_context_free(proto_ctx->packet);
973 proto_ctx->packet = silc_packet_context_dup(packet);
974 proto_ctx->dest_id_type = packet->src_id_type;
975 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
976 packet->src_id_type);
977 if (!proto_ctx->dest_id)
980 /* Let the protocol handle the packet */
981 sock->protocol->execute(client->timeout_queue, 0,
982 sock->protocol, sock->sock, 0, 0);
985 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
986 "protocol active, packet dropped."));
990 case SILC_PACKET_NEW_ID:
993 * Received new ID from server. This packet is received at
994 * the connection to the server. New ID is also received when
995 * user changes nickname but in that case the new ID is received
996 * as command reply and not as this packet type.
1000 idp = silc_id_payload_parse(buffer);
1003 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1006 silc_client_receive_new_id(client, sock, idp);
1007 silc_id_payload_free(idp);
1011 case SILC_PACKET_HEARTBEAT:
1013 * Received heartbeat packet
1015 SILC_LOG_DEBUG(("Heartbeat packet"));
1018 case SILC_PACKET_KEY_AGREEMENT:
1020 * Received key agreement packet
1022 SILC_LOG_DEBUG(("Key agreement packet"));
1023 silc_client_key_agreement(client, sock, packet);
1026 case SILC_PACKET_REKEY:
1027 SILC_LOG_DEBUG(("Re-key packet"));
1028 /* We ignore this for now */
1031 case SILC_PACKET_REKEY_DONE:
1032 SILC_LOG_DEBUG(("Re-key done packet"));
1034 if (sock->protocol && sock->protocol->protocol &&
1035 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1037 SilcClientRekeyInternalContext *proto_ctx =
1038 (SilcClientRekeyInternalContext *)sock->protocol->context;
1040 if (proto_ctx->packet)
1041 silc_packet_context_free(proto_ctx->packet);
1043 proto_ctx->packet = silc_packet_context_dup(packet);
1045 /* Let the protocol handle the packet */
1046 if (proto_ctx->responder == FALSE)
1047 sock->protocol->execute(client->timeout_queue, 0,
1048 sock->protocol, sock->sock, 0, 0);
1050 /* Let the protocol handle the packet */
1051 sock->protocol->execute(client->timeout_queue, 0,
1052 sock->protocol, sock->sock, 0, 100000);
1054 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1055 "protocol active, packet dropped."));
1060 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1065 /* Sends packet. This doesn't actually send the packet instead it assembles
1066 it and marks it to be sent. However, if force_send is TRUE the packet
1067 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1068 will be derived from sock argument. Otherwise the valid arguments sent
1071 void silc_client_packet_send(SilcClient client,
1072 SilcSocketConnection sock,
1073 SilcPacketType type,
1075 SilcIdType dst_id_type,
1078 unsigned char *data,
1082 SilcPacketContext packetdata;
1084 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1086 /* Get data used in the packet sending, keys and stuff */
1087 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1088 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1089 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1091 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1092 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1094 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1095 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1096 dst_id_type = SILC_ID_SERVER;
1100 /* Set the packet context pointers */
1101 packetdata.flags = 0;
1102 packetdata.type = type;
1103 if (sock->user_data &&
1104 ((SilcClientConnection)sock->user_data)->local_id_data)
1105 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1107 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1108 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1109 packetdata.src_id_type = SILC_ID_CLIENT;
1111 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1112 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1113 packetdata.dst_id_type = dst_id_type;
1115 packetdata.dst_id = NULL;
1116 packetdata.dst_id_len = 0;
1117 packetdata.dst_id_type = SILC_ID_NONE;
1119 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1120 packetdata.src_id_len + packetdata.dst_id_len;
1121 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1123 /* Prepare outgoing data buffer for packet sending */
1124 silc_packet_send_prepare(sock,
1125 SILC_PACKET_HEADER_LEN +
1126 packetdata.src_id_len +
1127 packetdata.dst_id_len,
1131 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1133 packetdata.buffer = sock->outbuf;
1135 /* Put the data to the buffer */
1136 if (data && data_len)
1137 silc_buffer_put(sock->outbuf, data, data_len);
1139 /* Create the outgoing packet */
1140 silc_packet_assemble(&packetdata);
1142 /* Encrypt the packet */
1144 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1146 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1147 sock->outbuf->data, sock->outbuf->len);
1149 /* Now actually send the packet */
1150 silc_client_packet_send_real(client, sock, force_send, FALSE);
1153 void silc_client_packet_send_flush(SilcClient client,
1154 SilcSocketConnection sock,
1155 SilcPacketType type,
1157 SilcIdType dst_id_type,
1160 unsigned char *data,
1163 SilcPacketContext packetdata;
1165 /* First flush the packet queue. */
1167 if (sock->outbuf->data - sock->outbuf->head)
1168 silc_buffer_push(sock->outbuf,
1169 sock->outbuf->data - sock->outbuf->head);
1171 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1173 /* The packet has been sent and now it is time to set the connection
1174 back to only for input. When there is again some outgoing data
1175 available for this connection it will be set for output as well.
1176 This call clears the output setting and sets it only for input. */
1177 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(sock->sock);
1178 SILC_UNSET_OUTBUF_PENDING(sock);
1179 silc_buffer_clear(sock->outbuf);
1181 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1183 /* Get data used in the packet sending, keys and stuff */
1184 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1185 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1186 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1188 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1189 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1191 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1192 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1193 dst_id_type = SILC_ID_SERVER;
1197 /* Set the packet context pointers */
1198 packetdata.flags = 0;
1199 packetdata.type = type;
1200 if (sock->user_data &&
1201 ((SilcClientConnection)sock->user_data)->local_id_data)
1202 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1204 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1205 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1206 packetdata.src_id_type = SILC_ID_CLIENT;
1208 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1209 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1210 packetdata.dst_id_type = dst_id_type;
1212 packetdata.dst_id = NULL;
1213 packetdata.dst_id_len = 0;
1214 packetdata.dst_id_type = SILC_ID_NONE;
1216 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1217 packetdata.src_id_len + packetdata.dst_id_len;
1218 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1220 /* Prepare outgoing data buffer for packet sending */
1221 silc_packet_send_prepare(sock,
1222 SILC_PACKET_HEADER_LEN +
1223 packetdata.src_id_len +
1224 packetdata.dst_id_len,
1228 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1230 packetdata.buffer = sock->outbuf;
1232 /* Put the data to the buffer */
1233 if (data && data_len)
1234 silc_buffer_put(sock->outbuf, data, data_len);
1236 /* Create the outgoing packet */
1237 silc_packet_assemble(&packetdata);
1239 /* Encrypt the packet */
1241 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1243 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1244 sock->outbuf->data, sock->outbuf->len);
1246 /* Now actually send the packet */
1247 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1250 /* Closes connection to remote end. Free's all allocated data except
1251 for some information such as nickname etc. that are valid at all time.
1252 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1253 provided it will be checked whether the sock and `conn->sock' are the
1254 same (they can be different, ie. a socket can use `conn' as its
1255 connection but `conn->sock' might be actually a different connection
1256 than the `sock'). */
1258 void silc_client_close_connection(SilcClient client,
1259 SilcSocketConnection sock,
1260 SilcClientConnection conn)
1264 if (!sock || (sock && conn->sock == sock))
1269 /* We won't listen for this connection anymore */
1270 silc_schedule_unset_listen_fd(sock->sock);
1272 /* Unregister all tasks */
1273 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1274 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1276 /* Close the actual connection */
1277 silc_net_close_connection(sock->sock);
1279 /* Free everything */
1280 if (del && sock->user_data) {
1281 /* XXX Free all client entries and channel entries. */
1283 client->ops->say(client, sock->user_data,
1284 "Closed connection to host %s", sock->hostname);
1286 /* Clear ID caches */
1287 silc_idcache_del_all(conn->client_cache);
1288 silc_idcache_del_all(conn->channel_cache);
1291 if (conn->remote_host)
1292 silc_free(conn->remote_host);
1294 silc_free(conn->local_id);
1295 if (conn->local_id_data)
1296 silc_free(conn->local_id_data);
1298 silc_cipher_free(conn->send_key);
1299 if (conn->receive_key)
1300 silc_cipher_free(conn->receive_key);
1301 if (conn->hmac_send) /* conn->hmac_receive is same */
1302 silc_hmac_free(conn->hmac_send);
1303 if (conn->pending_commands)
1304 silc_dlist_uninit(conn->pending_commands);
1306 silc_free(conn->rekey);
1309 conn->remote_port = 0;
1310 conn->remote_type = 0;
1311 conn->send_key = NULL;
1312 conn->receive_key = NULL;
1313 conn->hmac_send = NULL;
1314 conn->hmac_receive = NULL;
1315 conn->local_id = NULL;
1316 conn->local_id_data = NULL;
1317 conn->remote_host = NULL;
1318 conn->current_channel = NULL;
1319 conn->pending_commands = NULL;
1322 silc_client_del_connection(client, conn);
1325 if (sock->protocol) {
1326 silc_protocol_free(sock->protocol);
1327 sock->protocol = NULL;
1329 silc_socket_free(sock);
1332 /* Called when we receive disconnection packet from server. This
1333 closes our end properly and displays the reason of the disconnection
1336 void silc_client_disconnected_by_server(SilcClient client,
1337 SilcSocketConnection sock,
1342 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1344 msg = silc_calloc(message->len + 1, sizeof(char));
1345 memcpy(msg, message->data, message->len);
1346 client->ops->say(client, sock->user_data, msg);
1349 SILC_SET_DISCONNECTED(sock);
1350 silc_client_close_connection(client, sock, sock->user_data);
1353 /* Received error message from server. Display it on the screen.
1354 We don't take any action what so ever of the error message. */
1356 void silc_client_error_by_server(SilcClient client,
1357 SilcSocketConnection sock,
1362 msg = silc_calloc(message->len + 1, sizeof(char));
1363 memcpy(msg, message->data, message->len);
1364 client->ops->say(client, sock->user_data, msg);
1368 /* Processes the received new Client ID from server. Old Client ID is
1369 deleted from cache and new one is added. */
1371 void silc_client_receive_new_id(SilcClient client,
1372 SilcSocketConnection sock,
1375 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1376 int connecting = FALSE;
1378 if (!conn->local_entry)
1381 /* Delete old ID from ID cache */
1382 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1384 /* Save the new ID */
1386 silc_free(conn->local_id);
1387 if (conn->local_id_data)
1388 silc_free(conn->local_id_data);
1390 conn->local_id = silc_id_payload_get_id(idp);
1391 conn->local_id_data = silc_id_payload_get_data(idp);
1392 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1394 if (!conn->local_entry)
1395 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1397 conn->local_entry->nickname = conn->nickname;
1398 if (!conn->local_entry->username) {
1399 conn->local_entry->username =
1400 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1401 sizeof(conn->local_entry->username));
1402 sprintf(conn->local_entry->username, "%s@%s", client->username,
1405 conn->local_entry->server = strdup(conn->remote_host);
1406 conn->local_entry->id = conn->local_id;
1408 /* Put it to the ID cache */
1409 silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1410 SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1413 /* Notify application of successful connection. We do it here now that
1414 we've received the Client ID and are allowed to send traffic. */
1416 client->ops->connect(client, conn, TRUE);
1419 /* Processed received Channel ID for a channel. This is called when client
1420 joins to channel and server replies with channel ID. The ID is cached.
1421 Returns the created channel entry. */
1423 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1424 SilcSocketConnection sock,
1429 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1430 SilcChannelEntry channel;
1432 SILC_LOG_DEBUG(("New channel ID"));
1434 channel = silc_calloc(1, sizeof(*channel));
1435 channel->channel_name = channel_name;
1436 channel->id = silc_id_payload_get_id(idp);
1437 channel->mode = mode;
1438 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1440 conn->current_channel = channel;
1442 /* Put it to the ID cache */
1443 silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1444 SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
1450 /* Removes a client entry from all channel it has joined. This really is
1451 a performance killer (client_entry should have pointers to channel
1454 void silc_client_remove_from_channels(SilcClient client,
1455 SilcClientConnection conn,
1456 SilcClientEntry client_entry)
1458 SilcIDCacheEntry id_cache;
1459 SilcIDCacheList list;
1460 SilcChannelEntry channel;
1461 SilcChannelUser chu;
1463 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1464 SILC_ID_CHANNEL, &list))
1467 silc_idcache_list_first(list, &id_cache);
1468 channel = (SilcChannelEntry)id_cache->context;
1472 /* Remove client from channel */
1473 silc_list_start(channel->clients);
1474 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1475 if (chu->client == client_entry) {
1476 silc_list_del(channel->clients, chu);
1482 if (!silc_idcache_list_next(list, &id_cache))
1485 channel = (SilcChannelEntry)id_cache->context;
1488 silc_idcache_list_free(list);
1491 /* Replaces `old' client entries from all channels to `new' client entry.
1492 This can be called for example when nickname changes and old ID entry
1493 is replaced from ID cache with the new one. If the old ID entry is only
1494 updated, then this fucntion needs not to be called. */
1496 void silc_client_replace_from_channels(SilcClient client,
1497 SilcClientConnection conn,
1498 SilcClientEntry old,
1499 SilcClientEntry new)
1501 SilcIDCacheEntry id_cache;
1502 SilcIDCacheList list;
1503 SilcChannelEntry channel;
1504 SilcChannelUser chu;
1506 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1507 SILC_ID_CHANNEL, &list))
1510 silc_idcache_list_first(list, &id_cache);
1511 channel = (SilcChannelEntry)id_cache->context;
1515 /* Replace client entry */
1516 silc_list_start(channel->clients);
1517 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1518 if (chu->client == old) {
1524 if (!silc_idcache_list_next(list, &id_cache))
1527 channel = (SilcChannelEntry)id_cache->context;
1530 silc_idcache_list_free(list);
1533 /* Parses mode mask and returns the mode as string. */
1535 char *silc_client_chmode(uint32 mode, SilcChannelEntry channel)
1542 memset(string, 0, sizeof(string));
1544 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1545 strncat(string, "p", 1);
1547 if (mode & SILC_CHANNEL_MODE_SECRET)
1548 strncat(string, "s", 1);
1550 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1551 strncat(string, "k", 1);
1553 if (mode & SILC_CHANNEL_MODE_INVITE)
1554 strncat(string, "i", 1);
1556 if (mode & SILC_CHANNEL_MODE_TOPIC)
1557 strncat(string, "t", 1);
1559 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1560 strncat(string, "l", 1);
1562 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1563 strncat(string, "a", 1);
1565 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
1566 strncat(string, "f", 1);
1568 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1570 memset(cipher, 0, sizeof(cipher));
1571 snprintf(cipher, sizeof(cipher), " c (%s)",
1572 channel->channel_key->cipher->name);
1573 strncat(string, cipher, strlen(cipher));
1576 if (mode & SILC_CHANNEL_MODE_HMAC) {
1578 memset(hmac, 0, sizeof(hmac));
1579 snprintf(hmac, sizeof(hmac), " h (%s)",
1580 channel->hmac->hmac->name);
1581 strncat(string, hmac, strlen(hmac));
1584 /* Rest of mode is ignored */
1586 return strdup(string);
1589 /* Parses channel user mode mask and returns te mode as string */
1591 char *silc_client_chumode(uint32 mode)
1598 memset(string, 0, sizeof(string));
1600 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1601 strncat(string, "f", 1);
1603 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1604 strncat(string, "o", 1);
1606 return strdup(string);
1609 /* Parses channel user mode and returns it as special mode character. */
1611 char *silc_client_chumode_char(uint32 mode)
1618 memset(string, 0, sizeof(string));
1620 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1621 strncat(string, "*", 1);
1623 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1624 strncat(string, "@", 1);
1626 return strdup(string);
1629 /* Failure timeout callback. If this is called then we will immediately
1630 process the received failure. We always process the failure with timeout
1631 since we do not want to blindly trust to received failure packets.
1632 This won't be called (the timeout is cancelled) if the failure was
1633 bogus (it is bogus if remote does not close the connection after sending
1636 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1638 SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1640 if (f->sock->protocol) {
1641 f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1642 f->sock->protocol->execute(f->client->timeout_queue, 0,
1643 f->sock->protocol, f->sock->sock, 0, 0);
1645 /* Notify application */
1646 f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1647 (void *)f->failure);
1653 /* Registers failure timeout to process the received failure packet
1656 void silc_client_process_failure(SilcClient client,
1657 SilcSocketConnection sock,
1658 SilcPacketContext *packet)
1660 SilcClientFailureContext *f;
1663 if (sock->protocol) {
1664 if (packet->buffer->len >= 4)
1665 SILC_GET32_MSB(failure, packet->buffer->data);
1667 f = silc_calloc(1, sizeof(*f));
1670 f->failure = failure;
1672 /* We will wait 5 seconds to process this failure packet */
1673 silc_task_register(client->timeout_queue, sock->sock,
1674 silc_client_failure_callback, (void *)f, 5, 0,
1675 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1679 /* A timeout callback for the re-key. We will be the initiator of the
1682 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1684 SilcSocketConnection sock = (SilcSocketConnection)context;
1685 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1686 SilcClient client = (SilcClient)conn->rekey->context;
1687 SilcProtocol protocol;
1688 SilcClientRekeyInternalContext *proto_ctx;
1690 SILC_LOG_DEBUG(("Start"));
1692 /* Allocate internal protocol context. This is sent as context
1694 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1695 proto_ctx->client = (void *)client;
1696 proto_ctx->sock = sock;
1697 proto_ctx->responder = FALSE;
1698 proto_ctx->pfs = conn->rekey->pfs;
1700 /* Perform rekey protocol. Will call the final callback after the
1701 protocol is over. */
1702 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1703 &protocol, proto_ctx, silc_client_rekey_final);
1704 sock->protocol = protocol;
1706 /* Run the protocol */
1707 protocol->execute(client->timeout_queue, 0, protocol,
1710 /* Re-register re-key timeout */
1711 silc_task_register(client->timeout_queue, sock->sock,
1712 silc_client_rekey_callback,
1713 context, conn->rekey->timeout, 0,
1714 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1717 /* The final callback for the REKEY protocol. This will actually take the
1718 new key material into use. */
1720 SILC_TASK_CALLBACK(silc_client_rekey_final)
1722 SilcProtocol protocol = (SilcProtocol)context;
1723 SilcClientRekeyInternalContext *ctx =
1724 (SilcClientRekeyInternalContext *)protocol->context;
1725 SilcClient client = (SilcClient)ctx->client;
1726 SilcSocketConnection sock = ctx->sock;
1728 SILC_LOG_DEBUG(("Start"));
1730 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1731 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1732 /* Error occured during protocol */
1733 silc_protocol_cancel(client->timeout_queue, protocol);
1734 silc_protocol_free(protocol);
1735 sock->protocol = NULL;
1737 silc_packet_context_free(ctx->packet);
1739 silc_ske_free(ctx->ske);
1745 /* Take the keys into use */
1746 if (ctx->pfs == TRUE)
1747 silc_client_protocol_rekey_generate_pfs(client, ctx);
1749 silc_client_protocol_rekey_generate(client, ctx);
1753 silc_protocol_free(protocol);
1754 sock->protocol = NULL;
1756 silc_packet_context_free(ctx->packet);
1758 silc_ske_free(ctx->ske);