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);
144 conn->channel_cache = silc_idcache_alloc(0);
145 conn->server_cache = silc_idcache_alloc(0);
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;
280 /* Perform key exchange protocol. silc_client_connect_to_server_final
281 will be called after the protocol is finished. */
282 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
283 &protocol, (void *)proto_ctx,
284 silc_client_connect_to_server_second);
286 client->ops->say(client, conn,
287 "Error: Could not start authentication protocol");
290 conn->sock->protocol = protocol;
292 /* Register the connection for network input and output. This sets
293 that scheduler will listen for incoming packets for this connection
294 and sets that outgoing packets may be sent to this connection as well.
295 However, this doesn't set the scheduler for outgoing traffic, it will
296 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
297 later when outgoing data is available. */
298 context = (void *)client;
299 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
301 /* Execute the protocol */
302 protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
306 /* Start of the connection to the remote server. This is called after
307 succesful TCP/IP connection has been established to the remote host. */
309 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
311 SilcClientInternalConnectContext *ctx =
312 (SilcClientInternalConnectContext *)context;
313 SilcClient client = ctx->client;
314 SilcClientConnection conn = ctx->conn;
315 int opt, opt_len = sizeof(opt);
317 SILC_LOG_DEBUG(("Start"));
319 /* Check the socket status as it might be in error */
320 getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
322 if (ctx->tries < 2) {
323 /* Connection failed but lets try again */
324 client->ops->say(client, conn, "Could not connect to server %s: %s",
325 ctx->host, strerror(opt));
326 client->ops->say(client, conn,
327 "Connecting to port %d of server %s resumed",
328 ctx->port, ctx->host);
330 /* Unregister old connection try */
331 silc_schedule_unset_listen_fd(fd);
332 silc_net_close_connection(fd);
333 silc_task_unregister(client->io_queue, ctx->task);
336 silc_client_connect_to_server_internal(ctx);
339 /* Connection failed and we won't try anymore */
340 client->ops->say(client, conn, "Could not connect to server %s: %s",
341 ctx->host, strerror(opt));
342 silc_schedule_unset_listen_fd(fd);
343 silc_net_close_connection(fd);
344 silc_task_unregister(client->io_queue, ctx->task);
347 /* Notify application of failure */
348 client->ops->connect(client, conn, FALSE);
349 silc_client_del_connection(client, conn);
354 silc_schedule_unset_listen_fd(fd);
355 silc_task_unregister(client->io_queue, ctx->task);
358 if (!silc_client_start_key_exchange(client, conn, fd)) {
359 silc_net_close_connection(fd);
360 client->ops->connect(client, conn, FALSE);
364 /* Second part of the connecting to the server. This executed
365 authentication protocol. */
367 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
369 SilcProtocol protocol = (SilcProtocol)context;
370 SilcClientKEInternalContext *ctx =
371 (SilcClientKEInternalContext *)protocol->context;
372 SilcClient client = (SilcClient)ctx->client;
373 SilcSocketConnection sock = NULL;
374 SilcClientConnAuthInternalContext *proto_ctx;
376 SILC_LOG_DEBUG(("Start"));
378 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
379 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
380 /* Error occured during protocol */
381 SILC_LOG_DEBUG(("Error during KE protocol"));
382 silc_protocol_free(protocol);
383 silc_ske_free_key_material(ctx->keymat);
385 silc_ske_free(ctx->ske);
387 silc_free(ctx->dest_id);
388 ctx->sock->protocol = NULL;
389 silc_task_unregister_by_callback(client->timeout_queue,
390 silc_client_failure_callback);
392 /* Notify application of failure */
393 client->ops->connect(client, ctx->sock->user_data, FALSE);
398 /* We now have the key material as the result of the key exchange
399 protocol. Take the key material into use. Free the raw key material
400 as soon as we've set them into use. */
401 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
402 ctx->ske->prop->cipher,
403 ctx->ske->prop->pkcs,
404 ctx->ske->prop->hash,
405 ctx->ske->prop->hmac);
406 silc_ske_free_key_material(ctx->keymat);
408 /* Allocate internal context for the authentication protocol. This
409 is sent as context for the protocol. */
410 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
411 proto_ctx->client = (void *)client;
412 proto_ctx->sock = sock = ctx->sock;
413 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
414 proto_ctx->dest_id_type = ctx->dest_id_type;
415 proto_ctx->dest_id = ctx->dest_id;
417 /* Resolve the authentication method to be used in this connection */
418 if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
419 sock->port, &proto_ctx->auth_meth,
420 &proto_ctx->auth_data,
421 &proto_ctx->auth_data_len))
423 /* XXX do AUTH_REQUEST resolcing with server */
424 proto_ctx->auth_meth = SILC_AUTH_NONE;
427 /* Free old protocol as it is finished now */
428 silc_protocol_free(protocol);
430 silc_packet_context_free(ctx->packet);
432 /* silc_free(ctx->keymat....); */
433 sock->protocol = NULL;
435 /* Allocate the authentication protocol. This is allocated here
436 but we won't start it yet. We will be receiving party of this
437 protocol thus we will wait that connecting party will make
439 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
440 &sock->protocol, (void *)proto_ctx,
441 silc_client_connect_to_server_final);
443 /* Execute the protocol */
444 sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
447 /* Finalizes the connection to the remote SILC server. This is called
448 after authentication protocol has been completed. This send our
449 user information to the server to receive our client ID from
452 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
454 SilcProtocol protocol = (SilcProtocol)context;
455 SilcClientConnAuthInternalContext *ctx =
456 (SilcClientConnAuthInternalContext *)protocol->context;
457 SilcClient client = (SilcClient)ctx->client;
458 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
461 SILC_LOG_DEBUG(("Start"));
463 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
464 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
465 /* Error occured during protocol */
466 SILC_LOG_DEBUG(("Error during authentication protocol"));
467 silc_protocol_free(protocol);
469 silc_free(ctx->auth_data);
471 silc_ske_free(ctx->ske);
473 silc_free(ctx->dest_id);
474 conn->sock->protocol = NULL;
475 silc_task_unregister_by_callback(client->timeout_queue,
476 silc_client_failure_callback);
478 /* Notify application of failure */
479 client->ops->connect(client, ctx->sock->user_data, FALSE);
484 /* Send NEW_CLIENT packet to the server. We will become registered
485 to the SILC network after sending this packet and we will receive
486 client ID from the server. */
487 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
488 strlen(client->realname));
489 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
490 silc_buffer_format(packet,
491 SILC_STR_UI_SHORT(strlen(client->username)),
492 SILC_STR_UI_XNSTRING(client->username,
493 strlen(client->username)),
494 SILC_STR_UI_SHORT(strlen(client->realname)),
495 SILC_STR_UI_XNSTRING(client->realname,
496 strlen(client->realname)),
499 /* Send the packet */
500 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
502 packet->data, packet->len, TRUE);
503 silc_buffer_free(packet);
505 /* Save remote ID. */
506 conn->remote_id = ctx->dest_id;
507 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
508 conn->remote_id_data_len = SILC_ID_SERVER_LEN;
510 silc_task_unregister_by_callback(client->timeout_queue,
511 silc_client_failure_callback);
512 silc_protocol_free(protocol);
514 silc_free(ctx->auth_data);
516 silc_ske_free(ctx->ske);
518 conn->sock->protocol = NULL;
521 /* Internal routine that sends packet or marks packet to be sent. This
522 is used directly only in special cases. Normal cases should use
523 silc_server_packet_send. Returns < 0 on error. */
525 int silc_client_packet_send_real(SilcClient client,
526 SilcSocketConnection sock,
531 /* Send the packet */
532 ret = silc_packet_send(sock, force_send);
536 /* Mark that there is some outgoing data available for this connection.
537 This call sets the connection both for input and output (the input
538 is set always and this call keeps the input setting, actually).
539 Actual data sending is performed by silc_client_packet_process. */
540 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
542 /* Mark to socket that data is pending in outgoing buffer. This flag
543 is needed if new data is added to the buffer before the earlier
544 put data is sent to the network. */
545 SILC_SET_OUTBUF_PENDING(sock);
550 /* Packet processing callback. This is used to send and receive packets
551 from network. This is generic task. */
553 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
555 SilcClient client = (SilcClient)context;
556 SilcSocketConnection sock = NULL;
557 SilcClientConnection conn;
560 SILC_LOG_DEBUG(("Processing packet"));
562 SILC_CLIENT_GET_SOCK(client, fd, sock);
566 conn = (SilcClientConnection)sock->user_data;
569 if (type == SILC_TASK_WRITE) {
570 SILC_LOG_DEBUG(("Writing data to connection"));
572 if (sock->outbuf->data - sock->outbuf->head)
573 silc_buffer_push(sock->outbuf,
574 sock->outbuf->data - sock->outbuf->head);
576 ret = silc_client_packet_send_real(client, sock, TRUE);
578 /* If returned -2 could not write to connection now, will do
583 /* The packet has been sent and now it is time to set the connection
584 back to only for input. When there is again some outgoing data
585 available for this connection it will be set for output as well.
586 This call clears the output setting and sets it only for input. */
587 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
588 SILC_UNSET_OUTBUF_PENDING(sock);
590 silc_buffer_clear(sock->outbuf);
594 /* Packet receiving */
595 if (type == SILC_TASK_READ) {
596 SILC_LOG_DEBUG(("Reading data from connection"));
598 /* Read data from network */
599 ret = silc_packet_receive(sock);
605 SILC_LOG_DEBUG(("Read EOF"));
607 /* If connection is disconnecting already we will finally
608 close the connection */
609 if (SILC_IS_DISCONNECTING(sock)) {
610 client->ops->disconnect(client, conn);
611 silc_client_close_connection(client, conn);
615 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
616 client->ops->disconnect(client, conn);
617 silc_client_close_connection(client, conn);
621 /* Process the packet. This will call the parser that will then
622 decrypt and parse the packet. */
623 silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
624 silc_client_packet_parse, client);
628 /* Callback function that the silc_packet_decrypt will call to make the
629 decision whether the packet is normal or special packet. We will
630 return TRUE if it is normal and FALSE if it is special */
632 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
634 SilcPacketContext *packet,
638 /* Packet is normal packet, if:
640 1) packet is private message packet and does not have private key set
641 2) is other packet than channel message packet
643 all other packets are special packets
645 if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
646 !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
647 packet_type != SILC_PACKET_CHANNEL_MESSAGE)
653 /* Parses whole packet, received earlier. */
655 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
657 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
658 SilcClient client = (SilcClient)parse_ctx->context;
659 SilcPacketContext *packet = parse_ctx->packet;
660 SilcBuffer buffer = packet->buffer;
661 SilcSocketConnection sock = parse_ctx->sock;
662 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
665 SILC_LOG_DEBUG(("Start"));
667 /* Decrypt the received packet */
668 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
669 silc_client_packet_decrypt_check, parse_ctx);
674 /* Parse the packet. Packet type is returned. */
675 ret = silc_packet_parse(packet);
677 /* Parse the packet header in special way as this is "special"
679 ret = silc_packet_parse_special(packet);
682 if (ret == SILC_PACKET_NONE)
685 /* Parse the incoming packet type */
686 silc_client_packet_parse_type(client, sock, packet);
689 silc_buffer_clear(sock->inbuf);
690 silc_packet_context_free(packet);
691 silc_free(parse_ctx);
694 /* Parser callback called by silc_packet_receive_process. Thie merely
695 registers timeout that will handle the actual parsing when appropriate. */
697 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
699 SilcClient client = (SilcClient)parser_context->context;
701 /* Parse the packet */
702 silc_task_register(client->timeout_queue, parser_context->sock->sock,
703 silc_client_packet_parse_real,
704 (void *)parser_context, 0, 1,
706 SILC_TASK_PRI_NORMAL);
709 /* Parses the packet type and calls what ever routines the packet type
710 requires. This is done for all incoming packets. */
712 void silc_client_packet_parse_type(SilcClient client,
713 SilcSocketConnection sock,
714 SilcPacketContext *packet)
716 SilcBuffer buffer = packet->buffer;
717 SilcPacketType type = packet->type;
719 SILC_LOG_DEBUG(("Parsing packet type %d", type));
721 /* Parse the packet type */
723 case SILC_PACKET_DISCONNECT:
724 silc_client_disconnected_by_server(client, sock, buffer);
726 case SILC_PACKET_SUCCESS:
728 * Success received for something. For now we can have only
729 * one protocol for connection executing at once hence this
730 * success message is for whatever protocol is executing currently.
732 if (sock->protocol) {
733 sock->protocol->execute(client->timeout_queue, 0,
734 sock->protocol, sock->sock, 0, 0);
737 case SILC_PACKET_FAILURE:
739 * Failure received for some protocol. Set the protocol state to
740 * error and call the protocol callback. This fill cause error on
741 * protocol and it will call the final callback.
743 silc_client_process_failure(client, sock, packet);
745 case SILC_PACKET_REJECT:
748 case SILC_PACKET_NOTIFY:
750 * Received notify message
752 silc_client_notify_by_server(client, sock, packet);
755 case SILC_PACKET_ERROR:
757 * Received error message
759 silc_client_error_by_server(client, sock, buffer);
762 case SILC_PACKET_CHANNEL_MESSAGE:
764 * Received message to (from, actually) a channel
766 silc_client_channel_message(client, sock, packet);
768 case SILC_PACKET_CHANNEL_KEY:
770 * Received key for a channel. By receiving this key the client will be
771 * able to talk to the channel it has just joined. This can also be
772 * a new key for existing channel as keys expire peridiocally.
774 silc_client_receive_channel_key(client, sock, buffer);
777 case SILC_PACKET_PRIVATE_MESSAGE:
779 * Received private message
781 silc_client_private_message(client, sock, packet);
783 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
785 * Received private message key
789 case SILC_PACKET_COMMAND_REPLY:
791 * Recived reply for a command
793 silc_client_command_reply_process(client, sock, packet);
796 case SILC_PACKET_KEY_EXCHANGE:
797 if (sock->protocol) {
798 SilcClientKEInternalContext *proto_ctx =
799 (SilcClientKEInternalContext *)sock->protocol->context;
801 proto_ctx->packet = silc_packet_context_dup(packet);
802 proto_ctx->dest_id_type = packet->src_id_type;
803 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
804 packet->src_id_type);
805 if (!proto_ctx->dest_id)
808 /* Let the protocol handle the packet */
809 sock->protocol->execute(client->timeout_queue, 0,
810 sock->protocol, sock->sock, 0, 0);
812 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
813 "protocol active, packet dropped."));
815 /* XXX Trigger KE protocol?? Rekey actually! */
819 case SILC_PACKET_KEY_EXCHANGE_1:
820 if (sock->protocol) {
823 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
824 "protocol active, packet dropped."));
827 case SILC_PACKET_KEY_EXCHANGE_2:
828 if (sock->protocol) {
829 SilcClientKEInternalContext *proto_ctx =
830 (SilcClientKEInternalContext *)sock->protocol->context;
832 if (proto_ctx->packet)
833 silc_packet_context_free(proto_ctx->packet);
835 proto_ctx->packet = silc_packet_context_dup(packet);
836 proto_ctx->dest_id_type = packet->src_id_type;
837 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
838 packet->src_id_type);
839 if (!proto_ctx->dest_id)
842 /* Let the protocol handle the packet */
843 sock->protocol->execute(client->timeout_queue, 0,
844 sock->protocol, sock->sock, 0, 0);
846 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
847 "protocol active, packet dropped."));
851 case SILC_PACKET_NEW_ID:
854 * Received new ID from server. This packet is received at
855 * the connection to the server. New ID is also received when
856 * user changes nickname but in that case the new ID is received
857 * as command reply and not as this packet type.
861 idp = silc_id_payload_parse(buffer);
864 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
867 silc_client_receive_new_id(client, sock, idp);
868 silc_id_payload_free(idp);
872 case SILC_PACKET_HEARTBEAT:
874 * Received heartbeat packet
876 SILC_LOG_DEBUG(("Heartbeat packet"));
879 case SILC_PACKET_KEY_AGREEMENT:
881 * Received key agreement packet
883 SILC_LOG_DEBUG(("Key agreement packet"));
884 silc_client_key_agreement(client, sock, packet);
888 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
893 /* Sends packet. This doesn't actually send the packet instead it assembles
894 it and marks it to be sent. However, if force_send is TRUE the packet
895 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
896 will be derived from sock argument. Otherwise the valid arguments sent
899 void silc_client_packet_send(SilcClient client,
900 SilcSocketConnection sock,
903 SilcIdType dst_id_type,
907 unsigned int data_len,
910 SilcPacketContext packetdata;
912 SILC_LOG_DEBUG(("Sending packet, type %d", type));
914 /* Get data used in the packet sending, keys and stuff */
915 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
916 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
917 cipher = ((SilcClientConnection)sock->user_data)->send_key;
919 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
920 hmac = ((SilcClientConnection)sock->user_data)->hmac;
922 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
923 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
924 dst_id_type = SILC_ID_SERVER;
928 /* Set the packet context pointers */
929 packetdata.flags = 0;
930 packetdata.type = type;
931 if (((SilcClientConnection)sock->user_data)->local_id_data)
932 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
934 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
935 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
936 packetdata.src_id_type = SILC_ID_CLIENT;
938 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
939 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
940 packetdata.dst_id_type = dst_id_type;
942 packetdata.dst_id = NULL;
943 packetdata.dst_id_len = 0;
944 packetdata.dst_id_type = SILC_ID_NONE;
946 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
947 packetdata.src_id_len + packetdata.dst_id_len;
948 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
950 /* Prepare outgoing data buffer for packet sending */
951 silc_packet_send_prepare(sock,
952 SILC_PACKET_HEADER_LEN +
953 packetdata.src_id_len +
954 packetdata.dst_id_len,
958 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
960 packetdata.buffer = sock->outbuf;
962 /* Put the data to the buffer */
963 if (data && data_len)
964 silc_buffer_put(sock->outbuf, data, data_len);
966 /* Create the outgoing packet */
967 silc_packet_assemble(&packetdata);
969 /* Encrypt the packet */
971 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
973 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
974 sock->outbuf->data, sock->outbuf->len);
976 /* Now actually send the packet */
977 silc_client_packet_send_real(client, sock, force_send);
980 /* Closes connection to remote end. Free's all allocated data except
981 for some information such as nickname etc. that are valid at all time. */
983 void silc_client_close_connection(SilcClient client,
984 SilcClientConnection conn)
986 SilcSocketConnection sock = conn->sock;
988 /* We won't listen for this connection anymore */
989 silc_schedule_unset_listen_fd(sock->sock);
991 /* Unregister all tasks */
992 silc_task_unregister_by_fd(client->io_queue, sock->sock);
993 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
995 /* Close the actual connection */
996 silc_net_close_connection(sock->sock);
998 client->ops->say(client, sock->user_data,
999 "Closed connection to host %s", sock->hostname);
1001 /* Free everything */
1002 if (sock->user_data) {
1003 /* XXX Free all client entries and channel entries. */
1005 /* Clear ID caches */
1006 silc_idcache_del_all(conn->client_cache);
1007 silc_idcache_del_all(conn->channel_cache);
1010 if (conn->remote_host)
1011 silc_free(conn->remote_host);
1013 silc_free(conn->local_id);
1014 if (conn->local_id_data)
1015 silc_free(conn->local_id_data);
1017 silc_cipher_free(conn->send_key);
1018 if (conn->receive_key)
1019 silc_cipher_free(conn->receive_key);
1021 silc_hmac_free(conn->hmac);
1022 if (conn->hmac_key) {
1023 memset(conn->hmac_key, 0, conn->hmac_key_len);
1024 silc_free(conn->hmac_key);
1026 if (conn->pending_commands)
1027 silc_dlist_uninit(conn->pending_commands);
1030 conn->remote_port = 0;
1031 conn->remote_type = 0;
1032 conn->send_key = NULL;
1033 conn->receive_key = NULL;
1035 conn->hmac_key = NULL;
1036 conn->hmac_key_len = 0;
1037 conn->local_id = NULL;
1038 conn->local_id_data = NULL;
1039 conn->remote_host = NULL;
1040 conn->current_channel = NULL;
1041 conn->pending_commands = NULL;
1043 silc_client_del_connection(client, conn);
1046 if (sock->protocol) {
1047 silc_protocol_free(sock->protocol);
1048 sock->protocol = NULL;
1050 silc_socket_free(sock);
1053 /* Called when we receive disconnection packet from server. This
1054 closes our end properly and displays the reason of the disconnection
1057 void silc_client_disconnected_by_server(SilcClient client,
1058 SilcSocketConnection sock,
1063 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1065 msg = silc_calloc(message->len + 1, sizeof(char));
1066 memcpy(msg, message->data, message->len);
1067 client->ops->say(client, sock->user_data, msg);
1070 SILC_SET_DISCONNECTED(sock);
1071 silc_client_close_connection(client, sock->user_data);
1074 /* Received error message from server. Display it on the screen.
1075 We don't take any action what so ever of the error message. */
1077 void silc_client_error_by_server(SilcClient client,
1078 SilcSocketConnection sock,
1083 msg = silc_calloc(message->len + 1, sizeof(char));
1084 memcpy(msg, message->data, message->len);
1085 client->ops->say(client, sock->user_data, msg);
1089 /* Processes the received new Client ID from server. Old Client ID is
1090 deleted from cache and new one is added. */
1092 void silc_client_receive_new_id(SilcClient client,
1093 SilcSocketConnection sock,
1096 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1097 int connecting = FALSE;
1099 if (!conn->local_entry)
1102 /* Delete old ID from ID cache */
1103 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1105 /* Save the new ID */
1107 silc_free(conn->local_id);
1108 if (conn->local_id_data)
1109 silc_free(conn->local_id_data);
1111 conn->local_id = silc_id_payload_get_id(idp);
1112 conn->local_id_data = silc_id_payload_get_data(idp);
1113 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1115 if (!conn->local_entry)
1116 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1118 conn->local_entry->nickname = conn->nickname;
1119 if (!conn->local_entry->username) {
1120 conn->local_entry->username =
1121 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1122 sizeof(conn->local_entry->username));
1123 sprintf(conn->local_entry->username, "%s@%s", client->username,
1126 conn->local_entry->server = strdup(conn->remote_host);
1127 conn->local_entry->id = conn->local_id;
1129 /* Put it to the ID cache */
1130 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1131 conn->local_id, (void *)conn->local_entry, TRUE);
1133 /* Notify application of successful connection. We do it here now that
1134 we've received the Client ID and are allowed to send traffic. */
1136 client->ops->connect(client, conn, TRUE);
1139 /* Processed received Channel ID for a channel. This is called when client
1140 joins to channel and server replies with channel ID. The ID is cached.
1141 Returns the created channel entry. */
1143 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1144 SilcSocketConnection sock,
1149 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1150 SilcChannelEntry channel;
1152 SILC_LOG_DEBUG(("New channel ID"));
1154 channel = silc_calloc(1, sizeof(*channel));
1155 channel->channel_name = channel_name;
1156 channel->id = silc_id_payload_get_id(idp);
1157 channel->mode = mode;
1158 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1160 conn->current_channel = channel;
1162 /* Put it to the ID cache */
1163 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1164 (void *)channel->id, (void *)channel, TRUE);
1169 /* Removes a client entry from all channel it has joined. This really is
1170 a performance killer (client_entry should have pointers to channel
1173 void silc_client_remove_from_channels(SilcClient client,
1174 SilcClientConnection conn,
1175 SilcClientEntry client_entry)
1177 SilcIDCacheEntry id_cache;
1178 SilcIDCacheList list;
1179 SilcChannelEntry channel;
1180 SilcChannelUser chu;
1182 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1183 SILC_ID_CHANNEL, &list))
1186 silc_idcache_list_first(list, &id_cache);
1187 channel = (SilcChannelEntry)id_cache->context;
1191 /* Remove client from channel */
1192 silc_list_start(channel->clients);
1193 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1194 if (chu->client == client_entry) {
1195 silc_list_del(channel->clients, chu);
1201 if (!silc_idcache_list_next(list, &id_cache))
1204 channel = (SilcChannelEntry)id_cache->context;
1207 silc_idcache_list_free(list);
1210 /* Replaces `old' client entries from all channels to `new' client entry.
1211 This can be called for example when nickname changes and old ID entry
1212 is replaced from ID cache with the new one. If the old ID entry is only
1213 updated, then this fucntion needs not to be called. */
1215 void silc_client_replace_from_channels(SilcClient client,
1216 SilcClientConnection conn,
1217 SilcClientEntry old,
1218 SilcClientEntry new)
1220 SilcIDCacheEntry id_cache;
1221 SilcIDCacheList list;
1222 SilcChannelEntry channel;
1223 SilcChannelUser chu;
1225 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1226 SILC_ID_CHANNEL, &list))
1229 silc_idcache_list_first(list, &id_cache);
1230 channel = (SilcChannelEntry)id_cache->context;
1234 /* Replace client entry */
1235 silc_list_start(channel->clients);
1236 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1237 if (chu->client == old) {
1243 if (!silc_idcache_list_next(list, &id_cache))
1246 channel = (SilcChannelEntry)id_cache->context;
1249 silc_idcache_list_free(list);
1252 /* Parses mode mask and returns the mode as string. */
1254 char *silc_client_chmode(unsigned int mode)
1261 memset(string, 0, sizeof(string));
1263 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1264 strncat(string, "p", 1);
1266 if (mode & SILC_CHANNEL_MODE_SECRET)
1267 strncat(string, "s", 1);
1269 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1270 strncat(string, "k", 1);
1272 if (mode & SILC_CHANNEL_MODE_INVITE)
1273 strncat(string, "i", 1);
1275 if (mode & SILC_CHANNEL_MODE_TOPIC)
1276 strncat(string, "t", 1);
1278 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1279 strncat(string, "l", 1);
1281 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1282 strncat(string, "a", 1);
1284 /* Rest of mode is ignored */
1286 return strdup(string);
1289 /* Parses channel user mode mask and returns te mode as string */
1291 char *silc_client_chumode(unsigned int mode)
1298 memset(string, 0, sizeof(string));
1300 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1301 strncat(string, "f", 1);
1303 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1304 strncat(string, "o", 1);
1306 return strdup(string);
1309 /* Parses channel user mode and returns it as special mode character. */
1311 char *silc_client_chumode_char(unsigned int mode)
1318 memset(string, 0, sizeof(string));
1320 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1321 strncat(string, "*", 1);
1323 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1324 strncat(string, "@", 1);
1326 return strdup(string);
1329 /* Failure timeout callback. If this is called then we will immediately
1330 process the received failure. We always process the failure with timeout
1331 since we do not want to blindly trust to received failure packets.
1332 This won't be called (the timeout is cancelled) if the failure was
1333 bogus (it is bogus if remote does not close the connection after sending
1336 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1338 SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1340 if (f->sock->protocol) {
1341 f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1342 f->sock->protocol->execute(f->client->timeout_queue, 0,
1343 f->sock->protocol, f->sock->sock, 0, 0);
1345 /* Notify application */
1346 f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1347 (void *)f->failure);
1353 /* Registers failure timeout to process the received failure packet
1356 void silc_client_process_failure(SilcClient client,
1357 SilcSocketConnection sock,
1358 SilcPacketContext *packet)
1360 SilcClientFailureContext *f;
1361 unsigned int failure = 0;
1363 if (sock->protocol) {
1364 if (packet->buffer->len >= 4)
1365 SILC_GET32_MSB(failure, packet->buffer->data);
1367 f = silc_calloc(1, sizeof(*f));
1370 f->failure = failure;
1372 /* We will wait 5 seconds to process this failure packet */
1373 silc_task_register(client->timeout_queue, sock->sock,
1374 silc_client_failure_callback, (void *)f, 5, 0,
1375 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);