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;
438 /* Notify application of failure */
439 client->ops->connect(client, ctx->sock->user_data, FALSE);
444 /* We now have the key material as the result of the key exchange
445 protocol. Take the key material into use. Free the raw key material
446 as soon as we've set them into use. */
447 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
448 ctx->ske->prop->cipher,
449 ctx->ske->prop->pkcs,
450 ctx->ske->prop->hash,
451 ctx->ske->prop->hmac,
452 ctx->ske->prop->group);
453 silc_ske_free_key_material(ctx->keymat);
455 /* Allocate internal context for the authentication protocol. This
456 is sent as context for the protocol. */
457 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
458 proto_ctx->client = (void *)client;
459 proto_ctx->sock = sock = ctx->sock;
460 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
461 proto_ctx->dest_id_type = ctx->dest_id_type;
462 proto_ctx->dest_id = ctx->dest_id;
464 /* Resolve the authentication method to be used in this connection */
465 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
466 sock->port, &proto_ctx->auth_meth,
467 &proto_ctx->auth_data,
468 &proto_ctx->auth_data_len)) {
469 client->ops->say(client, ctx->sock->user_data,
470 "Could not resolve authentication method to use, "
471 "assume no authentication");
472 proto_ctx->auth_meth = SILC_AUTH_NONE;
475 /* Free old protocol as it is finished now */
476 silc_protocol_free(protocol);
478 silc_packet_context_free(ctx->packet);
480 sock->protocol = NULL;
482 /* Allocate the authentication protocol. This is allocated here
483 but we won't start it yet. We will be receiving party of this
484 protocol thus we will wait that connecting party will make
486 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
487 &sock->protocol, (void *)proto_ctx,
488 silc_client_connect_to_server_final);
490 /* Execute the protocol */
491 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
494 /* Finalizes the connection to the remote SILC server. This is called
495 after authentication protocol has been completed. This send our
496 user information to the server to receive our client ID from
499 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
501 SilcProtocol protocol = (SilcProtocol)context;
502 SilcClientConnAuthInternalContext *ctx =
503 (SilcClientConnAuthInternalContext *)protocol->context;
504 SilcClient client = (SilcClient)ctx->client;
505 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
508 SILC_LOG_DEBUG(("Start"));
510 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
511 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
512 /* Error occured during protocol */
513 SILC_LOG_DEBUG(("Error during authentication protocol"));
514 silc_protocol_free(protocol);
516 silc_free(ctx->auth_data);
518 silc_ske_free(ctx->ske);
520 silc_free(ctx->dest_id);
521 conn->sock->protocol = NULL;
523 /* Notify application of failure */
524 client->ops->connect(client, ctx->sock->user_data, FALSE);
529 /* Send NEW_CLIENT packet to the server. We will become registered
530 to the SILC network after sending this packet and we will receive
531 client ID from the server. */
532 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
533 strlen(client->realname));
534 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
535 silc_buffer_format(packet,
536 SILC_STR_UI_SHORT(strlen(client->username)),
537 SILC_STR_UI_XNSTRING(client->username,
538 strlen(client->username)),
539 SILC_STR_UI_SHORT(strlen(client->realname)),
540 SILC_STR_UI_XNSTRING(client->realname,
541 strlen(client->realname)),
544 /* Send the packet */
545 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
547 packet->data, packet->len, TRUE);
548 silc_buffer_free(packet);
550 /* Save remote ID. */
551 conn->remote_id = ctx->dest_id;
552 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
553 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
555 /* Register re-key timeout */
556 conn->rekey->timeout = 3600; /* XXX hardcoded */
557 conn->rekey->context = (void *)client;
558 silc_task_register(client->timeout_queue, conn->sock->sock,
559 silc_client_rekey_callback,
560 (void *)conn->sock, conn->rekey->timeout, 0,
561 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
563 silc_protocol_free(protocol);
565 silc_free(ctx->auth_data);
567 silc_ske_free(ctx->ske);
569 conn->sock->protocol = NULL;
572 /* Internal routine that sends packet or marks packet to be sent. This
573 is used directly only in special cases. Normal cases should use
574 silc_server_packet_send. Returns < 0 on error. */
576 int silc_client_packet_send_real(SilcClient client,
577 SilcSocketConnection sock,
583 /* If rekey protocol is active we must assure that all packets are
584 sent through packet queue. */
585 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
588 /* Send the packet */
589 ret = silc_packet_send(sock, force_send);
593 /* Mark that there is some outgoing data available for this connection.
594 This call sets the connection both for input and output (the input
595 is set always and this call keeps the input setting, actually).
596 Actual data sending is performed by silc_client_packet_process. */
597 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
599 /* Mark to socket that data is pending in outgoing buffer. This flag
600 is needed if new data is added to the buffer before the earlier
601 put data is sent to the network. */
602 SILC_SET_OUTBUF_PENDING(sock);
607 /* Packet processing callback. This is used to send and receive packets
608 from network. This is generic task. */
610 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
612 SilcClient client = (SilcClient)context;
613 SilcSocketConnection sock = NULL;
614 SilcClientConnection conn;
617 SILC_LOG_DEBUG(("Processing packet"));
619 SILC_CLIENT_GET_SOCK(client, fd, sock);
623 conn = (SilcClientConnection)sock->user_data;
626 if (type == SILC_TASK_WRITE) {
627 SILC_LOG_DEBUG(("Writing data to connection"));
629 if (sock->outbuf->data - sock->outbuf->head)
630 silc_buffer_push(sock->outbuf,
631 sock->outbuf->data - sock->outbuf->head);
633 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
635 /* If returned -2 could not write to connection now, will do
640 /* The packet has been sent and now it is time to set the connection
641 back to only for input. When there is again some outgoing data
642 available for this connection it will be set for output as well.
643 This call clears the output setting and sets it only for input. */
644 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
645 SILC_UNSET_OUTBUF_PENDING(sock);
647 silc_buffer_clear(sock->outbuf);
651 /* Packet receiving */
652 if (type == SILC_TASK_READ) {
653 SILC_LOG_DEBUG(("Reading data from connection"));
655 /* Read data from network */
656 ret = silc_packet_receive(sock);
662 SILC_LOG_DEBUG(("Read EOF"));
664 /* If connection is disconnecting already we will finally
665 close the connection */
666 if (SILC_IS_DISCONNECTING(sock)) {
667 if (sock == conn->sock)
668 client->ops->disconnect(client, conn);
669 silc_client_close_connection(client, sock, conn);
673 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
674 if (sock == conn->sock)
675 client->ops->disconnect(client, conn);
676 silc_client_close_connection(client, sock, conn);
680 /* Process the packet. This will call the parser that will then
681 decrypt and parse the packet. */
682 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
683 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
684 silc_client_packet_parse, client);
686 silc_packet_receive_process(sock, NULL, NULL,
687 silc_client_packet_parse, client);
691 /* Callback function that the silc_packet_decrypt will call to make the
692 decision whether the packet is normal or special packet. We will
693 return TRUE if it is normal and FALSE if it is special */
695 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
697 SilcPacketContext *packet,
701 /* Packet is normal packet, if:
703 1) packet is private message packet and does not have private key set
704 2) is other packet than channel message packet
706 all other packets are special packets
709 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
710 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
713 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
719 /* Parses whole packet, received earlier. */
721 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
723 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
724 SilcClient client = (SilcClient)parse_ctx->context;
725 SilcPacketContext *packet = parse_ctx->packet;
726 SilcBuffer buffer = packet->buffer;
727 SilcSocketConnection sock = parse_ctx->sock;
728 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
731 SILC_LOG_DEBUG(("Start"));
733 /* Decrypt the received packet */
734 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
735 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
737 silc_client_packet_decrypt_check, parse_ctx);
739 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
740 silc_client_packet_decrypt_check, parse_ctx);
746 /* Parse the packet. Packet type is returned. */
747 ret = silc_packet_parse(packet);
749 /* Parse the packet header in special way as this is "special"
751 ret = silc_packet_parse_special(packet);
754 if (ret == SILC_PACKET_NONE)
757 /* Parse the incoming packet type */
758 silc_client_packet_parse_type(client, sock, packet);
761 /* silc_buffer_clear(sock->inbuf); */
762 silc_packet_context_free(packet);
763 silc_free(parse_ctx);
766 /* Parser callback called by silc_packet_receive_process. Thie merely
767 registers timeout that will handle the actual parsing when appropriate. */
769 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
771 SilcClient client = (SilcClient)parser_context->context;
773 /* Parse the packet */
774 silc_task_register(client->timeout_queue, parser_context->sock->sock,
775 silc_client_packet_parse_real,
776 (void *)parser_context, 0, 1,
778 SILC_TASK_PRI_NORMAL);
781 /* Parses the packet type and calls what ever routines the packet type
782 requires. This is done for all incoming packets. */
784 void silc_client_packet_parse_type(SilcClient client,
785 SilcSocketConnection sock,
786 SilcPacketContext *packet)
788 SilcBuffer buffer = packet->buffer;
789 SilcPacketType type = packet->type;
791 SILC_LOG_DEBUG(("Parsing packet type %d", type));
793 /* Parse the packet type */
795 case SILC_PACKET_DISCONNECT:
796 silc_client_disconnected_by_server(client, sock, buffer);
798 case SILC_PACKET_SUCCESS:
800 * Success received for something. For now we can have only
801 * one protocol for connection executing at once hence this
802 * success message is for whatever protocol is executing currently.
804 if (sock->protocol) {
805 sock->protocol->execute(client->timeout_queue, 0,
806 sock->protocol, sock->sock, 0, 0);
809 case SILC_PACKET_FAILURE:
811 * Failure received for some protocol. Set the protocol state to
812 * error and call the protocol callback. This fill cause error on
813 * protocol and it will call the final callback.
815 silc_client_process_failure(client, sock, packet);
817 case SILC_PACKET_REJECT:
820 case SILC_PACKET_NOTIFY:
822 * Received notify message
824 silc_client_notify_by_server(client, sock, packet);
827 case SILC_PACKET_ERROR:
829 * Received error message
831 silc_client_error_by_server(client, sock, buffer);
834 case SILC_PACKET_CHANNEL_MESSAGE:
836 * Received message to (from, actually) a channel
838 silc_client_channel_message(client, sock, packet);
840 case SILC_PACKET_CHANNEL_KEY:
842 * Received key for a channel. By receiving this key the client will be
843 * able to talk to the channel it has just joined. This can also be
844 * a new key for existing channel as keys expire peridiocally.
846 silc_client_receive_channel_key(client, sock, buffer);
849 case SILC_PACKET_PRIVATE_MESSAGE:
851 * Received private message
853 silc_client_private_message(client, sock, packet);
855 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
857 * Received private message key
861 case SILC_PACKET_COMMAND_REPLY:
863 * Recived reply for a command
865 silc_client_command_reply_process(client, sock, packet);
868 case SILC_PACKET_KEY_EXCHANGE:
869 if (sock->protocol && sock->protocol->protocol &&
870 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
871 SilcClientKEInternalContext *proto_ctx =
872 (SilcClientKEInternalContext *)sock->protocol->context;
874 proto_ctx->packet = silc_packet_context_dup(packet);
875 proto_ctx->dest_id_type = packet->src_id_type;
876 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
877 packet->src_id_type);
878 if (!proto_ctx->dest_id)
881 /* Let the protocol handle the packet */
882 sock->protocol->execute(client->timeout_queue, 0,
883 sock->protocol, sock->sock, 0, 0);
885 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
886 "protocol active, packet dropped."));
888 /* XXX Trigger KE protocol?? Rekey actually! */
892 case SILC_PACKET_KEY_EXCHANGE_1:
893 if (sock->protocol && sock->protocol->protocol &&
894 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
895 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
897 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
898 SilcClientRekeyInternalContext *proto_ctx =
899 (SilcClientRekeyInternalContext *)sock->protocol->context;
901 if (proto_ctx->packet)
902 silc_packet_context_free(proto_ctx->packet);
904 proto_ctx->packet = silc_packet_context_dup(packet);
906 /* Let the protocol handle the packet */
907 sock->protocol->execute(client->timeout_queue, 0,
908 sock->protocol, sock->sock, 0, 0);
910 SilcClientKEInternalContext *proto_ctx =
911 (SilcClientKEInternalContext *)sock->protocol->context;
913 if (proto_ctx->packet)
914 silc_packet_context_free(proto_ctx->packet);
916 proto_ctx->packet = silc_packet_context_dup(packet);
917 proto_ctx->dest_id_type = packet->src_id_type;
918 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
919 packet->src_id_type);
920 if (!proto_ctx->dest_id)
923 /* Let the protocol handle the packet */
924 sock->protocol->execute(client->timeout_queue, 0,
925 sock->protocol, sock->sock, 0, 0);
928 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
929 "protocol active, packet dropped."));
932 case SILC_PACKET_KEY_EXCHANGE_2:
933 if (sock->protocol && sock->protocol->protocol &&
934 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
935 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
937 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
938 SilcClientRekeyInternalContext *proto_ctx =
939 (SilcClientRekeyInternalContext *)sock->protocol->context;
941 if (proto_ctx->packet)
942 silc_packet_context_free(proto_ctx->packet);
944 proto_ctx->packet = silc_packet_context_dup(packet);
946 /* Let the protocol handle the packet */
947 sock->protocol->execute(client->timeout_queue, 0,
948 sock->protocol, sock->sock, 0, 0);
950 SilcClientKEInternalContext *proto_ctx =
951 (SilcClientKEInternalContext *)sock->protocol->context;
953 if (proto_ctx->packet)
954 silc_packet_context_free(proto_ctx->packet);
956 proto_ctx->packet = silc_packet_context_dup(packet);
957 proto_ctx->dest_id_type = packet->src_id_type;
958 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
959 packet->src_id_type);
960 if (!proto_ctx->dest_id)
963 /* Let the protocol handle the packet */
964 sock->protocol->execute(client->timeout_queue, 0,
965 sock->protocol, sock->sock, 0, 0);
968 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
969 "protocol active, packet dropped."));
973 case SILC_PACKET_NEW_ID:
976 * Received new ID from server. This packet is received at
977 * the connection to the server. New ID is also received when
978 * user changes nickname but in that case the new ID is received
979 * as command reply and not as this packet type.
983 idp = silc_id_payload_parse(buffer);
986 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
989 silc_client_receive_new_id(client, sock, idp);
990 silc_id_payload_free(idp);
994 case SILC_PACKET_HEARTBEAT:
996 * Received heartbeat packet
998 SILC_LOG_DEBUG(("Heartbeat packet"));
1001 case SILC_PACKET_KEY_AGREEMENT:
1003 * Received key agreement packet
1005 SILC_LOG_DEBUG(("Key agreement packet"));
1006 silc_client_key_agreement(client, sock, packet);
1009 case SILC_PACKET_REKEY:
1010 SILC_LOG_DEBUG(("Re-key packet"));
1011 /* We ignore this for now */
1014 case SILC_PACKET_REKEY_DONE:
1015 SILC_LOG_DEBUG(("Re-key done packet"));
1017 if (sock->protocol && sock->protocol->protocol &&
1018 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1020 SilcClientRekeyInternalContext *proto_ctx =
1021 (SilcClientRekeyInternalContext *)sock->protocol->context;
1023 if (proto_ctx->packet)
1024 silc_packet_context_free(proto_ctx->packet);
1026 proto_ctx->packet = silc_packet_context_dup(packet);
1028 /* Let the protocol handle the packet */
1029 if (proto_ctx->responder == FALSE)
1030 sock->protocol->execute(client->timeout_queue, 0,
1031 sock->protocol, sock->sock, 0, 0);
1033 /* Let the protocol handle the packet */
1034 sock->protocol->execute(client->timeout_queue, 0,
1035 sock->protocol, sock->sock, 0, 100000);
1037 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1038 "protocol active, packet dropped."));
1043 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1048 /* Sends packet. This doesn't actually send the packet instead it assembles
1049 it and marks it to be sent. However, if force_send is TRUE the packet
1050 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1051 will be derived from sock argument. Otherwise the valid arguments sent
1054 void silc_client_packet_send(SilcClient client,
1055 SilcSocketConnection sock,
1056 SilcPacketType type,
1058 SilcIdType dst_id_type,
1061 unsigned char *data,
1065 SilcPacketContext packetdata;
1067 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1069 /* Get data used in the packet sending, keys and stuff */
1070 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1071 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1072 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1074 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1075 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1077 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1078 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1079 dst_id_type = SILC_ID_SERVER;
1083 /* Set the packet context pointers */
1084 packetdata.flags = 0;
1085 packetdata.type = type;
1086 if (sock->user_data &&
1087 ((SilcClientConnection)sock->user_data)->local_id_data)
1088 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1090 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1091 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1092 packetdata.src_id_type = SILC_ID_CLIENT;
1094 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1095 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1096 packetdata.dst_id_type = dst_id_type;
1098 packetdata.dst_id = NULL;
1099 packetdata.dst_id_len = 0;
1100 packetdata.dst_id_type = SILC_ID_NONE;
1102 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1103 packetdata.src_id_len + packetdata.dst_id_len;
1104 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1106 /* Prepare outgoing data buffer for packet sending */
1107 silc_packet_send_prepare(sock,
1108 SILC_PACKET_HEADER_LEN +
1109 packetdata.src_id_len +
1110 packetdata.dst_id_len,
1114 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1116 packetdata.buffer = sock->outbuf;
1118 /* Put the data to the buffer */
1119 if (data && data_len)
1120 silc_buffer_put(sock->outbuf, data, data_len);
1122 /* Create the outgoing packet */
1123 silc_packet_assemble(&packetdata);
1125 /* Encrypt the packet */
1127 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1129 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1130 sock->outbuf->data, sock->outbuf->len);
1132 /* Now actually send the packet */
1133 silc_client_packet_send_real(client, sock, force_send, FALSE);
1136 void silc_client_packet_send_flush(SilcClient client,
1137 SilcSocketConnection sock,
1138 SilcPacketType type,
1140 SilcIdType dst_id_type,
1143 unsigned char *data,
1146 SilcPacketContext packetdata;
1148 /* First flush the packet queue. */
1150 if (sock->outbuf->data - sock->outbuf->head)
1151 silc_buffer_push(sock->outbuf,
1152 sock->outbuf->data - sock->outbuf->head);
1154 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1156 /* The packet has been sent and now it is time to set the connection
1157 back to only for input. When there is again some outgoing data
1158 available for this connection it will be set for output as well.
1159 This call clears the output setting and sets it only for input. */
1160 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(sock->sock);
1161 SILC_UNSET_OUTBUF_PENDING(sock);
1162 silc_buffer_clear(sock->outbuf);
1164 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1166 /* Get data used in the packet sending, keys and stuff */
1167 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1168 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1169 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1171 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1172 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1174 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1175 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1176 dst_id_type = SILC_ID_SERVER;
1180 /* Set the packet context pointers */
1181 packetdata.flags = 0;
1182 packetdata.type = type;
1183 if (sock->user_data &&
1184 ((SilcClientConnection)sock->user_data)->local_id_data)
1185 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1187 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1188 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1189 packetdata.src_id_type = SILC_ID_CLIENT;
1191 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1192 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1193 packetdata.dst_id_type = dst_id_type;
1195 packetdata.dst_id = NULL;
1196 packetdata.dst_id_len = 0;
1197 packetdata.dst_id_type = SILC_ID_NONE;
1199 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1200 packetdata.src_id_len + packetdata.dst_id_len;
1201 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1203 /* Prepare outgoing data buffer for packet sending */
1204 silc_packet_send_prepare(sock,
1205 SILC_PACKET_HEADER_LEN +
1206 packetdata.src_id_len +
1207 packetdata.dst_id_len,
1211 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1213 packetdata.buffer = sock->outbuf;
1215 /* Put the data to the buffer */
1216 if (data && data_len)
1217 silc_buffer_put(sock->outbuf, data, data_len);
1219 /* Create the outgoing packet */
1220 silc_packet_assemble(&packetdata);
1222 /* Encrypt the packet */
1224 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1226 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1227 sock->outbuf->data, sock->outbuf->len);
1229 /* Now actually send the packet */
1230 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1233 /* Closes connection to remote end. Free's all allocated data except
1234 for some information such as nickname etc. that are valid at all time.
1235 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1236 provided it will be checked whether the sock and `conn->sock' are the
1237 same (they can be different, ie. a socket can use `conn' as its
1238 connection but `conn->sock' might be actually a different connection
1239 than the `sock'). */
1241 void silc_client_close_connection(SilcClient client,
1242 SilcSocketConnection sock,
1243 SilcClientConnection conn)
1247 if (!sock || (sock && conn->sock == sock))
1252 /* We won't listen for this connection anymore */
1253 silc_schedule_unset_listen_fd(sock->sock);
1255 /* Unregister all tasks */
1256 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1257 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1259 /* Close the actual connection */
1260 silc_net_close_connection(sock->sock);
1262 /* Free everything */
1263 if (del && sock->user_data) {
1264 /* XXX Free all client entries and channel entries. */
1266 client->ops->say(client, sock->user_data,
1267 "Closed connection to host %s", sock->hostname);
1269 /* Clear ID caches */
1270 silc_idcache_del_all(conn->client_cache);
1271 silc_idcache_del_all(conn->channel_cache);
1274 if (conn->remote_host)
1275 silc_free(conn->remote_host);
1277 silc_free(conn->local_id);
1278 if (conn->local_id_data)
1279 silc_free(conn->local_id_data);
1281 silc_cipher_free(conn->send_key);
1282 if (conn->receive_key)
1283 silc_cipher_free(conn->receive_key);
1284 if (conn->hmac_send) /* conn->hmac_receive is same */
1285 silc_hmac_free(conn->hmac_send);
1286 if (conn->pending_commands)
1287 silc_dlist_uninit(conn->pending_commands);
1289 silc_free(conn->rekey);
1292 conn->remote_port = 0;
1293 conn->remote_type = 0;
1294 conn->send_key = NULL;
1295 conn->receive_key = NULL;
1296 conn->hmac_send = NULL;
1297 conn->hmac_receive = NULL;
1298 conn->local_id = NULL;
1299 conn->local_id_data = NULL;
1300 conn->remote_host = NULL;
1301 conn->current_channel = NULL;
1302 conn->pending_commands = NULL;
1305 silc_client_del_connection(client, conn);
1308 if (sock->protocol) {
1309 silc_protocol_free(sock->protocol);
1310 sock->protocol = NULL;
1312 silc_socket_free(sock);
1315 /* Called when we receive disconnection packet from server. This
1316 closes our end properly and displays the reason of the disconnection
1319 void silc_client_disconnected_by_server(SilcClient client,
1320 SilcSocketConnection sock,
1325 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1327 msg = silc_calloc(message->len + 1, sizeof(char));
1328 memcpy(msg, message->data, message->len);
1329 client->ops->say(client, sock->user_data, msg);
1332 SILC_SET_DISCONNECTED(sock);
1333 silc_client_close_connection(client, sock, sock->user_data);
1336 /* Received error message from server. Display it on the screen.
1337 We don't take any action what so ever of the error message. */
1339 void silc_client_error_by_server(SilcClient client,
1340 SilcSocketConnection sock,
1345 msg = silc_calloc(message->len + 1, sizeof(char));
1346 memcpy(msg, message->data, message->len);
1347 client->ops->say(client, sock->user_data, msg);
1351 /* Processes the received new Client ID from server. Old Client ID is
1352 deleted from cache and new one is added. */
1354 void silc_client_receive_new_id(SilcClient client,
1355 SilcSocketConnection sock,
1358 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1359 int connecting = FALSE;
1361 if (!conn->local_entry)
1364 /* Delete old ID from ID cache */
1365 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1367 /* Save the new ID */
1369 silc_free(conn->local_id);
1370 if (conn->local_id_data)
1371 silc_free(conn->local_id_data);
1373 conn->local_id = silc_id_payload_get_id(idp);
1374 conn->local_id_data = silc_id_payload_get_data(idp);
1375 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1377 if (!conn->local_entry)
1378 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1380 conn->local_entry->nickname = conn->nickname;
1381 if (!conn->local_entry->username) {
1382 conn->local_entry->username =
1383 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1384 sizeof(conn->local_entry->username));
1385 sprintf(conn->local_entry->username, "%s@%s", client->username,
1388 conn->local_entry->server = strdup(conn->remote_host);
1389 conn->local_entry->id = conn->local_id;
1391 /* Put it to the ID cache */
1392 silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1393 SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1396 /* Notify application of successful connection. We do it here now that
1397 we've received the Client ID and are allowed to send traffic. */
1399 client->ops->connect(client, conn, TRUE);
1402 /* Processed received Channel ID for a channel. This is called when client
1403 joins to channel and server replies with channel ID. The ID is cached.
1404 Returns the created channel entry. */
1406 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1407 SilcSocketConnection sock,
1412 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1413 SilcChannelEntry channel;
1415 SILC_LOG_DEBUG(("New channel ID"));
1417 channel = silc_calloc(1, sizeof(*channel));
1418 channel->channel_name = channel_name;
1419 channel->id = silc_id_payload_get_id(idp);
1420 channel->mode = mode;
1421 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1423 conn->current_channel = channel;
1425 /* Put it to the ID cache */
1426 silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1427 SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
1433 /* Removes a client entry from all channel it has joined. This really is
1434 a performance killer (client_entry should have pointers to channel
1437 void silc_client_remove_from_channels(SilcClient client,
1438 SilcClientConnection conn,
1439 SilcClientEntry client_entry)
1441 SilcIDCacheEntry id_cache;
1442 SilcIDCacheList list;
1443 SilcChannelEntry channel;
1444 SilcChannelUser chu;
1446 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1447 SILC_ID_CHANNEL, &list))
1450 silc_idcache_list_first(list, &id_cache);
1451 channel = (SilcChannelEntry)id_cache->context;
1455 /* Remove client from channel */
1456 silc_list_start(channel->clients);
1457 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1458 if (chu->client == client_entry) {
1459 silc_list_del(channel->clients, chu);
1465 if (!silc_idcache_list_next(list, &id_cache))
1468 channel = (SilcChannelEntry)id_cache->context;
1471 silc_idcache_list_free(list);
1474 /* Replaces `old' client entries from all channels to `new' client entry.
1475 This can be called for example when nickname changes and old ID entry
1476 is replaced from ID cache with the new one. If the old ID entry is only
1477 updated, then this fucntion needs not to be called. */
1479 void silc_client_replace_from_channels(SilcClient client,
1480 SilcClientConnection conn,
1481 SilcClientEntry old,
1482 SilcClientEntry new)
1484 SilcIDCacheEntry id_cache;
1485 SilcIDCacheList list;
1486 SilcChannelEntry channel;
1487 SilcChannelUser chu;
1489 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1490 SILC_ID_CHANNEL, &list))
1493 silc_idcache_list_first(list, &id_cache);
1494 channel = (SilcChannelEntry)id_cache->context;
1498 /* Replace client entry */
1499 silc_list_start(channel->clients);
1500 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1501 if (chu->client == old) {
1507 if (!silc_idcache_list_next(list, &id_cache))
1510 channel = (SilcChannelEntry)id_cache->context;
1513 silc_idcache_list_free(list);
1516 /* Parses mode mask and returns the mode as string. */
1518 char *silc_client_chmode(uint32 mode, SilcChannelEntry channel)
1525 memset(string, 0, sizeof(string));
1527 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1528 strncat(string, "p", 1);
1530 if (mode & SILC_CHANNEL_MODE_SECRET)
1531 strncat(string, "s", 1);
1533 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1534 strncat(string, "k", 1);
1536 if (mode & SILC_CHANNEL_MODE_INVITE)
1537 strncat(string, "i", 1);
1539 if (mode & SILC_CHANNEL_MODE_TOPIC)
1540 strncat(string, "t", 1);
1542 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1543 strncat(string, "l", 1);
1545 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1546 strncat(string, "a", 1);
1548 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
1549 strncat(string, "f", 1);
1551 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1553 memset(cipher, 0, sizeof(cipher));
1554 snprintf(cipher, sizeof(cipher), " c (%s)",
1555 channel->channel_key->cipher->name);
1556 strncat(string, cipher, strlen(cipher));
1559 if (mode & SILC_CHANNEL_MODE_HMAC) {
1561 memset(hmac, 0, sizeof(hmac));
1562 snprintf(hmac, sizeof(hmac), " h (%s)",
1563 channel->hmac->hmac->name);
1564 strncat(string, hmac, strlen(hmac));
1567 /* Rest of mode is ignored */
1569 return strdup(string);
1572 /* Parses channel user mode mask and returns te mode as string */
1574 char *silc_client_chumode(uint32 mode)
1581 memset(string, 0, sizeof(string));
1583 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1584 strncat(string, "f", 1);
1586 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1587 strncat(string, "o", 1);
1589 return strdup(string);
1592 /* Parses channel user mode and returns it as special mode character. */
1594 char *silc_client_chumode_char(uint32 mode)
1601 memset(string, 0, sizeof(string));
1603 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1604 strncat(string, "*", 1);
1606 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1607 strncat(string, "@", 1);
1609 return strdup(string);
1612 /* Registers failure timeout to process the received failure packet
1615 void silc_client_process_failure(SilcClient client,
1616 SilcSocketConnection sock,
1617 SilcPacketContext *packet)
1621 if (sock->protocol) {
1622 if (packet->buffer->len >= 4)
1623 SILC_GET32_MSB(failure, packet->buffer->data);
1625 /* Notify application */
1626 client->ops->failure(client, sock->user_data, sock->protocol,
1631 /* A timeout callback for the re-key. We will be the initiator of the
1634 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1636 SilcSocketConnection sock = (SilcSocketConnection)context;
1637 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1638 SilcClient client = (SilcClient)conn->rekey->context;
1639 SilcProtocol protocol;
1640 SilcClientRekeyInternalContext *proto_ctx;
1642 SILC_LOG_DEBUG(("Start"));
1644 /* Allocate internal protocol context. This is sent as context
1646 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1647 proto_ctx->client = (void *)client;
1648 proto_ctx->sock = sock;
1649 proto_ctx->responder = FALSE;
1650 proto_ctx->pfs = conn->rekey->pfs;
1652 /* Perform rekey protocol. Will call the final callback after the
1653 protocol is over. */
1654 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1655 &protocol, proto_ctx, silc_client_rekey_final);
1656 sock->protocol = protocol;
1658 /* Run the protocol */
1659 protocol->execute(client->timeout_queue, 0, protocol,
1662 /* Re-register re-key timeout */
1663 silc_task_register(client->timeout_queue, sock->sock,
1664 silc_client_rekey_callback,
1665 context, conn->rekey->timeout, 0,
1666 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1669 /* The final callback for the REKEY protocol. This will actually take the
1670 new key material into use. */
1672 SILC_TASK_CALLBACK(silc_client_rekey_final)
1674 SilcProtocol protocol = (SilcProtocol)context;
1675 SilcClientRekeyInternalContext *ctx =
1676 (SilcClientRekeyInternalContext *)protocol->context;
1677 SilcClient client = (SilcClient)ctx->client;
1678 SilcSocketConnection sock = ctx->sock;
1680 SILC_LOG_DEBUG(("Start"));
1682 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1683 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1684 /* Error occured during protocol */
1685 silc_protocol_cancel(client->timeout_queue, protocol);
1686 silc_protocol_free(protocol);
1687 sock->protocol = NULL;
1689 silc_packet_context_free(ctx->packet);
1691 silc_ske_free(ctx->ske);
1697 /* Take the keys into use */
1698 if (ctx->pfs == TRUE)
1699 silc_client_protocol_rekey_generate_pfs(client, ctx);
1701 silc_client_protocol_rekey_generate(client, ctx);
1705 silc_protocol_free(protocol);
1706 sock->protocol = NULL;
1708 silc_packet_context_free(ctx->packet);
1710 silc_ske_free(ctx->ske);