5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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"
24 /* Static task callback prototypes */
25 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
28 SILC_TASK_CALLBACK(silc_client_packet_process);
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 /* Free's client object */
54 void silc_client_free(SilcClient client)
61 /* Initializes the client. This makes all the necessary steps to make
62 the client ready to be run. One must call silc_client_run to run the
65 int silc_client_init(SilcClient client)
67 SILC_LOG_DEBUG(("Initializing client"));
69 /* Initialize hash functions for client to use */
70 silc_hash_alloc("md5", &client->md5hash);
71 silc_hash_alloc("sha1", &client->sha1hash);
73 /* Initialize none cipher */
74 silc_cipher_alloc("none", &client->none_cipher);
76 /* Initialize random number generator */
77 client->rng = silc_rng_alloc();
78 silc_rng_init(client->rng);
79 silc_math_primegen_init(); /* XXX */
81 /* Register protocols */
82 silc_client_protocols_register();
84 /* Initialize the scheduler */
85 silc_schedule_init(&client->io_queue, &client->timeout_queue,
86 &client->generic_queue, 5000);
91 /* Stops the client. This is called to stop the client and thus to stop
94 void silc_client_stop(SilcClient client)
96 SILC_LOG_DEBUG(("Stopping client"));
98 /* Stop the scheduler, although it might be already stopped. This
99 doesn't hurt anyone. This removes all the tasks and task queues,
101 silc_schedule_stop();
102 silc_schedule_uninit();
104 silc_client_protocols_unregister();
106 SILC_LOG_DEBUG(("Client stopped"));
109 /* Runs the client. */
111 void silc_client_run(SilcClient client)
113 SILC_LOG_DEBUG(("Running client"));
115 /* Start the scheduler, the heart of the SILC client. When this returns
116 the program will be terminated. */
120 /* Allocates and adds new connection to the client. This adds the allocated
121 connection to the connection table and returns a pointer to it. A client
122 can have multiple connections to multiple servers. Every connection must
123 be added to the client using this function. User data `context' may
124 be sent as argument. */
126 SilcClientConnection silc_client_add_connection(SilcClient client,
129 SilcClientConnection conn;
132 conn = silc_calloc(1, sizeof(*conn));
134 /* Initialize ID caches */
135 conn->client_cache = silc_idcache_alloc(0);
136 conn->channel_cache = silc_idcache_alloc(0);
137 conn->server_cache = silc_idcache_alloc(0);
138 conn->client = client;
139 conn->context = context;
141 /* Add the connection to connections table */
142 for (i = 0; i < client->conns_count; i++)
143 if (client->conns && !client->conns[i]) {
144 client->conns[i] = conn;
148 client->conns = silc_realloc(client->conns, sizeof(*client->conns)
149 * (client->conns_count + 1));
150 client->conns[client->conns_count] = conn;
151 client->conns_count++;
156 /* Removes connection from client. */
158 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
162 for (i = 0; i < client->conns_count; i++)
163 if (client->conns[i] == conn) {
165 client->conns[i] = NULL;
169 /* Internal context for connection process. This is needed as we
170 doing asynchronous connecting. */
173 SilcClientConnection conn;
179 } SilcClientInternalConnectContext;
182 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
186 /* XXX In the future we should give up this non-blocking connect all
187 together and use threads instead. */
188 /* Create connection to server asynchronously */
189 sock = silc_net_create_connection_async(ctx->port, ctx->host);
193 /* Register task that will receive the async connect and will
195 ctx->task = silc_task_register(ctx->client->io_queue, sock,
196 silc_client_connect_to_server_start,
199 SILC_TASK_PRI_NORMAL);
200 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
201 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
208 /* Connects to remote server. This is the main routine used to connect
209 to SILC server. Returns -1 on error and the created socket otherwise.
210 The `context' is user context that is saved into the SilcClientConnection
211 that is created after the connection is created. */
213 int silc_client_connect_to_server(SilcClient client, int port,
214 char *host, void *context)
216 SilcClientInternalConnectContext *ctx;
217 SilcClientConnection conn;
219 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
222 conn = silc_client_add_connection(client, context);
223 conn->remote_host = strdup(host);
224 conn->remote_port = port;
226 client->ops->say(client, conn,
227 "Connecting to port %d of server %s", port, host);
229 /* Allocate internal context for connection process. This is
230 needed as we are doing async connecting. */
231 ctx = silc_calloc(1, sizeof(*ctx));
232 ctx->client = client;
234 ctx->host = strdup(host);
238 /* Do the actual connecting process */
239 return silc_client_connect_to_server_internal(ctx);
242 /* Start of the connection to the remote server. This is called after
243 succesful TCP/IP connection has been established to the remote host. */
245 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
247 SilcClientInternalConnectContext *ctx =
248 (SilcClientInternalConnectContext *)context;
249 SilcClient client = ctx->client;
250 SilcClientConnection conn = ctx->conn;
251 SilcProtocol protocol;
252 SilcClientKEInternalContext *proto_ctx;
253 int opt, opt_len = sizeof(opt);
255 SILC_LOG_DEBUG(("Start"));
257 /* Check the socket status as it might be in error */
258 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
260 if (ctx->tries < 2) {
261 /* Connection failed but lets try again */
262 client->ops->say(client, conn, "Could not connect to server %s: %s",
263 ctx->host, strerror(opt));
264 client->ops->say(client, conn,
265 "Connecting to port %d of server %s resumed",
266 ctx->port, ctx->host);
268 /* Unregister old connection try */
269 silc_schedule_unset_listen_fd(fd);
270 silc_net_close_connection(fd);
271 silc_task_unregister(client->io_queue, ctx->task);
274 silc_client_connect_to_server_internal(ctx);
277 /* Connection failed and we won't try anymore */
278 client->ops->say(client, conn, "Could not connect to server %s: %s",
279 ctx->host, strerror(opt));
280 silc_schedule_unset_listen_fd(fd);
281 silc_net_close_connection(fd);
282 silc_task_unregister(client->io_queue, ctx->task);
285 /* Notify application of failure */
286 client->ops->connect(client, conn, FALSE);
291 silc_schedule_unset_listen_fd(fd);
292 silc_task_unregister(client->io_queue, ctx->task);
295 /* Allocate new socket connection object */
296 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
297 if (conn->sock == NULL) {
298 client->ops->say(client, conn,
299 "Error: Could not allocate connection socket");
300 silc_net_close_connection(fd);
301 client->ops->connect(client, conn, FALSE);
305 conn->nickname = strdup(client->username);
306 conn->sock->hostname = conn->remote_host;
307 conn->sock->port = conn->remote_port;
309 /* Allocate internal Key Exchange context. This is sent to the
310 protocol as context. */
311 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
312 proto_ctx->client = (void *)client;
313 proto_ctx->sock = conn->sock;
314 proto_ctx->rng = client->rng;
315 proto_ctx->responder = FALSE;
317 /* Perform key exchange protocol. silc_client_connect_to_server_final
318 will be called after the protocol is finished. */
319 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
320 &protocol, (void *)proto_ctx,
321 silc_client_connect_to_server_second);
323 client->ops->say(client, conn,
324 "Error: Could not start authentication protocol");
325 client->ops->connect(client, conn, FALSE);
328 conn->sock->protocol = protocol;
330 /* Register the connection for network input and output. This sets
331 that scheduler will listen for incoming packets for this connection
332 and sets that outgoing packets may be sent to this connection as well.
333 However, this doesn't set the scheduler for outgoing traffic, it will
334 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
335 later when outgoing data is available. */
336 context = (void *)client;
337 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
339 /* Execute the protocol */
340 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
343 /* Second part of the connecting to the server. This executed
344 authentication protocol. */
346 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
348 SilcProtocol protocol = (SilcProtocol)context;
349 SilcClientKEInternalContext *ctx =
350 (SilcClientKEInternalContext *)protocol->context;
351 SilcClient client = (SilcClient)ctx->client;
352 SilcSocketConnection sock = NULL;
353 SilcClientConnAuthInternalContext *proto_ctx;
355 SILC_LOG_DEBUG(("Start"));
357 if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
358 /* Error occured during protocol */
359 SILC_LOG_DEBUG(("Error during KE protocol"));
360 silc_protocol_free(protocol);
362 silc_ske_free(ctx->ske);
364 silc_free(ctx->dest_id);
365 ctx->sock->protocol = NULL;
368 /* Notify application of failure */
369 client->ops->connect(client, ctx->sock->user_data, FALSE);
373 /* Allocate internal context for the authentication protocol. This
374 is sent as context for the protocol. */
375 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
376 proto_ctx->client = (void *)client;
377 proto_ctx->sock = sock = ctx->sock;
378 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
379 proto_ctx->dest_id_type = ctx->dest_id_type;
380 proto_ctx->dest_id = ctx->dest_id;
382 /* Resolve the authentication method to be used in this connection */
383 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
384 sock->port, &proto_ctx->auth_meth,
385 &proto_ctx->auth_data,
386 &proto_ctx->auth_data_len))
388 /* XXX do AUTH_REQUEST resolcing with server */
389 proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
392 /* Free old protocol as it is finished now */
393 silc_protocol_free(protocol);
395 silc_buffer_free(ctx->packet);
397 /* silc_free(ctx->keymat....); */
398 sock->protocol = NULL;
400 /* Allocate the authentication protocol. This is allocated here
401 but we won't start it yet. We will be receiving party of this
402 protocol thus we will wait that connecting party will make
404 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
405 &sock->protocol, (void *)proto_ctx,
406 silc_client_connect_to_server_final);
408 /* Execute the protocol */
409 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
412 /* Finalizes the connection to the remote SILC server. This is called
413 after authentication protocol has been completed. This send our
414 user information to the server to receive our client ID from
417 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
419 SilcProtocol protocol = (SilcProtocol)context;
420 SilcClientConnAuthInternalContext *ctx =
421 (SilcClientConnAuthInternalContext *)protocol->context;
422 SilcClient client = (SilcClient)ctx->client;
423 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
426 SILC_LOG_DEBUG(("Start"));
428 if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
429 /* Error occured during protocol */
430 SILC_LOG_DEBUG(("Error during authentication protocol"));
431 silc_protocol_free(protocol);
433 silc_free(ctx->auth_data);
435 silc_ske_free(ctx->ske);
437 silc_free(ctx->dest_id);
439 conn->sock->protocol = NULL;
441 /* Notify application of failure */
442 client->ops->connect(client, ctx->sock->user_data, FALSE);
446 /* Send NEW_CLIENT packet to the server. We will become registered
447 to the SILC network after sending this packet and we will receive
448 client ID from the server. */
449 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
450 strlen(client->realname));
451 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
452 silc_buffer_format(packet,
453 SILC_STR_UI_SHORT(strlen(client->username)),
454 SILC_STR_UI_XNSTRING(client->username,
455 strlen(client->username)),
456 SILC_STR_UI_SHORT(strlen(client->realname)),
457 SILC_STR_UI_XNSTRING(client->realname,
458 strlen(client->realname)),
461 /* Send the packet */
462 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
464 packet->data, packet->len, TRUE);
465 silc_buffer_free(packet);
467 /* Save remote ID. */
468 conn->remote_id = ctx->dest_id;
469 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
470 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
472 client->ops->say(client, conn, "Connected to port %d of host %s",
473 conn->remote_port, conn->remote_host);
475 /* Notify application of successful connection */
476 client->ops->connect(client, conn, TRUE);
478 silc_protocol_free(protocol);
480 silc_free(ctx->auth_data);
482 silc_ske_free(ctx->ske);
484 silc_free(ctx->dest_id);
486 conn->sock->protocol = NULL;
489 /* Internal routine that sends packet or marks packet to be sent. This
490 is used directly only in special cases. Normal cases should use
491 silc_server_packet_send. Returns < 0 on error. */
493 static int silc_client_packet_send_real(SilcClient client,
494 SilcSocketConnection sock,
499 /* Send the packet */
500 ret = silc_packet_send(sock, force_send);
504 /* Mark that there is some outgoing data available for this connection.
505 This call sets the connection both for input and output (the input
506 is set always and this call keeps the input setting, actually).
507 Actual data sending is performed by silc_client_packet_process. */
508 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
510 /* Mark to socket that data is pending in outgoing buffer. This flag
511 is needed if new data is added to the buffer before the earlier
512 put data is sent to the network. */
513 SILC_SET_OUTBUF_PENDING(sock);
518 /* Packet processing callback. This is used to send and receive packets
519 from network. This is generic task. */
521 SILC_TASK_CALLBACK(silc_client_packet_process)
523 SilcClient client = (SilcClient)context;
524 SilcSocketConnection sock = NULL;
525 SilcClientConnection conn;
528 SILC_LOG_DEBUG(("Processing packet"));
530 SILC_CLIENT_GET_SOCK(client, fd, sock);
534 conn = (SilcClientConnection)sock->user_data;
537 if (type == SILC_TASK_WRITE) {
538 SILC_LOG_DEBUG(("Writing data to connection"));
540 if (sock->outbuf->data - sock->outbuf->head)
541 silc_buffer_push(sock->outbuf,
542 sock->outbuf->data - sock->outbuf->head);
544 ret = silc_client_packet_send_real(client, sock, TRUE);
546 /* If returned -2 could not write to connection now, will do
551 /* The packet has been sent and now it is time to set the connection
552 back to only for input. When there is again some outgoing data
553 available for this connection it will be set for output as well.
554 This call clears the output setting and sets it only for input. */
555 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
556 SILC_UNSET_OUTBUF_PENDING(sock);
558 silc_buffer_clear(sock->outbuf);
562 /* Packet receiving */
563 if (type == SILC_TASK_READ) {
564 SILC_LOG_DEBUG(("Reading data from connection"));
566 /* Read data from network */
567 ret = silc_packet_receive(sock);
573 SILC_LOG_DEBUG(("Read EOF"));
575 /* If connection is disconnecting already we will finally
576 close the connection */
577 if (SILC_IS_DISCONNECTING(sock)) {
578 silc_client_close_connection(client, sock);
579 client->ops->disconnect(client, conn);
583 client->ops->say(client, conn, "Connection closed: premature EOF");
584 SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
585 silc_client_close_connection(client, sock);
586 client->ops->disconnect(client, conn);
590 /* Process the packet. This will call the parser that will then
591 decrypt and parse the packet. */
592 if (!silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
593 silc_client_packet_parse, client)) {
594 silc_buffer_clear(sock->inbuf);
600 /* Parses whole packet, received earlier. */
602 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
604 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
605 SilcClient client = (SilcClient)parse_ctx->context;
606 SilcPacketContext *packet = parse_ctx->packet;
607 SilcBuffer buffer = packet->buffer;
608 SilcSocketConnection sock = parse_ctx->sock;
609 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
612 SILC_LOG_DEBUG(("Start"));
614 /* Decrypt the received packet */
615 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
620 /* Parse the packet. Packet type is returned. */
621 ret = silc_packet_parse(packet);
623 /* Parse the packet header in special way as this is "special"
625 ret = silc_packet_parse_special(packet);
628 if (ret == SILC_PACKET_NONE)
631 /* Parse the incoming packet type */
632 silc_client_packet_parse_type(client, sock, packet);
635 silc_buffer_clear(buffer);
637 silc_free(parse_ctx);
640 /* Parser callback called by silc_packet_receive_process. Thie merely
641 registers timeout that will handle the actual parsing when appropriate. */
643 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
645 SilcClient client = (SilcClient)parser_context->context;
647 /* Parse the packet */
648 silc_task_register(client->timeout_queue, parser_context->sock->sock,
649 silc_client_packet_parse_real,
650 (void *)parser_context, 0, 1,
652 SILC_TASK_PRI_NORMAL);
655 /* Parses the packet type and calls what ever routines the packet type
656 requires. This is done for all incoming packets. */
658 void silc_client_packet_parse_type(SilcClient client,
659 SilcSocketConnection sock,
660 SilcPacketContext *packet)
662 SilcBuffer buffer = packet->buffer;
663 SilcPacketType type = packet->type;
665 SILC_LOG_DEBUG(("Parsing packet type %d", type));
667 /* Parse the packet type */
669 case SILC_PACKET_DISCONNECT:
670 silc_client_disconnected_by_server(client, sock, buffer);
672 case SILC_PACKET_SUCCESS:
674 * Success received for something. For now we can have only
675 * one protocol for connection executing at once hence this
676 * success message is for whatever protocol is executing currently.
678 if (sock->protocol) {
679 sock->protocol->execute(client->timeout_queue, 0,
680 sock->protocol, sock->sock, 0, 0);
683 case SILC_PACKET_FAILURE:
685 * Failure received for some protocol. Set the protocol state to
686 * error and call the protocol callback. This fill cause error on
687 * protocol and it will call the final callback.
689 if (sock->protocol) {
690 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
691 sock->protocol->execute(client->timeout_queue, 0,
692 sock->protocol, sock->sock, 0, 0);
695 case SILC_PACKET_REJECT:
698 case SILC_PACKET_NOTIFY:
700 * Received notify message
702 silc_client_notify_by_server(client, sock, buffer);
705 case SILC_PACKET_ERROR:
707 * Received error message
709 silc_client_error_by_server(client, sock, buffer);
712 case SILC_PACKET_CHANNEL_MESSAGE:
714 * Received message to (from, actually) a channel
716 silc_client_channel_message(client, sock, packet);
718 case SILC_PACKET_CHANNEL_KEY:
720 * Received key for a channel. By receiving this key the client will be
721 * able to talk to the channel it has just joined. This can also be
722 * a new key for existing channel as keys expire peridiocally.
724 silc_client_receive_channel_key(client, sock, buffer);
727 case SILC_PACKET_PRIVATE_MESSAGE:
729 * Received private message
731 silc_client_private_message(client, sock, packet);
733 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
735 * Received private message key
739 case SILC_PACKET_COMMAND_REPLY:
741 * Recived reply for a command
743 silc_client_command_reply_process(client, sock, packet);
746 case SILC_PACKET_KEY_EXCHANGE:
747 if (sock->protocol) {
748 SilcClientKEInternalContext *proto_ctx =
749 (SilcClientKEInternalContext *)sock->protocol->context;
751 proto_ctx->packet = buffer;
752 proto_ctx->dest_id_type = packet->src_id_type;
753 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
755 /* Let the protocol handle the packet */
756 sock->protocol->execute(client->timeout_queue, 0,
757 sock->protocol, sock->sock, 0, 0);
759 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
760 "protocol active, packet dropped."));
762 /* XXX Trigger KE protocol?? Rekey actually! */
766 case SILC_PACKET_KEY_EXCHANGE_1:
767 if (sock->protocol) {
770 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
771 "protocol active, packet dropped."));
774 case SILC_PACKET_KEY_EXCHANGE_2:
775 if (sock->protocol) {
776 SilcClientKEInternalContext *proto_ctx =
777 (SilcClientKEInternalContext *)sock->protocol->context;
779 if (proto_ctx->packet)
780 silc_buffer_free(proto_ctx->packet);
782 proto_ctx->packet = buffer;
783 proto_ctx->dest_id_type = packet->src_id_type;
784 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
786 /* Let the protocol handle the packet */
787 sock->protocol->execute(client->timeout_queue, 0,
788 sock->protocol, sock->sock, 0, 0);
790 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
791 "protocol active, packet dropped."));
795 case SILC_PACKET_NEW_ID:
798 * Received new ID from server. This packet is received at
799 * the connection to the server. New ID is also received when
800 * user changes nickname but in that case the new ID is received
801 * as command reply and not as this packet type.
803 unsigned char *id_string;
804 unsigned short id_type;
806 silc_buffer_unformat(buffer,
807 SILC_STR_UI_SHORT(&id_type),
808 SILC_STR_UI16_STRING_ALLOC(&id_string),
811 if ((SilcIdType)id_type != SILC_ID_CLIENT)
814 silc_client_receive_new_id(client, sock, id_string);
815 silc_free(id_string);
820 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
825 /* Sends packet. This doesn't actually send the packet instead it assembles
826 it and marks it to be sent. However, if force_send is TRUE the packet
827 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
828 will be derived from sock argument. Otherwise the valid arguments sent
831 void silc_client_packet_send(SilcClient client,
832 SilcSocketConnection sock,
835 SilcIdType dst_id_type,
839 unsigned int data_len,
842 SilcPacketContext packetdata;
844 SILC_LOG_DEBUG(("Sending packet, type %d", type));
846 /* Get data used in the packet sending, keys and stuff */
847 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
848 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
849 cipher = ((SilcClientConnection)sock->user_data)->send_key;
851 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
852 hmac = ((SilcClientConnection)sock->user_data)->hmac;
854 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
855 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
856 dst_id_type = SILC_ID_SERVER;
860 /* Set the packet context pointers */
861 packetdata.flags = 0;
862 packetdata.type = type;
863 if (((SilcClientConnection)sock->user_data)->local_id_data)
864 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
866 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
867 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
868 packetdata.src_id_type = SILC_ID_CLIENT;
870 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
871 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
872 packetdata.dst_id_type = dst_id_type;
874 packetdata.dst_id = NULL;
875 packetdata.dst_id_len = 0;
876 packetdata.dst_id_type = SILC_ID_NONE;
878 packetdata.rng = client->rng;
879 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
880 packetdata.src_id_len + packetdata.dst_id_len;
881 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
883 /* Prepare outgoing data buffer for packet sending */
884 silc_packet_send_prepare(sock,
885 SILC_PACKET_HEADER_LEN +
886 packetdata.src_id_len +
887 packetdata.dst_id_len,
891 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
893 packetdata.buffer = sock->outbuf;
895 /* Put the data to the buffer */
896 if (data && data_len)
897 silc_buffer_put(sock->outbuf, data, data_len);
899 /* Create the outgoing packet */
900 silc_packet_assemble(&packetdata);
902 /* Encrypt the packet */
904 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
906 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
907 sock->outbuf->data, sock->outbuf->len);
909 /* Now actually send the packet */
910 silc_client_packet_send_real(client, sock, force_send);
913 /* Sends packet to a channel. Packet to channel is always encrypted
914 differently from "normal" packets. SILC header of the packet is
915 encrypted with the next receiver's key and the rest of the packet is
916 encrypted with the channel specific key. Padding and HMAC is computed
917 with the next receiver's key. */
919 void silc_client_packet_send_to_channel(SilcClient client,
920 SilcSocketConnection sock,
921 SilcChannelEntry channel,
923 unsigned int data_len,
927 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
929 SilcPacketContext packetdata;
932 unsigned char *id_string;
934 SILC_LOG_DEBUG(("Sending packet to channel"));
936 if (!channel || !channel->key) {
937 client->ops->say(client, conn,
938 "Cannot talk to channel: key does not exist");
944 for (i = 0; i < 16; i++)
945 channel->iv[i] = silc_rng_get_byte(client->rng);
947 silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
949 /* Encode the channel payload */
950 payload = silc_channel_encode_payload(strlen(conn->nickname), conn->nickname,
951 data_len, data, 16, channel->iv,
954 client->ops->say(client, conn,
955 "Error: Could not create packet to be sent to channel");
959 /* Get data used in packet header encryption, keys and stuff. Rest
960 of the packet (the payload) is, however, encrypted with the
961 specified channel key. */
962 cipher = conn->send_key;
964 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
966 /* Set the packet context pointers. The destination ID is always
967 the Channel ID of the channel. Server and router will handle the
968 distribution of the packet. */
969 packetdata.flags = 0;
970 packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
971 packetdata.src_id = conn->local_id_data;
972 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
973 packetdata.src_id_type = SILC_ID_CLIENT;
974 packetdata.dst_id = id_string;
975 packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
976 packetdata.dst_id_type = SILC_ID_CHANNEL;
977 packetdata.rng = client->rng;
978 packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
979 packetdata.src_id_len + packetdata.dst_id_len;
980 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
981 packetdata.src_id_len +
982 packetdata.dst_id_len));
984 /* Prepare outgoing data buffer for packet sending */
985 silc_packet_send_prepare(sock,
986 SILC_PACKET_HEADER_LEN +
987 packetdata.src_id_len +
988 packetdata.dst_id_len,
992 packetdata.buffer = sock->outbuf;
994 /* Encrypt payload of the packet. This is encrypted with the channel key. */
995 channel->channel_key->cipher->encrypt(channel->channel_key->context,
996 payload->data, payload->data,
997 payload->len - 16, /* -IV_LEN */
1000 /* Put the actual encrypted payload data into the buffer. */
1001 silc_buffer_put(sock->outbuf, payload->data, payload->len);
1003 /* Create the outgoing packet */
1004 silc_packet_assemble(&packetdata);
1006 /* Encrypt the header and padding of the packet. This is encrypted
1007 with normal session key shared with our server. */
1008 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1009 packetdata.src_id_len + packetdata.dst_id_len +
1012 SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
1013 sock->outbuf->data, sock->outbuf->len);
1015 /* Now actually send the packet */
1016 silc_client_packet_send_real(client, sock, force_send);
1017 silc_buffer_free(payload);
1018 silc_free(id_string);
1021 /* Sends private message to remote client. If private message key has
1022 not been set with this client then the message will be encrypted using
1023 normal session keys. Private messages are special packets in SILC
1024 network hence we need this own function for them. This is similiar
1025 to silc_client_packet_send_to_channel except that we send private
1028 void silc_client_packet_send_private_message(SilcClient client,
1029 SilcSocketConnection sock,
1030 SilcClientEntry client_entry,
1031 unsigned char *data,
1032 unsigned int data_len,
1035 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1037 SilcPacketContext packetdata;
1038 unsigned int nick_len;
1042 SILC_LOG_DEBUG(("Sending private message"));
1044 /* Create private message payload */
1045 nick_len = strlen(conn->nickname);
1046 buffer = silc_buffer_alloc(2 + nick_len + data_len);
1047 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
1048 silc_buffer_format(buffer,
1049 SILC_STR_UI_SHORT(nick_len),
1050 SILC_STR_UI_XNSTRING(conn->nickname,
1052 SILC_STR_UI_XNSTRING(data, data_len),
1055 /* If we don't have private message specific key then private messages
1056 are just as any normal packet thus call normal packet sending. If
1057 the key exist then the encryption process is a bit different and
1058 will be done in the rest of this function. */
1059 if (!client_entry->send_key) {
1060 silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
1061 client_entry->id, SILC_ID_CLIENT, NULL, NULL,
1062 buffer->data, buffer->len, force_send);
1066 /* We have private message specific key */
1068 /* Get data used in the encryption */
1069 cipher = client_entry->send_key;
1072 /* Set the packet context pointers. */
1073 packetdata.flags = 0;
1074 packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
1075 packetdata.src_id = conn->local_id_data;
1076 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1077 packetdata.src_id_type = SILC_ID_CLIENT;
1079 packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
1081 packetdata.dst_id = conn->local_id_data;
1082 packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
1083 packetdata.dst_id_type = SILC_ID_CLIENT;
1084 packetdata.rng = client->rng;
1085 packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
1086 packetdata.src_id_len + packetdata.dst_id_len;
1087 packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
1088 packetdata.src_id_len +
1089 packetdata.dst_id_len));
1091 /* Prepare outgoing data buffer for packet sending */
1092 silc_packet_send_prepare(sock,
1093 SILC_PACKET_HEADER_LEN +
1094 packetdata.src_id_len +
1095 packetdata.dst_id_len,
1099 packetdata.buffer = sock->outbuf;
1101 /* Encrypt payload of the packet. Encrypt with private message specific
1102 key if it exist, otherwise with session key. */
1103 cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
1104 buffer->len, cipher->iv);
1106 /* Put the actual encrypted payload data into the buffer. */
1107 silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
1109 /* Create the outgoing packet */
1110 silc_packet_assemble(&packetdata);
1112 /* Encrypt the header and padding of the packet. */
1113 silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN +
1114 packetdata.src_id_len + packetdata.dst_id_len +
1117 SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
1118 sock->outbuf->data, sock->outbuf->len);
1120 /* Now actually send the packet */
1121 silc_client_packet_send_real(client, sock, force_send);
1122 silc_free(packetdata.dst_id);
1128 /* Closes connection to remote end. Free's all allocated data except
1129 for some information such as nickname etc. that are valid at all time. */
1131 void silc_client_close_connection(SilcClient client,
1132 SilcSocketConnection sock)
1134 SilcClientConnection conn;
1136 /* We won't listen for this connection anymore */
1137 silc_schedule_unset_listen_fd(sock->sock);
1139 /* Unregister all tasks */
1140 silc_task_unregister_by_fd(client->io_queue, sock->sock);
1141 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
1143 /* Close the actual connection */
1144 silc_net_close_connection(sock->sock);
1146 client->ops->say(client, sock->user_data,
1147 "Closed connection to host %s", sock->hostname ?
1148 sock->hostname : sock->ip);
1150 /* Free everything */
1151 if (sock->user_data) {
1152 conn = (SilcClientConnection)sock->user_data;
1154 /* XXX Free all client entries and channel entries. */
1156 /* Clear ID caches */
1157 silc_idcache_del_all(conn->client_cache);
1158 silc_idcache_del_all(conn->channel_cache);
1161 if (conn->remote_host)
1162 silc_free(conn->remote_host);
1164 silc_free(conn->local_id);
1165 if (conn->local_id_data)
1166 silc_free(conn->local_id_data);
1168 silc_cipher_free(conn->send_key);
1169 if (conn->receive_key)
1170 silc_cipher_free(conn->receive_key);
1172 silc_hmac_free(conn->hmac);
1173 if (conn->hmac_key) {
1174 memset(conn->hmac_key, 0, conn->hmac_key_len);
1175 silc_free(conn->hmac_key);
1179 conn->remote_port = 0;
1180 conn->remote_type = 0;
1181 conn->send_key = NULL;
1182 conn->receive_key = NULL;
1184 conn->hmac_key = NULL;
1185 conn->hmac_key_len = 0;
1186 conn->local_id = NULL;
1187 conn->local_id_data = NULL;
1188 conn->remote_host = NULL;
1189 conn->current_channel = NULL;
1192 if (sock->protocol) {
1193 silc_protocol_free(sock->protocol);
1194 sock->protocol = NULL;
1196 silc_socket_free(sock);
1199 /* Called when we receive disconnection packet from server. This
1200 closes our end properly and displays the reason of the disconnection
1203 void silc_client_disconnected_by_server(SilcClient client,
1204 SilcSocketConnection sock,
1209 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1211 msg = silc_calloc(message->len + 1, sizeof(char));
1212 memcpy(msg, message->data, message->len);
1213 client->ops->say(client, sock->user_data, msg);
1216 SILC_SET_DISCONNECTED(sock);
1217 silc_client_close_connection(client, sock);
1220 /* Received error message from server. Display it on the screen.
1221 We don't take any action what so ever of the error message. */
1223 void silc_client_error_by_server(SilcClient client,
1224 SilcSocketConnection sock,
1229 msg = silc_calloc(message->len + 1, sizeof(char));
1230 memcpy(msg, message->data, message->len);
1231 client->ops->say(client, sock->user_data, msg);
1235 /* Received notify message from server */
1237 void silc_client_notify_by_server(SilcClient client,
1238 SilcSocketConnection sock,
1243 msg = silc_calloc(message->len + 1, sizeof(char));
1244 memcpy(msg, message->data, message->len);
1245 client->ops->say(client, sock->user_data, msg);
1249 /* Processes the received new Client ID from server. Old Client ID is
1250 deleted from cache and new one is added. */
1252 void silc_client_receive_new_id(SilcClient client,
1253 SilcSocketConnection sock,
1254 unsigned char *id_string)
1256 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1258 /* Delete old ID from ID cache */
1259 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1261 /* Save the new ID */
1263 silc_free(conn->local_id);
1264 conn->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
1265 if (conn->local_id_data)
1266 silc_free(conn->local_id_data);
1267 conn->local_id_data =
1268 silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1269 memcpy(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN);
1270 conn->local_id_data_len = SILC_ID_CLIENT_LEN;
1271 if (!conn->local_entry)
1272 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1273 conn->local_entry->nickname = conn->nickname;
1274 conn->local_entry->id = conn->local_id;
1276 /* Put it to the ID cache */
1277 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1278 conn->local_id, (void *)conn->local_entry, TRUE);
1281 /* Processed received Channel ID for a channel. This is called when client
1282 joins to channel and server replies with channel ID. The ID is cached. */
1284 void silc_client_new_channel_id(SilcClient client,
1285 SilcSocketConnection sock,
1288 unsigned char *id_string)
1290 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1292 SilcChannelEntry channel;
1294 SILC_LOG_DEBUG(("New channel ID"));
1296 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1297 channel = silc_calloc(1, sizeof(*channel));
1298 channel->channel_name = channel_name;
1300 channel->mode = mode;
1301 conn->current_channel = channel;
1303 /* Put it to the ID cache */
1304 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1305 (void *)id, (void *)channel, TRUE);
1308 /* Processes received key for channel. The received key will be used
1309 to protect the traffic on the channel for now on. Client must receive
1310 the key to the channel before talking on the channel is possible.
1311 This is the key that server has generated, this is not the channel
1312 private key, it is entirely local setting. */
1314 void silc_client_receive_channel_key(SilcClient client,
1315 SilcSocketConnection sock,
1318 unsigned char *id_string, *key, *cipher;
1319 unsigned int key_len;
1320 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1322 SilcIDCacheEntry id_cache = NULL;
1323 SilcChannelEntry channel;
1324 SilcChannelKeyPayload payload;
1326 SILC_LOG_DEBUG(("Received key for channel"));
1328 payload = silc_channel_key_parse_payload(packet);
1332 id_string = silc_channel_key_get_id(payload, NULL);
1334 silc_channel_key_free_payload(payload);
1337 id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
1340 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1341 SILC_ID_CHANNEL, &id_cache))
1345 key = silc_channel_key_get_key(payload, &key_len);
1346 cipher = silc_channel_key_get_cipher(payload, NULL);
1348 channel = (SilcChannelEntry)id_cache->context;
1349 channel->key_len = key_len;
1350 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1351 memcpy(channel->key, key, key_len);
1353 silc_cipher_alloc(cipher, &channel->channel_key);
1354 if (!channel->channel_key) {
1355 client->ops->say(client, conn,
1356 "Cannot talk to channel: unsupported cipher %s", cipher);
1359 channel->channel_key->cipher->set_key(channel->channel_key->context,
1362 /* Client is now joined to the channel */
1363 channel->on_channel = TRUE;
1367 silc_channel_key_free_payload(payload);
1370 /* Process received message to a channel (or from a channel, really). This
1371 decrypts the channel message with channel specific key and parses the
1372 channel payload. Finally it displays the message on the screen. */
1374 void silc_client_channel_message(SilcClient client,
1375 SilcSocketConnection sock,
1376 SilcPacketContext *packet)
1378 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1379 SilcBuffer buffer = packet->buffer;
1380 SilcChannelPayload payload = NULL;
1381 SilcChannelID *id = NULL;
1382 SilcChannelEntry channel;
1383 SilcIDCacheEntry id_cache = NULL;
1386 if (packet->dst_id_type != SILC_ID_CHANNEL)
1389 id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
1391 /* Find the channel entry from channels on this window */
1392 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
1393 SILC_ID_CHANNEL, &id_cache))
1396 channel = (SilcChannelEntry)id_cache->context;
1398 /* Decrypt the channel message payload. Push the IV out of the way,
1399 since it is not encrypted (after pushing buffer->tail has the IV). */
1400 silc_buffer_push_tail(buffer, 16);
1401 channel->channel_key->cipher->decrypt(channel->channel_key->context,
1402 buffer->data, buffer->data,
1403 buffer->len, buffer->tail);
1404 silc_buffer_pull_tail(buffer, 16);
1406 /* Parse the channel message payload */
1407 payload = silc_channel_parse_payload(buffer);
1411 /* Pass the message to application */
1412 if (packet->src_id_type == SILC_ID_CLIENT) {
1413 client->ops->channel_message(client, conn,
1414 silc_channel_get_nickname(payload, NULL),
1415 channel->channel_name,
1416 silc_channel_get_data(payload, NULL));
1418 /* Message from server */
1419 /* XXX maybe this should be passed to app... */
1420 client->ops->say(client, conn, "%s", silc_channel_get_data(payload, NULL));
1427 silc_channel_free_payload(payload);
1430 /* Private message received. This processes the private message and
1431 finally displays it on the screen. */
1433 void silc_client_private_message(SilcClient client,
1434 SilcSocketConnection sock,
1435 SilcPacketContext *packet)
1437 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1438 SilcBuffer buffer = packet->buffer;
1439 unsigned short nick_len;
1440 unsigned char *nickname, *message;
1443 silc_buffer_unformat(buffer,
1444 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
1446 silc_buffer_pull(buffer, 2 + nick_len);
1448 message = silc_calloc(buffer->len + 1, sizeof(char));
1449 memcpy(message, buffer->data, buffer->len);
1451 /* Pass the private message to application */
1452 client->ops->private_message(client, conn, nickname, message);
1454 /* See if we are away (gone). If we are away we will reply to the
1455 sender with the set away message. */
1456 if (conn->away && conn->away->away) {
1457 SilcClientID *remote_id;
1458 SilcClientEntry remote_client;
1459 SilcIDCacheEntry id_cache;
1461 if (packet->src_id_type != SILC_ID_CLIENT)
1464 remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
1468 if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
1471 /* Check whether we know this client already */
1472 if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
1473 SILC_ID_CLIENT, &id_cache))
1475 /* Allocate client entry */
1476 remote_client = silc_calloc(1, sizeof(*remote_client));
1477 remote_client->id = remote_id;
1478 remote_client->nickname = strdup(nickname);
1480 /* Save the client to cache */
1481 silc_idcache_add(conn->client_cache, remote_client->nickname,
1482 SILC_ID_CLIENT, remote_client->id, remote_client,
1485 silc_free(remote_id);
1486 remote_client = (SilcClientEntry)id_cache->context;
1489 /* Send the away message */
1490 silc_client_packet_send_private_message(client, sock, remote_client,
1492 strlen(conn->away->away), TRUE);
1496 memset(message, 0, buffer->len);
1498 silc_free(nickname);