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] = silc_socket_dup(sock);
195 client->sockets_count = 1;
199 for (i = 0; i < client->sockets_count; i++) {
200 if (client->sockets[i] == NULL) {
201 client->sockets[i] = silc_socket_dup(sock);
206 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
207 (client->sockets_count + 1));
208 client->sockets[client->sockets_count] = silc_socket_dup(sock);
209 client->sockets_count++;
212 /* Deletes listener socket from the listener sockets table. */
214 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
218 if (!client->sockets)
221 for (i = 0; i < client->sockets_count; i++) {
222 if (client->sockets[i] == sock) {
223 silc_socket_free(sock);
224 client->sockets[i] = NULL;
231 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
235 /* XXX In the future we should give up this non-blocking connect all
236 together and use threads instead. */
237 /* Create connection to server asynchronously */
238 sock = silc_net_create_connection_async(ctx->port, ctx->host);
242 /* Register task that will receive the async connect and will
244 ctx->task = silc_task_register(ctx->client->io_queue, sock,
245 silc_client_connect_to_server_start,
248 SILC_TASK_PRI_NORMAL);
249 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
250 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
257 /* Connects to remote server. This is the main routine used to connect
258 to SILC server. Returns -1 on error and the created socket otherwise.
259 The `context' is user context that is saved into the SilcClientConnection
260 that is created after the connection is created. Note that application
261 may handle the connecting process outside the library. If this is the
262 case then this function is not used at all. When the connecting is
263 done the `connect' client operation is called. */
265 int silc_client_connect_to_server(SilcClient client, int port,
266 char *host, void *context)
268 SilcClientInternalConnectContext *ctx;
269 SilcClientConnection conn;
272 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
275 conn = silc_client_add_connection(client, host, port, context);
277 client->ops->say(client, conn,
278 "Connecting to port %d of server %s", port, host);
280 /* Allocate internal context for connection process. This is
281 needed as we are doing async connecting. */
282 ctx = silc_calloc(1, sizeof(*ctx));
283 ctx->client = client;
285 ctx->host = strdup(host);
289 /* Do the actual connecting process */
290 sock = silc_client_connect_to_server_internal(ctx);
292 silc_client_del_connection(client, conn);
296 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
297 key material between client and server. This function can be called
298 directly if application is performing its own connecting and does not
299 use the connecting provided by this library. This function is normally
300 used only if the application performed the connecting outside the library.
301 The library however may use this internally. */
303 int silc_client_start_key_exchange(SilcClient client,
304 SilcClientConnection conn,
307 SilcProtocol protocol;
308 SilcClientKEInternalContext *proto_ctx;
311 /* Allocate new socket connection object */
312 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
314 conn->nickname = strdup(client->username);
315 conn->sock->hostname = conn->remote_host;
316 conn->sock->ip = strdup(conn->remote_host);
317 conn->sock->port = conn->remote_port;
319 /* Allocate internal Key Exchange context. This is sent to the
320 protocol as context. */
321 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
322 proto_ctx->client = (void *)client;
323 proto_ctx->sock = silc_socket_dup(conn->sock);
324 proto_ctx->rng = client->rng;
325 proto_ctx->responder = FALSE;
326 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
327 proto_ctx->verify = silc_client_protocol_ke_verify_key;
329 /* Perform key exchange protocol. silc_client_connect_to_server_final
330 will be called after the protocol is finished. */
331 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
332 &protocol, (void *)proto_ctx,
333 silc_client_connect_to_server_second);
335 client->ops->say(client, conn,
336 "Error: Could not start authentication protocol");
339 conn->sock->protocol = protocol;
341 /* Register the connection for network input and output. This sets
342 that scheduler will listen for incoming packets for this connection
343 and sets that outgoing packets may be sent to this connection as well.
344 However, this doesn't set the scheduler for outgoing traffic, it will
345 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
346 later when outgoing data is available. */
347 context = (void *)client;
348 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
350 /* Execute the protocol */
351 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
355 /* Start of the connection to the remote server. This is called after
356 succesful TCP/IP connection has been established to the remote host. */
358 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
360 SilcClientInternalConnectContext *ctx =
361 (SilcClientInternalConnectContext *)context;
362 SilcClient client = ctx->client;
363 SilcClientConnection conn = ctx->conn;
364 int opt, opt_len = sizeof(opt);
366 SILC_LOG_DEBUG(("Start"));
368 /* Check the socket status as it might be in error */
369 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
371 if (ctx->tries < 2) {
372 /* Connection failed but lets try again */
373 client->ops->say(client, conn, "Could not connect to server %s: %s",
374 ctx->host, strerror(opt));
375 client->ops->say(client, conn,
376 "Connecting to port %d of server %s resumed",
377 ctx->port, ctx->host);
379 /* Unregister old connection try */
380 silc_schedule_unset_listen_fd(fd);
381 silc_net_close_connection(fd);
382 silc_task_unregister(client->io_queue, ctx->task);
385 silc_client_connect_to_server_internal(ctx);
388 /* Connection failed and we won't try anymore */
389 client->ops->say(client, conn, "Could not connect to server %s: %s",
390 ctx->host, strerror(opt));
391 silc_schedule_unset_listen_fd(fd);
392 silc_net_close_connection(fd);
393 silc_task_unregister(client->io_queue, ctx->task);
396 /* Notify application of failure */
397 client->ops->connect(client, conn, FALSE);
398 silc_client_del_connection(client, conn);
403 silc_schedule_unset_listen_fd(fd);
404 silc_task_unregister(client->io_queue, ctx->task);
407 if (!silc_client_start_key_exchange(client, conn, fd)) {
408 silc_net_close_connection(fd);
409 client->ops->connect(client, conn, FALSE);
413 /* Second part of the connecting to the server. This executed
414 authentication protocol. */
416 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
418 SilcProtocol protocol = (SilcProtocol)context;
419 SilcClientKEInternalContext *ctx =
420 (SilcClientKEInternalContext *)protocol->context;
421 SilcClient client = (SilcClient)ctx->client;
422 SilcSocketConnection sock = NULL;
423 SilcClientConnAuthInternalContext *proto_ctx;
425 SILC_LOG_DEBUG(("Start"));
427 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
428 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
429 /* Error occured during protocol */
430 SILC_LOG_DEBUG(("Error during KE protocol"));
431 silc_protocol_free(protocol);
432 silc_ske_free_key_material(ctx->keymat);
434 silc_ske_free(ctx->ske);
436 silc_free(ctx->dest_id);
437 ctx->sock->protocol = NULL;
438 silc_socket_free(ctx->sock);
440 /* Notify application of failure */
441 client->ops->connect(client, ctx->sock->user_data, FALSE);
446 /* We now have the key material as the result of the key exchange
447 protocol. Take the key material into use. Free the raw key material
448 as soon as we've set them into use. */
449 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
450 ctx->ske->prop->cipher,
451 ctx->ske->prop->pkcs,
452 ctx->ske->prop->hash,
453 ctx->ske->prop->hmac,
454 ctx->ske->prop->group);
455 silc_ske_free_key_material(ctx->keymat);
457 /* Allocate internal context for the authentication protocol. This
458 is sent as context for the protocol. */
459 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
460 proto_ctx->client = (void *)client;
461 proto_ctx->sock = sock = ctx->sock;
462 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
463 proto_ctx->dest_id_type = ctx->dest_id_type;
464 proto_ctx->dest_id = ctx->dest_id;
466 /* Resolve the authentication method to be used in this connection */
467 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
468 sock->port, &proto_ctx->auth_meth,
469 &proto_ctx->auth_data,
470 &proto_ctx->auth_data_len)) {
471 client->ops->say(client, ctx->sock->user_data,
472 "Could not resolve authentication method to use, "
473 "assume no authentication");
474 proto_ctx->auth_meth = SILC_AUTH_NONE;
477 /* Free old protocol as it is finished now */
478 silc_protocol_free(protocol);
480 silc_packet_context_free(ctx->packet);
482 sock->protocol = NULL;
484 /* Allocate the 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_socket_free(ctx->sock);
526 /* Notify application of failure */
527 client->ops->connect(client, ctx->sock->user_data, FALSE);
532 /* Send NEW_CLIENT packet to the server. We will become registered
533 to the SILC network after sending this packet and we will receive
534 client ID from the server. */
535 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
536 strlen(client->realname));
537 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
538 silc_buffer_format(packet,
539 SILC_STR_UI_SHORT(strlen(client->username)),
540 SILC_STR_UI_XNSTRING(client->username,
541 strlen(client->username)),
542 SILC_STR_UI_SHORT(strlen(client->realname)),
543 SILC_STR_UI_XNSTRING(client->realname,
544 strlen(client->realname)),
547 /* Send the packet */
548 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
550 packet->data, packet->len, TRUE);
551 silc_buffer_free(packet);
553 /* Save remote ID. */
554 conn->remote_id = ctx->dest_id;
555 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
556 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
558 /* Register re-key timeout */
559 conn->rekey->timeout = 3600; /* XXX hardcoded */
560 conn->rekey->context = (void *)client;
561 silc_task_register(client->timeout_queue, conn->sock->sock,
562 silc_client_rekey_callback,
563 (void *)conn->sock, conn->rekey->timeout, 0,
564 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
566 silc_protocol_free(protocol);
568 silc_free(ctx->auth_data);
570 silc_ske_free(ctx->ske);
571 silc_socket_free(ctx->sock);
573 conn->sock->protocol = NULL;
576 /* Internal routine that sends packet or marks packet to be sent. This
577 is used directly only in special cases. Normal cases should use
578 silc_server_packet_send. Returns < 0 on error. */
580 int silc_client_packet_send_real(SilcClient client,
581 SilcSocketConnection sock,
587 /* If rekey protocol is active we must assure that all packets are
588 sent through packet queue. */
589 if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
592 /* Send the packet */
593 ret = silc_packet_send(sock, force_send);
597 /* Mark that there is some outgoing data available for this connection.
598 This call sets the connection both for input and output (the input
599 is set always and this call keeps the input setting, actually).
600 Actual data sending is performed by silc_client_packet_process. */
601 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
603 /* Mark to socket that data is pending in outgoing buffer. This flag
604 is needed if new data is added to the buffer before the earlier
605 put data is sent to the network. */
606 SILC_SET_OUTBUF_PENDING(sock);
611 /* Packet processing callback. This is used to send and receive packets
612 from network. This is generic task. */
614 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
616 SilcClient client = (SilcClient)context;
617 SilcSocketConnection sock = NULL;
618 SilcClientConnection conn;
621 SILC_LOG_DEBUG(("Processing packet"));
623 SILC_CLIENT_GET_SOCK(client, fd, sock);
627 conn = (SilcClientConnection)sock->user_data;
630 if (type == SILC_TASK_WRITE) {
631 SILC_LOG_DEBUG(("Writing data to connection"));
633 if (sock->outbuf->data - sock->outbuf->head)
634 silc_buffer_push(sock->outbuf,
635 sock->outbuf->data - sock->outbuf->head);
637 ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
639 /* If returned -2 could not write to connection now, will do
644 /* The packet has been sent and now it is time to set the connection
645 back to only for input. When there is again some outgoing data
646 available for this connection it will be set for output as well.
647 This call clears the output setting and sets it only for input. */
648 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
649 SILC_UNSET_OUTBUF_PENDING(sock);
651 silc_buffer_clear(sock->outbuf);
655 /* Packet receiving */
656 if (type == SILC_TASK_READ) {
657 SILC_LOG_DEBUG(("Reading data from connection"));
659 /* Read data from network */
660 ret = silc_packet_receive(sock);
666 SILC_LOG_DEBUG(("Read EOF"));
668 /* If connection is disconnecting already we will finally
669 close the connection */
670 if (SILC_IS_DISCONNECTING(sock)) {
671 if (sock == conn->sock)
672 client->ops->disconnect(client, conn);
673 silc_client_close_connection(client, sock, conn);
677 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
678 if (sock == conn->sock)
679 client->ops->disconnect(client, conn);
680 silc_client_close_connection(client, sock, conn);
684 /* Process the packet. This will call the parser that will then
685 decrypt and parse the packet. */
686 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
687 silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
688 silc_client_packet_parse, client);
690 silc_packet_receive_process(sock, NULL, NULL,
691 silc_client_packet_parse, client);
695 /* Callback function that the silc_packet_decrypt will call to make the
696 decision whether the packet is normal or special packet. We will
697 return TRUE if it is normal and FALSE if it is special */
699 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
701 SilcPacketContext *packet,
705 /* Packet is normal packet, if:
707 1) packet is private message packet and does not have private key set
708 2) is other packet than channel message packet
710 all other packets are special packets
713 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
714 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
717 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
723 /* Parses whole packet, received earlier. */
725 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
727 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
728 SilcClient client = (SilcClient)parse_ctx->context;
729 SilcPacketContext *packet = parse_ctx->packet;
730 SilcBuffer buffer = packet->buffer;
731 SilcSocketConnection sock = parse_ctx->sock;
732 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
735 SILC_LOG_DEBUG(("Start"));
737 /* Decrypt the received packet */
738 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
739 ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
741 silc_client_packet_decrypt_check, parse_ctx);
743 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
744 silc_client_packet_decrypt_check, parse_ctx);
750 /* Parse the packet. Packet type is returned. */
751 ret = silc_packet_parse(packet);
753 /* Parse the packet header in special way as this is "special"
755 ret = silc_packet_parse_special(packet);
758 if (ret == SILC_PACKET_NONE)
761 /* Parse the incoming packet type */
762 silc_client_packet_parse_type(client, sock, packet);
765 /* silc_buffer_clear(sock->inbuf); */
766 silc_packet_context_free(packet);
767 silc_free(parse_ctx);
770 /* Parser callback called by silc_packet_receive_process. Thie merely
771 registers timeout that will handle the actual parsing when appropriate. */
773 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
775 SilcClient client = (SilcClient)parser_context->context;
777 /* Parse the packet */
778 silc_task_register(client->timeout_queue, parser_context->sock->sock,
779 silc_client_packet_parse_real,
780 (void *)parser_context, 0, 1,
782 SILC_TASK_PRI_NORMAL);
785 /* Parses the packet type and calls what ever routines the packet type
786 requires. This is done for all incoming packets. */
788 void silc_client_packet_parse_type(SilcClient client,
789 SilcSocketConnection sock,
790 SilcPacketContext *packet)
792 SilcBuffer buffer = packet->buffer;
793 SilcPacketType type = packet->type;
795 SILC_LOG_DEBUG(("Parsing packet type %d", type));
797 /* Parse the packet type */
799 case SILC_PACKET_DISCONNECT:
800 silc_client_disconnected_by_server(client, sock, buffer);
802 case SILC_PACKET_SUCCESS:
804 * Success received for something. For now we can have only
805 * one protocol for connection executing at once hence this
806 * success message is for whatever protocol is executing currently.
808 if (sock->protocol) {
809 sock->protocol->execute(client->timeout_queue, 0,
810 sock->protocol, sock->sock, 0, 0);
813 case SILC_PACKET_FAILURE:
815 * Failure received for some protocol. Set the protocol state to
816 * error and call the protocol callback. This fill cause error on
817 * protocol and it will call the final callback.
819 silc_client_process_failure(client, sock, packet);
821 case SILC_PACKET_REJECT:
824 case SILC_PACKET_NOTIFY:
826 * Received notify message
828 silc_client_notify_by_server(client, sock, packet);
831 case SILC_PACKET_ERROR:
833 * Received error message
835 silc_client_error_by_server(client, sock, buffer);
838 case SILC_PACKET_CHANNEL_MESSAGE:
840 * Received message to (from, actually) a channel
842 silc_client_channel_message(client, sock, packet);
844 case SILC_PACKET_CHANNEL_KEY:
846 * Received key for a channel. By receiving this key the client will be
847 * able to talk to the channel it has just joined. This can also be
848 * a new key for existing channel as keys expire peridiocally.
850 silc_client_receive_channel_key(client, sock, buffer);
853 case SILC_PACKET_PRIVATE_MESSAGE:
855 * Received private message
857 silc_client_private_message(client, sock, packet);
859 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
861 * Received private message key
865 case SILC_PACKET_COMMAND_REPLY:
867 * Recived reply for a command
869 silc_client_command_reply_process(client, sock, packet);
872 case SILC_PACKET_KEY_EXCHANGE:
873 if (sock->protocol && sock->protocol->protocol &&
874 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
875 SilcClientKEInternalContext *proto_ctx =
876 (SilcClientKEInternalContext *)sock->protocol->context;
878 proto_ctx->packet = silc_packet_context_dup(packet);
879 proto_ctx->dest_id_type = packet->src_id_type;
880 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
881 packet->src_id_type);
882 if (!proto_ctx->dest_id)
885 /* Let the protocol handle the packet */
886 sock->protocol->execute(client->timeout_queue, 0,
887 sock->protocol, sock->sock, 0, 0);
889 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
890 "protocol active, packet dropped."));
892 /* XXX Trigger KE protocol?? Rekey actually! */
896 case SILC_PACKET_KEY_EXCHANGE_1:
897 if (sock->protocol && sock->protocol->protocol &&
898 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
899 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
901 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
902 SilcClientRekeyInternalContext *proto_ctx =
903 (SilcClientRekeyInternalContext *)sock->protocol->context;
905 if (proto_ctx->packet)
906 silc_packet_context_free(proto_ctx->packet);
908 proto_ctx->packet = silc_packet_context_dup(packet);
910 /* Let the protocol handle the packet */
911 sock->protocol->execute(client->timeout_queue, 0,
912 sock->protocol, sock->sock, 0, 0);
914 SilcClientKEInternalContext *proto_ctx =
915 (SilcClientKEInternalContext *)sock->protocol->context;
917 if (proto_ctx->packet)
918 silc_packet_context_free(proto_ctx->packet);
920 proto_ctx->packet = silc_packet_context_dup(packet);
921 proto_ctx->dest_id_type = packet->src_id_type;
922 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
923 packet->src_id_type);
924 if (!proto_ctx->dest_id)
927 /* Let the protocol handle the packet */
928 sock->protocol->execute(client->timeout_queue, 0,
929 sock->protocol, sock->sock, 0, 0);
932 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
933 "protocol active, packet dropped."));
936 case SILC_PACKET_KEY_EXCHANGE_2:
937 if (sock->protocol && sock->protocol->protocol &&
938 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
939 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
941 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
942 SilcClientRekeyInternalContext *proto_ctx =
943 (SilcClientRekeyInternalContext *)sock->protocol->context;
945 if (proto_ctx->packet)
946 silc_packet_context_free(proto_ctx->packet);
948 proto_ctx->packet = silc_packet_context_dup(packet);
950 /* Let the protocol handle the packet */
951 sock->protocol->execute(client->timeout_queue, 0,
952 sock->protocol, sock->sock, 0, 0);
954 SilcClientKEInternalContext *proto_ctx =
955 (SilcClientKEInternalContext *)sock->protocol->context;
957 if (proto_ctx->packet)
958 silc_packet_context_free(proto_ctx->packet);
960 proto_ctx->packet = silc_packet_context_dup(packet);
961 proto_ctx->dest_id_type = packet->src_id_type;
962 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
963 packet->src_id_type);
964 if (!proto_ctx->dest_id)
967 /* Let the protocol handle the packet */
968 sock->protocol->execute(client->timeout_queue, 0,
969 sock->protocol, sock->sock, 0, 0);
972 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
973 "protocol active, packet dropped."));
977 case SILC_PACKET_NEW_ID:
980 * Received new ID from server. This packet is received at
981 * the connection to the server. New ID is also received when
982 * user changes nickname but in that case the new ID is received
983 * as command reply and not as this packet type.
987 idp = silc_id_payload_parse(buffer);
990 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
993 silc_client_receive_new_id(client, sock, idp);
994 silc_id_payload_free(idp);
998 case SILC_PACKET_HEARTBEAT:
1000 * Received heartbeat packet
1002 SILC_LOG_DEBUG(("Heartbeat packet"));
1005 case SILC_PACKET_KEY_AGREEMENT:
1007 * Received key agreement packet
1009 SILC_LOG_DEBUG(("Key agreement packet"));
1010 silc_client_key_agreement(client, sock, packet);
1013 case SILC_PACKET_REKEY:
1014 SILC_LOG_DEBUG(("Re-key packet"));
1015 /* We ignore this for now */
1018 case SILC_PACKET_REKEY_DONE:
1019 SILC_LOG_DEBUG(("Re-key done packet"));
1021 if (sock->protocol && sock->protocol->protocol &&
1022 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1024 SilcClientRekeyInternalContext *proto_ctx =
1025 (SilcClientRekeyInternalContext *)sock->protocol->context;
1027 if (proto_ctx->packet)
1028 silc_packet_context_free(proto_ctx->packet);
1030 proto_ctx->packet = silc_packet_context_dup(packet);
1032 /* Let the protocol handle the packet */
1033 if (proto_ctx->responder == FALSE)
1034 sock->protocol->execute(client->timeout_queue, 0,
1035 sock->protocol, sock->sock, 0, 0);
1037 /* Let the protocol handle the packet */
1038 sock->protocol->execute(client->timeout_queue, 0,
1039 sock->protocol, sock->sock, 0, 100000);
1041 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1042 "protocol active, packet dropped."));
1047 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1052 /* Sends packet. This doesn't actually send the packet instead it assembles
1053 it and marks it to be sent. However, if force_send is TRUE the packet
1054 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1055 will be derived from sock argument. Otherwise the valid arguments sent
1058 void silc_client_packet_send(SilcClient client,
1059 SilcSocketConnection sock,
1060 SilcPacketType type,
1062 SilcIdType dst_id_type,
1065 unsigned char *data,
1069 SilcPacketContext packetdata;
1071 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1073 /* Get data used in the packet sending, keys and stuff */
1074 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1075 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1076 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1078 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1079 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1081 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1082 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1083 dst_id_type = SILC_ID_SERVER;
1087 /* Set the packet context pointers */
1088 packetdata.flags = 0;
1089 packetdata.type = type;
1090 if (sock->user_data &&
1091 ((SilcClientConnection)sock->user_data)->local_id_data) {
1092 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1093 packetdata.src_id_len =
1094 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1097 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1098 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1100 packetdata.src_id_type = SILC_ID_CLIENT;
1102 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1103 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1104 packetdata.dst_id_type = dst_id_type;
1106 packetdata.dst_id = NULL;
1107 packetdata.dst_id_len = 0;
1108 packetdata.dst_id_type = SILC_ID_NONE;
1110 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1111 packetdata.src_id_len + packetdata.dst_id_len;
1112 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1114 /* Prepare outgoing data buffer for packet sending */
1115 silc_packet_send_prepare(sock,
1116 SILC_PACKET_HEADER_LEN +
1117 packetdata.src_id_len +
1118 packetdata.dst_id_len,
1122 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1124 packetdata.buffer = sock->outbuf;
1126 /* Put the data to the buffer */
1127 if (data && data_len)
1128 silc_buffer_put(sock->outbuf, data, data_len);
1130 /* Create the outgoing packet */
1131 silc_packet_assemble(&packetdata);
1133 /* Encrypt the packet */
1135 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1137 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1138 sock->outbuf->data, sock->outbuf->len);
1140 /* Now actually send the packet */
1141 silc_client_packet_send_real(client, sock, force_send, FALSE);
1144 void silc_client_packet_send_flush(SilcClient client,
1145 SilcSocketConnection sock,
1146 SilcPacketType type,
1148 SilcIdType dst_id_type,
1151 unsigned char *data,
1154 SilcPacketContext packetdata;
1156 /* First flush the packet queue. */
1158 if (sock->outbuf->data - sock->outbuf->head)
1159 silc_buffer_push(sock->outbuf,
1160 sock->outbuf->data - sock->outbuf->head);
1162 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1164 /* The packet has been sent and now it is time to set the connection
1165 back to only for input. When there is again some outgoing data
1166 available for this connection it will be set for output as well.
1167 This call clears the output setting and sets it only for input. */
1168 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(sock->sock);
1169 SILC_UNSET_OUTBUF_PENDING(sock);
1170 silc_buffer_clear(sock->outbuf);
1172 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1174 /* Get data used in the packet sending, keys and stuff */
1175 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1176 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1177 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1179 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1180 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1182 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1183 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1184 dst_id_type = SILC_ID_SERVER;
1188 /* Set the packet context pointers */
1189 packetdata.flags = 0;
1190 packetdata.type = type;
1191 if (sock->user_data &&
1192 ((SilcClientConnection)sock->user_data)->local_id_data) {
1193 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1194 packetdata.src_id_len =
1195 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1198 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1199 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1201 packetdata.src_id_type = SILC_ID_CLIENT;
1203 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1204 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1205 packetdata.dst_id_type = dst_id_type;
1207 packetdata.dst_id = NULL;
1208 packetdata.dst_id_len = 0;
1209 packetdata.dst_id_type = SILC_ID_NONE;
1211 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1212 packetdata.src_id_len + packetdata.dst_id_len;
1213 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1215 /* Prepare outgoing data buffer for packet sending */
1216 silc_packet_send_prepare(sock,
1217 SILC_PACKET_HEADER_LEN +
1218 packetdata.src_id_len +
1219 packetdata.dst_id_len,
1223 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1225 packetdata.buffer = sock->outbuf;
1227 /* Put the data to the buffer */
1228 if (data && data_len)
1229 silc_buffer_put(sock->outbuf, data, data_len);
1231 /* Create the outgoing packet */
1232 silc_packet_assemble(&packetdata);
1234 /* Encrypt the packet */
1236 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1238 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1239 sock->outbuf->data, sock->outbuf->len);
1241 /* Now actually send the packet */
1242 silc_client_packet_send_real(client, sock, TRUE, TRUE);
1245 /* Closes connection to remote end. Free's all allocated data except
1246 for some information such as nickname etc. that are valid at all time.
1247 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1248 provided it will be checked whether the sock and `conn->sock' are the
1249 same (they can be different, ie. a socket can use `conn' as its
1250 connection but `conn->sock' might be actually a different connection
1251 than the `sock'). */
1253 void silc_client_close_connection(SilcClient client,
1254 SilcSocketConnection sock,
1255 SilcClientConnection conn)
1259 if (!sock || (sock && conn->sock == sock))
1264 /* We won't listen for this connection anymore */
1265 silc_schedule_unset_listen_fd(sock->sock);
1267 /* Unregister all tasks */
1268 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1269 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1271 /* Close the actual connection */
1272 silc_net_close_connection(sock->sock);
1274 /* Free everything */
1275 if (del && sock->user_data) {
1276 /* XXX Free all client entries and channel entries. */
1278 client->ops->say(client, sock->user_data,
1279 "Closed connection to host %s", sock->hostname);
1281 /* Clear ID caches */
1282 silc_idcache_del_all(conn->client_cache);
1283 silc_idcache_del_all(conn->channel_cache);
1286 if (conn->remote_host)
1287 silc_free(conn->remote_host);
1289 silc_free(conn->local_id);
1290 if (conn->local_id_data)
1291 silc_free(conn->local_id_data);
1293 silc_cipher_free(conn->send_key);
1294 if (conn->receive_key)
1295 silc_cipher_free(conn->receive_key);
1296 if (conn->hmac_send) /* conn->hmac_receive is same */
1297 silc_hmac_free(conn->hmac_send);
1298 if (conn->pending_commands)
1299 silc_dlist_uninit(conn->pending_commands);
1301 silc_free(conn->rekey);
1304 conn->remote_port = 0;
1305 conn->remote_type = 0;
1306 conn->send_key = NULL;
1307 conn->receive_key = NULL;
1308 conn->hmac_send = NULL;
1309 conn->hmac_receive = NULL;
1310 conn->local_id = NULL;
1311 conn->local_id_data = NULL;
1312 conn->remote_host = NULL;
1313 conn->current_channel = NULL;
1314 conn->pending_commands = NULL;
1317 silc_client_del_connection(client, conn);
1320 if (sock->protocol) {
1321 silc_protocol_free(sock->protocol);
1322 sock->protocol = NULL;
1324 silc_socket_free(sock);
1327 /* Called when we receive disconnection packet from server. This
1328 closes our end properly and displays the reason of the disconnection
1331 void silc_client_disconnected_by_server(SilcClient client,
1332 SilcSocketConnection sock,
1337 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1339 msg = silc_calloc(message->len + 1, sizeof(char));
1340 memcpy(msg, message->data, message->len);
1341 client->ops->say(client, sock->user_data, msg);
1344 SILC_SET_DISCONNECTED(sock);
1345 silc_client_close_connection(client, sock, sock->user_data);
1348 /* Received error message from server. Display it on the screen.
1349 We don't take any action what so ever of the error message. */
1351 void silc_client_error_by_server(SilcClient client,
1352 SilcSocketConnection sock,
1357 msg = silc_calloc(message->len + 1, sizeof(char));
1358 memcpy(msg, message->data, message->len);
1359 client->ops->say(client, sock->user_data, msg);
1363 /* Processes the received new Client ID from server. Old Client ID is
1364 deleted from cache and new one is added. */
1366 void silc_client_receive_new_id(SilcClient client,
1367 SilcSocketConnection sock,
1370 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1371 int connecting = FALSE;
1373 if (!conn->local_entry)
1376 /* Delete old ID from ID cache */
1377 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1379 /* Save the new ID */
1381 silc_free(conn->local_id);
1382 if (conn->local_id_data)
1383 silc_free(conn->local_id_data);
1385 conn->local_id = silc_id_payload_get_id(idp);
1386 conn->local_id_data = silc_id_payload_get_data(idp);
1387 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1389 if (!conn->local_entry)
1390 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1392 conn->local_entry->nickname = conn->nickname;
1393 if (!conn->local_entry->username) {
1394 conn->local_entry->username =
1395 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1396 sizeof(conn->local_entry->username));
1397 sprintf(conn->local_entry->username, "%s@%s", client->username,
1400 conn->local_entry->server = strdup(conn->remote_host);
1401 conn->local_entry->id = conn->local_id;
1403 /* Put it to the ID cache */
1404 silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1405 SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1408 /* Notify application of successful connection. We do it here now that
1409 we've received the Client ID and are allowed to send traffic. */
1411 client->ops->connect(client, conn, TRUE);
1414 /* Processed received Channel ID for a channel. This is called when client
1415 joins to channel and server replies with channel ID. The ID is cached.
1416 Returns the created channel entry. */
1418 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1419 SilcSocketConnection sock,
1424 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1425 SilcChannelEntry channel;
1427 SILC_LOG_DEBUG(("New channel ID"));
1429 channel = silc_calloc(1, sizeof(*channel));
1430 channel->channel_name = channel_name;
1431 channel->id = silc_id_payload_get_id(idp);
1432 channel->mode = mode;
1433 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1435 conn->current_channel = channel;
1437 /* Put it to the ID cache */
1438 silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1439 SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
1445 /* Removes a client entry from all channel it has joined. This really is
1446 a performance killer (client_entry should have pointers to channel
1449 void silc_client_remove_from_channels(SilcClient client,
1450 SilcClientConnection conn,
1451 SilcClientEntry client_entry)
1453 SilcIDCacheEntry id_cache;
1454 SilcIDCacheList list;
1455 SilcChannelEntry channel;
1456 SilcChannelUser chu;
1458 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1459 SILC_ID_CHANNEL, &list))
1462 silc_idcache_list_first(list, &id_cache);
1463 channel = (SilcChannelEntry)id_cache->context;
1467 /* Remove client from channel */
1468 silc_list_start(channel->clients);
1469 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1470 if (chu->client == client_entry) {
1471 silc_list_del(channel->clients, chu);
1477 if (!silc_idcache_list_next(list, &id_cache))
1480 channel = (SilcChannelEntry)id_cache->context;
1483 silc_idcache_list_free(list);
1486 /* Replaces `old' client entries from all channels to `new' client entry.
1487 This can be called for example when nickname changes and old ID entry
1488 is replaced from ID cache with the new one. If the old ID entry is only
1489 updated, then this fucntion needs not to be called. */
1491 void silc_client_replace_from_channels(SilcClient client,
1492 SilcClientConnection conn,
1493 SilcClientEntry old,
1494 SilcClientEntry new)
1496 SilcIDCacheEntry id_cache;
1497 SilcIDCacheList list;
1498 SilcChannelEntry channel;
1499 SilcChannelUser chu;
1501 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1502 SILC_ID_CHANNEL, &list))
1505 silc_idcache_list_first(list, &id_cache);
1506 channel = (SilcChannelEntry)id_cache->context;
1510 /* Replace client entry */
1511 silc_list_start(channel->clients);
1512 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1513 if (chu->client == old) {
1519 if (!silc_idcache_list_next(list, &id_cache))
1522 channel = (SilcChannelEntry)id_cache->context;
1525 silc_idcache_list_free(list);
1528 /* Parses mode mask and returns the mode as string. */
1530 char *silc_client_chmode(uint32 mode, SilcChannelEntry channel)
1537 memset(string, 0, sizeof(string));
1539 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1540 strncat(string, "p", 1);
1542 if (mode & SILC_CHANNEL_MODE_SECRET)
1543 strncat(string, "s", 1);
1545 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1546 strncat(string, "k", 1);
1548 if (mode & SILC_CHANNEL_MODE_INVITE)
1549 strncat(string, "i", 1);
1551 if (mode & SILC_CHANNEL_MODE_TOPIC)
1552 strncat(string, "t", 1);
1554 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1555 strncat(string, "l", 1);
1557 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1558 strncat(string, "a", 1);
1560 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
1561 strncat(string, "f", 1);
1563 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1565 memset(cipher, 0, sizeof(cipher));
1566 snprintf(cipher, sizeof(cipher), " c (%s)",
1567 channel->channel_key->cipher->name);
1568 strncat(string, cipher, strlen(cipher));
1571 if (mode & SILC_CHANNEL_MODE_HMAC) {
1573 memset(hmac, 0, sizeof(hmac));
1574 snprintf(hmac, sizeof(hmac), " h (%s)",
1575 channel->hmac->hmac->name);
1576 strncat(string, hmac, strlen(hmac));
1579 /* Rest of mode is ignored */
1581 return strdup(string);
1584 /* Parses channel user mode mask and returns te mode as string */
1586 char *silc_client_chumode(uint32 mode)
1593 memset(string, 0, sizeof(string));
1595 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1596 strncat(string, "f", 1);
1598 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1599 strncat(string, "o", 1);
1601 return strdup(string);
1604 /* Parses channel user mode and returns it as special mode character. */
1606 char *silc_client_chumode_char(uint32 mode)
1613 memset(string, 0, sizeof(string));
1615 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1616 strncat(string, "*", 1);
1618 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1619 strncat(string, "@", 1);
1621 return strdup(string);
1624 /* Registers failure timeout to process the received failure packet
1627 void silc_client_process_failure(SilcClient client,
1628 SilcSocketConnection sock,
1629 SilcPacketContext *packet)
1633 if (sock->protocol) {
1634 if (packet->buffer->len >= 4)
1635 SILC_GET32_MSB(failure, packet->buffer->data);
1637 /* Notify application */
1638 client->ops->failure(client, sock->user_data, sock->protocol,
1643 /* A timeout callback for the re-key. We will be the initiator of the
1646 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1648 SilcSocketConnection sock = (SilcSocketConnection)context;
1649 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1650 SilcClient client = (SilcClient)conn->rekey->context;
1651 SilcProtocol protocol;
1652 SilcClientRekeyInternalContext *proto_ctx;
1654 SILC_LOG_DEBUG(("Start"));
1656 /* Allocate internal protocol context. This is sent as context
1658 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1659 proto_ctx->client = (void *)client;
1660 proto_ctx->sock = silc_socket_dup(sock);
1661 proto_ctx->responder = FALSE;
1662 proto_ctx->pfs = conn->rekey->pfs;
1664 /* Perform rekey protocol. Will call the final callback after the
1665 protocol is over. */
1666 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1667 &protocol, proto_ctx, silc_client_rekey_final);
1668 sock->protocol = protocol;
1670 /* Run the protocol */
1671 protocol->execute(client->timeout_queue, 0, protocol,
1674 /* Re-register re-key timeout */
1675 silc_task_register(client->timeout_queue, sock->sock,
1676 silc_client_rekey_callback,
1677 context, conn->rekey->timeout, 0,
1678 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1681 /* The final callback for the REKEY protocol. This will actually take the
1682 new key material into use. */
1684 SILC_TASK_CALLBACK(silc_client_rekey_final)
1686 SilcProtocol protocol = (SilcProtocol)context;
1687 SilcClientRekeyInternalContext *ctx =
1688 (SilcClientRekeyInternalContext *)protocol->context;
1689 SilcClient client = (SilcClient)ctx->client;
1690 SilcSocketConnection sock = ctx->sock;
1692 SILC_LOG_DEBUG(("Start"));
1694 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1695 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1696 /* Error occured during protocol */
1697 silc_protocol_cancel(client->timeout_queue, protocol);
1698 silc_protocol_free(protocol);
1699 sock->protocol = NULL;
1701 silc_packet_context_free(ctx->packet);
1703 silc_ske_free(ctx->ske);
1704 silc_socket_free(ctx->sock);
1710 silc_protocol_free(protocol);
1711 sock->protocol = NULL;
1713 silc_packet_context_free(ctx->packet);
1715 silc_ske_free(ctx->ske);
1716 silc_socket_free(ctx->sock);