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 SILC_LOG_DEBUG(("Start"));
377 /* XXX We should most likely use the resolved host name instead of the
378 one user provided for us. */
379 silc_free(conn->sock->hostname);
380 conn->sock->hostname = strdup(conn->remote_host);
382 conn->sock->ip = strdup(conn->remote_host);
383 conn->sock->port = conn->remote_port;
385 /* Allocate internal Key Exchange context. This is sent to the
386 protocol as context. */
387 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
388 proto_ctx->client = (void *)client;
389 proto_ctx->sock = silc_socket_dup(conn->sock);
390 proto_ctx->rng = client->rng;
391 proto_ctx->responder = FALSE;
392 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
393 proto_ctx->verify = silc_client_protocol_ke_verify_key;
395 /* Perform key exchange protocol. silc_client_connect_to_server_final
396 will be called after the protocol is finished. */
397 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
398 &protocol, (void *)proto_ctx,
399 silc_client_connect_to_server_second);
401 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
402 "Error: Could not start key exchange protocol");
403 silc_net_close_connection(conn->sock->sock);
404 client->internal->ops->connect(client, conn, FALSE);
407 conn->sock->protocol = protocol;
409 /* Register the connection for network input and output. This sets
410 that scheduler will listen for incoming packets for this connection
411 and sets that outgoing packets may be sent to this connection as well.
412 However, this doesn't set the scheduler for outgoing traffic, it will
413 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
414 later when outgoing data is available. */
415 context = (void *)client;
416 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
418 /* Execute the protocol */
419 silc_protocol_execute(protocol, client->schedule, 0, 0);
422 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
423 key material between client and server. This function can be called
424 directly if application is performing its own connecting and does not
425 use the connecting provided by this library. This function is normally
426 used only if the application performed the connecting outside the library.
427 The library however may use this internally. */
429 void silc_client_start_key_exchange(SilcClient client,
430 SilcClientConnection conn,
433 /* Allocate new socket connection object */
434 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
436 /* Sometimes when doing quick reconnects the new socket may be same as
437 the old one and there might be pending stuff for the old socket.
438 If new one is same then those pending sutff might cause problems.
439 Make sure they do not do that. */
440 silc_schedule_task_del_by_fd(client->schedule, fd);
442 conn->nickname = (client->nickname ? strdup(client->nickname) :
443 strdup(client->username));
445 /* Resolve the remote hostname and IP address for our socket connection */
446 silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
447 conn, client->schedule);
450 /* Callback called when error has occurred during connecting to the server.
451 The `connect' client operation will be called. */
453 SILC_TASK_CALLBACK(silc_client_connect_failure)
455 SilcClientKEInternalContext *ctx =
456 (SilcClientKEInternalContext *)context;
457 SilcClient client = (SilcClient)ctx->client;
459 client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
461 silc_packet_context_free(ctx->packet);
465 /* Start of the connection to the remote server. This is called after
466 succesful TCP/IP connection has been established to the remote host. */
468 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
470 SilcClientInternalConnectContext *ctx =
471 (SilcClientInternalConnectContext *)context;
472 SilcClient client = ctx->client;
473 SilcClientConnection conn = ctx->conn;
474 int opt, opt_len = sizeof(opt);
476 SILC_LOG_DEBUG(("Start"));
478 /* Check the socket status as it might be in error */
479 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
481 if (ctx->tries < 2) {
482 /* Connection failed but lets try again */
483 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
484 "Could not connect to server %s: %s",
485 ctx->host, strerror(opt));
486 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
487 "Connecting to port %d of server %s resumed",
488 ctx->port, ctx->host);
490 /* Unregister old connection try */
491 silc_schedule_unset_listen_fd(client->schedule, fd);
492 silc_net_close_connection(fd);
493 silc_schedule_task_del(client->schedule, ctx->task);
496 silc_client_connect_to_server_internal(ctx);
499 /* Connection failed and we won't try anymore */
500 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
501 "Could not connect to server %s: %s",
502 ctx->host, strerror(opt));
503 silc_schedule_unset_listen_fd(client->schedule, fd);
504 silc_net_close_connection(fd);
505 silc_schedule_task_del(client->schedule, ctx->task);
508 /* Notify application of failure */
509 client->internal->ops->connect(client, conn, FALSE);
510 silc_client_del_connection(client, conn);
515 silc_schedule_unset_listen_fd(client->schedule, fd);
516 silc_schedule_task_del(client->schedule, ctx->task);
519 silc_client_start_key_exchange(client, conn, fd);
522 /* Second part of the connecting to the server. This executed
523 authentication protocol. */
525 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
527 SilcProtocol protocol = (SilcProtocol)context;
528 SilcClientKEInternalContext *ctx =
529 (SilcClientKEInternalContext *)protocol->context;
530 SilcClient client = (SilcClient)ctx->client;
531 SilcSocketConnection sock = NULL;
532 SilcClientConnAuthInternalContext *proto_ctx;
534 SILC_LOG_DEBUG(("Start"));
536 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
537 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
538 /* Error occured during protocol */
539 SILC_LOG_DEBUG(("Error during KE protocol"));
540 silc_protocol_free(protocol);
541 silc_ske_free_key_material(ctx->keymat);
543 silc_ske_free(ctx->ske);
545 silc_free(ctx->dest_id);
546 ctx->sock->protocol = NULL;
547 silc_socket_free(ctx->sock);
549 /* Notify application of failure */
550 silc_schedule_task_add(client->schedule, ctx->sock->sock,
551 silc_client_connect_failure, ctx,
552 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
556 /* We now have the key material as the result of the key exchange
557 protocol. Take the key material into use. Free the raw key material
558 as soon as we've set them into use. */
559 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
560 ctx->ske->prop->cipher,
561 ctx->ske->prop->pkcs,
562 ctx->ske->prop->hash,
563 ctx->ske->prop->hmac,
564 ctx->ske->prop->group,
566 silc_ske_free_key_material(ctx->keymat);
568 /* Allocate internal context for the authentication protocol. This
569 is sent as context for the protocol. */
570 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
571 proto_ctx->client = (void *)client;
572 proto_ctx->sock = sock = ctx->sock;
573 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
574 proto_ctx->dest_id_type = ctx->dest_id_type;
575 proto_ctx->dest_id = ctx->dest_id;
577 /* Free old protocol as it is finished now */
578 silc_protocol_free(protocol);
580 silc_packet_context_free(ctx->packet);
582 sock->protocol = NULL;
584 /* Resolve the authentication method to be used in this connection. The
585 completion callback is called after the application has resolved
586 the authentication method. */
587 client->internal->ops->get_auth_method(client, sock->user_data,
590 silc_client_resolve_auth_method,
594 /* Authentication method resolving callback. Application calls this function
595 after we've called the client->internal->ops->get_auth_method
596 client operation to resolve the authentication method. We will continue
597 the executiong of the protocol in this function. */
599 void silc_client_resolve_auth_method(bool success,
600 SilcProtocolAuthMeth auth_meth,
601 const unsigned char *auth_data,
602 uint32 auth_data_len, void *context)
604 SilcClientConnAuthInternalContext *proto_ctx =
605 (SilcClientConnAuthInternalContext *)context;
606 SilcClient client = (SilcClient)proto_ctx->client;
609 auth_meth = SILC_AUTH_NONE;
611 proto_ctx->auth_meth = auth_meth;
613 if (auth_data && auth_data_len) {
614 proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
615 proto_ctx->auth_data_len = auth_data_len;
618 /* Allocate the authenteication protocol and execute it. */
619 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
620 &proto_ctx->sock->protocol, (void *)proto_ctx,
621 silc_client_connect_to_server_final);
623 /* Execute the protocol */
624 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
627 /* Finalizes the connection to the remote SILC server. This is called
628 after authentication protocol has been completed. This send our
629 user information to the server to receive our client ID from
632 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
634 SilcProtocol protocol = (SilcProtocol)context;
635 SilcClientConnAuthInternalContext *ctx =
636 (SilcClientConnAuthInternalContext *)protocol->context;
637 SilcClient client = (SilcClient)ctx->client;
638 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
641 SILC_LOG_DEBUG(("Start"));
643 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
644 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
645 /* Error occured during protocol */
646 SILC_LOG_DEBUG(("Error during authentication protocol"));
647 silc_protocol_free(protocol);
649 silc_free(ctx->auth_data);
651 silc_ske_free(ctx->ske);
653 silc_free(ctx->dest_id);
654 conn->sock->protocol = NULL;
655 silc_socket_free(ctx->sock);
657 /* Notify application of failure */
658 silc_schedule_task_add(client->schedule, ctx->sock->sock,
659 silc_client_connect_failure, ctx,
660 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
664 /* Send NEW_CLIENT packet to the server. We will become registered
665 to the SILC network after sending this packet and we will receive
666 client ID from the server. */
667 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
668 strlen(client->realname));
669 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
670 silc_buffer_format(packet,
671 SILC_STR_UI_SHORT(strlen(client->username)),
672 SILC_STR_UI_XNSTRING(client->username,
673 strlen(client->username)),
674 SILC_STR_UI_SHORT(strlen(client->realname)),
675 SILC_STR_UI_XNSTRING(client->realname,
676 strlen(client->realname)),
679 /* Send the packet */
680 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
682 packet->data, packet->len, TRUE);
683 silc_buffer_free(packet);
685 /* Save remote ID. */
686 conn->remote_id = ctx->dest_id;
687 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
688 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
690 /* Register re-key timeout */
691 conn->rekey->timeout = client->internal->params->rekey_secs;
692 conn->rekey->context = (void *)client;
693 silc_schedule_task_add(client->schedule, conn->sock->sock,
694 silc_client_rekey_callback,
695 (void *)conn->sock, conn->rekey->timeout, 0,
696 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
698 silc_protocol_free(protocol);
700 silc_free(ctx->auth_data);
702 silc_ske_free(ctx->ske);
703 silc_socket_free(ctx->sock);
705 conn->sock->protocol = NULL;
708 /* Internal routine that sends packet or marks packet to be sent. This
709 is used directly only in special cases. Normal cases should use
710 silc_server_packet_send. Returns < 0 on error. */
712 int silc_client_packet_send_real(SilcClient client,
713 SilcSocketConnection sock,
718 /* If rekey protocol is active we must assure that all packets are
719 sent through packet queue. */
720 if (SILC_CLIENT_IS_REKEY(sock))
723 /* If outbound data is already pending do not force send */
724 if (SILC_IS_OUTBUF_PENDING(sock))
727 /* Send the packet */
728 ret = silc_packet_send(sock, force_send);
732 /* Mark that there is some outgoing data available for this connection.
733 This call sets the connection both for input and output (the input
734 is set always and this call keeps the input setting, actually).
735 Actual data sending is performed by silc_client_packet_process. */
736 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
738 /* Mark to socket that data is pending in outgoing buffer. This flag
739 is needed if new data is added to the buffer before the earlier
740 put data is sent to the network. */
741 SILC_SET_OUTBUF_PENDING(sock);
746 /* Packet processing callback. This is used to send and receive packets
747 from network. This is generic task. */
749 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
751 SilcClient client = (SilcClient)context;
752 SilcSocketConnection sock = NULL;
753 SilcClientConnection conn;
756 SILC_LOG_DEBUG(("Processing packet"));
758 SILC_CLIENT_GET_SOCK(client, fd, sock);
762 conn = (SilcClientConnection)sock->user_data;
765 if (type == SILC_TASK_WRITE) {
766 /* Do not send data to disconnected connection */
767 if (SILC_IS_DISCONNECTED(sock))
770 if (sock->outbuf->data - sock->outbuf->head)
771 silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
773 ret = silc_packet_send(sock, TRUE);
775 /* If returned -2 could not write to connection now, will do
784 /* The packet has been sent and now it is time to set the connection
785 back to only for input. When there is again some outgoing data
786 available for this connection it will be set for output as well.
787 This call clears the output setting and sets it only for input. */
788 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
789 SILC_UNSET_OUTBUF_PENDING(sock);
791 silc_buffer_clear(sock->outbuf);
795 /* Packet receiving */
796 if (type == SILC_TASK_READ) {
797 /* Read data from network */
798 ret = silc_packet_receive(sock);
804 SILC_LOG_DEBUG(("Read EOF"));
806 /* If connection is disconnecting already we will finally
807 close the connection */
808 if (SILC_IS_DISCONNECTING(sock)) {
809 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
810 client->internal->ops->disconnect(client, conn);
811 silc_client_close_connection(client, sock, conn);
815 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
816 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
817 client->internal->ops->disconnect(client, conn);
818 silc_client_close_connection(client, sock, conn);
822 /* Process the packet. This will call the parser that will then
823 decrypt and parse the packet. */
824 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
825 silc_packet_receive_process(sock, FALSE, conn->receive_key,
826 conn->hmac_receive, conn->psn_receive,
827 silc_client_packet_parse, client);
829 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
830 silc_client_packet_parse, client);
834 /* Parser callback called by silc_packet_receive_process. Thie merely
835 registers timeout that will handle the actual parsing when appropriate. */
837 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
840 SilcClient client = (SilcClient)context;
841 SilcSocketConnection sock = parser_context->sock;
842 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
843 SilcPacketContext *packet = parser_context->packet;
846 if (conn && conn->hmac_receive && conn->sock == sock)
847 conn->psn_receive = parser_context->packet->sequence + 1;
849 /* Parse the packet immediately */
850 if (parser_context->normal)
851 ret = silc_packet_parse(packet, conn->receive_key);
853 ret = silc_packet_parse_special(packet, conn->receive_key);
855 if (ret == SILC_PACKET_NONE) {
856 silc_packet_context_free(packet);
857 silc_free(parser_context);
861 /* If protocol for this connection is key exchange or rekey then we'll
862 process all packets synchronously, since there might be packets in
863 queue that we are not able to decrypt without first processing the
864 packets before them. */
865 if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
866 (sock->protocol && sock->protocol->protocol &&
867 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
868 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
870 /* Parse the incoming packet type */
871 silc_client_packet_parse_type(client, sock, packet);
872 silc_packet_context_free(packet);
873 silc_free(parser_context);
875 /* Reprocess the buffer since we'll return FALSE. This is because
876 the `conn->receive_key' might have become valid by processing
877 the previous packet */
878 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
879 silc_packet_receive_process(sock, FALSE, conn->receive_key,
880 conn->hmac_receive, conn->psn_receive,
881 silc_client_packet_parse, client);
883 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
884 silc_client_packet_parse, client);
889 /* Parse the incoming packet type */
890 silc_client_packet_parse_type(client, sock, packet);
891 silc_packet_context_free(packet);
892 silc_free(parser_context);
896 /* Parses the packet type and calls what ever routines the packet type
897 requires. This is done for all incoming packets. */
899 void silc_client_packet_parse_type(SilcClient client,
900 SilcSocketConnection sock,
901 SilcPacketContext *packet)
903 SilcBuffer buffer = packet->buffer;
904 SilcPacketType type = packet->type;
906 SILC_LOG_DEBUG(("Parsing packet type %d", type));
908 /* Parse the packet type */
910 case SILC_PACKET_DISCONNECT:
911 silc_client_disconnected_by_server(client, sock, buffer);
913 case SILC_PACKET_SUCCESS:
915 * Success received for something. For now we can have only
916 * one protocol for connection executing at once hence this
917 * success message is for whatever protocol is executing currently.
920 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
922 case SILC_PACKET_FAILURE:
924 * Failure received for some protocol. Set the protocol state to
925 * error and call the protocol callback. This fill cause error on
926 * protocol and it will call the final callback.
928 silc_client_process_failure(client, sock, packet);
930 case SILC_PACKET_REJECT:
933 case SILC_PACKET_NOTIFY:
935 * Received notify message
937 silc_client_notify_by_server(client, sock, packet);
940 case SILC_PACKET_ERROR:
942 * Received error message
944 silc_client_error_by_server(client, sock, buffer);
947 case SILC_PACKET_CHANNEL_MESSAGE:
949 * Received message to (from, actually) a channel
951 silc_client_channel_message(client, sock, packet);
953 case SILC_PACKET_CHANNEL_KEY:
955 * Received key for a channel. By receiving this key the client will be
956 * able to talk to the channel it has just joined. This can also be
957 * a new key for existing channel as keys expire peridiocally.
959 silc_client_receive_channel_key(client, sock, buffer);
962 case SILC_PACKET_PRIVATE_MESSAGE:
964 * Received private message
966 silc_client_private_message(client, sock, packet);
968 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
970 * Received private message key
974 case SILC_PACKET_COMMAND_REPLY:
976 * Recived reply for a command
978 silc_client_command_reply_process(client, sock, packet);
981 case SILC_PACKET_KEY_EXCHANGE:
982 if (sock->protocol && sock->protocol->protocol &&
983 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
984 SilcClientKEInternalContext *proto_ctx =
985 (SilcClientKEInternalContext *)sock->protocol->context;
987 proto_ctx->packet = silc_packet_context_dup(packet);
988 proto_ctx->dest_id_type = packet->src_id_type;
989 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
990 packet->src_id_type);
991 if (!proto_ctx->dest_id)
994 /* Let the protocol handle the packet */
995 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
997 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
998 "protocol active, packet dropped."));
1002 case SILC_PACKET_KEY_EXCHANGE_1:
1003 if (sock->protocol && sock->protocol->protocol &&
1004 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1005 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1007 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1008 SilcClientRekeyInternalContext *proto_ctx =
1009 (SilcClientRekeyInternalContext *)sock->protocol->context;
1011 if (proto_ctx->packet)
1012 silc_packet_context_free(proto_ctx->packet);
1014 proto_ctx->packet = silc_packet_context_dup(packet);
1016 /* Let the protocol handle the packet */
1017 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1019 SilcClientKEInternalContext *proto_ctx =
1020 (SilcClientKEInternalContext *)sock->protocol->context;
1022 if (proto_ctx->packet)
1023 silc_packet_context_free(proto_ctx->packet);
1025 proto_ctx->packet = silc_packet_context_dup(packet);
1026 proto_ctx->dest_id_type = packet->src_id_type;
1027 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1028 packet->src_id_type);
1029 if (!proto_ctx->dest_id)
1032 /* Let the protocol handle the packet */
1033 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1036 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1037 "protocol active, packet dropped."));
1040 case SILC_PACKET_KEY_EXCHANGE_2:
1041 if (sock->protocol && sock->protocol->protocol &&
1042 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1043 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1045 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1046 SilcClientRekeyInternalContext *proto_ctx =
1047 (SilcClientRekeyInternalContext *)sock->protocol->context;
1049 if (proto_ctx->packet)
1050 silc_packet_context_free(proto_ctx->packet);
1052 proto_ctx->packet = silc_packet_context_dup(packet);
1054 /* Let the protocol handle the packet */
1055 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1057 SilcClientKEInternalContext *proto_ctx =
1058 (SilcClientKEInternalContext *)sock->protocol->context;
1060 if (proto_ctx->packet)
1061 silc_packet_context_free(proto_ctx->packet);
1062 if (proto_ctx->dest_id)
1063 silc_free(proto_ctx->dest_id);
1064 proto_ctx->packet = silc_packet_context_dup(packet);
1065 proto_ctx->dest_id_type = packet->src_id_type;
1066 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1067 packet->src_id_type);
1068 if (!proto_ctx->dest_id)
1071 /* Let the protocol handle the packet */
1072 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1075 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1076 "protocol active, packet dropped."));
1080 case SILC_PACKET_NEW_ID:
1083 * Received new ID from server. This packet is received at
1084 * the connection to the server. New ID is also received when
1085 * user changes nickname but in that case the new ID is received
1086 * as command reply and not as this packet type.
1090 idp = silc_id_payload_parse(buffer->data, buffer->len);
1093 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1096 silc_client_receive_new_id(client, sock, idp);
1097 silc_id_payload_free(idp);
1101 case SILC_PACKET_HEARTBEAT:
1103 * Received heartbeat packet
1105 SILC_LOG_DEBUG(("Heartbeat packet"));
1108 case SILC_PACKET_KEY_AGREEMENT:
1110 * Received key agreement packet
1112 SILC_LOG_DEBUG(("Key agreement packet"));
1113 silc_client_key_agreement(client, sock, packet);
1116 case SILC_PACKET_REKEY:
1117 SILC_LOG_DEBUG(("Re-key packet"));
1118 /* We ignore this for now */
1121 case SILC_PACKET_REKEY_DONE:
1122 SILC_LOG_DEBUG(("Re-key done packet"));
1124 if (sock->protocol && sock->protocol->protocol &&
1125 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1127 SilcClientRekeyInternalContext *proto_ctx =
1128 (SilcClientRekeyInternalContext *)sock->protocol->context;
1130 if (proto_ctx->packet)
1131 silc_packet_context_free(proto_ctx->packet);
1133 proto_ctx->packet = silc_packet_context_dup(packet);
1135 /* Let the protocol handle the packet */
1136 if (proto_ctx->responder == FALSE)
1137 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1139 /* Let the protocol handle the packet */
1140 silc_protocol_execute(sock->protocol, client->schedule,
1143 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1144 "protocol active, packet dropped."));
1148 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1150 * Reveived reply to our connection authentication method request
1151 * packet. This is used to resolve the authentication method for the
1152 * current session from the server if the client does not know it.
1154 silc_client_connection_auth_request(client, sock, packet);
1157 case SILC_PACKET_FTP:
1158 /* Received file transfer packet. */
1159 silc_client_ftp(client, sock, packet);
1163 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1168 /* Sends packet. This doesn't actually send the packet instead it assembles
1169 it and marks it to be sent. However, if force_send is TRUE the packet
1170 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1171 will be derived from sock argument. Otherwise the valid arguments sent
1174 void silc_client_packet_send(SilcClient client,
1175 SilcSocketConnection sock,
1176 SilcPacketType type,
1178 SilcIdType dst_id_type,
1181 unsigned char *data,
1185 SilcPacketContext packetdata;
1187 uint32 sequence = 0;
1192 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1194 /* Get data used in the packet sending, keys and stuff */
1195 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1196 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1197 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1199 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1200 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1202 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1203 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1204 dst_id_type = SILC_ID_SERVER;
1208 sequence = ((SilcClientConnection)sock->user_data)->psn_send++;
1211 block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1213 /* Set the packet context pointers */
1214 packetdata.flags = 0;
1215 packetdata.type = type;
1216 if (sock->user_data &&
1217 ((SilcClientConnection)sock->user_data)->local_id_data) {
1218 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1219 packetdata.src_id_len =
1220 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1223 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1224 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1226 packetdata.src_id_type = SILC_ID_CLIENT;
1228 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1229 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1230 packetdata.dst_id_type = dst_id_type;
1232 packetdata.dst_id = NULL;
1233 packetdata.dst_id_len = 0;
1234 packetdata.dst_id_type = SILC_ID_NONE;
1236 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1237 packetdata.src_id_len + packetdata.dst_id_len;
1238 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
1240 /* Prepare outgoing data buffer for packet sending */
1241 silc_packet_send_prepare(sock,
1242 SILC_PACKET_HEADER_LEN +
1243 packetdata.src_id_len +
1244 packetdata.dst_id_len,
1248 SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
1250 packetdata.buffer = sock->outbuf;
1252 /* Put the data to the buffer */
1253 if (data && data_len)
1254 silc_buffer_put(sock->outbuf, data, data_len);
1256 /* Create the outgoing packet */
1257 silc_packet_assemble(&packetdata, cipher);
1259 /* Encrypt the packet */
1261 silc_packet_encrypt(cipher, hmac, sequence, sock->outbuf,
1264 SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, sock->outbuf->len),
1265 sock->outbuf->data, sock->outbuf->len);
1267 /* Now actually send the packet */
1268 silc_client_packet_send_real(client, sock, force_send);
1271 void silc_client_packet_queue_purge(SilcClient client,
1272 SilcSocketConnection sock)
1274 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1275 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1276 if (sock->outbuf->data - sock->outbuf->head)
1277 silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
1279 silc_packet_send(sock, TRUE);
1281 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
1282 SILC_UNSET_OUTBUF_PENDING(sock);
1283 silc_buffer_clear(sock->outbuf);
1287 /* Closes connection to remote end. Free's all allocated data except
1288 for some information such as nickname etc. that are valid at all time.
1289 If the `sock' is NULL then the conn->sock will be used. If `sock' is
1290 provided it will be checked whether the sock and `conn->sock' are the
1291 same (they can be different, ie. a socket can use `conn' as its
1292 connection but `conn->sock' might be actually a different connection
1293 than the `sock'). */
1295 void silc_client_close_connection(SilcClient client,
1296 SilcSocketConnection sock,
1297 SilcClientConnection conn)
1301 SILC_LOG_DEBUG(("Start"));
1303 if (!sock || (sock && conn->sock == sock))
1308 /* We won't listen for this connection anymore */
1309 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
1311 /* Unregister all tasks */
1312 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1313 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
1315 /* Close the actual connection */
1316 silc_net_close_connection(sock->sock);
1318 /* Cancel any active protocol */
1319 if (sock->protocol) {
1320 if (sock->protocol->protocol->type ==
1321 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1322 sock->protocol->protocol->type ==
1323 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1324 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1325 silc_protocol_execute_final(sock->protocol, client->schedule);
1326 /* The application will recall this function with these protocols
1327 (the ops->connect client operation). */
1330 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
1331 silc_protocol_execute_final(sock->protocol, client->schedule);
1332 sock->protocol = NULL;
1336 /* Free everything */
1337 if (del && sock->user_data) {
1338 /* Free all cache entries */
1339 SilcIDCacheList list;
1340 SilcIDCacheEntry entry;
1343 if (silc_idcache_get_all(conn->client_cache, &list)) {
1344 ret = silc_idcache_list_first(list, &entry);
1346 silc_client_del_client(client, conn, entry->context);
1347 ret = silc_idcache_list_next(list, &entry);
1349 silc_idcache_list_free(list);
1352 if (silc_idcache_get_all(conn->channel_cache, &list)) {
1353 ret = silc_idcache_list_first(list, &entry);
1355 silc_client_del_channel(client, conn, entry->context);
1356 ret = silc_idcache_list_next(list, &entry);
1358 silc_idcache_list_free(list);
1361 if (silc_idcache_get_all(conn->server_cache, &list)) {
1362 ret = silc_idcache_list_first(list, &entry);
1364 silc_client_del_server(client, conn, entry->context);
1365 ret = silc_idcache_list_next(list, &entry);
1367 silc_idcache_list_free(list);
1370 /* Clear ID caches */
1371 if (conn->client_cache)
1372 silc_idcache_free(conn->client_cache);
1373 if (conn->channel_cache)
1374 silc_idcache_free(conn->channel_cache);
1375 if (conn->server_cache)
1376 silc_idcache_free(conn->server_cache);
1378 /* Free data (my ID is freed in above silc_client_del_client).
1379 conn->nickname is freed when freeing the local_entry->nickname. */
1380 if (conn->remote_host)
1381 silc_free(conn->remote_host);
1382 if (conn->local_id_data)
1383 silc_free(conn->local_id_data);
1385 silc_cipher_free(conn->send_key);
1386 if (conn->receive_key)
1387 silc_cipher_free(conn->receive_key);
1388 if (conn->hmac_send)
1389 silc_hmac_free(conn->hmac_send);
1390 if (conn->hmac_receive)
1391 silc_hmac_free(conn->hmac_receive);
1392 if (conn->pending_commands)
1393 silc_dlist_uninit(conn->pending_commands);
1395 silc_free(conn->rekey);
1397 if (conn->active_session) {
1398 sock->user_data = NULL;
1399 silc_client_ftp_session_free(conn->active_session);
1400 conn->active_session = NULL;
1403 silc_client_ftp_free_sessions(client, conn);
1405 memset(conn, 0, sizeof(*conn));
1406 silc_client_del_connection(client, conn);
1409 silc_socket_free(sock);
1412 /* Called when we receive disconnection packet from server. This
1413 closes our end properly and displays the reason of the disconnection
1416 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1418 SilcClient client = (SilcClient)context;
1419 SilcSocketConnection sock;
1421 SILC_CLIENT_GET_SOCK(client, fd, sock);
1425 silc_client_close_connection(client, sock, sock->user_data);
1428 /* Called when we receive disconnection packet from server. This
1429 closes our end properly and displays the reason of the disconnection
1432 void silc_client_disconnected_by_server(SilcClient client,
1433 SilcSocketConnection sock,
1438 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1440 msg = silc_memdup(message->data, message->len);
1441 client->internal->ops->say(client, sock->user_data,
1442 SILC_CLIENT_MESSAGE_AUDIT, msg);
1445 SILC_SET_DISCONNECTED(sock);
1447 /* Close connection through scheduler. */
1448 silc_schedule_task_add(client->schedule, sock->sock,
1449 silc_client_disconnected_by_server_later,
1450 client, 0, 1, SILC_TASK_TIMEOUT,
1451 SILC_TASK_PRI_NORMAL);
1454 /* Received error message from server. Display it on the screen.
1455 We don't take any action what so ever of the error message. */
1457 void silc_client_error_by_server(SilcClient client,
1458 SilcSocketConnection sock,
1463 msg = silc_memdup(message->data, message->len);
1464 client->internal->ops->say(client, sock->user_data,
1465 SILC_CLIENT_MESSAGE_AUDIT, msg);
1469 /* Auto-nicking callback to send NICK command to server. */
1471 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1473 SilcClientConnection conn = (SilcClientConnection)context;
1474 SilcClient client = conn->client;
1476 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1477 ++conn->cmd_ident, 1, 1,
1478 client->nickname, strlen(client->nickname));
1481 /* Processes the received new Client ID from server. Old Client ID is
1482 deleted from cache and new one is added. */
1484 void silc_client_receive_new_id(SilcClient client,
1485 SilcSocketConnection sock,
1488 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1489 int connecting = FALSE;
1490 SilcClientID *client_id = silc_id_payload_get_id(idp);
1493 if (!conn->local_entry)
1496 /* Delete old ID from ID cache */
1497 if (conn->local_id) {
1498 /* Check whether they are different */
1499 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1500 silc_free(client_id);
1504 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1505 silc_free(conn->local_id);
1508 /* Save the new ID */
1510 if (conn->local_id_data)
1511 silc_free(conn->local_id_data);
1513 conn->local_id = client_id;
1514 conn->local_id_data = silc_id_payload_get_data(idp);
1515 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1517 if (!conn->local_entry)
1518 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1520 conn->local_entry->nickname = conn->nickname;
1521 if (!conn->local_entry->username)
1522 conn->local_entry->username = strdup(client->username);
1523 if (!conn->local_entry->hostname)
1524 conn->local_entry->hostname = strdup(client->hostname);
1525 if (!conn->local_entry->server)
1526 conn->local_entry->server = strdup(conn->remote_host);
1527 conn->local_entry->id = conn->local_id;
1528 conn->local_entry->valid = TRUE;
1529 if (!conn->local_entry->channels)
1530 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1535 /* Put it to the ID cache */
1536 silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
1537 (void *)conn->local_entry, 0, NULL);
1540 /* Send NICK command if the nickname was set by the application (and is
1541 not same as the username). Send this with little timeout. */
1542 if (client->nickname && strcmp(client->nickname, client->username))
1543 silc_schedule_task_add(client->schedule, 0,
1544 silc_client_send_auto_nick, conn,
1545 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1547 /* Issue INFO command to fetch the real server name and server information
1549 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1550 silc_client_command_reply_info_i, 0,
1552 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1553 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1554 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1555 silc_buffer_free(sidp);
1557 /* Notify application of successful connection. We do it here now that
1558 we've received the Client ID and are allowed to send traffic. */
1559 client->internal->ops->connect(client, conn, TRUE);
1563 /* Removes a client entry from all channels it has joined. */
1565 void silc_client_remove_from_channels(SilcClient client,
1566 SilcClientConnection conn,
1567 SilcClientEntry client_entry)
1569 SilcHashTableList htl;
1570 SilcChannelUser chu;
1572 silc_hash_table_list(client_entry->channels, &htl);
1573 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1574 silc_hash_table_del(chu->client->channels, chu->channel);
1575 silc_hash_table_del(chu->channel->user_list, chu->client);
1579 silc_hash_table_list_reset(&htl);
1582 /* Replaces `old' client entries from all channels to `new' client entry.
1583 This can be called for example when nickname changes and old ID entry
1584 is replaced from ID cache with the new one. If the old ID entry is only
1585 updated, then this fucntion needs not to be called. */
1587 void silc_client_replace_from_channels(SilcClient client,
1588 SilcClientConnection conn,
1589 SilcClientEntry old,
1590 SilcClientEntry new)
1592 SilcHashTableList htl;
1593 SilcChannelUser chu;
1595 silc_hash_table_list(old->channels, &htl);
1596 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1597 /* Replace client entry */
1598 silc_hash_table_del(chu->client->channels, chu->channel);
1599 silc_hash_table_del(chu->channel->user_list, chu->client);
1602 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1603 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1605 silc_hash_table_list_reset(&htl);
1608 /* Registers failure timeout to process the received failure packet
1611 void silc_client_process_failure(SilcClient client,
1612 SilcSocketConnection sock,
1613 SilcPacketContext *packet)
1617 if (sock->protocol) {
1618 if (packet->buffer->len >= 4)
1619 SILC_GET32_MSB(failure, packet->buffer->data);
1621 /* Notify application */
1622 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1627 /* A timeout callback for the re-key. We will be the initiator of the
1630 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1632 SilcSocketConnection sock = (SilcSocketConnection)context;
1633 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1634 SilcClient client = (SilcClient)conn->rekey->context;
1635 SilcProtocol protocol;
1636 SilcClientRekeyInternalContext *proto_ctx;
1638 SILC_LOG_DEBUG(("Start"));
1640 /* Allocate internal protocol context. This is sent as context
1642 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1643 proto_ctx->client = (void *)client;
1644 proto_ctx->sock = silc_socket_dup(sock);
1645 proto_ctx->responder = FALSE;
1646 proto_ctx->pfs = conn->rekey->pfs;
1648 /* Perform rekey protocol. Will call the final callback after the
1649 protocol is over. */
1650 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1651 &protocol, proto_ctx, silc_client_rekey_final);
1652 sock->protocol = protocol;
1654 /* Run the protocol */
1655 silc_protocol_execute(protocol, client->schedule, 0, 0);
1657 /* Re-register re-key timeout */
1658 silc_schedule_task_add(client->schedule, sock->sock,
1659 silc_client_rekey_callback,
1660 context, conn->rekey->timeout, 0,
1661 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1664 /* The final callback for the REKEY protocol. This will actually take the
1665 new key material into use. */
1667 SILC_TASK_CALLBACK(silc_client_rekey_final)
1669 SilcProtocol protocol = (SilcProtocol)context;
1670 SilcClientRekeyInternalContext *ctx =
1671 (SilcClientRekeyInternalContext *)protocol->context;
1672 SilcClient client = (SilcClient)ctx->client;
1673 SilcSocketConnection sock = ctx->sock;
1675 SILC_LOG_DEBUG(("Start"));
1677 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1678 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1679 /* Error occured during protocol */
1680 silc_protocol_cancel(protocol, client->schedule);
1681 silc_protocol_free(protocol);
1682 sock->protocol = NULL;
1684 silc_packet_context_free(ctx->packet);
1686 silc_ske_free(ctx->ske);
1687 silc_socket_free(ctx->sock);
1692 /* Purge the outgoing data queue to assure that all rekey packets really
1693 go to the network before we quit the protocol. */
1694 silc_client_packet_queue_purge(client, sock);
1697 silc_protocol_free(protocol);
1698 sock->protocol = NULL;
1700 silc_packet_context_free(ctx->packet);
1702 silc_ske_free(ctx->ske);
1703 silc_socket_free(ctx->sock);
1707 /* Processes incoming connection authentication method request packet.
1708 It is a reply to our previously sent request. The packet can be used
1709 to resolve the authentication method for the current session if the
1710 client does not know it beforehand. */
1712 void silc_client_connection_auth_request(SilcClient client,
1713 SilcSocketConnection sock,
1714 SilcPacketContext *packet)
1716 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1717 uint16 conn_type, auth_meth;
1720 /* If we haven't send our request then ignore this one. */
1721 if (!conn->connauth)
1724 /* Parse the payload */
1725 ret = silc_buffer_unformat(packet->buffer,
1726 SILC_STR_UI_SHORT(&conn_type),
1727 SILC_STR_UI_SHORT(&auth_meth),
1730 auth_meth = SILC_AUTH_NONE;
1732 /* Call the request callback to notify application for received
1733 authentication method information. */
1734 if (conn->connauth->callback)
1735 (*conn->connauth->callback)(client, conn, auth_meth,
1736 conn->connauth->context);
1738 silc_schedule_task_del(client->schedule, conn->connauth->timeout);
1740 silc_free(conn->connauth);
1741 conn->connauth = NULL;
1744 /* Timeout task callback called if the server does not reply to our
1745 connection authentication method request in the specified time interval. */
1747 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1749 SilcClientConnection conn = (SilcClientConnection)context;
1750 SilcClient client = conn->client;
1752 if (!conn->connauth)
1755 /* Call the request callback to notify application */
1756 if (conn->connauth->callback)
1757 (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
1758 conn->connauth->context);
1760 silc_free(conn->connauth);
1761 conn->connauth = NULL;
1764 /* This function can be used to request the current authentication method
1765 from the server. This may be called when connecting to the server
1766 and the client library requests the authentication data from the
1767 application. If the application does not know the current authentication
1768 method it can request it from the server using this function.
1769 The `callback' with `context' will be called after the server has
1770 replied back with the current authentication method. */
1773 silc_client_request_authentication_method(SilcClient client,
1774 SilcClientConnection conn,
1775 SilcConnectionAuthRequest callback,
1778 SilcClientConnAuthRequest connauth;
1781 connauth = silc_calloc(1, sizeof(*connauth));
1782 connauth->callback = callback;
1783 connauth->context = context;
1786 silc_free(conn->connauth);
1788 conn->connauth = connauth;
1790 /* Assemble the request packet and send it to the server */
1791 packet = silc_buffer_alloc(4);
1792 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1793 silc_buffer_format(packet,
1794 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1795 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1797 silc_client_packet_send(client, conn->sock,
1798 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1799 NULL, 0, NULL, NULL,
1800 packet->data, packet->len, FALSE);
1801 silc_buffer_free(packet);
1803 /* Register a timeout in case server does not reply anything back. */
1805 silc_schedule_task_add(client->schedule, conn->sock->sock,
1806 silc_client_request_authentication_method_timeout,
1808 client->internal->params->connauth_request_secs, 0,
1809 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);