5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "clientlibincludes.h"
22 #include "client_internal.h"
24 /* Static task callback prototypes */
25 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
28 SILC_TASK_CALLBACK(silc_client_rekey_callback);
29 SILC_TASK_CALLBACK(silc_client_rekey_final);
31 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
33 static void silc_client_packet_parse_type(SilcClient client,
34 SilcSocketConnection sock,
35 SilcPacketContext *packet);
36 void silc_client_resolve_auth_method(bool success,
37 SilcProtocolAuthMeth auth_meth,
38 const unsigned char *auth_data,
39 uint32 auth_data_len, void *context);
41 /* Allocates new client object. This has to be done before client may
42 work. After calling this one must call silc_client_init to initialize
43 the client. The `application' is application specific user data pointer
44 and caller must free it. */
46 SilcClient silc_client_alloc(SilcClientOperations *ops,
47 SilcClientParams *params,
49 const char *silc_version)
51 SilcClient new_client;
53 new_client = silc_calloc(1, sizeof(*new_client));
54 new_client->application = application;
56 new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
57 new_client->internal->ops = ops;
58 new_client->internal->params =
59 silc_calloc(1, sizeof(*new_client->internal->params));
60 new_client->internal->silc_client_version = strdup(silc_version);
63 memcpy(new_client->internal->params, params, sizeof(*params));
65 if (!new_client->internal->params->task_max)
66 new_client->internal->params->task_max = 200;
68 if (!new_client->internal->params->rekey_secs)
69 new_client->internal->params->rekey_secs = 3600;
71 if (!new_client->internal->params->connauth_request_secs)
72 new_client->internal->params->connauth_request_secs = 2;
74 new_client->internal->params->
75 nickname_format[sizeof(new_client->internal->
76 params->nickname_format) - 1] = 0;
81 /* Frees client object and its internals. */
83 void silc_client_free(SilcClient client)
87 silc_rng_free(client->rng);
89 silc_free(client->internal->params);
90 silc_free(client->internal->silc_client_version);
91 silc_free(client->internal);
96 /* Initializes the client. This makes all the necessary steps to make
97 the client ready to be run. One must call silc_client_run to run the
98 client. Returns FALSE if error occured, TRUE otherwise. */
100 int silc_client_init(SilcClient client)
102 SILC_LOG_DEBUG(("Initializing client"));
104 /* Initialize hash functions for client to use */
105 silc_hash_alloc("md5", &client->internal->md5hash);
106 silc_hash_alloc("sha1", &client->internal->sha1hash);
108 /* Initialize none cipher */
109 silc_cipher_alloc("none", &client->internal->none_cipher);
111 /* Initialize random number generator */
112 client->rng = silc_rng_alloc();
113 silc_rng_init(client->rng);
114 silc_rng_global_init(client->rng);
116 /* Register protocols */
117 silc_client_protocols_register();
119 /* Initialize the scheduler */
121 silc_schedule_init(client->internal->params->task_max ?
122 client->internal->params->task_max : 200);
123 if (!client->schedule)
126 /* Register commands */
127 silc_client_commands_register(client);
132 /* Stops the client. This is called to stop the client and thus to stop
135 void silc_client_stop(SilcClient client)
137 SILC_LOG_DEBUG(("Stopping client"));
139 silc_schedule_stop(client->schedule);
140 silc_schedule_uninit(client->schedule);
142 silc_client_protocols_unregister();
143 silc_client_commands_unregister(client);
145 SILC_LOG_DEBUG(("Client stopped"));
148 /* Runs the client. This starts the scheduler from the utility library.
149 When this functions returns the execution of the appliation is over. */
151 void silc_client_run(SilcClient client)
153 SILC_LOG_DEBUG(("Running client"));
155 /* Start the scheduler, the heart of the SILC client. When this returns
156 the program will be terminated. */
157 silc_schedule(client->schedule);
160 /* Runs the client and returns immeadiately. This function is used when
161 the SILC Client object indicated by the `client' is run under some
162 other scheduler, or event loop or main loop. On GUI applications,
163 for example this may be desired to use to run the client under the
164 GUI application's main loop. Typically the GUI application would
165 register an idle task that calls this function multiple times in
166 a second to quickly process the SILC specific data. */
168 void silc_client_run_one(SilcClient client)
170 /* Run the scheduler once. */
171 silc_schedule_one(client->schedule, 0);
174 static void silc_client_entry_destructor(SilcIDCache cache,
175 SilcIDCacheEntry entry)
177 silc_free(entry->name);
180 /* Allocates and adds new connection to the client. This adds the allocated
181 connection to the connection table and returns a pointer to it. A client
182 can have multiple connections to multiple servers. Every connection must
183 be added to the client using this function. User data `context' may
184 be sent as argument. This function is normally used only if the
185 application performed the connecting outside the library. The library
186 however may use this internally. */
188 SilcClientConnection silc_client_add_connection(SilcClient client,
193 SilcClientConnection conn;
196 conn = silc_calloc(1, sizeof(*conn));
198 /* Initialize ID caches */
199 conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
200 silc_client_entry_destructor);
201 conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
202 conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
203 conn->client = client;
204 conn->remote_host = strdup(hostname);
205 conn->remote_port = port;
206 conn->context = context;
207 conn->pending_commands = silc_dlist_init();
208 conn->ftp_sessions = silc_dlist_init();
210 /* Add the connection to connections table */
211 for (i = 0; i < client->internal->conns_count; i++)
212 if (client->internal->conns && !client->internal->conns[i]) {
213 client->internal->conns[i] = conn;
217 client->internal->conns =
218 silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
219 * (client->internal->conns_count + 1));
220 client->internal->conns[client->internal->conns_count] = conn;
221 client->internal->conns_count++;
226 /* Removes connection from client. Frees all memory. */
228 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
232 for (i = 0; i < client->internal->conns_count; i++)
233 if (client->internal->conns[i] == conn) {
235 silc_idcache_free(conn->client_cache);
236 silc_idcache_free(conn->channel_cache);
237 silc_idcache_free(conn->server_cache);
238 if (conn->pending_commands)
239 silc_dlist_uninit(conn->pending_commands);
240 silc_free(conn->remote_host);
241 silc_dlist_uninit(conn->ftp_sessions);
244 client->internal->conns[i] = NULL;
248 /* Adds listener socket to the listener sockets table. This function is
249 used to add socket objects that are listeners to the client. This should
250 not be used to add other connection objects. */
252 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
256 if (!client->internal->sockets) {
257 client->internal->sockets =
258 silc_calloc(1, sizeof(*client->internal->sockets));
259 client->internal->sockets[0] = silc_socket_dup(sock);
260 client->internal->sockets_count = 1;
264 for (i = 0; i < client->internal->sockets_count; i++) {
265 if (client->internal->sockets[i] == NULL) {
266 client->internal->sockets[i] = silc_socket_dup(sock);
271 client->internal->sockets =
272 silc_realloc(client->internal->sockets,
273 sizeof(*client->internal->sockets) *
274 (client->internal->sockets_count + 1));
275 client->internal->sockets[client->internal->sockets_count] =
276 silc_socket_dup(sock);
277 client->internal->sockets_count++;
280 /* Deletes listener socket from the listener sockets table. */
282 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
286 if (!client->internal->sockets)
289 for (i = 0; i < client->internal->sockets_count; i++) {
290 if (client->internal->sockets[i] == sock) {
291 silc_socket_free(sock);
292 client->internal->sockets[i] = NULL;
299 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
303 /* XXX In the future we should give up this non-blocking connect all
304 together and use threads instead. */
305 /* Create connection to server asynchronously */
306 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
310 /* Register task that will receive the async connect and will
312 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
313 silc_client_connect_to_server_start,
316 SILC_TASK_PRI_NORMAL);
317 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
324 /* Connects to remote server. This is the main routine used to connect
325 to SILC server. Returns -1 on error and the created socket otherwise.
326 The `context' is user context that is saved into the SilcClientConnection
327 that is created after the connection is created. Note that application
328 may handle the connecting process outside the library. If this is the
329 case then this function is not used at all. When the connecting is
330 done the `connect' client operation is called. */
332 int silc_client_connect_to_server(SilcClient client, int port,
333 char *host, void *context)
335 SilcClientInternalConnectContext *ctx;
336 SilcClientConnection conn;
339 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
342 conn = silc_client_add_connection(client, host, port, context);
344 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
345 "Connecting to port %d of server %s", port, host);
347 /* Allocate internal context for connection process. This is
348 needed as we are doing async connecting. */
349 ctx = silc_calloc(1, sizeof(*ctx));
350 ctx->client = client;
352 ctx->host = strdup(host);
356 /* Do the actual connecting process */
357 sock = silc_client_connect_to_server_internal(ctx);
359 silc_client_del_connection(client, conn);
363 /* Socket hostname and IP lookup callback that is called before actually
364 starting the key exchange. The lookup is called from the function
365 silc_client_start_key_exchange. */
367 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
370 SilcClientConnection conn = (SilcClientConnection)context;
371 SilcClient client = conn->client;
372 SilcProtocol protocol;
373 SilcClientKEInternalContext *proto_ctx;
375 if (!conn->sock->hostname)
376 conn->sock->hostname = strdup(conn->remote_host);
378 conn->sock->ip = strdup(conn->remote_host);
379 conn->sock->port = conn->remote_port;
381 /* Allocate internal Key Exchange context. This is sent to the
382 protocol as context. */
383 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
384 proto_ctx->client = (void *)client;
385 proto_ctx->sock = silc_socket_dup(conn->sock);
386 proto_ctx->rng = client->rng;
387 proto_ctx->responder = FALSE;
388 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
389 proto_ctx->verify = silc_client_protocol_ke_verify_key;
391 /* Perform key exchange protocol. silc_client_connect_to_server_final
392 will be called after the protocol is finished. */
393 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
394 &protocol, (void *)proto_ctx,
395 silc_client_connect_to_server_second);
397 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
398 "Error: Could not start key exchange protocol");
399 silc_net_close_connection(conn->sock->sock);
400 client->internal->ops->connect(client, conn, FALSE);
403 conn->sock->protocol = protocol;
405 /* Register the connection for network input and output. This sets
406 that scheduler will listen for incoming packets for this connection
407 and sets that outgoing packets may be sent to this connection as well.
408 However, this doesn't set the scheduler for outgoing traffic, it will
409 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
410 later when outgoing data is available. */
411 context = (void *)client;
412 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
414 /* Execute the protocol */
415 silc_protocol_execute(protocol, client->schedule, 0, 0);
418 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
419 key material between client and server. This function can be called
420 directly if application is performing its own connecting and does not
421 use the connecting provided by this library. This function is normally
422 used only if the application performed the connecting outside the library.
423 The library however may use this internally. */
425 void silc_client_start_key_exchange(SilcClient client,
426 SilcClientConnection conn,
429 /* Allocate new socket connection object */
430 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
432 /* Sometimes when doing quick reconnects the new socket may be same as
433 the old one and there might be pending stuff for the old socket.
434 If new one is same then those pending sutff might cause problems.
435 Make sure they do not do that. */
436 silc_schedule_task_del_by_fd(client->schedule, fd);
438 conn->nickname = (client->nickname ? strdup(client->nickname) :
439 strdup(client->username));
441 /* Resolve the remote hostname and IP address for our socket connection */
442 silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
443 conn, client->schedule);
446 /* Callback called when error has occurred during connecting to the server.
447 The `connect' client operation will be called. */
449 SILC_TASK_CALLBACK(silc_client_connect_failure)
451 SilcClientKEInternalContext *ctx =
452 (SilcClientKEInternalContext *)context;
453 SilcClient client = (SilcClient)ctx->client;
455 client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
459 /* Start of the connection to the remote server. This is called after
460 succesful TCP/IP connection has been established to the remote host. */
462 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
464 SilcClientInternalConnectContext *ctx =
465 (SilcClientInternalConnectContext *)context;
466 SilcClient client = ctx->client;
467 SilcClientConnection conn = ctx->conn;
468 int opt, opt_len = sizeof(opt);
470 SILC_LOG_DEBUG(("Start"));
472 /* Check the socket status as it might be in error */
473 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
475 if (ctx->tries < 2) {
476 /* Connection failed but lets try again */
477 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
478 "Could not connect to server %s: %s",
479 ctx->host, strerror(opt));
480 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
481 "Connecting to port %d of server %s resumed",
482 ctx->port, ctx->host);
484 /* Unregister old connection try */
485 silc_schedule_unset_listen_fd(client->schedule, fd);
486 silc_net_close_connection(fd);
487 silc_schedule_task_del(client->schedule, ctx->task);
490 silc_client_connect_to_server_internal(ctx);
493 /* Connection failed and we won't try anymore */
494 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
495 "Could not connect to server %s: %s",
496 ctx->host, strerror(opt));
497 silc_schedule_unset_listen_fd(client->schedule, fd);
498 silc_net_close_connection(fd);
499 silc_schedule_task_del(client->schedule, ctx->task);
502 /* Notify application of failure */
503 client->internal->ops->connect(client, conn, FALSE);
504 silc_client_del_connection(client, conn);
509 silc_schedule_unset_listen_fd(client->schedule, fd);
510 silc_schedule_task_del(client->schedule, ctx->task);
513 silc_client_start_key_exchange(client, conn, fd);
516 /* Second part of the connecting to the server. This executed
517 authentication protocol. */
519 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
521 SilcProtocol protocol = (SilcProtocol)context;
522 SilcClientKEInternalContext *ctx =
523 (SilcClientKEInternalContext *)protocol->context;
524 SilcClient client = (SilcClient)ctx->client;
525 SilcSocketConnection sock = NULL;
526 SilcClientConnAuthInternalContext *proto_ctx;
528 SILC_LOG_DEBUG(("Start"));
530 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
531 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
532 /* Error occured during protocol */
533 SILC_LOG_DEBUG(("Error during KE protocol"));
534 silc_protocol_free(protocol);
535 silc_ske_free_key_material(ctx->keymat);
537 silc_ske_free(ctx->ske);
539 silc_free(ctx->dest_id);
540 ctx->sock->protocol = NULL;
541 silc_socket_free(ctx->sock);
543 /* Notify application of failure */
544 silc_schedule_task_add(client->schedule, ctx->sock->sock,
545 silc_client_connect_failure, ctx,
546 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
550 /* We now have the key material as the result of the key exchange
551 protocol. Take the key material into use. Free the raw key material
552 as soon as we've set them into use. */
553 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
554 ctx->ske->prop->cipher,
555 ctx->ske->prop->pkcs,
556 ctx->ske->prop->hash,
557 ctx->ske->prop->hmac,
558 ctx->ske->prop->group,
560 silc_ske_free_key_material(ctx->keymat);
562 /* Allocate internal context for the authentication protocol. This
563 is sent as context for the protocol. */
564 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
565 proto_ctx->client = (void *)client;
566 proto_ctx->sock = sock = ctx->sock;
567 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
568 proto_ctx->dest_id_type = ctx->dest_id_type;
569 proto_ctx->dest_id = ctx->dest_id;
571 /* Free old protocol as it is finished now */
572 silc_protocol_free(protocol);
574 silc_packet_context_free(ctx->packet);
576 sock->protocol = NULL;
578 /* Resolve the authentication method to be used in this connection. The
579 completion callback is called after the application has resolved
580 the authentication method. */
581 client->internal->ops->get_auth_method(client, sock->user_data,
584 silc_client_resolve_auth_method,
588 /* Authentication method resolving callback. Application calls this function
589 after we've called the client->internal->ops->get_auth_method
590 client operation to resolve the authentication method. We will continue
591 the executiong of the protocol in this function. */
593 void silc_client_resolve_auth_method(bool success,
594 SilcProtocolAuthMeth auth_meth,
595 const unsigned char *auth_data,
596 uint32 auth_data_len, void *context)
598 SilcClientConnAuthInternalContext *proto_ctx =
599 (SilcClientConnAuthInternalContext *)context;
600 SilcClient client = (SilcClient)proto_ctx->client;
603 auth_meth = SILC_AUTH_NONE;
605 proto_ctx->auth_meth = auth_meth;
607 if (auth_data && auth_data_len) {
608 proto_ctx->auth_data = silc_calloc(auth_data_len, sizeof(*auth_data));
609 memcpy(proto_ctx->auth_data, auth_data, auth_data_len);
610 proto_ctx->auth_data_len = auth_data_len;
613 /* Allocate the authenteication protocol and execute it. */
614 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
615 &proto_ctx->sock->protocol, (void *)proto_ctx,
616 silc_client_connect_to_server_final);
618 /* Execute the protocol */
619 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
622 /* Finalizes the connection to the remote SILC server. This is called
623 after authentication protocol has been completed. This send our
624 user information to the server to receive our client ID from
627 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
629 SilcProtocol protocol = (SilcProtocol)context;
630 SilcClientConnAuthInternalContext *ctx =
631 (SilcClientConnAuthInternalContext *)protocol->context;
632 SilcClient client = (SilcClient)ctx->client;
633 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
636 SILC_LOG_DEBUG(("Start"));
638 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
639 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
640 /* Error occured during protocol */
641 SILC_LOG_DEBUG(("Error during authentication protocol"));
642 silc_protocol_free(protocol);
644 silc_free(ctx->auth_data);
646 silc_ske_free(ctx->ske);
648 silc_free(ctx->dest_id);
649 conn->sock->protocol = NULL;
650 silc_socket_free(ctx->sock);
652 /* Notify application of failure */
653 silc_schedule_task_add(client->schedule, ctx->sock->sock,
654 silc_client_connect_failure, ctx,
655 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
659 /* Send NEW_CLIENT packet to the server. We will become registered
660 to the SILC network after sending this packet and we will receive
661 client ID from the server. */
662 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
663 strlen(client->realname));
664 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
665 silc_buffer_format(packet,
666 SILC_STR_UI_SHORT(strlen(client->username)),
667 SILC_STR_UI_XNSTRING(client->username,
668 strlen(client->username)),
669 SILC_STR_UI_SHORT(strlen(client->realname)),
670 SILC_STR_UI_XNSTRING(client->realname,
671 strlen(client->realname)),
674 /* Send the packet */
675 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
677 packet->data, packet->len, TRUE);
678 silc_buffer_free(packet);
680 /* Save remote ID. */
681 conn->remote_id = ctx->dest_id;
682 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
683 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
685 /* Register re-key timeout */
686 conn->rekey->timeout = client->internal->params->rekey_secs;
687 conn->rekey->context = (void *)client;
688 silc_schedule_task_add(client->schedule, conn->sock->sock,
689 silc_client_rekey_callback,
690 (void *)conn->sock, conn->rekey->timeout, 0,
691 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
693 silc_protocol_free(protocol);
695 silc_free(ctx->auth_data);
697 silc_ske_free(ctx->ske);
698 silc_socket_free(ctx->sock);
700 conn->sock->protocol = NULL;
703 /* Internal routine that sends packet or marks packet to be sent. This
704 is used directly only in special cases. Normal cases should use
705 silc_server_packet_send. Returns < 0 on error. */
707 int silc_client_packet_send_real(SilcClient client,
708 SilcSocketConnection sock,
713 /* If rekey protocol is active we must assure that all packets are
714 sent through packet queue. */
715 if (SILC_CLIENT_IS_REKEY(sock))
718 /* If outbound data is already pending do not force send */
719 if (SILC_IS_OUTBUF_PENDING(sock))
722 /* Send the packet */
723 ret = silc_packet_send(sock, force_send);
727 /* Mark that there is some outgoing data available for this connection.
728 This call sets the connection both for input and output (the input
729 is set always and this call keeps the input setting, actually).
730 Actual data sending is performed by silc_client_packet_process. */
731 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
733 /* Mark to socket that data is pending in outgoing buffer. This flag
734 is needed if new data is added to the buffer before the earlier
735 put data is sent to the network. */
736 SILC_SET_OUTBUF_PENDING(sock);
741 /* Packet processing callback. This is used to send and receive packets
742 from network. This is generic task. */
744 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
746 SilcClient client = (SilcClient)context;
747 SilcSocketConnection sock = NULL;
748 SilcClientConnection conn;
751 SILC_LOG_DEBUG(("Processing packet"));
753 SILC_CLIENT_GET_SOCK(client, fd, sock);
757 conn = (SilcClientConnection)sock->user_data;
760 if (type == SILC_TASK_WRITE) {
761 /* Do not send data to disconnected connection */
762 if (SILC_IS_DISCONNECTED(sock))
765 if (sock->outbuf->data - sock->outbuf->head)
766 silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
768 ret = silc_packet_send(sock, TRUE);
770 /* If returned -2 could not write to connection now, will do
779 /* The packet has been sent and now it is time to set the connection
780 back to only for input. When there is again some outgoing data
781 available for this connection it will be set for output as well.
782 This call clears the output setting and sets it only for input. */
783 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
784 SILC_UNSET_OUTBUF_PENDING(sock);
786 silc_buffer_clear(sock->outbuf);
790 /* Packet receiving */
791 if (type == SILC_TASK_READ) {
792 /* Read data from network */
793 ret = silc_packet_receive(sock);
799 SILC_LOG_DEBUG(("Read EOF"));
801 /* If connection is disconnecting already we will finally
802 close the connection */
803 if (SILC_IS_DISCONNECTING(sock)) {
804 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
805 client->internal->ops->disconnect(client, conn);
806 silc_client_close_connection(client, sock, conn);
810 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
811 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
812 client->internal->ops->disconnect(client, conn);
813 silc_client_close_connection(client, sock, conn);
817 /* Process the packet. This will call the parser that will then
818 decrypt and parse the packet. */
819 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
820 silc_packet_receive_process(sock, FALSE, conn->receive_key,
821 conn->hmac_receive, conn->psn_receive,
822 silc_client_packet_parse, client);
824 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
825 silc_client_packet_parse, client);
829 /* Parser callback called by silc_packet_receive_process. Thie merely
830 registers timeout that will handle the actual parsing when appropriate. */
832 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
835 SilcClient client = (SilcClient)context;
836 SilcSocketConnection sock = parser_context->sock;
837 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
838 SilcPacketContext *packet = parser_context->packet;
841 if (conn && conn->hmac_receive && conn->sock == sock)
842 conn->psn_receive = parser_context->packet->sequence + 1;
844 /* Parse the packet immediately */
845 if (parser_context->normal)
846 ret = silc_packet_parse(packet, conn->receive_key);
848 ret = silc_packet_parse_special(packet, conn->receive_key);
850 if (ret == SILC_PACKET_NONE) {
851 silc_packet_context_free(packet);
852 silc_free(parser_context);
856 /* If protocol for this connection is key exchange or rekey then we'll
857 process all packets synchronously, since there might be packets in
858 queue that we are not able to decrypt without first processing the
859 packets before them. */
860 if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
861 (sock->protocol && sock->protocol->protocol &&
862 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
863 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
865 /* Parse the incoming packet type */
866 silc_client_packet_parse_type(client, sock, packet);
867 silc_packet_context_free(packet);
868 silc_free(parser_context);
870 /* Reprocess the buffer since we'll return FALSE. This is because
871 the `conn->receive_key' might have become valid by processing
872 the previous packet */
873 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
874 silc_packet_receive_process(sock, FALSE, conn->receive_key,
875 conn->hmac_receive, conn->psn_receive,
876 silc_client_packet_parse, client);
878 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
879 silc_client_packet_parse, client);
884 /* Parse the incoming packet type */
885 silc_client_packet_parse_type(client, sock, packet);
886 silc_packet_context_free(packet);
887 silc_free(parser_context);
891 /* Parses the packet type and calls what ever routines the packet type
892 requires. This is done for all incoming packets. */
894 void silc_client_packet_parse_type(SilcClient client,
895 SilcSocketConnection sock,
896 SilcPacketContext *packet)
898 SilcBuffer buffer = packet->buffer;
899 SilcPacketType type = packet->type;
901 SILC_LOG_DEBUG(("Parsing packet type %d", type));
903 /* Parse the packet type */
905 case SILC_PACKET_DISCONNECT:
906 silc_client_disconnected_by_server(client, sock, buffer);
908 case SILC_PACKET_SUCCESS:
910 * Success received for something. For now we can have only
911 * one protocol for connection executing at once hence this
912 * success message is for whatever protocol is executing currently.
915 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
917 case SILC_PACKET_FAILURE:
919 * Failure received for some protocol. Set the protocol state to
920 * error and call the protocol callback. This fill cause error on
921 * protocol and it will call the final callback.
923 silc_client_process_failure(client, sock, packet);
925 case SILC_PACKET_REJECT:
928 case SILC_PACKET_NOTIFY:
930 * Received notify message
932 silc_client_notify_by_server(client, sock, packet);
935 case SILC_PACKET_ERROR:
937 * Received error message
939 silc_client_error_by_server(client, sock, buffer);
942 case SILC_PACKET_CHANNEL_MESSAGE:
944 * Received message to (from, actually) a channel
946 silc_client_channel_message(client, sock, packet);
948 case SILC_PACKET_CHANNEL_KEY:
950 * Received key for a channel. By receiving this key the client will be
951 * able to talk to the channel it has just joined. This can also be
952 * a new key for existing channel as keys expire peridiocally.
954 silc_client_receive_channel_key(client, sock, buffer);
957 case SILC_PACKET_PRIVATE_MESSAGE:
959 * Received private message
961 silc_client_private_message(client, sock, packet);
963 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
965 * Received private message key
969 case SILC_PACKET_COMMAND_REPLY:
971 * Recived reply for a command
973 silc_client_command_reply_process(client, sock, packet);
976 case SILC_PACKET_KEY_EXCHANGE:
977 if (sock->protocol && sock->protocol->protocol &&
978 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
979 SilcClientKEInternalContext *proto_ctx =
980 (SilcClientKEInternalContext *)sock->protocol->context;
982 proto_ctx->packet = silc_packet_context_dup(packet);
983 proto_ctx->dest_id_type = packet->src_id_type;
984 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
985 packet->src_id_type);
986 if (!proto_ctx->dest_id)
989 /* Let the protocol handle the packet */
990 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
992 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
993 "protocol active, packet dropped."));
997 case SILC_PACKET_KEY_EXCHANGE_1:
998 if (sock->protocol && sock->protocol->protocol &&
999 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1000 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1002 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1003 SilcClientRekeyInternalContext *proto_ctx =
1004 (SilcClientRekeyInternalContext *)sock->protocol->context;
1006 if (proto_ctx->packet)
1007 silc_packet_context_free(proto_ctx->packet);
1009 proto_ctx->packet = silc_packet_context_dup(packet);
1011 /* Let the protocol handle the packet */
1012 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1014 SilcClientKEInternalContext *proto_ctx =
1015 (SilcClientKEInternalContext *)sock->protocol->context;
1017 if (proto_ctx->packet)
1018 silc_packet_context_free(proto_ctx->packet);
1020 proto_ctx->packet = silc_packet_context_dup(packet);
1021 proto_ctx->dest_id_type = packet->src_id_type;
1022 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1023 packet->src_id_type);
1024 if (!proto_ctx->dest_id)
1027 /* Let the protocol handle the packet */
1028 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1031 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1032 "protocol active, packet dropped."));
1035 case SILC_PACKET_KEY_EXCHANGE_2:
1036 if (sock->protocol && sock->protocol->protocol &&
1037 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1038 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1040 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1041 SilcClientRekeyInternalContext *proto_ctx =
1042 (SilcClientRekeyInternalContext *)sock->protocol->context;
1044 if (proto_ctx->packet)
1045 silc_packet_context_free(proto_ctx->packet);
1047 proto_ctx->packet = silc_packet_context_dup(packet);
1049 /* Let the protocol handle the packet */
1050 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1052 SilcClientKEInternalContext *proto_ctx =
1053 (SilcClientKEInternalContext *)sock->protocol->context;
1055 if (proto_ctx->packet)
1056 silc_packet_context_free(proto_ctx->packet);
1058 proto_ctx->packet = silc_packet_context_dup(packet);
1059 proto_ctx->dest_id_type = packet->src_id_type;
1060 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1061 packet->src_id_type);
1062 if (!proto_ctx->dest_id)
1065 /* Let the protocol handle the packet */
1066 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1069 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1070 "protocol active, packet dropped."));
1074 case SILC_PACKET_NEW_ID:
1077 * Received new ID from server. This packet is received at
1078 * the connection to the server. New ID is also received when
1079 * user changes nickname but in that case the new ID is received
1080 * as command reply and not as this packet type.
1084 idp = silc_id_payload_parse(buffer->data, buffer->len);
1087 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1090 silc_client_receive_new_id(client, sock, idp);
1091 silc_id_payload_free(idp);
1095 case SILC_PACKET_HEARTBEAT:
1097 * Received heartbeat packet
1099 SILC_LOG_DEBUG(("Heartbeat packet"));
1102 case SILC_PACKET_KEY_AGREEMENT:
1104 * Received key agreement packet
1106 SILC_LOG_DEBUG(("Key agreement packet"));
1107 silc_client_key_agreement(client, sock, packet);
1110 case SILC_PACKET_REKEY:
1111 SILC_LOG_DEBUG(("Re-key packet"));
1112 /* We ignore this for now */
1115 case SILC_PACKET_REKEY_DONE:
1116 SILC_LOG_DEBUG(("Re-key done packet"));
1118 if (sock->protocol && sock->protocol->protocol &&
1119 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1121 SilcClientRekeyInternalContext *proto_ctx =
1122 (SilcClientRekeyInternalContext *)sock->protocol->context;
1124 if (proto_ctx->packet)
1125 silc_packet_context_free(proto_ctx->packet);
1127 proto_ctx->packet = silc_packet_context_dup(packet);
1129 /* Let the protocol handle the packet */
1130 if (proto_ctx->responder == FALSE)
1131 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1133 /* Let the protocol handle the packet */
1134 silc_protocol_execute(sock->protocol, client->schedule,
1137 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1138 "protocol active, packet dropped."));
1142 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1144 * Reveived reply to our connection authentication method request
1145 * packet. This is used to resolve the authentication method for the
1146 * current session from the server if the client does not know it.
1148 silc_client_connection_auth_request(client, sock, packet);
1151 case SILC_PACKET_FTP:
1152 /* Received file transfer packet. */
1153 silc_client_ftp(client, sock, packet);
1157 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1162 /* Sends packet. This doesn't actually send the packet instead it assembles
1163 it and marks it to be sent. However, if force_send is TRUE the packet
1164 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1165 will be derived from sock argument. Otherwise the valid arguments sent
1168 void silc_client_packet_send(SilcClient client,
1169 SilcSocketConnection sock,
1170 SilcPacketType type,
1172 SilcIdType dst_id_type,
1175 unsigned char *data,
1179 SilcPacketContext packetdata;
1181 uint32 sequence = 0;
1186 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1188 /* Get data used in the packet sending, keys and stuff */
1189 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1190 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1191 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1193 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1194 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1196 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1197 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1198 dst_id_type = SILC_ID_SERVER;
1202 sequence = ((SilcClientConnection)sock->user_data)->psn_send++;
1205 block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1207 /* Set the packet context pointers */
1208 packetdata.flags = 0;
1209 packetdata.type = type;
1210 if (sock->user_data &&
1211 ((SilcClientConnection)sock->user_data)->local_id_data) {
1212 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1213 packetdata.src_id_len =
1214 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1217 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1218 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1220 packetdata.src_id_type = SILC_ID_CLIENT;
1222 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1223 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1224 packetdata.dst_id_type = dst_id_type;
1226 packetdata.dst_id = NULL;
1227 packetdata.dst_id_len = 0;
1228 packetdata.dst_id_type = SILC_ID_NONE;
1230 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1231 packetdata.src_id_len + packetdata.dst_id_len;
1232 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
1234 /* Prepare outgoing data buffer for packet sending */
1235 silc_packet_send_prepare(sock,
1236 SILC_PACKET_HEADER_LEN +
1237 packetdata.src_id_len +
1238 packetdata.dst_id_len,
1242 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1244 packetdata.buffer = sock->outbuf;
1246 /* Put the data to the buffer */
1247 if (data && data_len)
1248 silc_buffer_put(sock->outbuf, data, data_len);
1250 /* Create the outgoing packet */
1251 silc_packet_assemble(&packetdata, cipher);
1253 /* Encrypt the packet */
1255 silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
1258 SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, sock->outbuf->len),
1259 sock->outbuf->data, sock->outbuf->len);
1261 /* Now actually send the packet */
1262 silc_client_packet_send_real(client, sock, force_send);
1265 void silc_client_packet_queue_purge(SilcClient client,
1266 SilcSocketConnection sock)
1268 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1269 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1270 if (sock->outbuf->data - sock->outbuf->head)
1271 silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
1273 silc_packet_send(sock, TRUE);
1275 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1276 SILC_UNSET_OUTBUF_PENDING(sock);
1277 silc_buffer_clear(sock->outbuf);
1281 /* Closes connection to remote end. Free's all allocated data except
1282 for some information such as nickname etc. that are valid at all time.
1283 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1284 provided it will be checked whether the sock and `conn->sock' are the
1285 same (they can be different, ie. a socket can use `conn' as its
1286 connection but `conn->sock' might be actually a different connection
1287 than the `sock'). */
1289 void silc_client_close_connection(SilcClient client,
1290 SilcSocketConnection sock,
1291 SilcClientConnection conn)
1295 SILC_LOG_DEBUG(("Start"));
1297 if (!sock || (sock && conn->sock == sock))
1302 /* We won't listen for this connection anymore */
1303 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1305 /* Unregister all tasks */
1306 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1307 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1309 /* Close the actual connection */
1310 silc_net_close_connection(sock->sock);
1312 /* Cancel any active protocol */
1313 if (sock->protocol) {
1314 if (sock->protocol->protocol->type ==
1315 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1316 sock->protocol->protocol->type ==
1317 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1318 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1319 silc_protocol_execute_final(sock->protocol, client->schedule);
1320 /* The application will recall this function with these protocols
1321 (the ops->connect client operation). */
1324 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1325 silc_protocol_execute_final(sock->protocol, client->schedule);
1326 sock->protocol = NULL;
1330 /* Free everything */
1331 if (del && sock->user_data) {
1332 /* Free all cache entries */
1333 SilcIDCacheList list;
1334 SilcIDCacheEntry entry;
1337 if (silc_idcache_get_all(conn->client_cache, &list)) {
1338 ret = silc_idcache_list_first(list, &entry);
1340 silc_client_del_client(client, conn, entry->context);
1341 ret = silc_idcache_list_next(list, &entry);
1343 silc_idcache_list_free(list);
1346 if (silc_idcache_get_all(conn->channel_cache, &list)) {
1347 ret = silc_idcache_list_first(list, &entry);
1349 silc_client_del_channel(client, conn, entry->context);
1350 ret = silc_idcache_list_next(list, &entry);
1352 silc_idcache_list_free(list);
1355 if (silc_idcache_get_all(conn->server_cache, &list)) {
1356 ret = silc_idcache_list_first(list, &entry);
1358 silc_client_del_server(client, conn, entry->context);
1359 ret = silc_idcache_list_next(list, &entry);
1361 silc_idcache_list_free(list);
1364 /* Clear ID caches */
1365 if (conn->client_cache)
1366 silc_idcache_del_all(conn->client_cache);
1367 if (conn->channel_cache)
1368 silc_idcache_del_all(conn->channel_cache);
1369 if (conn->server_cache)
1370 silc_idcache_del_all(conn->server_cache);
1372 /* Free data (my ID is freed in above silc_client_del_client) */
1373 if (conn->remote_host)
1374 silc_free(conn->remote_host);
1375 if (conn->local_id_data)
1376 silc_free(conn->local_id_data);
1378 silc_cipher_free(conn->send_key);
1379 if (conn->receive_key)
1380 silc_cipher_free(conn->receive_key);
1381 if (conn->hmac_send)
1382 silc_hmac_free(conn->hmac_send);
1383 if (conn->hmac_receive)
1384 silc_hmac_free(conn->hmac_receive);
1385 if (conn->pending_commands)
1386 silc_dlist_uninit(conn->pending_commands);
1388 silc_free(conn->rekey);
1390 if (conn->active_session) {
1391 sock->user_data = NULL;
1392 silc_client_ftp_session_free(conn->active_session);
1393 conn->active_session = NULL;
1396 silc_client_ftp_free_sessions(client, conn);
1398 memset(conn, 0, sizeof(*conn));
1399 silc_client_del_connection(client, conn);
1402 silc_socket_free(sock);
1405 /* Called when we receive disconnection packet from server. This
1406 closes our end properly and displays the reason of the disconnection
1409 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1411 SilcClient client = (SilcClient)context;
1412 SilcSocketConnection sock;
1414 SILC_CLIENT_GET_SOCK(client, fd, sock);
1418 silc_client_close_connection(client, sock, sock->user_data);
1421 /* Called when we receive disconnection packet from server. This
1422 closes our end properly and displays the reason of the disconnection
1425 void silc_client_disconnected_by_server(SilcClient client,
1426 SilcSocketConnection sock,
1431 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1433 msg = silc_calloc(message->len + 1, sizeof(char));
1434 memcpy(msg, message->data, message->len);
1435 client->internal->ops->say(client, sock->user_data,
1436 SILC_CLIENT_MESSAGE_AUDIT, msg);
1439 SILC_SET_DISCONNECTED(sock);
1441 /* Close connection through scheduler. */
1442 silc_schedule_task_add(client->schedule, sock->sock,
1443 silc_client_disconnected_by_server_later,
1444 client, 0, 1, SILC_TASK_TIMEOUT,
1445 SILC_TASK_PRI_NORMAL);
1448 /* Received error message from server. Display it on the screen.
1449 We don't take any action what so ever of the error message. */
1451 void silc_client_error_by_server(SilcClient client,
1452 SilcSocketConnection sock,
1457 msg = silc_calloc(message->len + 1, sizeof(char));
1458 memcpy(msg, message->data, message->len);
1459 client->internal->ops->say(client, sock->user_data,
1460 SILC_CLIENT_MESSAGE_AUDIT, msg);
1464 /* Processes the received new Client ID from server. Old Client ID is
1465 deleted from cache and new one is added. */
1467 void silc_client_receive_new_id(SilcClient client,
1468 SilcSocketConnection sock,
1471 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1472 int connecting = FALSE;
1473 SilcClientID *client_id = silc_id_payload_get_id(idp);
1476 if (!conn->local_entry)
1479 /* Delete old ID from ID cache */
1480 if (conn->local_id) {
1481 /* Check whether they are different */
1482 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1483 silc_free(client_id);
1487 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1488 silc_free(conn->local_id);
1491 /* Save the new ID */
1493 if (conn->local_id_data)
1494 silc_free(conn->local_id_data);
1496 conn->local_id = client_id;
1497 conn->local_id_data = silc_id_payload_get_data(idp);
1498 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1500 if (!conn->local_entry)
1501 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1503 conn->local_entry->nickname = conn->nickname;
1504 if (!conn->local_entry->username)
1505 conn->local_entry->username = strdup(client->username);
1506 if (!conn->local_entry->hostname)
1507 conn->local_entry->hostname = strdup(client->hostname);
1508 conn->local_entry->server = strdup(conn->remote_host);
1509 conn->local_entry->id = conn->local_id;
1510 conn->local_entry->valid = TRUE;
1512 /* Put it to the ID cache */
1513 silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
1514 (void *)conn->local_entry, 0, NULL);
1517 /* Send NICK command if the nickname was set by the application (and is
1518 not same as the username). */
1519 if (client->nickname && strcmp(client->nickname, client->username))
1520 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1521 ++conn->cmd_ident, 1, 1,
1522 client->nickname, strlen(client->nickname));
1524 /* Issue INFO command to fetch the real server name and server information
1526 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1527 silc_client_command_reply_info_i, 0,
1529 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1530 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1531 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1532 silc_buffer_free(sidp);
1534 /* Notify application of successful connection. We do it here now that
1535 we've received the Client ID and are allowed to send traffic. */
1536 client->internal->ops->connect(client, conn, TRUE);
1540 /* Processed received Channel ID for a channel. This is called when client
1541 joins to channel and server replies with channel ID. The ID is cached.
1542 Returns the created channel entry. This is also called when received
1543 channel ID in for example USERS command reply that we do not have. */
1545 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1546 SilcSocketConnection sock,
1551 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1552 SilcChannelEntry channel;
1554 SILC_LOG_DEBUG(("New channel ID"));
1556 channel = silc_calloc(1, sizeof(*channel));
1557 channel->channel_name = channel_name;
1558 channel->id = silc_id_payload_get_id(idp);
1559 channel->mode = mode;
1560 silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1562 /* Put it to the ID cache */
1563 silc_idcache_add(conn->channel_cache, channel->channel_name,
1564 (void *)channel->id, (void *)channel, 0, NULL);
1569 /* Removes a client entry from all channel it has joined. This really is
1570 a performance killer (client_entry should have pointers to channel
1573 void silc_client_remove_from_channels(SilcClient client,
1574 SilcClientConnection conn,
1575 SilcClientEntry client_entry)
1577 SilcIDCacheEntry id_cache;
1578 SilcIDCacheList list;
1579 SilcChannelEntry channel;
1580 SilcChannelUser chu;
1582 if (!silc_idcache_get_all(conn->channel_cache, &list))
1585 silc_idcache_list_first(list, &id_cache);
1586 channel = (SilcChannelEntry)id_cache->context;
1590 /* Remove client from channel */
1591 silc_list_start(channel->clients);
1592 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1593 if (chu->client == client_entry) {
1594 silc_list_del(channel->clients, chu);
1600 if (!silc_idcache_list_next(list, &id_cache))
1603 channel = (SilcChannelEntry)id_cache->context;
1606 silc_idcache_list_free(list);
1609 /* Replaces `old' client entries from all channels to `new' client entry.
1610 This can be called for example when nickname changes and old ID entry
1611 is replaced from ID cache with the new one. If the old ID entry is only
1612 updated, then this fucntion needs not to be called. */
1614 void silc_client_replace_from_channels(SilcClient client,
1615 SilcClientConnection conn,
1616 SilcClientEntry old,
1617 SilcClientEntry new)
1619 SilcIDCacheEntry id_cache;
1620 SilcIDCacheList list;
1621 SilcChannelEntry channel;
1622 SilcChannelUser chu;
1624 if (!silc_idcache_get_all(conn->channel_cache, &list))
1627 silc_idcache_list_first(list, &id_cache);
1628 channel = (SilcChannelEntry)id_cache->context;
1632 /* Replace client entry */
1633 silc_list_start(channel->clients);
1634 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1635 if (chu->client == old) {
1641 if (!silc_idcache_list_next(list, &id_cache))
1644 channel = (SilcChannelEntry)id_cache->context;
1647 silc_idcache_list_free(list);
1650 /* Registers failure timeout to process the received failure packet
1653 void silc_client_process_failure(SilcClient client,
1654 SilcSocketConnection sock,
1655 SilcPacketContext *packet)
1659 if (sock->protocol) {
1660 if (packet->buffer->len >= 4)
1661 SILC_GET32_MSB(failure, packet->buffer->data);
1663 /* Notify application */
1664 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1669 /* A timeout callback for the re-key. We will be the initiator of the
1672 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1674 SilcSocketConnection sock = (SilcSocketConnection)context;
1675 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1676 SilcClient client = (SilcClient)conn->rekey->context;
1677 SilcProtocol protocol;
1678 SilcClientRekeyInternalContext *proto_ctx;
1680 SILC_LOG_DEBUG(("Start"));
1682 /* Allocate internal protocol context. This is sent as context
1684 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1685 proto_ctx->client = (void *)client;
1686 proto_ctx->sock = silc_socket_dup(sock);
1687 proto_ctx->responder = FALSE;
1688 proto_ctx->pfs = conn->rekey->pfs;
1690 /* Perform rekey protocol. Will call the final callback after the
1691 protocol is over. */
1692 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1693 &protocol, proto_ctx, silc_client_rekey_final);
1694 sock->protocol = protocol;
1696 /* Run the protocol */
1697 silc_protocol_execute(protocol, client->schedule, 0, 0);
1699 /* Re-register re-key timeout */
1700 silc_schedule_task_add(client->schedule, sock->sock,
1701 silc_client_rekey_callback,
1702 context, conn->rekey->timeout, 0,
1703 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1706 /* The final callback for the REKEY protocol. This will actually take the
1707 new key material into use. */
1709 SILC_TASK_CALLBACK(silc_client_rekey_final)
1711 SilcProtocol protocol = (SilcProtocol)context;
1712 SilcClientRekeyInternalContext *ctx =
1713 (SilcClientRekeyInternalContext *)protocol->context;
1714 SilcClient client = (SilcClient)ctx->client;
1715 SilcSocketConnection sock = ctx->sock;
1717 SILC_LOG_DEBUG(("Start"));
1719 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1720 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1721 /* Error occured during protocol */
1722 silc_protocol_cancel(protocol, client->schedule);
1723 silc_protocol_free(protocol);
1724 sock->protocol = NULL;
1726 silc_packet_context_free(ctx->packet);
1728 silc_ske_free(ctx->ske);
1729 silc_socket_free(ctx->sock);
1734 /* Purge the outgoing data queue to assure that all rekey packets really
1735 go to the network before we quit the protocol. */
1736 silc_client_packet_queue_purge(client, sock);
1739 silc_protocol_free(protocol);
1740 sock->protocol = NULL;
1742 silc_packet_context_free(ctx->packet);
1744 silc_ske_free(ctx->ske);
1745 silc_socket_free(ctx->sock);
1749 /* Processes incoming connection authentication method request packet.
1750 It is a reply to our previously sent request. The packet can be used
1751 to resolve the authentication method for the current session if the
1752 client does not know it beforehand. */
1754 void silc_client_connection_auth_request(SilcClient client,
1755 SilcSocketConnection sock,
1756 SilcPacketContext *packet)
1758 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1759 uint16 conn_type, auth_meth;
1762 /* If we haven't send our request then ignore this one. */
1763 if (!conn->connauth)
1766 /* Parse the payload */
1767 ret = silc_buffer_unformat(packet->buffer,
1768 SILC_STR_UI_SHORT(&conn_type),
1769 SILC_STR_UI_SHORT(&auth_meth),
1772 auth_meth = SILC_AUTH_NONE;
1774 /* Call the request callback to notify application for received
1775 authentication method information. */
1776 if (conn->connauth->callback)
1777 (*conn->connauth->callback)(client, conn, auth_meth,
1778 conn->connauth->context);
1780 silc_schedule_task_del(client->schedule, conn->connauth->timeout);
1782 silc_free(conn->connauth);
1783 conn->connauth = NULL;
1786 /* Timeout task callback called if the server does not reply to our
1787 connection authentication method request in the specified time interval. */
1789 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1791 SilcClientConnection conn = (SilcClientConnection)context;
1792 SilcClient client = conn->client;
1794 if (!conn->connauth)
1797 /* Call the request callback to notify application */
1798 if (conn->connauth->callback)
1799 (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
1800 conn->connauth->context);
1802 silc_free(conn->connauth);
1803 conn->connauth = NULL;
1806 /* This function can be used to request the current authentication method
1807 from the server. This may be called when connecting to the server
1808 and the client library requests the authentication data from the
1809 application. If the application does not know the current authentication
1810 method it can request it from the server using this function.
1811 The `callback' with `context' will be called after the server has
1812 replied back with the current authentication method. */
1815 silc_client_request_authentication_method(SilcClient client,
1816 SilcClientConnection conn,
1817 SilcConnectionAuthRequest callback,
1820 SilcClientConnAuthRequest connauth;
1823 connauth = silc_calloc(1, sizeof(*connauth));
1824 connauth->callback = callback;
1825 connauth->context = context;
1828 silc_free(conn->connauth);
1830 conn->connauth = connauth;
1832 /* Assemble the request packet and send it to the server */
1833 packet = silc_buffer_alloc(4);
1834 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1835 silc_buffer_format(packet,
1836 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1837 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1839 silc_client_packet_send(client, conn->sock,
1840 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1841 NULL, 0, NULL, NULL,
1842 packet->data, packet->len, FALSE);
1843 silc_buffer_free(packet);
1845 /* Register a timeout in case server does not reply anything back. */
1847 silc_schedule_task_add(client->schedule, conn->sock->sock,
1848 silc_client_request_authentication_method_timeout,
1850 client->internal->params->connauth_request_secs, 0,
1851 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);