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 "silcincludes.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /* Static task callback prototypes */
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
28 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
29 SILC_TASK_CALLBACK(silc_client_rekey_callback);
30 SILC_TASK_CALLBACK(silc_client_rekey_final);
32 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
34 static void silc_client_packet_parse_type(SilcClient client,
35 SilcSocketConnection sock,
36 SilcPacketContext *packet);
37 void silc_client_resolve_auth_method(bool success,
38 SilcProtocolAuthMeth auth_meth,
39 const unsigned char *auth_data,
40 SilcUInt32 auth_data_len, void *context);
42 /* Allocates new client object. This has to be done before client may
43 work. After calling this one must call silc_client_init to initialize
44 the client. The `application' is application specific user data pointer
45 and caller must free it. */
47 SilcClient silc_client_alloc(SilcClientOperations *ops,
48 SilcClientParams *params,
50 const char *silc_version)
52 SilcClient new_client;
54 new_client = silc_calloc(1, sizeof(*new_client));
55 new_client->application = application;
57 new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
58 new_client->internal->ops = ops;
59 new_client->internal->params =
60 silc_calloc(1, sizeof(*new_client->internal->params));
61 new_client->internal->silc_client_version = strdup(silc_version);
64 memcpy(new_client->internal->params, params, sizeof(*params));
66 if (!new_client->internal->params->task_max)
67 new_client->internal->params->task_max = 200;
69 if (!new_client->internal->params->rekey_secs)
70 new_client->internal->params->rekey_secs = 3600;
72 if (!new_client->internal->params->connauth_request_secs)
73 new_client->internal->params->connauth_request_secs = 2;
75 new_client->internal->params->
76 nickname_format[sizeof(new_client->internal->
77 params->nickname_format) - 1] = 0;
82 /* Frees client object and its internals. */
84 void silc_client_free(SilcClient client)
88 silc_rng_free(client->rng);
90 silc_free(client->internal->params);
91 silc_free(client->internal->silc_client_version);
92 silc_free(client->internal);
97 /* Initializes the client. This makes all the necessary steps to make
98 the client ready to be run. One must call silc_client_run to run the
99 client. Returns FALSE if error occured, TRUE otherwise. */
101 int silc_client_init(SilcClient client)
103 SILC_LOG_DEBUG(("Initializing client"));
105 /* Initialize hash functions for client to use */
106 silc_hash_alloc("md5", &client->internal->md5hash);
107 silc_hash_alloc("sha1", &client->internal->sha1hash);
109 /* Initialize none cipher */
110 silc_cipher_alloc("none", &client->internal->none_cipher);
112 /* Initialize random number generator */
113 client->rng = silc_rng_alloc();
114 silc_rng_init(client->rng);
115 silc_rng_global_init(client->rng);
117 /* Register protocols */
118 silc_client_protocols_register();
120 /* Initialize the scheduler */
122 silc_schedule_init(client->internal->params->task_max ?
123 client->internal->params->task_max : 200);
124 if (!client->schedule)
127 /* Register commands */
128 silc_client_commands_register(client);
133 /* Stops the client. This is called to stop the client and thus to stop
136 void silc_client_stop(SilcClient client)
138 SILC_LOG_DEBUG(("Stopping client"));
140 silc_schedule_stop(client->schedule);
141 silc_schedule_uninit(client->schedule);
143 silc_client_protocols_unregister();
144 silc_client_commands_unregister(client);
146 SILC_LOG_DEBUG(("Client stopped"));
149 /* Runs the client. This starts the scheduler from the utility library.
150 When this functions returns the execution of the appliation is over. */
152 void silc_client_run(SilcClient client)
154 SILC_LOG_DEBUG(("Running client"));
156 /* Start the scheduler, the heart of the SILC client. When this returns
157 the program will be terminated. */
158 silc_schedule(client->schedule);
161 /* Runs the client and returns immeadiately. This function is used when
162 the SILC Client object indicated by the `client' is run under some
163 other scheduler, or event loop or main loop. On GUI applications,
164 for example this may be desired to use to run the client under the
165 GUI application's main loop. Typically the GUI application would
166 register an idle task that calls this function multiple times in
167 a second to quickly process the SILC specific data. */
169 void silc_client_run_one(SilcClient client)
171 /* Run the scheduler once. */
172 silc_schedule_one(client->schedule, 0);
175 static void silc_client_entry_destructor(SilcIDCache cache,
176 SilcIDCacheEntry entry)
178 silc_free(entry->name);
181 /* Allocates and adds new connection to the client. This adds the allocated
182 connection to the connection table and returns a pointer to it. A client
183 can have multiple connections to multiple servers. Every connection must
184 be added to the client using this function. User data `context' may
185 be sent as argument. This function is normally used only if the
186 application performed the connecting outside the library. The library
187 however may use this internally. */
190 silc_client_add_connection(SilcClient client,
191 SilcClientConnectionParams *params,
192 char *hostname, int port, void *context)
194 SilcClientConnection conn;
197 conn = silc_calloc(1, sizeof(*conn));
199 /* Initialize ID caches */
200 conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
201 silc_client_entry_destructor);
202 conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
203 conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
204 conn->client = client;
205 conn->remote_host = strdup(hostname);
206 conn->remote_port = port;
207 conn->context = context;
208 conn->pending_commands = silc_dlist_init();
209 conn->ftp_sessions = silc_dlist_init();
212 if (params->detach_data)
213 conn->params.detach_data = silc_memdup(params->detach_data,
214 params->detach_data_len);
215 conn->params.detach_data_len = params->detach_data_len;
218 /* Add the connection to connections table */
219 for (i = 0; i < client->internal->conns_count; i++)
220 if (client->internal->conns && !client->internal->conns[i]) {
221 client->internal->conns[i] = conn;
225 client->internal->conns =
226 silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
227 * (client->internal->conns_count + 1));
228 client->internal->conns[client->internal->conns_count] = conn;
229 client->internal->conns_count++;
234 /* Removes connection from client. Frees all memory. */
236 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
240 for (i = 0; i < client->internal->conns_count; i++)
241 if (client->internal->conns[i] == conn) {
243 silc_idcache_free(conn->client_cache);
244 silc_idcache_free(conn->channel_cache);
245 silc_idcache_free(conn->server_cache);
246 if (conn->pending_commands)
247 silc_dlist_uninit(conn->pending_commands);
248 silc_free(conn->remote_host);
249 silc_dlist_uninit(conn->ftp_sessions);
252 client->internal->conns[i] = NULL;
256 /* Adds listener socket to the listener sockets table. This function is
257 used to add socket objects that are listeners to the client. This should
258 not be used to add other connection objects. */
260 void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
264 if (!client->internal->sockets) {
265 client->internal->sockets =
266 silc_calloc(1, sizeof(*client->internal->sockets));
267 client->internal->sockets[0] = silc_socket_dup(sock);
268 client->internal->sockets_count = 1;
272 for (i = 0; i < client->internal->sockets_count; i++) {
273 if (client->internal->sockets[i] == NULL) {
274 client->internal->sockets[i] = silc_socket_dup(sock);
279 client->internal->sockets =
280 silc_realloc(client->internal->sockets,
281 sizeof(*client->internal->sockets) *
282 (client->internal->sockets_count + 1));
283 client->internal->sockets[client->internal->sockets_count] =
284 silc_socket_dup(sock);
285 client->internal->sockets_count++;
288 /* Deletes listener socket from the listener sockets table. */
290 void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
294 if (!client->internal->sockets)
297 for (i = 0; i < client->internal->sockets_count; i++) {
298 if (client->internal->sockets[i] == sock) {
299 silc_socket_free(sock);
300 client->internal->sockets[i] = NULL;
307 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
311 /* XXX In the future we should give up this non-blocking connect all
312 together and use threads instead. */
313 /* Create connection to server asynchronously */
314 sock = silc_net_create_connection_async(NULL, ctx->port, ctx->host);
318 /* Register task that will receive the async connect and will
320 ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
321 silc_client_connect_to_server_start,
324 SILC_TASK_PRI_NORMAL);
325 silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE);
332 /* Connects to remote server. This is the main routine used to connect
333 to SILC server. Returns -1 on error and the created socket otherwise.
334 The `context' is user context that is saved into the SilcClientConnection
335 that is created after the connection is created. Note that application
336 may handle the connecting process outside the library. If this is the
337 case then this function is not used at all. When the connecting is
338 done the `connect' client operation is called. */
340 int silc_client_connect_to_server(SilcClient client,
341 SilcClientConnectionParams *params,
342 int port, char *host, void *context)
344 SilcClientInternalConnectContext *ctx;
345 SilcClientConnection conn;
348 SILC_LOG_DEBUG(("Connecting to port %d of server %s",
351 conn = silc_client_add_connection(client, params, host, port, context);
353 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
354 "Connecting to port %d of server %s", port, host);
356 /* Allocate internal context for connection process. This is
357 needed as we are doing async connecting. */
358 ctx = silc_calloc(1, sizeof(*ctx));
359 ctx->client = client;
361 ctx->host = strdup(host);
365 /* Do the actual connecting process */
366 sock = silc_client_connect_to_server_internal(ctx);
368 silc_client_del_connection(client, conn);
372 /* Socket hostname and IP lookup callback that is called before actually
373 starting the key exchange. The lookup is called from the function
374 silc_client_start_key_exchange. */
376 static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
379 SilcClientConnection conn = (SilcClientConnection)context;
380 SilcClient client = conn->client;
381 SilcProtocol protocol;
382 SilcClientKEInternalContext *proto_ctx;
384 SILC_LOG_DEBUG(("Start"));
386 /* XXX We should most likely use the resolved host name instead of the
387 one user provided for us. */
388 silc_free(conn->sock->hostname);
389 conn->sock->hostname = strdup(conn->remote_host);
391 conn->sock->ip = strdup(conn->remote_host);
392 conn->sock->port = conn->remote_port;
394 /* Allocate internal Key Exchange context. This is sent to the
395 protocol as context. */
396 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
397 proto_ctx->client = (void *)client;
398 proto_ctx->sock = silc_socket_dup(conn->sock);
399 proto_ctx->rng = client->rng;
400 proto_ctx->responder = FALSE;
401 proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
402 proto_ctx->verify = silc_client_protocol_ke_verify_key;
404 /* Perform key exchange protocol. silc_client_connect_to_server_final
405 will be called after the protocol is finished. */
406 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
407 &protocol, (void *)proto_ctx,
408 silc_client_connect_to_server_second);
410 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
411 "Error: Could not start key exchange protocol");
412 silc_net_close_connection(conn->sock->sock);
413 client->internal->ops->connect(client, conn, FALSE);
416 conn->sock->protocol = protocol;
418 /* Register the connection for network input and output. This sets
419 that scheduler will listen for incoming packets for this connection
420 and sets that outgoing packets may be sent to this connection as well.
421 However, this doesn't set the scheduler for outgoing traffic, it will
422 be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
423 later when outgoing data is available. */
424 context = (void *)client;
425 SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(conn->sock->sock);
427 /* Execute the protocol */
428 silc_protocol_execute(protocol, client->schedule, 0, 0);
431 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
432 key material between client and server. This function can be called
433 directly if application is performing its own connecting and does not
434 use the connecting provided by this library. This function is normally
435 used only if the application performed the connecting outside the library.
436 The library however may use this internally. */
438 void silc_client_start_key_exchange(SilcClient client,
439 SilcClientConnection conn,
442 /* Allocate new socket connection object */
443 silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
445 /* Sometimes when doing quick reconnects the new socket may be same as
446 the old one and there might be pending stuff for the old socket.
447 If new one is same then those pending sutff might cause problems.
448 Make sure they do not do that. */
449 silc_schedule_task_del_by_fd(client->schedule, fd);
451 conn->nickname = (client->nickname ? strdup(client->nickname) :
452 strdup(client->username));
454 /* Resolve the remote hostname and IP address for our socket connection */
455 silc_socket_host_lookup(conn->sock, FALSE, silc_client_start_key_exchange_cb,
456 conn, client->schedule);
459 /* Callback called when error has occurred during connecting to the server.
460 The `connect' client operation will be called. */
462 SILC_TASK_CALLBACK(silc_client_connect_failure)
464 SilcClientKEInternalContext *ctx =
465 (SilcClientKEInternalContext *)context;
466 SilcClient client = (SilcClient)ctx->client;
468 client->internal->ops->connect(client, ctx->sock->user_data, FALSE);
470 silc_packet_context_free(ctx->packet);
474 /* Start of the connection to the remote server. This is called after
475 succesful TCP/IP connection has been established to the remote host. */
477 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
479 SilcClientInternalConnectContext *ctx =
480 (SilcClientInternalConnectContext *)context;
481 SilcClient client = ctx->client;
482 SilcClientConnection conn = ctx->conn;
483 int opt, opt_len = sizeof(opt);
485 SILC_LOG_DEBUG(("Start"));
487 /* Check the socket status as it might be in error */
488 silc_net_get_socket_opt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
490 if (ctx->tries < 2) {
491 /* Connection failed but lets try again */
492 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
493 "Could not connect to server %s: %s",
494 ctx->host, strerror(opt));
495 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
496 "Connecting to port %d of server %s resumed",
497 ctx->port, ctx->host);
499 /* Unregister old connection try */
500 silc_schedule_unset_listen_fd(client->schedule, fd);
501 silc_net_close_connection(fd);
502 silc_schedule_task_del(client->schedule, ctx->task);
505 silc_client_connect_to_server_internal(ctx);
508 /* Connection failed and we won't try anymore */
509 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
510 "Could not connect to server %s: %s",
511 ctx->host, strerror(opt));
512 silc_schedule_unset_listen_fd(client->schedule, fd);
513 silc_net_close_connection(fd);
514 silc_schedule_task_del(client->schedule, ctx->task);
517 /* Notify application of failure */
518 client->internal->ops->connect(client, conn, FALSE);
519 silc_client_del_connection(client, conn);
524 silc_schedule_unset_listen_fd(client->schedule, fd);
525 silc_schedule_task_del(client->schedule, ctx->task);
528 silc_client_start_key_exchange(client, conn, fd);
531 /* Second part of the connecting to the server. This executed
532 authentication protocol. */
534 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
536 SilcProtocol protocol = (SilcProtocol)context;
537 SilcClientKEInternalContext *ctx =
538 (SilcClientKEInternalContext *)protocol->context;
539 SilcClient client = (SilcClient)ctx->client;
540 SilcSocketConnection sock = NULL;
541 SilcClientConnAuthInternalContext *proto_ctx;
543 SILC_LOG_DEBUG(("Start"));
545 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
546 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
547 /* Error occured during protocol */
548 SILC_LOG_DEBUG(("Error during KE protocol"));
549 silc_protocol_free(protocol);
550 silc_ske_free_key_material(ctx->keymat);
552 silc_ske_free(ctx->ske);
554 silc_free(ctx->dest_id);
555 ctx->sock->protocol = NULL;
556 silc_socket_free(ctx->sock);
558 /* Notify application of failure */
559 silc_schedule_task_add(client->schedule, ctx->sock->sock,
560 silc_client_connect_failure, ctx,
561 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
565 /* We now have the key material as the result of the key exchange
566 protocol. Take the key material into use. Free the raw key material
567 as soon as we've set them into use. */
568 silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
569 ctx->ske->prop->cipher,
570 ctx->ske->prop->pkcs,
571 ctx->ske->prop->hash,
572 ctx->ske->prop->hmac,
573 ctx->ske->prop->group,
575 silc_ske_free_key_material(ctx->keymat);
577 /* Allocate internal context for the authentication protocol. This
578 is sent as context for the protocol. */
579 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
580 proto_ctx->client = (void *)client;
581 proto_ctx->sock = sock = ctx->sock;
582 proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
583 proto_ctx->dest_id_type = ctx->dest_id_type;
584 proto_ctx->dest_id = ctx->dest_id;
586 /* Free old protocol as it is finished now */
587 silc_protocol_free(protocol);
589 silc_packet_context_free(ctx->packet);
591 sock->protocol = NULL;
593 /* Resolve the authentication method to be used in this connection. The
594 completion callback is called after the application has resolved
595 the authentication method. */
596 client->internal->ops->get_auth_method(client, sock->user_data,
599 silc_client_resolve_auth_method,
603 /* Authentication method resolving callback. Application calls this function
604 after we've called the client->internal->ops->get_auth_method
605 client operation to resolve the authentication method. We will continue
606 the executiong of the protocol in this function. */
608 void silc_client_resolve_auth_method(bool success,
609 SilcProtocolAuthMeth auth_meth,
610 const unsigned char *auth_data,
611 SilcUInt32 auth_data_len, void *context)
613 SilcClientConnAuthInternalContext *proto_ctx =
614 (SilcClientConnAuthInternalContext *)context;
615 SilcClient client = (SilcClient)proto_ctx->client;
618 auth_meth = SILC_AUTH_NONE;
620 proto_ctx->auth_meth = auth_meth;
622 if (auth_data && auth_data_len) {
623 proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
624 proto_ctx->auth_data_len = auth_data_len;
627 /* Allocate the authenteication protocol and execute it. */
628 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
629 &proto_ctx->sock->protocol, (void *)proto_ctx,
630 silc_client_connect_to_server_final);
632 /* Execute the protocol */
633 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
636 /* Finalizes the connection to the remote SILC server. This is called
637 after authentication protocol has been completed. This send our
638 user information to the server to receive our client ID from
641 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
643 SilcProtocol protocol = (SilcProtocol)context;
644 SilcClientConnAuthInternalContext *ctx =
645 (SilcClientConnAuthInternalContext *)protocol->context;
646 SilcClient client = (SilcClient)ctx->client;
647 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
650 SILC_LOG_DEBUG(("Start"));
652 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
653 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
654 /* Error occured during protocol */
655 SILC_LOG_DEBUG(("Error during authentication protocol"));
656 silc_protocol_free(protocol);
658 silc_free(ctx->auth_data);
660 silc_ske_free(ctx->ske);
662 silc_free(ctx->dest_id);
663 conn->sock->protocol = NULL;
664 silc_socket_free(ctx->sock);
666 /* Notify application of failure */
667 silc_schedule_task_add(client->schedule, ctx->sock->sock,
668 silc_client_connect_failure, ctx,
669 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
673 /* Send NEW_CLIENT packet to the server. We will become registered
674 to the SILC network after sending this packet and we will receive
675 client ID from the server. */
676 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
677 strlen(client->realname));
678 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
679 silc_buffer_format(packet,
680 SILC_STR_UI_SHORT(strlen(client->username)),
681 SILC_STR_UI_XNSTRING(client->username,
682 strlen(client->username)),
683 SILC_STR_UI_SHORT(strlen(client->realname)),
684 SILC_STR_UI_XNSTRING(client->realname,
685 strlen(client->realname)),
688 /* Send the packet */
689 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
691 packet->data, packet->len, TRUE);
692 silc_buffer_free(packet);
694 /* Save remote ID. */
695 conn->remote_id = ctx->dest_id;
696 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
697 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
699 /* Register re-key timeout */
700 conn->rekey->timeout = client->internal->params->rekey_secs;
701 conn->rekey->context = (void *)client;
702 silc_schedule_task_add(client->schedule, conn->sock->sock,
703 silc_client_rekey_callback,
704 (void *)conn->sock, conn->rekey->timeout, 0,
705 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
707 silc_protocol_free(protocol);
709 silc_free(ctx->auth_data);
711 silc_ske_free(ctx->ske);
712 silc_socket_free(ctx->sock);
714 conn->sock->protocol = NULL;
717 /* Internal routine that sends packet or marks packet to be sent. This
718 is used directly only in special cases. Normal cases should use
719 silc_server_packet_send. Returns < 0 on error. */
721 int silc_client_packet_send_real(SilcClient client,
722 SilcSocketConnection sock,
727 /* If rekey protocol is active we must assure that all packets are
728 sent through packet queue. */
729 if (SILC_CLIENT_IS_REKEY(sock))
732 /* If outbound data is already pending do not force send */
733 if (SILC_IS_OUTBUF_PENDING(sock))
736 /* Send the packet */
737 ret = silc_packet_send(sock, force_send);
741 /* Mark that there is some outgoing data available for this connection.
742 This call sets the connection both for input and output (the input
743 is set always and this call keeps the input setting, actually).
744 Actual data sending is performed by silc_client_packet_process. */
745 SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
747 /* Mark to socket that data is pending in outgoing buffer. This flag
748 is needed if new data is added to the buffer before the earlier
749 put data is sent to the network. */
750 SILC_SET_OUTBUF_PENDING(sock);
755 /* Packet processing callback. This is used to send and receive packets
756 from network. This is generic task. */
758 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
760 SilcClient client = (SilcClient)context;
761 SilcSocketConnection sock = NULL;
762 SilcClientConnection conn;
765 SILC_LOG_DEBUG(("Processing packet"));
767 SILC_CLIENT_GET_SOCK(client, fd, sock);
771 conn = (SilcClientConnection)sock->user_data;
774 if (type == SILC_TASK_WRITE) {
775 /* Do not send data to disconnected connection */
776 if (SILC_IS_DISCONNECTED(sock))
779 ret = silc_packet_send(sock, TRUE);
781 /* If returned -2 could not write to connection now, will do
790 /* The packet has been sent and now it is time to set the connection
791 back to only for input. When there is again some outgoing data
792 available for this connection it will be set for output as well.
793 This call clears the output setting and sets it only for input. */
794 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
795 SILC_UNSET_OUTBUF_PENDING(sock);
797 silc_buffer_clear(sock->outbuf);
801 /* Packet receiving */
802 if (type == SILC_TASK_READ) {
803 /* Read data from network */
804 ret = silc_packet_receive(sock);
810 SILC_LOG_DEBUG(("Read EOF"));
812 /* If connection is disconnecting already we will finally
813 close the connection */
814 if (SILC_IS_DISCONNECTING(sock)) {
815 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
816 client->internal->ops->disconnect(client, conn);
817 silc_client_close_connection_real(client, sock, conn);
821 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
822 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
823 client->internal->ops->disconnect(client, conn);
824 silc_client_close_connection_real(client, sock, conn);
828 /* Process the packet. This will call the parser that will then
829 decrypt and parse the packet. */
830 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
831 silc_packet_receive_process(sock, FALSE, conn->receive_key,
832 conn->hmac_receive, conn->psn_receive,
833 silc_client_packet_parse, client);
835 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
836 silc_client_packet_parse, client);
840 /* Parser callback called by silc_packet_receive_process. Thie merely
841 registers timeout that will handle the actual parsing when appropriate. */
843 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
846 SilcClient client = (SilcClient)context;
847 SilcSocketConnection sock = parser_context->sock;
848 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
849 SilcPacketContext *packet = parser_context->packet;
852 if (conn && conn->hmac_receive && conn->sock == sock)
853 conn->psn_receive = parser_context->packet->sequence + 1;
855 /* Parse the packet immediately */
856 if (parser_context->normal)
857 ret = silc_packet_parse(packet, conn->receive_key);
859 ret = silc_packet_parse_special(packet, conn->receive_key);
861 if (ret == SILC_PACKET_NONE) {
862 silc_packet_context_free(packet);
863 silc_free(parser_context);
867 /* If protocol for this connection is key exchange or rekey then we'll
868 process all packets synchronously, since there might be packets in
869 queue that we are not able to decrypt without first processing the
870 packets before them. */
871 if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
872 (sock->protocol && sock->protocol->protocol &&
873 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
874 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
876 /* Parse the incoming packet type */
877 silc_client_packet_parse_type(client, sock, packet);
878 silc_packet_context_free(packet);
879 silc_free(parser_context);
881 /* Reprocess the buffer since we'll return FALSE. This is because
882 the `conn->receive_key' might have become valid by processing
883 the previous packet */
884 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
885 silc_packet_receive_process(sock, FALSE, conn->receive_key,
886 conn->hmac_receive, conn->psn_receive,
887 silc_client_packet_parse, client);
889 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
890 silc_client_packet_parse, client);
895 /* Parse the incoming packet type */
896 silc_client_packet_parse_type(client, sock, packet);
897 silc_packet_context_free(packet);
898 silc_free(parser_context);
902 /* Parses the packet type and calls what ever routines the packet type
903 requires. This is done for all incoming packets. */
905 void silc_client_packet_parse_type(SilcClient client,
906 SilcSocketConnection sock,
907 SilcPacketContext *packet)
909 SilcBuffer buffer = packet->buffer;
910 SilcPacketType type = packet->type;
912 SILC_LOG_DEBUG(("Parsing packet type %d", type));
914 /* Parse the packet type */
916 case SILC_PACKET_DISCONNECT:
917 silc_client_disconnected_by_server(client, sock, buffer);
919 case SILC_PACKET_SUCCESS:
921 * Success received for something. For now we can have only
922 * one protocol for connection executing at once hence this
923 * success message is for whatever protocol is executing currently.
926 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
928 case SILC_PACKET_FAILURE:
930 * Failure received for some protocol. Set the protocol state to
931 * error and call the protocol callback. This fill cause error on
932 * protocol and it will call the final callback.
934 silc_client_process_failure(client, sock, packet);
936 case SILC_PACKET_REJECT:
939 case SILC_PACKET_NOTIFY:
941 * Received notify message
943 silc_client_notify_by_server(client, sock, packet);
946 case SILC_PACKET_ERROR:
948 * Received error message
950 silc_client_error_by_server(client, sock, buffer);
953 case SILC_PACKET_CHANNEL_MESSAGE:
955 * Received message to (from, actually) a channel
957 silc_client_channel_message(client, sock, packet);
959 case SILC_PACKET_CHANNEL_KEY:
961 * Received key for a channel. By receiving this key the client will be
962 * able to talk to the channel it has just joined. This can also be
963 * a new key for existing channel as keys expire peridiocally.
965 silc_client_receive_channel_key(client, sock, buffer);
968 case SILC_PACKET_PRIVATE_MESSAGE:
970 * Received private message
972 silc_client_private_message(client, sock, packet);
974 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
976 * Received private message key
980 case SILC_PACKET_COMMAND_REPLY:
982 * Recived reply for a command
984 silc_client_command_reply_process(client, sock, packet);
987 case SILC_PACKET_KEY_EXCHANGE:
988 if (sock->protocol && sock->protocol->protocol &&
989 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
990 SilcClientKEInternalContext *proto_ctx =
991 (SilcClientKEInternalContext *)sock->protocol->context;
993 proto_ctx->packet = silc_packet_context_dup(packet);
994 proto_ctx->dest_id_type = packet->src_id_type;
995 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
996 packet->src_id_type);
997 if (!proto_ctx->dest_id)
1000 /* Let the protocol handle the packet */
1001 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1003 SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
1004 "protocol active, packet dropped."));
1008 case SILC_PACKET_KEY_EXCHANGE_1:
1009 if (sock->protocol && sock->protocol->protocol &&
1010 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1011 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1013 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1014 SilcClientRekeyInternalContext *proto_ctx =
1015 (SilcClientRekeyInternalContext *)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);
1022 /* Let the protocol handle the packet */
1023 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1025 SilcClientKEInternalContext *proto_ctx =
1026 (SilcClientKEInternalContext *)sock->protocol->context;
1028 if (proto_ctx->packet)
1029 silc_packet_context_free(proto_ctx->packet);
1031 proto_ctx->packet = silc_packet_context_dup(packet);
1032 proto_ctx->dest_id_type = packet->src_id_type;
1033 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1034 packet->src_id_type);
1035 if (!proto_ctx->dest_id)
1038 /* Let the protocol handle the packet */
1039 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1042 SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
1043 "protocol active, packet dropped."));
1046 case SILC_PACKET_KEY_EXCHANGE_2:
1047 if (sock->protocol && sock->protocol->protocol &&
1048 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
1049 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
1051 if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1052 SilcClientRekeyInternalContext *proto_ctx =
1053 (SilcClientRekeyInternalContext *)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);
1060 /* Let the protocol handle the packet */
1061 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1063 SilcClientKEInternalContext *proto_ctx =
1064 (SilcClientKEInternalContext *)sock->protocol->context;
1066 if (proto_ctx->packet)
1067 silc_packet_context_free(proto_ctx->packet);
1068 if (proto_ctx->dest_id)
1069 silc_free(proto_ctx->dest_id);
1070 proto_ctx->packet = silc_packet_context_dup(packet);
1071 proto_ctx->dest_id_type = packet->src_id_type;
1072 proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
1073 packet->src_id_type);
1074 if (!proto_ctx->dest_id)
1077 /* Let the protocol handle the packet */
1078 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1081 SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
1082 "protocol active, packet dropped."));
1086 case SILC_PACKET_NEW_ID:
1089 * Received new ID from server. This packet is received at
1090 * the connection to the server. New ID is also received when
1091 * user changes nickname but in that case the new ID is received
1092 * as command reply and not as this packet type.
1096 idp = silc_id_payload_parse(buffer->data, buffer->len);
1099 if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
1102 silc_client_receive_new_id(client, sock, idp);
1103 silc_id_payload_free(idp);
1107 case SILC_PACKET_HEARTBEAT:
1109 * Received heartbeat packet
1111 SILC_LOG_DEBUG(("Heartbeat packet"));
1114 case SILC_PACKET_KEY_AGREEMENT:
1116 * Received key agreement packet
1118 SILC_LOG_DEBUG(("Key agreement packet"));
1119 silc_client_key_agreement(client, sock, packet);
1122 case SILC_PACKET_REKEY:
1123 SILC_LOG_DEBUG(("Re-key packet"));
1124 /* We ignore this for now */
1127 case SILC_PACKET_REKEY_DONE:
1128 SILC_LOG_DEBUG(("Re-key done packet"));
1130 if (sock->protocol && sock->protocol->protocol &&
1131 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
1133 SilcClientRekeyInternalContext *proto_ctx =
1134 (SilcClientRekeyInternalContext *)sock->protocol->context;
1136 if (proto_ctx->packet)
1137 silc_packet_context_free(proto_ctx->packet);
1139 proto_ctx->packet = silc_packet_context_dup(packet);
1141 /* Let the protocol handle the packet */
1142 if (proto_ctx->responder == FALSE)
1143 silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
1145 /* Let the protocol handle the packet */
1146 silc_protocol_execute(sock->protocol, client->schedule,
1149 SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
1150 "protocol active, packet dropped."));
1154 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
1156 * Reveived reply to our connection authentication method request
1157 * packet. This is used to resolve the authentication method for the
1158 * current session from the server if the client does not know it.
1160 silc_client_connection_auth_request(client, sock, packet);
1163 case SILC_PACKET_FTP:
1164 /* Received file transfer packet. */
1165 silc_client_ftp(client, sock, packet);
1169 SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
1174 /* Sends packet. This doesn't actually send the packet instead it assembles
1175 it and marks it to be sent. However, if force_send is TRUE the packet
1176 is sent immediately. if dst_id, cipher and hmac are NULL those parameters
1177 will be derived from sock argument. Otherwise the valid arguments sent
1180 void silc_client_packet_send(SilcClient client,
1181 SilcSocketConnection sock,
1182 SilcPacketType type,
1184 SilcIdType dst_id_type,
1187 unsigned char *data,
1188 SilcUInt32 data_len,
1191 SilcPacketContext packetdata;
1192 const SilcBufferStruct packet;
1194 SilcUInt32 sequence = 0;
1199 SILC_LOG_DEBUG(("Sending packet, type %d", type));
1201 /* Get data used in the packet sending, keys and stuff */
1202 if ((!cipher || !hmac || !dst_id) && sock->user_data) {
1203 if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
1204 cipher = ((SilcClientConnection)sock->user_data)->send_key;
1206 if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
1207 hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
1209 if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
1210 dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
1211 dst_id_type = SILC_ID_SERVER;
1215 sequence = ((SilcClientConnection)sock->user_data)->psn_send++;
1218 block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
1220 /* Set the packet context pointers */
1221 packetdata.flags = 0;
1222 packetdata.type = type;
1223 if (sock->user_data &&
1224 ((SilcClientConnection)sock->user_data)->local_id_data) {
1225 packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
1226 packetdata.src_id_len =
1227 silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
1230 packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
1231 packetdata.src_id_len = SILC_ID_CLIENT_LEN;
1233 packetdata.src_id_type = SILC_ID_CLIENT;
1235 packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
1236 packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
1237 packetdata.dst_id_type = dst_id_type;
1239 packetdata.dst_id = NULL;
1240 packetdata.dst_id_len = 0;
1241 packetdata.dst_id_type = SILC_ID_NONE;
1243 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1244 packetdata.src_id_len +
1245 packetdata.dst_id_len));
1246 packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
1247 packetdata.src_id_len + packetdata.dst_id_len;
1248 packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen, block_len);
1250 /* Create the outgoing packet */
1251 if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
1252 data, data_len, (const SilcBuffer)&packet)) {
1253 SILC_LOG_ERROR(("Error assembling packet"));
1257 /* Encrypt the packet */
1259 silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
1262 SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
1263 packet.data, packet.len);
1265 /* Now actually send the packet */
1266 silc_client_packet_send_real(client, sock, force_send);
1269 void silc_client_packet_queue_purge(SilcClient client,
1270 SilcSocketConnection sock)
1272 if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
1273 (SILC_IS_DISCONNECTED(sock) == FALSE)) {
1274 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_real(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_free(conn->client_cache);
1367 if (conn->channel_cache)
1368 silc_idcache_free(conn->channel_cache);
1369 if (conn->server_cache)
1370 silc_idcache_free(conn->server_cache);
1372 /* Free data (my ID is freed in above silc_client_del_client).
1373 conn->nickname is freed when freeing the local_entry->nickname. */
1374 if (conn->remote_host)
1375 silc_free(conn->remote_host);
1376 if (conn->local_id_data)
1377 silc_free(conn->local_id_data);
1379 silc_cipher_free(conn->send_key);
1380 if (conn->receive_key)
1381 silc_cipher_free(conn->receive_key);
1382 if (conn->hmac_send)
1383 silc_hmac_free(conn->hmac_send);
1384 if (conn->hmac_receive)
1385 silc_hmac_free(conn->hmac_receive);
1386 if (conn->pending_commands)
1387 silc_dlist_uninit(conn->pending_commands);
1389 silc_free(conn->rekey);
1391 if (conn->active_session) {
1392 sock->user_data = NULL;
1393 silc_client_ftp_session_free(conn->active_session);
1394 conn->active_session = NULL;
1397 silc_client_ftp_free_sessions(client, conn);
1399 memset(conn, 0, sizeof(*conn));
1400 silc_client_del_connection(client, conn);
1403 silc_socket_free(sock);
1406 /* Closes the connection to the remote end */
1408 void silc_client_close_connection(SilcClient client,
1409 SilcClientConnection conn)
1411 silc_client_close_connection_real(client, NULL, conn);
1414 /* Called when we receive disconnection packet from server. This
1415 closes our end properly and displays the reason of the disconnection
1418 SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
1420 SilcClient client = (SilcClient)context;
1421 SilcSocketConnection sock;
1423 SILC_CLIENT_GET_SOCK(client, fd, sock);
1427 silc_client_close_connection_real(client, sock, sock->user_data);
1430 /* Called when we receive disconnection packet from server. This
1431 closes our end properly and displays the reason of the disconnection
1434 void silc_client_disconnected_by_server(SilcClient client,
1435 SilcSocketConnection sock,
1440 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1442 msg = silc_memdup(message->data, message->len);
1443 client->internal->ops->say(client, sock->user_data,
1444 SILC_CLIENT_MESSAGE_AUDIT, msg);
1447 SILC_SET_DISCONNECTED(sock);
1449 /* Close connection through scheduler. */
1450 silc_schedule_task_add(client->schedule, sock->sock,
1451 silc_client_disconnected_by_server_later,
1452 client, 0, 1, SILC_TASK_TIMEOUT,
1453 SILC_TASK_PRI_NORMAL);
1456 /* Received error message from server. Display it on the screen.
1457 We don't take any action what so ever of the error message. */
1459 void silc_client_error_by_server(SilcClient client,
1460 SilcSocketConnection sock,
1465 msg = silc_memdup(message->data, message->len);
1466 client->internal->ops->say(client, sock->user_data,
1467 SILC_CLIENT_MESSAGE_AUDIT, msg);
1471 /* Auto-nicking callback to send NICK command to server. */
1473 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1475 SilcClientConnection conn = (SilcClientConnection)context;
1476 SilcClient client = conn->client;
1478 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1479 ++conn->cmd_ident, 1, 1,
1480 client->nickname, strlen(client->nickname));
1483 /* Processes the received new Client ID from server. Old Client ID is
1484 deleted from cache and new one is added. */
1486 void silc_client_receive_new_id(SilcClient client,
1487 SilcSocketConnection sock,
1490 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1491 int connecting = FALSE;
1492 SilcClientID *client_id = silc_id_payload_get_id(idp);
1495 if (!conn->local_entry)
1498 /* Delete old ID from ID cache */
1499 if (conn->local_id) {
1500 /* Check whether they are different */
1501 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1502 silc_free(client_id);
1506 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
1507 silc_free(conn->local_id);
1510 /* Save the new ID */
1512 if (conn->local_id_data)
1513 silc_free(conn->local_id_data);
1515 conn->local_id = client_id;
1516 conn->local_id_data = silc_id_payload_get_data(idp);
1517 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1519 if (!conn->local_entry)
1520 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1522 conn->local_entry->nickname = conn->nickname;
1523 if (!conn->local_entry->username)
1524 conn->local_entry->username = strdup(client->username);
1525 if (!conn->local_entry->hostname)
1526 conn->local_entry->hostname = strdup(client->hostname);
1527 if (!conn->local_entry->server)
1528 conn->local_entry->server = strdup(conn->remote_host);
1529 conn->local_entry->id = conn->local_id;
1530 conn->local_entry->valid = TRUE;
1531 if (!conn->local_entry->channels)
1532 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1537 /* Put it to the ID cache */
1538 silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id,
1539 (void *)conn->local_entry, 0, NULL);
1542 /* Send NICK command if the nickname was set by the application (and is
1543 not same as the username). Send this with little timeout. */
1544 if (client->nickname && strcmp(client->nickname, client->username))
1545 silc_schedule_task_add(client->schedule, 0,
1546 silc_client_send_auto_nick, conn,
1547 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1549 /* Issue INFO command to fetch the real server name and server information
1551 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1552 silc_client_command_reply_info_i, 0,
1554 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1555 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1556 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1557 silc_buffer_free(sidp);
1559 /* Notify application of successful connection. We do it here now that
1560 we've received the Client ID and are allowed to send traffic. */
1561 client->internal->ops->connect(client, conn, TRUE);
1565 /* Removes a client entry from all channels it has joined. */
1567 void silc_client_remove_from_channels(SilcClient client,
1568 SilcClientConnection conn,
1569 SilcClientEntry client_entry)
1571 SilcHashTableList htl;
1572 SilcChannelUser chu;
1574 silc_hash_table_list(client_entry->channels, &htl);
1575 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1576 silc_hash_table_del(chu->client->channels, chu->channel);
1577 silc_hash_table_del(chu->channel->user_list, chu->client);
1581 silc_hash_table_list_reset(&htl);
1584 /* Replaces `old' client entries from all channels to `new' client entry.
1585 This can be called for example when nickname changes and old ID entry
1586 is replaced from ID cache with the new one. If the old ID entry is only
1587 updated, then this fucntion needs not to be called. */
1589 void silc_client_replace_from_channels(SilcClient client,
1590 SilcClientConnection conn,
1591 SilcClientEntry old,
1592 SilcClientEntry new)
1594 SilcHashTableList htl;
1595 SilcChannelUser chu;
1597 silc_hash_table_list(old->channels, &htl);
1598 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1599 /* Replace client entry */
1600 silc_hash_table_del(chu->client->channels, chu->channel);
1601 silc_hash_table_del(chu->channel->user_list, chu->client);
1604 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1605 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1607 silc_hash_table_list_reset(&htl);
1610 /* Registers failure timeout to process the received failure packet
1613 void silc_client_process_failure(SilcClient client,
1614 SilcSocketConnection sock,
1615 SilcPacketContext *packet)
1617 SilcUInt32 failure = 0;
1619 if (sock->protocol) {
1620 if (packet->buffer->len >= 4)
1621 SILC_GET32_MSB(failure, packet->buffer->data);
1623 /* Notify application */
1624 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1629 /* A timeout callback for the re-key. We will be the initiator of the
1632 SILC_TASK_CALLBACK(silc_client_rekey_callback)
1634 SilcSocketConnection sock = (SilcSocketConnection)context;
1635 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1636 SilcClient client = (SilcClient)conn->rekey->context;
1637 SilcProtocol protocol;
1638 SilcClientRekeyInternalContext *proto_ctx;
1640 SILC_LOG_DEBUG(("Start"));
1642 /* Allocate internal protocol context. This is sent as context
1644 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1645 proto_ctx->client = (void *)client;
1646 proto_ctx->sock = silc_socket_dup(sock);
1647 proto_ctx->responder = FALSE;
1648 proto_ctx->pfs = conn->rekey->pfs;
1650 /* Perform rekey protocol. Will call the final callback after the
1651 protocol is over. */
1652 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1653 &protocol, proto_ctx, silc_client_rekey_final);
1654 sock->protocol = protocol;
1656 /* Run the protocol */
1657 silc_protocol_execute(protocol, client->schedule, 0, 0);
1659 /* Re-register re-key timeout */
1660 silc_schedule_task_add(client->schedule, sock->sock,
1661 silc_client_rekey_callback,
1662 context, conn->rekey->timeout, 0,
1663 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1666 /* The final callback for the REKEY protocol. This will actually take the
1667 new key material into use. */
1669 SILC_TASK_CALLBACK(silc_client_rekey_final)
1671 SilcProtocol protocol = (SilcProtocol)context;
1672 SilcClientRekeyInternalContext *ctx =
1673 (SilcClientRekeyInternalContext *)protocol->context;
1674 SilcClient client = (SilcClient)ctx->client;
1675 SilcSocketConnection sock = ctx->sock;
1677 SILC_LOG_DEBUG(("Start"));
1679 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1680 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1681 /* Error occured during protocol */
1682 silc_protocol_cancel(protocol, client->schedule);
1683 silc_protocol_free(protocol);
1684 sock->protocol = NULL;
1686 silc_packet_context_free(ctx->packet);
1688 silc_ske_free(ctx->ske);
1689 silc_socket_free(ctx->sock);
1694 /* Purge the outgoing data queue to assure that all rekey packets really
1695 go to the network before we quit the protocol. */
1696 silc_client_packet_queue_purge(client, sock);
1699 silc_protocol_free(protocol);
1700 sock->protocol = NULL;
1702 silc_packet_context_free(ctx->packet);
1704 silc_ske_free(ctx->ske);
1705 silc_socket_free(ctx->sock);
1709 /* Processes incoming connection authentication method request packet.
1710 It is a reply to our previously sent request. The packet can be used
1711 to resolve the authentication method for the current session if the
1712 client does not know it beforehand. */
1714 void silc_client_connection_auth_request(SilcClient client,
1715 SilcSocketConnection sock,
1716 SilcPacketContext *packet)
1718 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1719 SilcUInt16 conn_type, auth_meth;
1722 /* If we haven't send our request then ignore this one. */
1723 if (!conn->connauth)
1726 /* Parse the payload */
1727 ret = silc_buffer_unformat(packet->buffer,
1728 SILC_STR_UI_SHORT(&conn_type),
1729 SILC_STR_UI_SHORT(&auth_meth),
1732 auth_meth = SILC_AUTH_NONE;
1734 /* Call the request callback to notify application for received
1735 authentication method information. */
1736 if (conn->connauth->callback)
1737 (*conn->connauth->callback)(client, conn, auth_meth,
1738 conn->connauth->context);
1740 silc_schedule_task_del(client->schedule, conn->connauth->timeout);
1742 silc_free(conn->connauth);
1743 conn->connauth = NULL;
1746 /* Timeout task callback called if the server does not reply to our
1747 connection authentication method request in the specified time interval. */
1749 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1751 SilcClientConnection conn = (SilcClientConnection)context;
1752 SilcClient client = conn->client;
1754 if (!conn->connauth)
1757 /* Call the request callback to notify application */
1758 if (conn->connauth->callback)
1759 (*conn->connauth->callback)(client, conn, SILC_AUTH_NONE,
1760 conn->connauth->context);
1762 silc_free(conn->connauth);
1763 conn->connauth = NULL;
1766 /* This function can be used to request the current authentication method
1767 from the server. This may be called when connecting to the server
1768 and the client library requests the authentication data from the
1769 application. If the application does not know the current authentication
1770 method it can request it from the server using this function.
1771 The `callback' with `context' will be called after the server has
1772 replied back with the current authentication method. */
1775 silc_client_request_authentication_method(SilcClient client,
1776 SilcClientConnection conn,
1777 SilcConnectionAuthRequest callback,
1780 SilcClientConnAuthRequest connauth;
1783 connauth = silc_calloc(1, sizeof(*connauth));
1784 connauth->callback = callback;
1785 connauth->context = context;
1788 silc_free(conn->connauth);
1790 conn->connauth = connauth;
1792 /* Assemble the request packet and send it to the server */
1793 packet = silc_buffer_alloc(4);
1794 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1795 silc_buffer_format(packet,
1796 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1797 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1799 silc_client_packet_send(client, conn->sock,
1800 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1801 NULL, 0, NULL, NULL,
1802 packet->data, packet->len, FALSE);
1803 silc_buffer_free(packet);
1805 /* Register a timeout in case server does not reply anything back. */
1807 silc_schedule_task_add(client->schedule, conn->sock->sock,
1808 silc_client_request_authentication_method_timeout,
1810 client->internal->params->connauth_request_secs, 0,
1811 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1814 SilcBuffer silc_client_get_detach_data(SilcClient client,
1815 SilcClientConnection conn)
1818 SilcHashTableList htl;
1819 SilcChannelUser chu;
1821 SILC_LOG_DEBUG(("Creating detachment data"));
1823 /* Save the nickname, Client ID and user mode in SILC network */
1824 detach = silc_buffer_alloc_size(2 + strlen(conn->nickname) +
1825 2 + conn->local_id_data_len + 4);
1826 silc_buffer_format(detach,
1827 SILC_STR_UI_SHORT(strlen(conn->nickname)),
1828 SILC_STR_UI_XNSTRING(conn->nickname,
1829 strlen(conn->nickname)),
1830 SILC_STR_UI_SHORT(conn->local_id_data_len),
1831 SILC_STR_UI_XNSTRING(conn->local_id_data,
1832 conn->local_id_data_len),
1833 SILC_STR_UI_INT(conn->local_entry->mode),
1836 /* Save all joined channels */
1837 silc_hash_table_list(conn->local_entry->channels, &htl);
1838 while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
1839 unsigned char *chid = silc_id_id2str(chu->channel->id, SILC_ID_CHANNEL);
1840 SilcUInt16 chid_len = silc_id_get_len(chu->channel->id, SILC_ID_CHANNEL);
1842 detach = silc_buffer_realloc(detach, detach->truelen + 2 +
1843 strlen(chu->channel->channel_name) +
1845 silc_buffer_pull(detach, detach->len);
1846 silc_buffer_format(detach,
1847 SILC_STR_UI_SHORT(strlen(chu->channel->channel_name)),
1848 SILC_STR_UI_XNSTRING(chu->channel->channel_name,
1849 strlen(chu->channel->channel_name)),
1850 SILC_STR_UI_SHORT(chid_len),
1851 SILC_STR_UI_XNSTRING(chid, chid_len),
1852 SILC_STR_UI_INT(chu->channel->mode),
1857 silc_hash_table_list_reset(&htl);
1859 silc_buffer_push(detach, detach->data - detach->head);
1861 SILC_LOG_HEXDUMP(("Detach data"), detach->data, detach->len);