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 /* Parses whole packet, received earlier. */
630 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
632 SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
633 SilcClient client = (SilcClient)parse_ctx->context;
634 SilcPacketContext *packet = parse_ctx->packet;
635 SilcBuffer buffer = packet->buffer;
636 SilcSocketConnection sock = parse_ctx->sock;
637 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
640 SILC_LOG_DEBUG(("Start"));
642 /* Decrypt the received packet */
643 ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
648 /* Parse the packet. Packet type is returned. */
649 ret = silc_packet_parse(packet);
651 /* Parse the packet header in special way as this is "special"
653 ret = silc_packet_parse_special(packet);
656 if (ret == SILC_PACKET_NONE)
659 /* Parse the incoming packet type */
660 silc_client_packet_parse_type(client, sock, packet);
663 silc_buffer_clear(sock->inbuf);
664 silc_packet_context_free(packet);
665 silc_free(parse_ctx);
668 /* Parser callback called by silc_packet_receive_process. Thie merely
669 registers timeout that will handle the actual parsing when appropriate. */
671 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
673 SilcClient client = (SilcClient)parser_context->context;
675 /* Parse the packet */
676 silc_task_register(client->timeout_queue, parser_context->sock->sock,
677 silc_client_packet_parse_real,
678 (void *)parser_context, 0, 1,
680 SILC_TASK_PRI_NORMAL);
683 /* Parses the packet type and calls what ever routines the packet type
684 requires. This is done for all incoming packets. */
686 void silc_client_packet_parse_type(SilcClient client,
687 SilcSocketConnection sock,
688 SilcPacketContext *packet)
690 SilcBuffer buffer = packet->buffer;
691 SilcPacketType type = packet->type;
693 SILC_LOG_DEBUG(("Parsing packet type %d", type));
695 /* Parse the packet type */
697 case SILC_PACKET_DISCONNECT:
698 silc_client_disconnected_by_server(client, sock, buffer);
700 case SILC_PACKET_SUCCESS:
702 * Success received for something. For now we can have only
703 * one protocol for connection executing at once hence this
704 * success message is for whatever protocol is executing currently.
706 if (sock->protocol) {
707 sock->protocol->execute(client->timeout_queue, 0,
708 sock->protocol, sock->sock, 0, 0);
711 case SILC_PACKET_FAILURE:
713 * Failure received for some protocol. Set the protocol state to
714 * error and call the protocol callback. This fill cause error on
715 * protocol and it will call the final callback.
717 silc_client_process_failure(client, sock, packet);
719 case SILC_PACKET_REJECT:
722 case SILC_PACKET_NOTIFY:
724 * Received notify message
726 silc_client_notify_by_server(client, sock, packet);
729 case SILC_PACKET_ERROR:
731 * Received error message
733 silc_client_error_by_server(client, sock, buffer);
736 case SILC_PACKET_CHANNEL_MESSAGE:
738 * Received message to (from, actually) a channel
740 silc_client_channel_message(client, sock, packet);
742 case SILC_PACKET_CHANNEL_KEY:
744 * Received key for a channel. By receiving this key the client will be
745 * able to talk to the channel it has just joined. This can also be
746 * a new key for existing channel as keys expire peridiocally.
748 silc_client_receive_channel_key(client, sock, buffer);
751 case SILC_PACKET_PRIVATE_MESSAGE:
753 * Received private message
755 silc_client_private_message(client, sock, packet);
757 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
759 * Received private message key
763 case SILC_PACKET_COMMAND_REPLY:
765 * Recived reply for a command
767 silc_client_command_reply_process(client, sock, packet);
770 case SILC_PACKET_KEY_EXCHANGE:
771 if (sock->protocol) {
772 SilcClientKEInternalContext *proto_ctx =
773 (SilcClientKEInternalContext *)sock->protocol->context;
775 proto_ctx->packet = silc_packet_context_dup(packet);
776 proto_ctx->dest_id_type = packet->src_id_type;
777 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
778 packet->src_id_type);
779 if (!proto_ctx->dest_id)
782 /* Let the protocol handle the packet */
783 sock->protocol->execute(client->timeout_queue, 0,
784 sock->protocol, sock->sock, 0, 0);
786 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
787 "protocol active, packet dropped."));
789 /* XXX Trigger KE protocol?? Rekey actually! */
793 case SILC_PACKET_KEY_EXCHANGE_1:
794 if (sock->protocol) {
797 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
798 "protocol active, packet dropped."));
801 case SILC_PACKET_KEY_EXCHANGE_2:
802 if (sock->protocol) {
803 SilcClientKEInternalContext *proto_ctx =
804 (SilcClientKEInternalContext *)sock->protocol->context;
806 if (proto_ctx->packet)
807 silc_packet_context_free(proto_ctx->packet);
809 proto_ctx->packet = silc_packet_context_dup(packet);
810 proto_ctx->dest_id_type = packet->src_id_type;
811 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
812 packet->src_id_type);
813 if (!proto_ctx->dest_id)
816 /* Let the protocol handle the packet */
817 sock->protocol->execute(client->timeout_queue, 0,
818 sock->protocol, sock->sock, 0, 0);
820 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
821 "protocol active, packet dropped."));
825 case SILC_PACKET_NEW_ID:
828 * Received new ID from server. This packet is received at
829 * the connection to the server. New ID is also received when
830 * user changes nickname but in that case the new ID is received
831 * as command reply and not as this packet type.
835 idp = silc_id_payload_parse(buffer);
838 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
841 silc_client_receive_new_id(client, sock, idp);
842 silc_id_payload_free(idp);
846 case SILC_PACKET_HEARTBEAT:
848 * Received heartbeat packet
850 SILC_LOG_DEBUG(("Heartbeat packet"));
853 case SILC_PACKET_KEY_AGREEMENT:
855 * Received key agreement packet
857 SILC_LOG_DEBUG(("Key agreement packet"));
858 silc_client_key_agreement(client, sock, packet);
862 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
867 /* Sends packet. This doesn't actually send the packet instead it assembles
868 it and marks it to be sent. However, if force_send is TRUE the packet
869 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
870 will be derived from sock argument. Otherwise the valid arguments sent
873 void silc_client_packet_send(SilcClient client,
874 SilcSocketConnection sock,
877 SilcIdType dst_id_type,
881 unsigned int data_len,
884 SilcPacketContext packetdata;
886 SILC_LOG_DEBUG(("Sending packet, type %d", type));
888 /* Get data used in the packet sending, keys and stuff */
889 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
890 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
891 cipher = ((SilcClientConnection)sock->user_data)->send_key;
893 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
894 hmac = ((SilcClientConnection)sock->user_data)->hmac;
896 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
897 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
898 dst_id_type = SILC_ID_SERVER;
902 /* Set the packet context pointers */
903 packetdata.flags = 0;
904 packetdata.type = type;
905 if (((SilcClientConnection)sock->user_data)->local_id_data)
906 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
908 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
909 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
910 packetdata.src_id_type = SILC_ID_CLIENT;
912 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
913 packetdata.dst_id_len = silc_id_get_len(dst_id_type);
914 packetdata.dst_id_type = dst_id_type;
916 packetdata.dst_id = NULL;
917 packetdata.dst_id_len = 0;
918 packetdata.dst_id_type = SILC_ID_NONE;
920 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
921 packetdata.src_id_len + packetdata.dst_id_len;
922 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
924 /* Prepare outgoing data buffer for packet sending */
925 silc_packet_send_prepare(sock,
926 SILC_PACKET_HEADER_LEN +
927 packetdata.src_id_len +
928 packetdata.dst_id_len,
932 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
934 packetdata.buffer = sock->outbuf;
936 /* Put the data to the buffer */
937 if (data && data_len)
938 silc_buffer_put(sock->outbuf, data, data_len);
940 /* Create the outgoing packet */
941 silc_packet_assemble(&packetdata);
943 /* Encrypt the packet */
945 silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
947 SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
948 sock->outbuf->data, sock->outbuf->len);
950 /* Now actually send the packet */
951 silc_client_packet_send_real(client, sock, force_send);
954 /* Closes connection to remote end. Free's all allocated data except
955 for some information such as nickname etc. that are valid at all time. */
957 void silc_client_close_connection(SilcClient client,
958 SilcClientConnection conn)
960 SilcSocketConnection sock = conn->sock;
962 /* We won't listen for this connection anymore */
963 silc_schedule_unset_listen_fd(sock->sock);
965 /* Unregister all tasks */
966 silc_task_unregister_by_fd(client->io_queue, sock->sock);
967 silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
969 /* Close the actual connection */
970 silc_net_close_connection(sock->sock);
972 client->ops->say(client, sock->user_data,
973 "Closed connection to host %s", sock->hostname);
975 /* Free everything */
976 if (sock->user_data) {
977 /* XXX Free all client entries and channel entries. */
979 /* Clear ID caches */
980 silc_idcache_del_all(conn->client_cache);
981 silc_idcache_del_all(conn->channel_cache);
984 if (conn->remote_host)
985 silc_free(conn->remote_host);
987 silc_free(conn->local_id);
988 if (conn->local_id_data)
989 silc_free(conn->local_id_data);
991 silc_cipher_free(conn->send_key);
992 if (conn->receive_key)
993 silc_cipher_free(conn->receive_key);
995 silc_hmac_free(conn->hmac);
996 if (conn->hmac_key) {
997 memset(conn->hmac_key, 0, conn->hmac_key_len);
998 silc_free(conn->hmac_key);
1000 if (conn->pending_commands)
1001 silc_dlist_uninit(conn->pending_commands);
1004 conn->remote_port = 0;
1005 conn->remote_type = 0;
1006 conn->send_key = NULL;
1007 conn->receive_key = NULL;
1009 conn->hmac_key = NULL;
1010 conn->hmac_key_len = 0;
1011 conn->local_id = NULL;
1012 conn->local_id_data = NULL;
1013 conn->remote_host = NULL;
1014 conn->current_channel = NULL;
1015 conn->pending_commands = NULL;
1017 silc_client_del_connection(client, conn);
1020 if (sock->protocol) {
1021 silc_protocol_free(sock->protocol);
1022 sock->protocol = NULL;
1024 silc_socket_free(sock);
1027 /* Called when we receive disconnection packet from server. This
1028 closes our end properly and displays the reason of the disconnection
1031 void silc_client_disconnected_by_server(SilcClient client,
1032 SilcSocketConnection sock,
1037 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1039 msg = silc_calloc(message->len + 1, sizeof(char));
1040 memcpy(msg, message->data, message->len);
1041 client->ops->say(client, sock->user_data, msg);
1044 SILC_SET_DISCONNECTED(sock);
1045 silc_client_close_connection(client, sock->user_data);
1048 /* Received error message from server. Display it on the screen.
1049 We don't take any action what so ever of the error message. */
1051 void silc_client_error_by_server(SilcClient client,
1052 SilcSocketConnection sock,
1057 msg = silc_calloc(message->len + 1, sizeof(char));
1058 memcpy(msg, message->data, message->len);
1059 client->ops->say(client, sock->user_data, msg);
1063 /* Processes the received new Client ID from server. Old Client ID is
1064 deleted from cache and new one is added. */
1066 void silc_client_receive_new_id(SilcClient client,
1067 SilcSocketConnection sock,
1070 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1071 int connecting = FALSE;
1073 if (!conn->local_entry)
1076 /* Delete old ID from ID cache */
1077 silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1079 /* Save the new ID */
1081 silc_free(conn->local_id);
1082 if (conn->local_id_data)
1083 silc_free(conn->local_id_data);
1085 conn->local_id = silc_id_payload_get_id(idp);
1086 conn->local_id_data = silc_id_payload_get_data(idp);
1087 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1089 if (!conn->local_entry)
1090 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1092 conn->local_entry->nickname = conn->nickname;
1093 if (!conn->local_entry->username) {
1094 conn->local_entry->username =
1095 silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1096 sizeof(conn->local_entry->username));
1097 sprintf(conn->local_entry->username, "%s@%s", client->username,
1100 conn->local_entry->server = strdup(conn->remote_host);
1101 conn->local_entry->id = conn->local_id;
1103 /* Put it to the ID cache */
1104 silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
1105 conn->local_id, (void *)conn->local_entry, TRUE);
1107 /* Notify application of successful connection. We do it here now that
1108 we've received the Client ID and are allowed to send traffic. */
1110 client->ops->connect(client, conn, TRUE);
1113 /* Processed received Channel ID for a channel. This is called when client
1114 joins to channel and server replies with channel ID. The ID is cached.
1115 Returns the created channel entry. */
1117 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1118 SilcSocketConnection sock,
1123 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1124 SilcChannelEntry channel;
1126 SILC_LOG_DEBUG(("New channel ID"));
1128 channel = silc_calloc(1, sizeof(*channel));
1129 channel->channel_name = channel_name;
1130 channel->id = silc_id_payload_get_id(idp);
1131 channel->mode = mode;
1132 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1134 conn->current_channel = channel;
1136 /* Put it to the ID cache */
1137 silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
1138 (void *)channel->id, (void *)channel, TRUE);
1143 /* Removes a client entry from all channel it has joined. This really is
1144 a performance killer (client_entry should have pointers to channel
1147 void silc_client_remove_from_channels(SilcClient client,
1148 SilcClientConnection conn,
1149 SilcClientEntry client_entry)
1151 SilcIDCacheEntry id_cache;
1152 SilcIDCacheList list;
1153 SilcChannelEntry channel;
1154 SilcChannelUser chu;
1156 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1157 SILC_ID_CHANNEL, &list))
1160 silc_idcache_list_first(list, &id_cache);
1161 channel = (SilcChannelEntry)id_cache->context;
1165 /* Remove client from channel */
1166 silc_list_start(channel->clients);
1167 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1168 if (chu->client == client_entry) {
1169 silc_list_del(channel->clients, chu);
1175 if (!silc_idcache_list_next(list, &id_cache))
1178 channel = (SilcChannelEntry)id_cache->context;
1181 silc_idcache_list_free(list);
1184 /* Replaces `old' client entries from all channels to `new' client entry.
1185 This can be called for example when nickname changes and old ID entry
1186 is replaced from ID cache with the new one. If the old ID entry is only
1187 updated, then this fucntion needs not to be called. */
1189 void silc_client_replace_from_channels(SilcClient client,
1190 SilcClientConnection conn,
1191 SilcClientEntry old,
1192 SilcClientEntry new)
1194 SilcIDCacheEntry id_cache;
1195 SilcIDCacheList list;
1196 SilcChannelEntry channel;
1197 SilcChannelUser chu;
1199 if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1200 SILC_ID_CHANNEL, &list))
1203 silc_idcache_list_first(list, &id_cache);
1204 channel = (SilcChannelEntry)id_cache->context;
1208 /* Replace client entry */
1209 silc_list_start(channel->clients);
1210 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1211 if (chu->client == old) {
1217 if (!silc_idcache_list_next(list, &id_cache))
1220 channel = (SilcChannelEntry)id_cache->context;
1223 silc_idcache_list_free(list);
1226 /* Parses mode mask and returns the mode as string. */
1228 char *silc_client_chmode(unsigned int mode)
1235 memset(string, 0, sizeof(string));
1237 if (mode & SILC_CHANNEL_MODE_PRIVATE)
1238 strncat(string, "p", 1);
1240 if (mode & SILC_CHANNEL_MODE_SECRET)
1241 strncat(string, "s", 1);
1243 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1244 strncat(string, "k", 1);
1246 if (mode & SILC_CHANNEL_MODE_INVITE)
1247 strncat(string, "i", 1);
1249 if (mode & SILC_CHANNEL_MODE_TOPIC)
1250 strncat(string, "t", 1);
1252 if (mode & SILC_CHANNEL_MODE_ULIMIT)
1253 strncat(string, "l", 1);
1255 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1256 strncat(string, "a", 1);
1258 /* Rest of mode is ignored */
1260 return strdup(string);
1263 /* Parses channel user mode mask and returns te mode as string */
1265 char *silc_client_chumode(unsigned int mode)
1272 memset(string, 0, sizeof(string));
1274 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1275 strncat(string, "f", 1);
1277 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1278 strncat(string, "o", 1);
1280 return strdup(string);
1283 /* Parses channel user mode and returns it as special mode character. */
1285 char *silc_client_chumode_char(unsigned int mode)
1292 memset(string, 0, sizeof(string));
1294 if (mode & SILC_CHANNEL_UMODE_CHANFO)
1295 strncat(string, "*", 1);
1297 if (mode & SILC_CHANNEL_UMODE_CHANOP)
1298 strncat(string, "@", 1);
1300 return strdup(string);
1303 /* Failure timeout callback. If this is called then we will immediately
1304 process the received failure. We always process the failure with timeout
1305 since we do not want to blindly trust to received failure packets.
1306 This won't be called (the timeout is cancelled) if the failure was
1307 bogus (it is bogus if remote does not close the connection after sending
1310 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1312 SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1314 if (f->sock->protocol) {
1315 f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1316 f->sock->protocol->execute(f->client->timeout_queue, 0,
1317 f->sock->protocol, f->sock->sock, 0, 0);
1319 /* Notify application */
1320 f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1321 (void *)f->failure);
1327 /* Registers failure timeout to process the received failure packet
1330 void silc_client_process_failure(SilcClient client,
1331 SilcSocketConnection sock,
1332 SilcPacketContext *packet)
1334 SilcClientFailureContext *f;
1335 unsigned int failure = 0;
1337 if (sock->protocol) {
1338 if (packet->buffer->len >= 4)
1339 SILC_GET32_MSB(failure, packet->buffer->data);
1341 f = silc_calloc(1, sizeof(*f));
1344 f->failure = failure;
1346 /* We will wait 5 seconds to process this failure packet */
1347 silc_task_register(client->timeout_queue, sock->sock,
1348 silc_client_failure_callback, (void *)f, 5, 0,
1349 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);