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;
183 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
187 /* XXX In the future we should give up this non-blocking connect all
188 together and use threads instead. */
189 /* Create connection to server asynchronously */
190 sock = silc_net_create_connection_async(ctx->port, ctx->host);
194 /* Register task that will receive the async connect and will
196 ctx->task = silc_task_register(ctx->client->io_queue, sock,
197 silc_client_connect_to_server_start,
200 SILC_TASK_PRI_NORMAL);
201 silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
202 silc_schedule_set_listen_fd(sock, ctx->task->iomask);
209 /* Connects to remote server. This is the main routine used to connect
210 to SILC server. Returns -1 on error and the created socket otherwise.
211 The `context' is user context that is saved into the SilcClientConnection
212 that is created after the connection is created. Note that application
213 may handle the connecting process outside the library. If this is the
214 case then this function is not used at all. When the connecting is
215 done the `connect' client operation is called. */
217 int silc_client_connect_to_server(SilcClient client, int port,
218 char *host, void *context)
220 SilcClientInternalConnectContext *ctx;
221 SilcClientConnection conn;
224 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
227 conn = silc_client_add_connection(client, host, port, context);
229 client->ops->say(client, conn,
230 "Connecting to port %d of server %s", port, host);
232 /* Allocate internal context for connection process. This is
233 needed as we are doing async connecting. */
234 ctx = silc_calloc(1, sizeof(*ctx));
235 ctx->client = client;
237 ctx->host = strdup(host);
241 /* Do the actual connecting process */
242 sock = silc_client_connect_to_server_internal(ctx);
244 silc_client_del_connection(client, conn);
248 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
249 key material between client and server. This function can be called
250 directly if application is performing its own connecting and does not
251 use the connecting provided by this library. This function is normally
252 used only if the application performed the connecting outside the library.
253 The library however may use this internally. */
255 int silc_client_start_key_exchange(SilcClient client,
256 SilcClientConnection conn,
259 SilcProtocol protocol;
260 SilcClientKEInternalContext *proto_ctx;
263 /* Allocate new socket connection object */
264 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
266 conn->nickname = strdup(client->username);
267 conn->sock->hostname = conn->remote_host;
268 conn->sock->ip = strdup(conn->remote_host);
269 conn->sock->port = conn->remote_port;
271 /* Allocate internal Key Exchange context. This is sent to the
272 protocol as context. */
273 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
274 proto_ctx->client = (void *)client;
275 proto_ctx->sock = conn->sock;
276 proto_ctx->rng = client->rng;
277 proto_ctx->responder = FALSE;
278 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
279 proto_ctx->verify = silc_client_protocol_ke_verify_key;
281 /* Perform key exchange protocol. silc_client_connect_to_server_final
282 will be called after the protocol is finished. */
283 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
284 &protocol, (void *)proto_ctx,
285 silc_client_connect_to_server_second);
287 client->ops->say(client, conn,
288 "Error: Could not start authentication protocol");
291 conn->sock->protocol = protocol;
293 /* Register the connection for network input and output. This sets
294 that scheduler will listen for incoming packets for this connection
295 and sets that outgoing packets may be sent to this connection as well.
296 However, this doesn't set the scheduler for outgoing traffic, it will
297 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
298 later when outgoing data is available. */
299 context = (void *)client;
300 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
302 /* Execute the protocol */
303 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
307 /* Start of the connection to the remote server. This is called after
308 succesful TCP/IP connection has been established to the remote host. */
310 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
312 SilcClientInternalConnectContext *ctx =
313 (SilcClientInternalConnectContext *)context;
314 SilcClient client = ctx->client;
315 SilcClientConnection conn = ctx->conn;
316 int opt, opt_len = sizeof(opt);
318 SILC_LOG_DEBUG(("Start"));
320 /* Check the socket status as it might be in error */
321 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
323 if (ctx->tries < 2) {
324 /* Connection failed but lets try again */
325 client->ops->say(client, conn, "Could not connect to server %s: %s",
326 ctx->host, strerror(opt));
327 client->ops->say(client, conn,
328 "Connecting to port %d of server %s resumed",
329 ctx->port, ctx->host);
331 /* Unregister old connection try */
332 silc_schedule_unset_listen_fd(fd);
333 silc_net_close_connection(fd);
334 silc_task_unregister(client->io_queue, ctx->task);
337 silc_client_connect_to_server_internal(ctx);
340 /* Connection failed and we won't try anymore */
341 client->ops->say(client, conn, "Could not connect to server %s: %s",
342 ctx->host, strerror(opt));
343 silc_schedule_unset_listen_fd(fd);
344 silc_net_close_connection(fd);
345 silc_task_unregister(client->io_queue, ctx->task);
348 /* Notify application of failure */
349 client->ops->connect(client, conn, FALSE);
350 silc_client_del_connection(client, conn);
355 silc_schedule_unset_listen_fd(fd);
356 silc_task_unregister(client->io_queue, ctx->task);
359 if (!silc_client_start_key_exchange(client, conn, fd)) {
360 silc_net_close_connection(fd);
361 client->ops->connect(client, conn, FALSE);
365 /* Second part of the connecting to the server. This executed
366 authentication protocol. */
368 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
370 SilcProtocol protocol = (SilcProtocol)context;
371 SilcClientKEInternalContext *ctx =
372 (SilcClientKEInternalContext *)protocol->context;
373 SilcClient client = (SilcClient)ctx->client;
374 SilcSocketConnection sock = NULL;
375 SilcClientConnAuthInternalContext *proto_ctx;
377 SILC_LOG_DEBUG(("Start"));
379 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
380 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
381 /* Error occured during protocol */
382 SILC_LOG_DEBUG(("Error during KE protocol"));
383 silc_protocol_free(protocol);
384 silc_ske_free_key_material(ctx->keymat);
386 silc_ske_free(ctx->ske);
388 silc_free(ctx->dest_id);
389 ctx->sock->protocol = NULL;
390 silc_task_unregister_by_callback(client->timeout_queue,
391 silc_client_failure_callback);
393 /* Notify application of failure */
394 client->ops->connect(client, ctx->sock->user_data, FALSE);
399 /* We now have the key material as the result of the key exchange
400 protocol. Take the key material into use. Free the raw key material
401 as soon as we've set them into use. */
402 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
403 ctx->ske->prop->cipher,
404 ctx->ske->prop->pkcs,
405 ctx->ske->prop->hash,
406 ctx->ske->prop->hmac);
407 silc_ske_free_key_material(ctx->keymat);
409 /* Allocate internal context for the authentication protocol. This
410 is sent as context for the protocol. */
411 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
412 proto_ctx->client = (void *)client;
413 proto_ctx->sock = sock = ctx->sock;
414 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
415 proto_ctx->dest_id_type = ctx->dest_id_type;
416 proto_ctx->dest_id = ctx->dest_id;
418 /* Resolve the authentication method to be used in this connection */
419 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
420 sock->port, &proto_ctx->auth_meth,
421 &proto_ctx->auth_data,
422 &proto_ctx->auth_data_len)) {
423 client->ops->say(client, ctx->sock->user_data,
424 "Could not resolve authentication method to use, "
425 "assume no authentication");
426 proto_ctx->auth_meth = SILC_AUTH_NONE;
429 /* Free old protocol as it is finished now */
430 silc_protocol_free(protocol);
432 silc_packet_context_free(ctx->packet);
434 sock->protocol = NULL;
436 /* Allocate the authentication protocol. This is allocated here
437 but we won't start it yet. We will be receiving party of this
438 protocol thus we will wait that connecting party will make
440 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
441 &sock->protocol, (void *)proto_ctx,
442 silc_client_connect_to_server_final);
444 /* Execute the protocol */
445 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
448 /* Finalizes the connection to the remote SILC server. This is called
449 after authentication protocol has been completed. This send our
450 user information to the server to receive our client ID from
453 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
455 SilcProtocol protocol = (SilcProtocol)context;
456 SilcClientConnAuthInternalContext *ctx =
457 (SilcClientConnAuthInternalContext *)protocol->context;
458 SilcClient client = (SilcClient)ctx->client;
459 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
462 SILC_LOG_DEBUG(("Start"));
464 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
465 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
466 /* Error occured during protocol */
467 SILC_LOG_DEBUG(("Error during authentication protocol"));
468 silc_protocol_free(protocol);
470 silc_free(ctx->auth_data);
472 silc_ske_free(ctx->ske);
474 silc_free(ctx->dest_id);
475 conn->sock->protocol = NULL;
476 silc_task_unregister_by_callback(client->timeout_queue,
477 silc_client_failure_callback);
479 /* Notify application of failure */
480 client->ops->connect(client, ctx->sock->user_data, FALSE);
485 /* Send NEW_CLIENT packet to the server. We will become registered
486 to the SILC network after sending this packet and we will receive
487 client ID from the server. */
488 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
489 strlen(client->realname));
490 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
491 silc_buffer_format(packet,
492 SILC_STR_UI_SHORT(strlen(client->username)),
493 SILC_STR_UI_XNSTRING(client->username,
494 strlen(client->username)),
495 SILC_STR_UI_SHORT(strlen(client->realname)),
496 SILC_STR_UI_XNSTRING(client->realname,
497 strlen(client->realname)),
500 /* Send the packet */
501 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
503 packet->data, packet->len, TRUE);
504 silc_buffer_free(packet);
506 /* Save remote ID. */
507 conn->remote_id = ctx->dest_id;
508 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
509 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
511 silc_task_unregister_by_callback(client->timeout_queue,
512 silc_client_failure_callback);
513 silc_protocol_free(protocol);
515 silc_free(ctx->auth_data);
517 silc_ske_free(ctx->ske);
519 conn->sock->protocol = NULL;
522 /* Internal routine that sends packet or marks packet to be sent. This
523 is used directly only in special cases. Normal cases should use
524 silc_server_packet_send. Returns < 0 on error. */
526 int silc_client_packet_send_real(SilcClient client,
527 SilcSocketConnection sock,
532 /* Send the packet */
533 ret = silc_packet_send(sock, force_send);
537 /* Mark that there is some outgoing data available for this connection.
538 This call sets the connection both for input and output (the input
539 is set always and this call keeps the input setting, actually).
540 Actual data sending is performed by silc_client_packet_process. */
541 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
543 /* Mark to socket that data is pending in outgoing buffer. This flag
544 is needed if new data is added to the buffer before the earlier
545 put data is sent to the network. */
546 SILC_SET_OUTBUF_PENDING(sock);
551 /* Packet processing callback. This is used to send and receive packets
552 from network. This is generic task. */
554 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
556 SilcClient client = (SilcClient)context;
557 SilcSocketConnection sock = NULL;
558 SilcClientConnection conn;
561 SILC_LOG_DEBUG(("Processing packet"));
563 SILC_CLIENT_GET_SOCK(client, fd, sock);
567 conn = (SilcClientConnection)sock->user_data;
570 if (type == SILC_TASK_WRITE) {
571 SILC_LOG_DEBUG(("Writing data to connection"));
573 if (sock->outbuf->data - sock->outbuf->head)
574 silc_buffer_push(sock->outbuf,
575 sock->outbuf->data - sock->outbuf->head);
577 ret = silc_client_packet_send_real(client, sock, TRUE);
579 /* If returned -2 could not write to connection now, will do
584 /* The packet has been sent and now it is time to set the connection
585 back to only for input. When there is again some outgoing data
586 available for this connection it will be set for output as well.
587 This call clears the output setting and sets it only for input. */
588 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
589 SILC_UNSET_OUTBUF_PENDING(sock);
591 silc_buffer_clear(sock->outbuf);
595 /* Packet receiving */
596 if (type == SILC_TASK_READ) {
597 SILC_LOG_DEBUG(("Reading data from connection"));
599 /* Read data from network */
600 ret = silc_packet_receive(sock);
606 SILC_LOG_DEBUG(("Read EOF"));
608 /* If connection is disconnecting already we will finally
609 close the connection */
610 if (SILC_IS_DISCONNECTING(sock)) {
611 client->ops->disconnect(client, conn);
612 silc_client_close_connection(client, conn);
616 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
617 client->ops->disconnect(client, conn);
618 silc_client_close_connection(client, conn);
622 /* Process the packet. This will call the parser that will then
623 decrypt and parse the packet. */
624 silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
625 silc_client_packet_parse, client);
629 /* Callback function that the silc_packet_decrypt will call to make the
630 decision whether the packet is normal or special packet. We will
631 return TRUE if it is normal and FALSE if it is special */
633 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
635 SilcPacketContext *packet,
639 /* Packet is normal packet, if:
641 1) packet is private message packet and does not have private key set
642 2) is other packet than channel message packet
644 all other packets are special packets
646 if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
647 !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
648 packet_type != SILC_PACKET_CHANNEL_MESSAGE)
654 /* Parses whole packet, received earlier. */
656 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
658 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
659 SilcClient client = (SilcClient)parse_ctx->context;
660 SilcPacketContext *packet = parse_ctx->packet;
661 SilcBuffer buffer = packet->buffer;
662 SilcSocketConnection sock = parse_ctx->sock;
663 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
666 SILC_LOG_DEBUG(("Start"));
668 /* Decrypt the received packet */
669 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
670 silc_client_packet_decrypt_check, parse_ctx);
675 /* Parse the packet. Packet type is returned. */
676 ret = silc_packet_parse(packet);
678 /* Parse the packet header in special way as this is "special"
680 ret = silc_packet_parse_special(packet);
683 if (ret == SILC_PACKET_NONE)
686 /* Parse the incoming packet type */
687 silc_client_packet_parse_type(client, sock, packet);
690 silc_buffer_clear(sock->inbuf);
691 silc_packet_context_free(packet);
692 silc_free(parse_ctx);
695 /* Parser callback called by silc_packet_receive_process. Thie merely
696 registers timeout that will handle the actual parsing when appropriate. */
698 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
700 SilcClient client = (SilcClient)parser_context->context;
702 /* Parse the packet */
703 silc_task_register(client->timeout_queue, parser_context->sock->sock,
704 silc_client_packet_parse_real,
705 (void *)parser_context, 0, 1,
707 SILC_TASK_PRI_NORMAL);
710 /* Parses the packet type and calls what ever routines the packet type
711 requires. This is done for all incoming packets. */
713 void silc_client_packet_parse_type(SilcClient client,
714 SilcSocketConnection sock,
715 SilcPacketContext *packet)
717 SilcBuffer buffer = packet->buffer;
718 SilcPacketType type = packet->type;
720 SILC_LOG_DEBUG(("Parsing packet type %d", type));
722 /* Parse the packet type */
724 case SILC_PACKET_DISCONNECT:
725 silc_client_disconnected_by_server(client, sock, buffer);
727 case SILC_PACKET_SUCCESS:
729 * Success received for something. For now we can have only
730 * one protocol for connection executing at once hence this
731 * success message is for whatever protocol is executing currently.
733 if (sock->protocol) {
734 sock->protocol->execute(client->timeout_queue, 0,
735 sock->protocol, sock->sock, 0, 0);
738 case SILC_PACKET_FAILURE:
740 * Failure received for some protocol. Set the protocol state to
741 * error and call the protocol callback. This fill cause error on
742 * protocol and it will call the final callback.
744 silc_client_process_failure(client, sock, packet);
746 case SILC_PACKET_REJECT:
749 case SILC_PACKET_NOTIFY:
751 * Received notify message
753 silc_client_notify_by_server(client, sock, packet);
756 case SILC_PACKET_ERROR:
758 * Received error message
760 silc_client_error_by_server(client, sock, buffer);
763 case SILC_PACKET_CHANNEL_MESSAGE:
765 * Received message to (from, actually) a channel
767 silc_client_channel_message(client, sock, packet);
769 case SILC_PACKET_CHANNEL_KEY:
771 * Received key for a channel. By receiving this key the client will be
772 * able to talk to the channel it has just joined. This can also be
773 * a new key for existing channel as keys expire peridiocally.
775 silc_client_receive_channel_key(client, sock, buffer);
778 case SILC_PACKET_PRIVATE_MESSAGE:
780 * Received private message
782 silc_client_private_message(client, sock, packet);
784 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
786 * Received private message key
790 case SILC_PACKET_COMMAND_REPLY:
792 * Recived reply for a command
794 silc_client_command_reply_process(client, sock, packet);
797 case SILC_PACKET_KEY_EXCHANGE:
798 if (sock->protocol) {
799 SilcClientKEInternalContext *proto_ctx =
800 (SilcClientKEInternalContext *)sock->protocol->context;
802 proto_ctx->packet = silc_packet_context_dup(packet);
803 proto_ctx->dest_id_type = packet->src_id_type;
804 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
805 packet->src_id_type);
806 if (!proto_ctx->dest_id)
809 /* Let the protocol handle the packet */
810 sock->protocol->execute(client->timeout_queue, 0,
811 sock->protocol, sock->sock, 0, 0);
813 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
814 "protocol active, packet dropped."));
816 /* XXX Trigger KE protocol?? Rekey actually! */
820 case SILC_PACKET_KEY_EXCHANGE_1:
821 if (sock->protocol) {
824 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
825 "protocol active, packet dropped."));
828 case SILC_PACKET_KEY_EXCHANGE_2:
829 if (sock->protocol) {
830 SilcClientKEInternalContext *proto_ctx =
831 (SilcClientKEInternalContext *)sock->protocol->context;
833 if (proto_ctx->packet)
834 silc_packet_context_free(proto_ctx->packet);
836 proto_ctx->packet = silc_packet_context_dup(packet);
837 proto_ctx->dest_id_type = packet->src_id_type;
838 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
839 packet->src_id_type);
840 if (!proto_ctx->dest_id)
843 /* Let the protocol handle the packet */
844 sock->protocol->execute(client->timeout_queue, 0,
845 sock->protocol, sock->sock, 0, 0);
847 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
848 "protocol active, packet dropped."));
852 case SILC_PACKET_NEW_ID:
855 * Received new ID from server. This packet is received at
856 * the connection to the server. New ID is also received when
857 * user changes nickname but in that case the new ID is received
858 * as command reply and not as this packet type.
862 idp = silc_id_payload_parse(buffer);
865 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
868 silc_client_receive_new_id(client, sock, idp);
869 silc_id_payload_free(idp);
873 case SILC_PACKET_HEARTBEAT:
875 * Received heartbeat packet
877 SILC_LOG_DEBUG(("Heartbeat packet"));
880 case SILC_PACKET_KEY_AGREEMENT:
882 * Received key agreement packet
884 SILC_LOG_DEBUG(("Key agreement packet"));
885 silc_client_key_agreement(client, sock, packet);
889 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
894 /* Sends packet. This doesn't actually send the packet instead it assembles
895 it and marks it to be sent. However, if force_send is TRUE the packet
896 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
897 will be derived from sock argument. Otherwise the valid arguments sent
900 void silc_client_packet_send(SilcClient client,
901 SilcSocketConnection sock,
904 SilcIdType dst_id_type,
908 unsigned int data_len,
911 SilcPacketContext packetdata;
913 SILC_LOG_DEBUG(("Sending packet, type %d", type));
915 /* Get data used in the packet sending, keys and stuff */
916 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
917 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
918 cipher = ((SilcClientConnection)sock->user_data)->send_key;
920 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
921 hmac = ((SilcClientConnection)sock->user_data)->hmac;
923 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
924 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
925 dst_id_type = SILC_ID_SERVER;
929 /* Set the packet context pointers */
930 packetdata.flags = 0;
931 packetdata.type = type;
932 if (((SilcClientConnection)sock->user_data)->local_id_data)
933 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
935 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
936 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
937 packetdata.src_id_type = SILC_ID_CLIENT;
939 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
940 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
941 packetdata.dst_id_type = dst_id_type;
943 packetdata.dst_id = NULL;
944 packetdata.dst_id_len = 0;
945 packetdata.dst_id_type = SILC_ID_NONE;
947 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
948 packetdata.src_id_len + packetdata.dst_id_len;
949 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
951 /* Prepare outgoing data buffer for packet sending */
952 silc_packet_send_prepare(sock,
953 SILC_PACKET_HEADER_LEN +
954 packetdata.src_id_len +
955 packetdata.dst_id_len,
959 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
961 packetdata.buffer = sock->outbuf;
963 /* Put the data to the buffer */
964 if (data && data_len)
965 silc_buffer_put(sock->outbuf, data, data_len);
967 /* Create the outgoing packet */
968 silc_packet_assemble(&packetdata);
970 /* Encrypt the packet */
972 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
974 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
975 sock->outbuf->data, sock->outbuf->len);
977 /* Now actually send the packet */
978 silc_client_packet_send_real(client, sock, force_send);
981 /* Closes connection to remote end. Free's all allocated data except
982 for some information such as nickname etc. that are valid at all time. */
984 void silc_client_close_connection(SilcClient client,
985 SilcClientConnection conn)
987 SilcSocketConnection sock = conn->sock;
989 /* We won't listen for this connection anymore */
990 silc_schedule_unset_listen_fd(sock->sock);
992 /* Unregister all tasks */
993 silc_task_unregister_by_fd(client->io_queue, sock->sock);
994 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
996 /* Close the actual connection */
997 silc_net_close_connection(sock->sock);
999 client->ops->say(client, sock->user_data,
1000 "Closed connection to host %s", sock->hostname);
1002 /* Free everything */
1003 if (sock->user_data) {
1004 /* XXX Free all client entries and channel entries. */
1006 /* Clear ID caches */
1007 silc_idcache_del_all(conn->client_cache);
1008 silc_idcache_del_all(conn->channel_cache);
1011 if (conn->remote_host)
1012 silc_free(conn->remote_host);
1014 silc_free(conn->local_id);
1015 if (conn->local_id_data)
1016 silc_free(conn->local_id_data);
1018 silc_cipher_free(conn->send_key);
1019 if (conn->receive_key)
1020 silc_cipher_free(conn->receive_key);
1022 silc_hmac_free(conn->hmac);
1023 if (conn->hmac_key) {
1024 memset(conn->hmac_key, 0, conn->hmac_key_len);
1025 silc_free(conn->hmac_key);
1027 if (conn->pending_commands)
1028 silc_dlist_uninit(conn->pending_commands);
1031 conn->remote_port = 0;
1032 conn->remote_type = 0;
1033 conn->send_key = NULL;
1034 conn->receive_key = NULL;
1036 conn->hmac_key = NULL;
1037 conn->hmac_key_len = 0;
1038 conn->local_id = NULL;
1039 conn->local_id_data = NULL;
1040 conn->remote_host = NULL;
1041 conn->current_channel = NULL;
1042 conn->pending_commands = NULL;
1044 silc_client_del_connection(client, conn);
1047 if (sock->protocol) {
1048 silc_protocol_free(sock->protocol);
1049 sock->protocol = NULL;
1051 silc_socket_free(sock);
1054 /* Called when we receive disconnection packet from server. This
1055 closes our end properly and displays the reason of the disconnection
1058 void silc_client_disconnected_by_server(SilcClient client,
1059 SilcSocketConnection sock,
1064 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1066 msg = silc_calloc(message->len + 1, sizeof(char));
1067 memcpy(msg, message->data, message->len);
1068 client->ops->say(client, sock->user_data, msg);
1071 SILC_SET_DISCONNECTED(sock);
1072 silc_client_close_connection(client, sock->user_data);
1075 /* Received error message from server. Display it on the screen.
1076 We don't take any action what so ever of the error message. */
1078 void silc_client_error_by_server(SilcClient client,
1079 SilcSocketConnection sock,
1084 msg = silc_calloc(message->len + 1, sizeof(char));
1085 memcpy(msg, message->data, message->len);
1086 client->ops->say(client, sock->user_data, msg);
1090 /* Processes the received new Client ID from server. Old Client ID is
1091 deleted from cache and new one is added. */
1093 void silc_client_receive_new_id(SilcClient client,
1094 SilcSocketConnection sock,
1097 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1098 int connecting = FALSE;
1100 if (!conn->local_entry)
1103 /* Delete old ID from ID cache */
1104 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1106 /* Save the new ID */
1108 silc_free(conn->local_id);
1109 if (conn->local_id_data)
1110 silc_free(conn->local_id_data);
1112 conn->local_id = silc_id_payload_get_id(idp);
1113 conn->local_id_data = silc_id_payload_get_data(idp);
1114 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1116 if (!conn->local_entry)
1117 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1119 conn->local_entry->nickname = conn->nickname;
1120 if (!conn->local_entry->username) {
1121 conn->local_entry->username =
1122 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1123 sizeof(conn->local_entry->username));
1124 sprintf(conn->local_entry->username, "%s@%s", client->username,
1127 conn->local_entry->server = strdup(conn->remote_host);
1128 conn->local_entry->id = conn->local_id;
1130 /* Put it to the ID cache */
1131 silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1132 SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1135 /* Notify application of successful connection. We do it here now that
1136 we've received the Client ID and are allowed to send traffic. */
1138 client->ops->connect(client, conn, TRUE);
1141 /* Processed received Channel ID for a channel. This is called when client
1142 joins to channel and server replies with channel ID. The ID is cached.
1143 Returns the created channel entry. */
1145 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1146 SilcSocketConnection sock,
1151 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1152 SilcChannelEntry channel;
1154 SILC_LOG_DEBUG(("New channel ID"));
1156 channel = silc_calloc(1, sizeof(*channel));
1157 channel->channel_name = channel_name;
1158 channel->id = silc_id_payload_get_id(idp);
1159 channel->mode = mode;
1160 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1162 conn->current_channel = channel;
1164 /* Put it to the ID cache */
1165 silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1166 SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
1172 /* Removes a client entry from all channel it has joined. This really is
1173 a performance killer (client_entry should have pointers to channel
1176 void silc_client_remove_from_channels(SilcClient client,
1177 SilcClientConnection conn,
1178 SilcClientEntry client_entry)
1180 SilcIDCacheEntry id_cache;
1181 SilcIDCacheList list;
1182 SilcChannelEntry channel;
1183 SilcChannelUser chu;
1185 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1186 SILC_ID_CHANNEL, &list))
1189 silc_idcache_list_first(list, &id_cache);
1190 channel = (SilcChannelEntry)id_cache->context;
1194 /* Remove client from channel */
1195 silc_list_start(channel->clients);
1196 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1197 if (chu->client == client_entry) {
1198 silc_list_del(channel->clients, chu);
1204 if (!silc_idcache_list_next(list, &id_cache))
1207 channel = (SilcChannelEntry)id_cache->context;
1210 silc_idcache_list_free(list);
1213 /* Replaces `old' client entries from all channels to `new' client entry.
1214 This can be called for example when nickname changes and old ID entry
1215 is replaced from ID cache with the new one. If the old ID entry is only
1216 updated, then this fucntion needs not to be called. */
1218 void silc_client_replace_from_channels(SilcClient client,
1219 SilcClientConnection conn,
1220 SilcClientEntry old,
1221 SilcClientEntry new)
1223 SilcIDCacheEntry id_cache;
1224 SilcIDCacheList list;
1225 SilcChannelEntry channel;
1226 SilcChannelUser chu;
1228 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1229 SILC_ID_CHANNEL, &list))
1232 silc_idcache_list_first(list, &id_cache);
1233 channel = (SilcChannelEntry)id_cache->context;
1237 /* Replace client entry */
1238 silc_list_start(channel->clients);
1239 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1240 if (chu->client == old) {
1246 if (!silc_idcache_list_next(list, &id_cache))
1249 channel = (SilcChannelEntry)id_cache->context;
1252 silc_idcache_list_free(list);
1255 /* Parses mode mask and returns the mode as string. */
1257 char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
1264 memset(string, 0, sizeof(string));
1266 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1267 strncat(string, "p", 1);
1269 if (mode & SILC_CHANNEL_MODE_SECRET)
1270 strncat(string, "s", 1);
1272 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1273 strncat(string, "k", 1);
1275 if (mode & SILC_CHANNEL_MODE_INVITE)
1276 strncat(string, "i", 1);
1278 if (mode & SILC_CHANNEL_MODE_TOPIC)
1279 strncat(string, "t", 1);
1281 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1282 strncat(string, "l", 1);
1284 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1285 strncat(string, "a", 1);
1287 if (mode & SILC_CHANNEL_MODE_CIPHER) {
1289 memset(cipher, 0, sizeof(cipher));
1290 snprintf(cipher, sizeof(cipher), " c (%s)",
1291 channel->channel_key->cipher->name);
1292 strncat(string, cipher, strlen(cipher));
1295 if (mode & SILC_CHANNEL_MODE_HMAC) {
1297 memset(hmac, 0, sizeof(hmac));
1298 snprintf(hmac, sizeof(hmac), " h (%s)",
1299 channel->hmac->hmac->name);
1300 strncat(string, hmac, strlen(hmac));
1303 /* Rest of mode is ignored */
1305 return strdup(string);
1308 /* Parses channel user mode mask and returns te mode as string */
1310 char *silc_client_chumode(unsigned int mode)
1317 memset(string, 0, sizeof(string));
1319 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1320 strncat(string, "f", 1);
1322 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1323 strncat(string, "o", 1);
1325 return strdup(string);
1328 /* Parses channel user mode and returns it as special mode character. */
1330 char *silc_client_chumode_char(unsigned int mode)
1337 memset(string, 0, sizeof(string));
1339 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1340 strncat(string, "*", 1);
1342 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1343 strncat(string, "@", 1);
1345 return strdup(string);
1348 /* Failure timeout callback. If this is called then we will immediately
1349 process the received failure. We always process the failure with timeout
1350 since we do not want to blindly trust to received failure packets.
1351 This won't be called (the timeout is cancelled) if the failure was
1352 bogus (it is bogus if remote does not close the connection after sending
1355 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1357 SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1359 if (f->sock->protocol) {
1360 f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1361 f->sock->protocol->execute(f->client->timeout_queue, 0,
1362 f->sock->protocol, f->sock->sock, 0, 0);
1364 /* Notify application */
1365 f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1366 (void *)f->failure);
1372 /* Registers failure timeout to process the received failure packet
1375 void silc_client_process_failure(SilcClient client,
1376 SilcSocketConnection sock,
1377 SilcPacketContext *packet)
1379 SilcClientFailureContext *f;
1380 unsigned int failure = 0;
1382 if (sock->protocol) {
1383 if (packet->buffer->len >= 4)
1384 SILC_GET32_MSB(failure, packet->buffer->data);
1386 f = silc_calloc(1, sizeof(*f));
1389 f->failure = failure;
1391 /* We will wait 5 seconds to process this failure packet */
1392 silc_task_register(client->timeout_queue, sock->sock,
1393 silc_client_failure_callback, (void *)f, 5, 0,
1394 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);