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);
31 static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
32 static void silc_client_packet_parse_type(SilcClient client,
33 SilcSocketConnection sock,
34 SilcPacketContext *packet);
36 /* Allocates new client object. This has to be done before client may
37 work. After calling this one must call silc_client_init to initialize
38 the client. The `application' is application specific user data pointer
39 and caller must free it. */
41 SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
43 SilcClient new_client;
45 new_client = silc_calloc(1, sizeof(*new_client));
46 new_client->application = application;
47 new_client->ops = ops;
52 /* Frees client object and its internals. */
54 void silc_client_free(SilcClient client)
58 silc_rng_free(client->rng);
64 /* Initializes the client. This makes all the necessary steps to make
65 the client ready to be run. One must call silc_client_run to run the
66 client. Returns FALSE if error occured, TRUE otherwise. */
68 int silc_client_init(SilcClient client)
70 SILC_LOG_DEBUG(("Initializing client"));
72 /* Initialize hash functions for client to use */
73 silc_hash_alloc("md5", &client->md5hash);
74 silc_hash_alloc("sha1", &client->sha1hash);
76 /* Initialize none cipher */
77 silc_cipher_alloc("none", &client->none_cipher);
79 /* Initialize random number generator */
80 client->rng = silc_rng_alloc();
81 silc_rng_init(client->rng);
82 silc_rng_global_init(client->rng);
84 /* Register protocols */
85 silc_client_protocols_register();
87 /* Initialize the scheduler */
88 silc_schedule_init(&client->io_queue, &client->timeout_queue,
89 &client->generic_queue, 5000);
94 /* Stops the client. This is called to stop the client and thus to stop
97 void silc_client_stop(SilcClient client)
99 SILC_LOG_DEBUG(("Stopping client"));
101 /* Stop the scheduler, although it might be already stopped. This
102 doesn't hurt anyone. This removes all the tasks and task queues,
104 silc_schedule_stop();
105 silc_schedule_uninit();
107 silc_client_protocols_unregister();
109 SILC_LOG_DEBUG(("Client stopped"));
112 /* Runs the client. This starts the scheduler from the utility library.
113 When this functions returns the execution of the appliation is over. */
115 void silc_client_run(SilcClient client)
117 SILC_LOG_DEBUG(("Running client"));
119 /* Start the scheduler, the heart of the SILC client. When this returns
120 the program will be terminated. */
124 /* Allocates and adds new connection to the client. This adds the allocated
125 connection to the connection table and returns a pointer to it. A client
126 can have multiple connections to multiple servers. Every connection must
127 be added to the client using this function. User data `context' may
128 be sent as argument. This function is normally used only if the
129 application performed the connecting outside the library. The library
130 however may use this internally. */
132 SilcClientConnection silc_client_add_connection(SilcClient client,
137 SilcClientConnection conn;
140 conn = silc_calloc(1, sizeof(*conn));
142 /* Initialize ID caches */
143 conn->client_cache = silc_idcache_alloc(0, NULL);
144 conn->channel_cache = silc_idcache_alloc(0, NULL);
145 conn->server_cache = silc_idcache_alloc(0, NULL);
146 conn->client = client;
147 conn->remote_host = strdup(hostname);
148 conn->remote_port = port;
149 conn->context = context;
150 conn->pending_commands = silc_dlist_init();
152 /* Add the connection to connections table */
153 for (i = 0; i < client->conns_count; i++)
154 if (client->conns && !client->conns[i]) {
155 client->conns[i] = conn;
159 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
160 * (client->conns_count + 1));
161 client->conns[client->conns_count] = conn;
162 client->conns_count++;
167 /* Removes connection from client. Frees all memory. */
169 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
173 for (i = 0; i < client->conns_count; i++)
174 if (client->conns[i] == conn) {
175 if (conn->pending_commands)
176 silc_dlist_uninit(conn->pending_commands);
178 client->conns[i] = NULL;
182 /* Adds listener socket to the listener sockets table. This function is
183 used to add socket objects that are listeners to the client. This should
184 not be used to add other connection objects. */
186 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
190 if (!client->sockets) {
191 client->sockets = silc_calloc(1, sizeof(*client->sockets));
192 client->sockets[0] = sock;
193 client->sockets_count = 1;
197 for (i = 0; i < client->sockets_count; i++) {
198 if (client->sockets[i] == NULL) {
199 client->sockets[i] = sock;
204 client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
205 (client->sockets_count + 1));
206 client->sockets[client->sockets_count] = sock;
207 client->sockets_count++;
210 /* Deletes listener socket from the listener sockets table. */
212 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
216 if (!client->sockets)
219 for (i = 0; i < client->sockets_count; i++) {
220 if (client->sockets[i] == sock) {
221 client->sockets[i] = NULL;
228 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
232 /* XXX In the future we should give up this non-blocking connect all
233 together and use threads instead. */
234 /* Create connection to server asynchronously */
235 sock = silc_net_create_connection_async(ctx->port, ctx->host);
239 /* Register task that will receive the async connect and will
241 ctx->task = silc_task_register(ctx->client->io_queue, sock,
242 silc_client_connect_to_server_start,
245 SILC_TASK_PRI_NORMAL);
246 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
247 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
254 /* Connects to remote server. This is the main routine used to connect
255 to SILC server. Returns -1 on error and the created socket otherwise.
256 The `context' is user context that is saved into the SilcClientConnection
257 that is created after the connection is created. Note that application
258 may handle the connecting process outside the library. If this is the
259 case then this function is not used at all. When the connecting is
260 done the `connect' client operation is called. */
262 int silc_client_connect_to_server(SilcClient client, int port,
263 char *host, void *context)
265 SilcClientInternalConnectContext *ctx;
266 SilcClientConnection conn;
269 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
272 conn = silc_client_add_connection(client, host, port, context);
274 client->ops->say(client, conn,
275 "Connecting to port %d of server %s", port, host);
277 /* Allocate internal context for connection process. This is
278 needed as we are doing async connecting. */
279 ctx = silc_calloc(1, sizeof(*ctx));
280 ctx->client = client;
282 ctx->host = strdup(host);
286 /* Do the actual connecting process */
287 sock = silc_client_connect_to_server_internal(ctx);
289 silc_client_del_connection(client, conn);
293 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
294 key material between client and server. This function can be called
295 directly if application is performing its own connecting and does not
296 use the connecting provided by this library. This function is normally
297 used only if the application performed the connecting outside the library.
298 The library however may use this internally. */
300 int silc_client_start_key_exchange(SilcClient client,
301 SilcClientConnection conn,
304 SilcProtocol protocol;
305 SilcClientKEInternalContext *proto_ctx;
308 /* Allocate new socket connection object */
309 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
311 conn->nickname = strdup(client->username);
312 conn->sock->hostname = conn->remote_host;
313 conn->sock->ip = strdup(conn->remote_host);
314 conn->sock->port = conn->remote_port;
316 /* Allocate internal Key Exchange context. This is sent to the
317 protocol as context. */
318 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
319 proto_ctx->client = (void *)client;
320 proto_ctx->sock = conn->sock;
321 proto_ctx->rng = client->rng;
322 proto_ctx->responder = FALSE;
323 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
324 proto_ctx->verify = silc_client_protocol_ke_verify_key;
326 /* Perform key exchange protocol. silc_client_connect_to_server_final
327 will be called after the protocol is finished. */
328 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
329 &protocol, (void *)proto_ctx,
330 silc_client_connect_to_server_second);
332 client->ops->say(client, conn,
333 "Error: Could not start authentication protocol");
336 conn->sock->protocol = protocol;
338 /* Register the connection for network input and output. This sets
339 that scheduler will listen for incoming packets for this connection
340 and sets that outgoing packets may be sent to this connection as well.
341 However, this doesn't set the scheduler for outgoing traffic, it will
342 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
343 later when outgoing data is available. */
344 context = (void *)client;
345 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
347 /* Execute the protocol */
348 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
352 /* Start of the connection to the remote server. This is called after
353 succesful TCP/IP connection has been established to the remote host. */
355 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
357 SilcClientInternalConnectContext *ctx =
358 (SilcClientInternalConnectContext *)context;
359 SilcClient client = ctx->client;
360 SilcClientConnection conn = ctx->conn;
361 int opt, opt_len = sizeof(opt);
363 SILC_LOG_DEBUG(("Start"));
365 /* Check the socket status as it might be in error */
366 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
368 if (ctx->tries < 2) {
369 /* Connection failed but lets try again */
370 client->ops->say(client, conn, "Could not connect to server %s: %s",
371 ctx->host, strerror(opt));
372 client->ops->say(client, conn,
373 "Connecting to port %d of server %s resumed",
374 ctx->port, ctx->host);
376 /* Unregister old connection try */
377 silc_schedule_unset_listen_fd(fd);
378 silc_net_close_connection(fd);
379 silc_task_unregister(client->io_queue, ctx->task);
382 silc_client_connect_to_server_internal(ctx);
385 /* Connection failed and we won't try anymore */
386 client->ops->say(client, conn, "Could not connect to server %s: %s",
387 ctx->host, strerror(opt));
388 silc_schedule_unset_listen_fd(fd);
389 silc_net_close_connection(fd);
390 silc_task_unregister(client->io_queue, ctx->task);
393 /* Notify application of failure */
394 client->ops->connect(client, conn, FALSE);
395 silc_client_del_connection(client, conn);
400 silc_schedule_unset_listen_fd(fd);
401 silc_task_unregister(client->io_queue, ctx->task);
404 if (!silc_client_start_key_exchange(client, conn, fd)) {
405 silc_net_close_connection(fd);
406 client->ops->connect(client, conn, FALSE);
410 /* Second part of the connecting to the server. This executed
411 authentication protocol. */
413 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
415 SilcProtocol protocol = (SilcProtocol)context;
416 SilcClientKEInternalContext *ctx =
417 (SilcClientKEInternalContext *)protocol->context;
418 SilcClient client = (SilcClient)ctx->client;
419 SilcSocketConnection sock = NULL;
420 SilcClientConnAuthInternalContext *proto_ctx;
422 SILC_LOG_DEBUG(("Start"));
424 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
425 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
426 /* Error occured during protocol */
427 SILC_LOG_DEBUG(("Error during KE protocol"));
428 silc_protocol_free(protocol);
429 silc_ske_free_key_material(ctx->keymat);
431 silc_ske_free(ctx->ske);
433 silc_free(ctx->dest_id);
434 ctx->sock->protocol = NULL;
435 silc_task_unregister_by_callback(client->timeout_queue,
436 silc_client_failure_callback);
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 silc_ske_free_key_material(ctx->keymat);
454 /* Allocate internal context for the authentication protocol. This
455 is sent as context for the protocol. */
456 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
457 proto_ctx->client = (void *)client;
458 proto_ctx->sock = sock = ctx->sock;
459 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
460 proto_ctx->dest_id_type = ctx->dest_id_type;
461 proto_ctx->dest_id = ctx->dest_id;
463 /* Resolve the authentication method to be used in this connection */
464 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
465 sock->port, &proto_ctx->auth_meth,
466 &proto_ctx->auth_data,
467 &proto_ctx->auth_data_len)) {
468 client->ops->say(client, ctx->sock->user_data,
469 "Could not resolve authentication method to use, "
470 "assume no authentication");
471 proto_ctx->auth_meth = SILC_AUTH_NONE;
474 /* Free old protocol as it is finished now */
475 silc_protocol_free(protocol);
477 silc_packet_context_free(ctx->packet);
479 sock->protocol = NULL;
481 /* Allocate the authentication protocol. This is allocated here
482 but we won't start it yet. We will be receiving party of this
483 protocol thus we will wait that connecting party will make
485 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
486 &sock->protocol, (void *)proto_ctx,
487 silc_client_connect_to_server_final);
489 /* Execute the protocol */
490 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
493 /* Finalizes the connection to the remote SILC server. This is called
494 after authentication protocol has been completed. This send our
495 user information to the server to receive our client ID from
498 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
500 SilcProtocol protocol = (SilcProtocol)context;
501 SilcClientConnAuthInternalContext *ctx =
502 (SilcClientConnAuthInternalContext *)protocol->context;
503 SilcClient client = (SilcClient)ctx->client;
504 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
507 SILC_LOG_DEBUG(("Start"));
509 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
510 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
511 /* Error occured during protocol */
512 SILC_LOG_DEBUG(("Error during authentication protocol"));
513 silc_protocol_free(protocol);
515 silc_free(ctx->auth_data);
517 silc_ske_free(ctx->ske);
519 silc_free(ctx->dest_id);
520 conn->sock->protocol = NULL;
521 silc_task_unregister_by_callback(client->timeout_queue,
522 silc_client_failure_callback);
524 /* Notify application of failure */
525 client->ops->connect(client, ctx->sock->user_data, FALSE);
530 /* Send NEW_CLIENT packet to the server. We will become registered
531 to the SILC network after sending this packet and we will receive
532 client ID from the server. */
533 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
534 strlen(client->realname));
535 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
536 silc_buffer_format(packet,
537 SILC_STR_UI_SHORT(strlen(client->username)),
538 SILC_STR_UI_XNSTRING(client->username,
539 strlen(client->username)),
540 SILC_STR_UI_SHORT(strlen(client->realname)),
541 SILC_STR_UI_XNSTRING(client->realname,
542 strlen(client->realname)),
545 /* Send the packet */
546 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
548 packet->data, packet->len, TRUE);
549 silc_buffer_free(packet);
551 /* Save remote ID. */
552 conn->remote_id = ctx->dest_id;
553 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
554 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
556 silc_task_unregister_by_callback(client->timeout_queue,
557 silc_client_failure_callback);
558 silc_protocol_free(protocol);
560 silc_free(ctx->auth_data);
562 silc_ske_free(ctx->ske);
564 conn->sock->protocol = NULL;
567 /* Internal routine that sends packet or marks packet to be sent. This
568 is used directly only in special cases. Normal cases should use
569 silc_server_packet_send. Returns < 0 on error. */
571 int silc_client_packet_send_real(SilcClient client,
572 SilcSocketConnection sock,
577 /* Send the packet */
578 ret = silc_packet_send(sock, force_send);
582 /* Mark that there is some outgoing data available for this connection.
583 This call sets the connection both for input and output (the input
584 is set always and this call keeps the input setting, actually).
585 Actual data sending is performed by silc_client_packet_process. */
586 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
588 /* Mark to socket that data is pending in outgoing buffer. This flag
589 is needed if new data is added to the buffer before the earlier
590 put data is sent to the network. */
591 SILC_SET_OUTBUF_PENDING(sock);
596 /* Packet processing callback. This is used to send and receive packets
597 from network. This is generic task. */
599 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
601 SilcClient client = (SilcClient)context;
602 SilcSocketConnection sock = NULL;
603 SilcClientConnection conn;
606 SILC_LOG_DEBUG(("Processing packet"));
608 SILC_CLIENT_GET_SOCK(client, fd, sock);
612 conn = (SilcClientConnection)sock->user_data;
615 if (type == SILC_TASK_WRITE) {
616 SILC_LOG_DEBUG(("Writing data to connection"));
618 if (sock->outbuf->data - sock->outbuf->head)
619 silc_buffer_push(sock->outbuf,
620 sock->outbuf->data - sock->outbuf->head);
622 ret = silc_client_packet_send_real(client, sock, TRUE);
624 /* If returned -2 could not write to connection now, will do
629 /* The packet has been sent and now it is time to set the connection
630 back to only for input. When there is again some outgoing data
631 available for this connection it will be set for output as well.
632 This call clears the output setting and sets it only for input. */
633 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
634 SILC_UNSET_OUTBUF_PENDING(sock);
636 silc_buffer_clear(sock->outbuf);
640 /* Packet receiving */
641 if (type == SILC_TASK_READ) {
642 SILC_LOG_DEBUG(("Reading data from connection"));
644 /* Read data from network */
645 ret = silc_packet_receive(sock);
651 SILC_LOG_DEBUG(("Read EOF"));
653 /* If connection is disconnecting already we will finally
654 close the connection */
655 if (SILC_IS_DISCONNECTING(sock)) {
656 if (sock == conn->sock)
657 client->ops->disconnect(client, conn);
658 silc_client_close_connection(client, sock, conn);
662 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
663 if (sock == conn->sock)
664 client->ops->disconnect(client, conn);
665 silc_client_close_connection(client, sock, conn);
669 /* Process the packet. This will call the parser that will then
670 decrypt and parse the packet. */
671 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
672 silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
673 silc_client_packet_parse, client);
675 silc_packet_receive_process(sock, NULL, NULL,
676 silc_client_packet_parse, client);
680 /* Callback function that the silc_packet_decrypt will call to make the
681 decision whether the packet is normal or special packet. We will
682 return TRUE if it is normal and FALSE if it is special */
684 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
686 SilcPacketContext *packet,
690 /* Packet is normal packet, if:
692 1) packet is private message packet and does not have private key set
693 2) is other packet than channel message packet
695 all other packets are special packets
698 if (packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
699 (buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
702 if (packet_type != SILC_PACKET_CHANNEL_MESSAGE)
708 /* Parses whole packet, received earlier. */
710 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
712 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
713 SilcClient client = (SilcClient)parse_ctx->context;
714 SilcPacketContext *packet = parse_ctx->packet;
715 SilcBuffer buffer = packet->buffer;
716 SilcSocketConnection sock = parse_ctx->sock;
717 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
720 SILC_LOG_DEBUG(("Start"));
722 /* Decrypt the received packet */
723 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
724 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
725 silc_client_packet_decrypt_check, parse_ctx);
727 ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
728 silc_client_packet_decrypt_check, parse_ctx);
734 /* Parse the packet. Packet type is returned. */
735 ret = silc_packet_parse(packet);
737 /* Parse the packet header in special way as this is "special"
739 ret = silc_packet_parse_special(packet);
742 if (ret == SILC_PACKET_NONE)
745 /* Parse the incoming packet type */
746 silc_client_packet_parse_type(client, sock, packet);
749 /* silc_buffer_clear(sock->inbuf); */
750 silc_packet_context_free(packet);
751 silc_free(parse_ctx);
754 /* Parser callback called by silc_packet_receive_process. Thie merely
755 registers timeout that will handle the actual parsing when appropriate. */
757 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
759 SilcClient client = (SilcClient)parser_context->context;
761 /* Parse the packet */
762 silc_task_register(client->timeout_queue, parser_context->sock->sock,
763 silc_client_packet_parse_real,
764 (void *)parser_context, 0, 1,
766 SILC_TASK_PRI_NORMAL);
769 /* Parses the packet type and calls what ever routines the packet type
770 requires. This is done for all incoming packets. */
772 void silc_client_packet_parse_type(SilcClient client,
773 SilcSocketConnection sock,
774 SilcPacketContext *packet)
776 SilcBuffer buffer = packet->buffer;
777 SilcPacketType type = packet->type;
779 SILC_LOG_DEBUG(("Parsing packet type %d", type));
781 /* Parse the packet type */
783 case SILC_PACKET_DISCONNECT:
784 silc_client_disconnected_by_server(client, sock, buffer);
786 case SILC_PACKET_SUCCESS:
788 * Success received for something. For now we can have only
789 * one protocol for connection executing at once hence this
790 * success message is for whatever protocol is executing currently.
792 if (sock->protocol) {
793 sock->protocol->execute(client->timeout_queue, 0,
794 sock->protocol, sock->sock, 0, 0);
797 case SILC_PACKET_FAILURE:
799 * Failure received for some protocol. Set the protocol state to
800 * error and call the protocol callback. This fill cause error on
801 * protocol and it will call the final callback.
803 silc_client_process_failure(client, sock, packet);
805 case SILC_PACKET_REJECT:
808 case SILC_PACKET_NOTIFY:
810 * Received notify message
812 silc_client_notify_by_server(client, sock, packet);
815 case SILC_PACKET_ERROR:
817 * Received error message
819 silc_client_error_by_server(client, sock, buffer);
822 case SILC_PACKET_CHANNEL_MESSAGE:
824 * Received message to (from, actually) a channel
826 silc_client_channel_message(client, sock, packet);
828 case SILC_PACKET_CHANNEL_KEY:
830 * Received key for a channel. By receiving this key the client will be
831 * able to talk to the channel it has just joined. This can also be
832 * a new key for existing channel as keys expire peridiocally.
834 silc_client_receive_channel_key(client, sock, buffer);
837 case SILC_PACKET_PRIVATE_MESSAGE:
839 * Received private message
841 silc_client_private_message(client, sock, packet);
843 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
845 * Received private message key
849 case SILC_PACKET_COMMAND_REPLY:
851 * Recived reply for a command
853 silc_client_command_reply_process(client, sock, packet);
856 case SILC_PACKET_KEY_EXCHANGE:
857 if (sock->protocol && sock->protocol->protocol &&
858 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
859 SilcClientKEInternalContext *proto_ctx =
860 (SilcClientKEInternalContext *)sock->protocol->context;
862 proto_ctx->packet = silc_packet_context_dup(packet);
863 proto_ctx->dest_id_type = packet->src_id_type;
864 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
865 packet->src_id_type);
866 if (!proto_ctx->dest_id)
869 /* Let the protocol handle the packet */
870 sock->protocol->execute(client->timeout_queue, 0,
871 sock->protocol, sock->sock, 0, 0);
873 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
874 "protocol active, packet dropped."));
876 /* XXX Trigger KE protocol?? Rekey actually! */
880 case SILC_PACKET_KEY_EXCHANGE_1:
881 if (sock->protocol && sock->protocol->protocol &&
882 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
883 SilcClientKEInternalContext *proto_ctx =
884 (SilcClientKEInternalContext *)sock->protocol->context;
886 if (proto_ctx->packet)
887 silc_packet_context_free(proto_ctx->packet);
889 proto_ctx->packet = silc_packet_context_dup(packet);
890 proto_ctx->dest_id_type = packet->src_id_type;
891 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
892 packet->src_id_type);
893 if (!proto_ctx->dest_id)
896 /* Let the protocol handle the packet */
897 sock->protocol->execute(client->timeout_queue, 0,
898 sock->protocol, sock->sock, 0, 0);
900 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
901 "protocol active, packet dropped."));
904 case SILC_PACKET_KEY_EXCHANGE_2:
905 if (sock->protocol && sock->protocol->protocol &&
906 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
907 SilcClientKEInternalContext *proto_ctx =
908 (SilcClientKEInternalContext *)sock->protocol->context;
910 if (proto_ctx->packet)
911 silc_packet_context_free(proto_ctx->packet);
913 proto_ctx->packet = silc_packet_context_dup(packet);
914 proto_ctx->dest_id_type = packet->src_id_type;
915 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
916 packet->src_id_type);
917 if (!proto_ctx->dest_id)
920 /* Let the protocol handle the packet */
921 sock->protocol->execute(client->timeout_queue, 0,
922 sock->protocol, sock->sock, 0, 0);
924 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
925 "protocol active, packet dropped."));
929 case SILC_PACKET_NEW_ID:
932 * Received new ID from server. This packet is received at
933 * the connection to the server. New ID is also received when
934 * user changes nickname but in that case the new ID is received
935 * as command reply and not as this packet type.
939 idp = silc_id_payload_parse(buffer);
942 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
945 silc_client_receive_new_id(client, sock, idp);
946 silc_id_payload_free(idp);
950 case SILC_PACKET_HEARTBEAT:
952 * Received heartbeat packet
954 SILC_LOG_DEBUG(("Heartbeat packet"));
957 case SILC_PACKET_KEY_AGREEMENT:
959 * Received key agreement packet
961 SILC_LOG_DEBUG(("Key agreement packet"));
962 silc_client_key_agreement(client, sock, packet);
966 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
971 /* Sends packet. This doesn't actually send the packet instead it assembles
972 it and marks it to be sent. However, if force_send is TRUE the packet
973 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
974 will be derived from sock argument. Otherwise the valid arguments sent
977 void silc_client_packet_send(SilcClient client,
978 SilcSocketConnection sock,
981 SilcIdType dst_id_type,
988 SilcPacketContext packetdata;
990 SILC_LOG_DEBUG(("Sending packet, type %d", type));
992 /* Get data used in the packet sending, keys and stuff */
993 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
994 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
995 cipher = ((SilcClientConnection)sock->user_data)->send_key;
997 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
998 hmac = ((SilcClientConnection)sock->user_data)->hmac;
1000 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1001 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1002 dst_id_type = SILC_ID_SERVER;
1006 /* Set the packet context pointers */
1007 packetdata.flags = 0;
1008 packetdata.type = type;
1009 if (sock->user_data &&
1010 ((SilcClientConnection)sock->user_data)->local_id_data)
1011 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1013 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1014 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1015 packetdata.src_id_type = SILC_ID_CLIENT;
1017 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1018 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
1019 packetdata.dst_id_type = dst_id_type;
1021 packetdata.dst_id = NULL;
1022 packetdata.dst_id_len = 0;
1023 packetdata.dst_id_type = SILC_ID_NONE;
1025 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1026 packetdata.src_id_len + packetdata.dst_id_len;
1027 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
1029 /* Prepare outgoing data buffer for packet sending */
1030 silc_packet_send_prepare(sock,
1031 SILC_PACKET_HEADER_LEN +
1032 packetdata.src_id_len +
1033 packetdata.dst_id_len,
1037 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1039 packetdata.buffer = sock->outbuf;
1041 /* Put the data to the buffer */
1042 if (data && data_len)
1043 silc_buffer_put(sock->outbuf, data, data_len);
1045 /* Create the outgoing packet */
1046 silc_packet_assemble(&packetdata);
1048 /* Encrypt the packet */
1050 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
1052 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
1053 sock->outbuf->data, sock->outbuf->len);
1055 /* Now actually send the packet */
1056 silc_client_packet_send_real(client, sock, force_send);
1059 /* Closes connection to remote end. Free's all allocated data except
1060 for some information such as nickname etc. that are valid at all time.
1061 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1062 provided it will be checked whether the sock and `conn->sock' are the
1063 same (they can be different, ie. a socket can use `conn' as its
1064 connection but `conn->sock' might be actually a different connection
1065 than the `sock'). */
1067 void silc_client_close_connection(SilcClient client,
1068 SilcSocketConnection sock,
1069 SilcClientConnection conn)
1073 if (!sock || (sock && conn->sock == sock))
1078 /* We won't listen for this connection anymore */
1079 silc_schedule_unset_listen_fd(sock->sock);
1081 /* Unregister all tasks */
1082 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1083 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1085 /* Close the actual connection */
1086 silc_net_close_connection(sock->sock);
1088 /* Free everything */
1089 if (del && sock->user_data) {
1090 /* XXX Free all client entries and channel entries. */
1092 client->ops->say(client, sock->user_data,
1093 "Closed connection to host %s", sock->hostname);
1095 /* Clear ID caches */
1096 silc_idcache_del_all(conn->client_cache);
1097 silc_idcache_del_all(conn->channel_cache);
1100 if (conn->remote_host)
1101 silc_free(conn->remote_host);
1103 silc_free(conn->local_id);
1104 if (conn->local_id_data)
1105 silc_free(conn->local_id_data);
1107 silc_cipher_free(conn->send_key);
1108 if (conn->receive_key)
1109 silc_cipher_free(conn->receive_key);
1111 silc_hmac_free(conn->hmac);
1112 if (conn->hmac_key) {
1113 memset(conn->hmac_key, 0, conn->hmac_key_len);
1114 silc_free(conn->hmac_key);
1116 if (conn->pending_commands)
1117 silc_dlist_uninit(conn->pending_commands);
1120 conn->remote_port = 0;
1121 conn->remote_type = 0;
1122 conn->send_key = NULL;
1123 conn->receive_key = NULL;
1125 conn->hmac_key = NULL;
1126 conn->hmac_key_len = 0;
1127 conn->local_id = NULL;
1128 conn->local_id_data = NULL;
1129 conn->remote_host = NULL;
1130 conn->current_channel = NULL;
1131 conn->pending_commands = NULL;
1133 silc_client_del_connection(client, conn);
1136 if (sock->protocol) {
1137 silc_protocol_free(sock->protocol);
1138 sock->protocol = NULL;
1140 silc_socket_free(sock);
1143 /* Called when we receive disconnection packet from server. This
1144 closes our end properly and displays the reason of the disconnection
1147 void silc_client_disconnected_by_server(SilcClient client,
1148 SilcSocketConnection sock,
1153 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1155 msg = silc_calloc(message->len + 1, sizeof(char));
1156 memcpy(msg, message->data, message->len);
1157 client->ops->say(client, sock->user_data, msg);
1160 SILC_SET_DISCONNECTED(sock);
1161 silc_client_close_connection(client, sock, sock->user_data);
1164 /* Received error message from server. Display it on the screen.
1165 We don't take any action what so ever of the error message. */
1167 void silc_client_error_by_server(SilcClient client,
1168 SilcSocketConnection sock,
1173 msg = silc_calloc(message->len + 1, sizeof(char));
1174 memcpy(msg, message->data, message->len);
1175 client->ops->say(client, sock->user_data, msg);
1179 /* Processes the received new Client ID from server. Old Client ID is
1180 deleted from cache and new one is added. */
1182 void silc_client_receive_new_id(SilcClient client,
1183 SilcSocketConnection sock,
1186 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1187 int connecting = FALSE;
1189 if (!conn->local_entry)
1192 /* Delete old ID from ID cache */
1193 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1195 /* Save the new ID */
1197 silc_free(conn->local_id);
1198 if (conn->local_id_data)
1199 silc_free(conn->local_id_data);
1201 conn->local_id = silc_id_payload_get_id(idp);
1202 conn->local_id_data = silc_id_payload_get_data(idp);
1203 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1205 if (!conn->local_entry)
1206 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1208 conn->local_entry->nickname = conn->nickname;
1209 if (!conn->local_entry->username) {
1210 conn->local_entry->username =
1211 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1212 sizeof(conn->local_entry->username));
1213 sprintf(conn->local_entry->username, "%s@%s", client->username,
1216 conn->local_entry->server = strdup(conn->remote_host);
1217 conn->local_entry->id = conn->local_id;
1219 /* Put it to the ID cache */
1220 silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1221 SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1224 /* Notify application of successful connection. We do it here now that
1225 we've received the Client ID and are allowed to send traffic. */
1227 client->ops->connect(client, conn, TRUE);
1230 /* Processed received Channel ID for a channel. This is called when client
1231 joins to channel and server replies with channel ID. The ID is cached.
1232 Returns the created channel entry. */
1234 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1235 SilcSocketConnection sock,
1240 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1241 SilcChannelEntry channel;
1243 SILC_LOG_DEBUG(("New channel ID"));
1245 channel = silc_calloc(1, sizeof(*channel));
1246 channel->channel_name = channel_name;
1247 channel->id = silc_id_payload_get_id(idp);
1248 channel->mode = mode;
1249 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1251 conn->current_channel = channel;
1253 /* Put it to the ID cache */
1254 silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1255 SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
1261 /* Removes a client entry from all channel it has joined. This really is
1262 a performance killer (client_entry should have pointers to channel
1265 void silc_client_remove_from_channels(SilcClient client,
1266 SilcClientConnection conn,
1267 SilcClientEntry client_entry)
1269 SilcIDCacheEntry id_cache;
1270 SilcIDCacheList list;
1271 SilcChannelEntry channel;
1272 SilcChannelUser chu;
1274 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1275 SILC_ID_CHANNEL, &list))
1278 silc_idcache_list_first(list, &id_cache);
1279 channel = (SilcChannelEntry)id_cache->context;
1283 /* Remove client from channel */
1284 silc_list_start(channel->clients);
1285 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1286 if (chu->client == client_entry) {
1287 silc_list_del(channel->clients, chu);
1293 if (!silc_idcache_list_next(list, &id_cache))
1296 channel = (SilcChannelEntry)id_cache->context;
1299 silc_idcache_list_free(list);
1302 /* Replaces `old' client entries from all channels to `new' client entry.
1303 This can be called for example when nickname changes and old ID entry
1304 is replaced from ID cache with the new one. If the old ID entry is only
1305 updated, then this fucntion needs not to be called. */
1307 void silc_client_replace_from_channels(SilcClient client,
1308 SilcClientConnection conn,
1309 SilcClientEntry old,
1310 SilcClientEntry new)
1312 SilcIDCacheEntry id_cache;
1313 SilcIDCacheList list;
1314 SilcChannelEntry channel;
1315 SilcChannelUser chu;
1317 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1318 SILC_ID_CHANNEL, &list))
1321 silc_idcache_list_first(list, &id_cache);
1322 channel = (SilcChannelEntry)id_cache->context;
1326 /* Replace client entry */
1327 silc_list_start(channel->clients);
1328 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1329 if (chu->client == old) {
1335 if (!silc_idcache_list_next(list, &id_cache))
1338 channel = (SilcChannelEntry)id_cache->context;
1341 silc_idcache_list_free(list);
1344 /* Parses mode mask and returns the mode as string. */
1346 char *silc_client_chmode(uint32 mode, SilcChannelEntry channel)
1353 memset(string, 0, sizeof(string));
1355 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1356 strncat(string, "p", 1);
1358 if (mode & SILC_CHANNEL_MODE_SECRET)
1359 strncat(string, "s", 1);
1361 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1362 strncat(string, "k", 1);
1364 if (mode & SILC_CHANNEL_MODE_INVITE)
1365 strncat(string, "i", 1);
1367 if (mode & SILC_CHANNEL_MODE_TOPIC)
1368 strncat(string, "t", 1);
1370 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1371 strncat(string, "l", 1);
1373 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1374 strncat(string, "a", 1);
1376 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
1377 strncat(string, "f", 1);
1379 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1381 memset(cipher, 0, sizeof(cipher));
1382 snprintf(cipher, sizeof(cipher), " c (%s)",
1383 channel->channel_key->cipher->name);
1384 strncat(string, cipher, strlen(cipher));
1387 if (mode & SILC_CHANNEL_MODE_HMAC) {
1389 memset(hmac, 0, sizeof(hmac));
1390 snprintf(hmac, sizeof(hmac), " h (%s)",
1391 channel->hmac->hmac->name);
1392 strncat(string, hmac, strlen(hmac));
1395 /* Rest of mode is ignored */
1397 return strdup(string);
1400 /* Parses channel user mode mask and returns te mode as string */
1402 char *silc_client_chumode(uint32 mode)
1409 memset(string, 0, sizeof(string));
1411 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1412 strncat(string, "f", 1);
1414 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1415 strncat(string, "o", 1);
1417 return strdup(string);
1420 /* Parses channel user mode and returns it as special mode character. */
1422 char *silc_client_chumode_char(uint32 mode)
1429 memset(string, 0, sizeof(string));
1431 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1432 strncat(string, "*", 1);
1434 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1435 strncat(string, "@", 1);
1437 return strdup(string);
1440 /* Failure timeout callback. If this is called then we will immediately
1441 process the received failure. We always process the failure with timeout
1442 since we do not want to blindly trust to received failure packets.
1443 This won't be called (the timeout is cancelled) if the failure was
1444 bogus (it is bogus if remote does not close the connection after sending
1447 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1449 SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1451 if (f->sock->protocol) {
1452 f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1453 f->sock->protocol->execute(f->client->timeout_queue, 0,
1454 f->sock->protocol, f->sock->sock, 0, 0);
1456 /* Notify application */
1457 f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1458 (void *)f->failure);
1464 /* Registers failure timeout to process the received failure packet
1467 void silc_client_process_failure(SilcClient client,
1468 SilcSocketConnection sock,
1469 SilcPacketContext *packet)
1471 SilcClientFailureContext *f;
1474 if (sock->protocol) {
1475 if (packet->buffer->len >= 4)
1476 SILC_GET32_MSB(failure, packet->buffer->data);
1478 f = silc_calloc(1, sizeof(*f));
1481 f->failure = failure;
1483 /* We will wait 5 seconds to process this failure packet */
1484 silc_task_register(client->timeout_queue, sock->sock,
1485 silc_client_failure_callback, (void *)f, 5, 0,
1486 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);