5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /************************** Types and definitions ***************************/
27 SILC_FSM_STATE(silc_client_connection_st_run);
28 SILC_FSM_STATE(silc_client_new_id);
31 /************************ Static utility functions **************************/
33 /* Packet engine callback to receive a packet */
35 static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
36 SilcPacketStream stream,
38 void *callback_context,
41 SilcClientConnection conn = stream_context;
43 /* Packets we do not handle */
44 switch (packet->type) {
45 case SILC_PACKET_HEARTBEAT:
46 case SILC_PACKET_SUCCESS:
47 case SILC_PACKET_FAILURE:
48 case SILC_PACKET_REJECT:
49 case SILC_PACKET_KEY_EXCHANGE:
50 case SILC_PACKET_KEY_EXCHANGE_1:
51 case SILC_PACKET_KEY_EXCHANGE_2:
52 case SILC_PACKET_REKEY:
53 case SILC_PACKET_REKEY_DONE:
54 case SILC_PACKET_CONNECTION_AUTH:
55 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
60 /* Signal packet processor thread for a new packet */
61 conn->internal->new_packet = TRUE;
62 silc_fsm_set_state_context(&conn->internal->packet_thread, packet);
63 silc_fsm_continue_sync(&conn->internal->packet_thread);
68 /* Packet engine callback to indicate end of stream */
70 static void silc_client_packet_eos(SilcPacketEngine engine,
71 SilcPacketStream stream,
72 void *callback_context,
75 SILC_LOG_DEBUG(("End of stream received"));
78 /* Packet engine callback to indicate error */
80 static void silc_client_packet_error(SilcPacketEngine engine,
81 SilcPacketStream stream,
82 SilcPacketError error,
83 void *callback_context,
89 /* Packet stream callbacks */
90 static SilcPacketCallbacks silc_client_stream_cbs =
92 silc_client_packet_receive,
93 silc_client_packet_eos,
94 silc_client_packet_error
99 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
100 void *destructor_context)
106 /************************** Connection's machine ****************************/
108 /* Start the connection's state machine. If threads are in use the machine
109 is always executed in a real thread. */
111 SILC_FSM_STATE(silc_client_connection_st_start)
113 SilcClientConnection conn = fsm_context;
115 /* Take scheduler for connection */
116 conn->internal->schedule = silc_fsm_get_schedule(fsm);
118 /*** Run connection machine */
119 silc_fsm_init(&conn->internal->fsm, conn, NULL, NULL,
120 conn->internal->schedule);
121 silc_fsm_sema_init(&conn->internal->wait_event, &conn->internal->fsm, 0);
122 silc_fsm_start_sync(&conn->internal->fsm, silc_client_connection_st_run);
124 /*** Run packet processor FSM thread */
125 silc_fsm_thread_init(&conn->internal->packet_thread, &conn->internal->fsm,
126 conn, silc_client_fsm_destructor, NULL, FALSE);
127 silc_fsm_start_sync(&conn->internal->packet_thread,
128 silc_client_connection_st_packet);
130 /* Schedule any events set in initialization */
131 if (conn->internal->connect)
132 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
133 if (conn->internal->key_exchange)
134 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
136 /* Wait until this thread is terminated */
137 return SILC_FSM_WAIT;
140 /* Connection machine main state. */
142 SILC_FSM_STATE(silc_client_connection_st_run)
144 SilcClientConnection conn = fsm_context;
146 /* Wait for events */
147 SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
151 if (conn->internal->connect) {
152 SILC_LOG_DEBUG(("Event: connect"));
153 conn->internal->connect = FALSE;
155 /** Connect remote host */
156 silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
157 conn, NULL, NULL, FALSE);
158 silc_fsm_start_sync(&conn->internal->event_thread, silc_client_st_connect);
159 return SILC_FSM_CONTINUE;
162 if (conn->internal->key_exchange) {
163 SILC_LOG_DEBUG(("Event: key exchange"));
164 conn->internal->key_exchange = FALSE;
166 /** Start key exchange */
167 silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
168 conn, NULL, NULL, FALSE);
169 silc_fsm_start_sync(&conn->internal->event_thread,
170 silc_client_st_connect_key_exchange);
171 return SILC_FSM_CONTINUE;
174 if (conn->internal->disconnected) {
175 SILC_LOG_DEBUG(("Event: disconnected"));
176 conn->internal->disconnected = FALSE;
178 return SILC_FSM_CONTINUE;
182 #if defined(SILC_DEBUG)
184 #endif /* SILC_DEBUG */
185 return SILC_FSM_CONTINUE;
188 /* Connection's packet processor main state. Packet processor thread waits
189 here for a new packet and processes received packets. */
191 SILC_FSM_STATE(silc_client_connection_st_packet)
193 SilcClientConnection conn = fsm_context;
194 SilcClient client = conn->client;
195 SilcPacket packet = state_context;
197 /* Wait for packet to arrive */
198 if (!conn->internal->new_packet) {
199 SILC_LOG_DEBUG(("Wait for packet"));
200 return SILC_FSM_WAIT;
202 conn->internal->new_packet = FALSE;
204 SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
206 switch (packet->type) {
208 case SILC_PACKET_PRIVATE_MESSAGE:
209 /** Private message */
210 silc_fsm_next(fsm, silc_client_private_message);
213 case SILC_PACKET_CHANNEL_MESSAGE:
214 /* Channel message */
215 // silc_client_channel_message(client, conn, packet);
218 case SILC_PACKET_FTP:
219 /* File transfer packet */
220 // silc_client_ftp(client, conn, packet);
223 case SILC_PACKET_CHANNEL_KEY:
224 /* Received channel key */
225 // silc_client_channel_key(client, conn, packet);
228 case SILC_PACKET_COMMAND_REPLY:
230 silc_fsm_next(fsm, silc_client_command_reply);
233 case SILC_PACKET_NOTIFY:
235 // silc_client_notify(client, conn, packet);
238 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
239 /* Private message key indicator */
240 // silc_client_private_message_key(client, conn, packet);
243 case SILC_PACKET_DISCONNECT:
244 /* Server disconnects */
245 // silc_client_disconnect(client, conn, packet);
248 case SILC_PACKET_ERROR:
249 /* Error by server */
250 // silc_client_error(client, conn, packet);
253 case SILC_PACKET_KEY_AGREEMENT:
255 // silc_client_key_agreement(client, conn, packet);
258 case SILC_PACKET_COMMAND:
259 /** Command packet */
260 silc_fsm_next(fsm, silc_client_command);
263 case SILC_PACKET_NEW_ID:
265 silc_fsm_next(fsm, silc_client_new_id);
267 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
268 /* Reply to connection authentication request to resolve authentication
269 method from server. */
270 // silc_client_connection_auth_request(client, conn, packet);
274 silc_packet_free(packet);
278 return SILC_FSM_CONTINUE;
282 /*************************** Main client machine ****************************/
284 /* The client's main state where we wait for various events */
286 SILC_FSM_STATE(silc_client_st_run)
288 SilcClient client = fsm_context;
290 /* Wait for events */
291 SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
295 if (client->internal->run_callback && client->internal->ops->running) {
296 /* Call running callbcak back to application */
297 client->internal->run_callback = FALSE;
298 client->internal->ops->running(client, client->application);
299 return SILC_FSM_CONTINUE;
303 #if defined(SILC_DEBUG)
305 #endif /* SILC_DEBUG */
306 return SILC_FSM_CONTINUE;
310 /**************************** Packet Processing *****************************/
312 /* Received new ID from server during registering to SILC network */
314 SILC_FSM_STATE(silc_client_new_id)
316 SilcClientConnection conn = fsm_context;
317 SilcClient client = conn->client;
318 SilcPacket packet = state_context;
324 SILC_LOG_DEBUG(("New ID received from server"));
326 if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
327 silc_buffer_len(&packet->buffer), &id))
330 /* Create local client entry */
331 conn->local_entry = silc_client_add_client(client, conn,
338 if (!conn->local_entry)
342 conn->local_id = &conn->local_entry->id;
343 conn->local_idp = silc_buffer_copy(&packet->buffer);
345 /* Save cache entry */
346 silc_idcache_find_by_id_one(conn->internal->client_cache, conn->local_id,
347 &conn->internal->local_entry);
350 if (packet->src_id_len) {
351 conn->remote_idp = silc_id_payload_encode_data(packet->src_id,
353 packet->src_id_type);
354 if (!conn->remote_idp)
356 silc_id_payload_parse_id(silc_buffer_data(conn->remote_idp),
357 silc_buffer_len(conn->remote_idp),
361 /* Signal connection that new ID was received so it can continue
362 with the registering. */
363 if (conn->internal->registering)
364 silc_fsm_continue_sync(&conn->internal->event_thread);
367 /** Packet processed */
368 silc_packet_free(packet);
369 silc_fsm_next(fsm, silc_client_connection_st_packet);
370 return SILC_FSM_CONTINUE;
374 /******************************* Public API *********************************/
376 /* Allocates and adds new connection to the client. This adds the allocated
377 connection to the connection table and returns a pointer to it. A client
378 can have multiple connections to multiple servers. Every connection must
379 be added to the client using this function. User data `context' may
380 be sent as argument. This function is normally used only if the
381 application performed the connecting outside the library. The library
382 however may use this internally. */
385 silc_client_add_connection(SilcClient client,
386 SilcConnectionType conn_type,
387 SilcClientConnectionParams *params,
388 SilcPublicKey public_key,
389 SilcPrivateKey private_key,
390 char *remote_host, int port,
391 SilcClientConnectCallback callback,
394 SilcClientConnection conn;
395 SilcFSMThread thread;
400 SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port));
402 conn = silc_calloc(1, sizeof(*conn));
405 conn->internal = silc_calloc(1, sizeof(*conn->internal));
406 if (!conn->internal) {
411 conn->client = client;
412 conn->public_key = public_key;
413 conn->private_key = private_key;
414 conn->remote_host = strdup(remote_host);
415 conn->remote_port = port ? port : 706;
416 conn->type = conn_type;
417 conn->callback = callback;
418 conn->context = context;
419 conn->internal->client_cache =
420 silc_idcache_alloc(0, SILC_ID_CLIENT, NULL, NULL);
421 conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL,
423 conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL,
425 conn->internal->ftp_sessions = silc_dlist_init();
426 conn->internal->verbose = TRUE;
427 silc_list_init(conn->internal->pending_commands,
428 struct SilcClientCommandContextStruct, next);
431 if (params->detach_data)
432 conn->internal->params.detach_data =
433 silc_memdup(params->detach_data,
434 params->detach_data_len);
435 conn->internal->params.detach_data_len = params->detach_data_len;
438 /* Add the connection to connections list */
439 // silc_dlist_add(client->internal->conns, conn);
441 /* Run the connection state machine. If threads are in use the machine
442 is always run in a real thread. */
443 thread = silc_fsm_thread_alloc(&client->internal->fsm, conn,
444 silc_client_fsm_destructor, NULL,
445 client->internal->params->threads);
447 silc_client_del_connection(client, conn);
450 silc_fsm_start_sync(thread, silc_client_connection_st_start);
455 /* Removes connection from client. Frees all memory. */
457 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
460 SilcClientConnection c;
461 SilcIDCacheList list;
462 SilcIDCacheEntry entry;
463 SilcClientCommandPending *r;
466 silc_dlist_start(client->internal->conns);
467 while ((c = silc_dlist_get(client->internal->conns)) != SILC_LIST_END) {
471 /* Free all cache entries */
472 if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
473 ret = silc_idcache_list_first(list, &entry);
475 silc_client_del_client(client, conn, entry->context);
476 ret = silc_idcache_list_next(list, &entry);
478 silc_idcache_list_free(list);
481 if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
482 ret = silc_idcache_list_first(list, &entry);
484 silc_client_del_channel(client, conn, entry->context);
485 ret = silc_idcache_list_next(list, &entry);
487 silc_idcache_list_free(list);
490 if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
491 ret = silc_idcache_list_first(list, &entry);
493 silc_client_del_server(client, conn, entry->context);
494 ret = silc_idcache_list_next(list, &entry);
496 silc_idcache_list_free(list);
499 /* Clear ID caches */
500 if (conn->internal->client_cache)
501 silc_idcache_free(conn->internal->client_cache);
502 if (conn->internal->channel_cache)
503 silc_idcache_free(conn->internal->channel_cache);
504 if (conn->internal->server_cache)
505 silc_idcache_free(conn->internal->server_cache);
507 /* Free data (my ID is freed in above silc_client_del_client).
508 conn->nickname is freed when freeing the local_entry->nickname. */
509 silc_free(conn->remote_host);
510 silc_free(conn->local_id_data);
511 if (conn->internal->send_key)
512 silc_cipher_free(conn->internal->send_key);
513 if (conn->internal->receive_key)
514 silc_cipher_free(conn->internal->receive_key);
515 if (conn->internal->hmac_send)
516 silc_hmac_free(conn->internal->hmac_send);
517 if (conn->internal->hmac_receive)
518 silc_hmac_free(conn->internal->hmac_receive);
519 silc_free(conn->internal->rekey);
521 if (conn->internal->active_session) {
523 conn->sock->user_data = NULL;
524 silc_client_ftp_session_free(conn->internal->active_session);
525 conn->internal->active_session = NULL;
528 silc_client_ftp_free_sessions(client, conn);
530 if (conn->internal->pending_commands) {
531 silc_dlist_start(conn->internal->pending_commands);
532 while ((r = silc_dlist_get(conn->internal->pending_commands))
534 silc_dlist_del(conn->internal->pending_commands, r);
535 silc_dlist_uninit(conn->internal->pending_commands);
538 silc_free(conn->internal);
539 memset(conn, 0, sizeof(*conn));
542 silc_dlist_del(client->internal->conns, conn);
547 /* Connects to remote server. This is the main routine used to connect
548 to remote SILC server. Returns FALSE on error. */
550 void silc_client_connect_to_server(SilcClient client,
551 SilcClientConnectionParams *params,
552 SilcPublicKey public_key,
553 SilcPrivateKey private_key,
554 char *remote_host, int port,
555 SilcClientConnectCallback callback,
558 SilcClientConnection conn;
560 if (!client || !remote_host)
563 /* Add new connection */
564 conn = silc_client_add_connection(client, SILC_CONN_SERVER, params,
565 public_key, private_key, remote_host,
566 port, callback, context);
568 callback(client, NULL, SILC_CLIENT_CONN_ERROR, context);
572 client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
573 "Connecting to port %d of server %s",
576 /* Signal connection machine to start connecting */
577 conn->internal->connect = TRUE;
580 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
581 key material between client and server. This function can be called
582 directly if application is performing its own connecting and does not
583 use the connecting provided by this library. This function is normally
584 used only if the application performed the connecting outside the library.
585 The library however may use this internally. */
587 void silc_client_start_key_exchange(SilcClient client,
588 SilcClientConnection conn,
592 assert(conn && stream);
593 assert(client->public_key);
594 assert(client->private_key);
596 conn->nickname = (client->nickname ? strdup(client->nickname) :
597 strdup(client->username));
605 /* Authentication method resolving callback. Application calls this function
606 after we've called the client->internal->ops->get_auth_method
607 client operation to resolve the authentication method. We will continue
608 the executiong of the protocol in this function. */
610 void silc_client_resolve_auth_method(SilcBool success,
611 SilcProtocolAuthMeth auth_meth,
612 const unsigned char *auth_data,
613 SilcUInt32 auth_data_len, void *context)
615 SilcClientConnAuthInternalContext *proto_ctx =
616 (SilcClientConnAuthInternalContext *)context;
617 SilcClient client = (SilcClient)proto_ctx->client;
620 auth_meth = SILC_AUTH_NONE;
622 proto_ctx->auth_meth = auth_meth;
624 if (success && auth_data && auth_data_len) {
626 /* Passphrase must be UTF-8 encoded, if it isn't encode it */
627 if (auth_meth == SILC_AUTH_PASSWORD &&
628 !silc_utf8_valid(auth_data, auth_data_len)) {
630 unsigned char *autf8 = NULL;
631 payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
633 autf8 = silc_calloc(payload_len, sizeof(*autf8));
634 auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
635 SILC_STRING_ASCII, autf8, payload_len);
639 proto_ctx->auth_data = silc_memdup(auth_data, auth_data_len);
640 proto_ctx->auth_data_len = auth_data_len;
643 /* Allocate the authenteication protocol and execute it. */
644 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
645 &proto_ctx->sock->protocol, (void *)proto_ctx,
646 silc_client_connect_to_server_final);
648 /* Execute the protocol */
649 silc_protocol_execute(proto_ctx->sock->protocol, client->schedule, 0, 0);
652 /* Finalizes the connection to the remote SILC server. This is called
653 after authentication protocol has been completed. This send our
654 user information to the server to receive our client ID from
657 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
659 SilcProtocol protocol = (SilcProtocol)context;
660 SilcClientConnAuthInternalContext *ctx =
661 (SilcClientConnAuthInternalContext *)protocol->context;
662 SilcClient client = (SilcClient)ctx->client;
663 SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
666 SILC_LOG_DEBUG(("Start"));
668 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
669 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
670 /* Error occured during protocol */
671 SILC_LOG_DEBUG(("Error during authentication protocol"));
672 ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
676 if (conn->internal->params.detach_data) {
677 /* Send RESUME_CLIENT packet to the server, which is used to resume
678 old detached session back. */
680 SilcClientID *old_client_id;
681 unsigned char *old_id;
682 SilcUInt16 old_id_len;
684 if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
685 ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
689 old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
690 if (!old_client_id) {
692 ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
696 /* Generate authentication data that server will verify */
697 auth = silc_auth_public_key_auth_generate(client->public_key,
700 conn->internal->hash,
701 old_client_id, SILC_ID_CLIENT);
703 silc_free(old_client_id);
705 ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
709 packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
710 silc_buffer_format(packet,
711 SILC_STR_UI_SHORT(old_id_len),
712 SILC_STR_UI_XNSTRING(old_id, old_id_len),
713 SILC_STR_UI_XNSTRING(auth->data, auth->len),
716 /* Send the packet */
717 silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
719 packet->data, packet->len, TRUE);
720 silc_buffer_free(packet);
721 silc_buffer_free(auth);
722 silc_free(old_client_id);
725 /* Send NEW_CLIENT packet to the server. We will become registered
726 to the SILC network after sending this packet and we will receive
727 client ID from the server. */
728 packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
729 strlen(client->realname));
730 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
731 silc_buffer_format(packet,
732 SILC_STR_UI_SHORT(strlen(client->username)),
733 SILC_STR_UI_XNSTRING(client->username,
734 strlen(client->username)),
735 SILC_STR_UI_SHORT(strlen(client->realname)),
736 SILC_STR_UI_XNSTRING(client->realname,
737 strlen(client->realname)),
740 /* Send the packet */
741 silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
743 packet->data, packet->len, TRUE);
744 silc_buffer_free(packet);
747 /* Save remote ID. */
748 conn->remote_id = ctx->dest_id;
749 conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
750 conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
752 /* Register re-key timeout */
753 conn->internal->rekey->timeout = client->internal->params->rekey_secs;
754 conn->internal->rekey->context = (void *)client;
755 silc_schedule_task_add(client->schedule, conn->sock->sock,
756 silc_client_rekey_callback,
757 (void *)conn->sock, conn->internal->rekey->timeout, 0,
758 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
760 silc_protocol_free(protocol);
761 silc_free(ctx->auth_data);
763 silc_ske_free(ctx->ske);
764 silc_socket_free(ctx->sock);
766 conn->sock->protocol = NULL;
770 silc_protocol_free(protocol);
771 silc_free(ctx->auth_data);
772 silc_free(ctx->dest_id);
774 silc_ske_free(ctx->ske);
775 conn->sock->protocol = NULL;
776 silc_socket_free(ctx->sock);
778 /* Notify application of failure */
779 silc_schedule_task_add(client->schedule, ctx->sock->sock,
780 silc_client_connect_failure_auth, ctx,
781 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
784 /* Packet processing callback. This is used to send and receive packets
785 from network. This is generic task. */
787 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
789 SilcClient client = (SilcClient)context;
790 SilcClientConnection conn = NULL;
791 SilcClientConnection conn;
794 SILC_LOG_DEBUG(("Processing packet"));
796 SILC_CLIENT_GET_SOCK(client, fd, sock);
800 conn = (SilcClientConnection)sock->user_data;
803 if (type == SILC_TASK_WRITE) {
804 /* Do not send data to disconnected connection */
805 if (SILC_IS_DISCONNECTED(sock))
808 ret = silc_packet_send(sock, TRUE);
810 /* If returned -2 could not write to connection now, will do
819 /* The packet has been sent and now it is time to set the connection
820 back to only for input. When there is again some outgoing data
821 available for this connection it will be set for output as well.
822 This call clears the output setting and sets it only for input. */
823 SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
824 SILC_UNSET_OUTBUF_PENDING(sock);
826 silc_buffer_clear(sock->outbuf);
830 /* Packet receiving */
831 if (type == SILC_TASK_READ) {
832 /* Read data from network */
833 ret = silc_packet_receive(sock);
839 SILC_LOG_DEBUG(("Read EOF"));
841 /* If connection is disconnecting already we will finally
842 close the connection */
843 if (SILC_IS_DISCONNECTING(sock)) {
844 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
845 client->internal->ops->disconnected(client, conn, 0, NULL);
846 silc_client_close_connection_real(client, sock, conn);
850 SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
851 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
852 client->internal->ops->disconnected(client, conn, 0, NULL);
853 silc_client_close_connection_real(client, sock, conn);
857 /* Process the packet. This will call the parser that will then
858 decrypt and parse the packet. */
859 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
860 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
861 conn->internal->hmac_receive,
862 conn->internal->psn_receive,
863 silc_client_packet_parse, client);
865 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
866 silc_client_packet_parse, client);
870 /* Parser callback called by silc_packet_receive_process. Thie merely
871 registers timeout that will handle the actual parsing when appropriate. */
873 static SilcBool silc_client_packet_parse(SilcPacketParserContext *parser_context,
876 SilcClient client = (SilcClient)context;
877 SilcClientConnection conn = parser_context->sock;
878 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
879 SilcPacketContext *packet = parser_context->packet;
882 if (conn && conn->internal->hmac_receive && conn->sock == sock)
883 conn->internal->psn_receive = parser_context->packet->sequence + 1;
885 /* Parse the packet immediately */
886 if (parser_context->normal)
887 ret = silc_packet_parse(packet, conn->internal->receive_key);
889 ret = silc_packet_parse_special(packet, conn->internal->receive_key);
891 if (ret == SILC_PACKET_NONE) {
892 silc_packet_context_free(packet);
893 silc_free(parser_context);
897 /* If protocol for this connection is key exchange or rekey then we'll
898 process all packets synchronously, since there might be packets in
899 queue that we are not able to decrypt without first processing the
900 packets before them. */
901 if (sock->protocol && sock->protocol->protocol &&
902 (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
903 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
905 /* Parse the incoming packet type */
906 silc_client_packet_parse_type(client, sock, packet);
908 /* Reprocess the buffer since we'll return FALSE. This is because
909 the `conn->internal->receive_key' might have become valid by processing
910 the previous packet */
911 if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
912 silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
913 conn->internal->hmac_receive,
914 conn->internal->psn_receive,
915 silc_client_packet_parse, client);
917 silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
918 silc_client_packet_parse, client);
920 silc_packet_context_free(packet);
921 silc_free(parser_context);
926 /* Parse the incoming packet type */
927 silc_client_packet_parse_type(client, sock, packet);
928 silc_packet_context_free(packet);
929 silc_free(parser_context);
934 /* Closes connection to remote end. Free's all allocated data except
935 for some information such as nickname etc. that are valid at all time.
936 If the `sock' is NULL then the conn->sock will be used. If `sock' is
937 provided it will be checked whether the sock and `conn->sock' are the
938 same (they can be different, ie. a socket can use `conn' as its
939 connection but `conn->sock' might be actually a different connection
943 void silc_client_close_connection_real(SilcClient client,
944 SilcClientConnection conn)
948 SILC_LOG_DEBUG(("Start"));
953 if (!sock || (sock && conn->sock == sock))
960 silc_client_del_connection(client, conn);
964 /* We won't listen for this connection anymore */
965 silc_schedule_unset_listen_fd(client->schedule, sock->sock);
967 /* Unregister all tasks */
968 silc_schedule_task_del_by_fd(client->schedule, sock->sock);
970 /* Close the actual connection */
971 silc_net_close_connection(sock->sock);
973 /* Cancel any active protocol */
974 if (sock->protocol) {
975 if (sock->protocol->protocol->type ==
976 SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
977 sock->protocol->protocol->type ==
978 SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
979 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
980 silc_protocol_execute_final(sock->protocol, client->schedule);
981 /* The application will recall this function with these protocols
982 (the ops->connected client operation). */
985 sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
986 silc_protocol_execute_final(sock->protocol, client->schedule);
987 sock->protocol = NULL;
991 /* Free everything */
992 if (del && sock->user_data)
993 silc_client_del_connection(client, conn);
995 silc_socket_free(sock);
998 /* Closes the connection to the remote end */
1000 void silc_client_close_connection(SilcClient client,
1001 SilcClientConnection conn)
1003 // silc_client_close_connection_real(client, NULL, conn);
1006 /* Called when we receive disconnection packet from server. This
1007 closes our end properly and displays the reason of the disconnection
1010 void silc_client_disconnect(SilcClient client,
1011 SilcClientConnection conn,
1014 SilcClientConnection conn;
1016 char *message = NULL;
1018 SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1020 if (packet->len < 1)
1023 status = (SilcStatus)packet->data[0];
1025 if (packet->len > 1 &&
1026 silc_utf8_valid(packet->data + 1, packet->len - 1))
1027 message = silc_memdup(packet->data + 1, packet->len - 1);
1029 conn = (SilcClientConnection)sock->user_data;
1030 if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
1031 client->internal->ops->disconnected(client, conn, status, message);
1035 SILC_SET_DISCONNECTED(sock);
1037 /* Close connection through scheduler. */
1038 silc_schedule_task_add(client->schedule, sock->sock,
1039 silc_client_disconnected_by_server_later,
1040 client, 0, 1, SILC_TASK_TIMEOUT,
1041 SILC_TASK_PRI_NORMAL);
1044 /* Received error message from server. Display it on the screen.
1045 We don't take any action what so ever of the error message. */
1047 void silc_client_error_by_server(SilcClient client,
1048 SilcClientConnection conn,
1053 msg = silc_memdup(message->data, message->len);
1054 client->internal->ops->say(client, sock->user_data,
1055 SILC_CLIENT_MESSAGE_AUDIT, msg);
1059 /* Auto-nicking callback to send NICK command to server. */
1061 SILC_TASK_CALLBACK(silc_client_send_auto_nick)
1063 SilcClientConnection conn = (SilcClientConnection)context;
1064 SilcClient client = conn->client;
1066 silc_client_command_send(client, conn, SILC_COMMAND_NICK,
1067 ++conn->cmd_ident, 1, 1,
1068 client->nickname, strlen(client->nickname));
1071 /* Client session resuming callback. If the session was resumed
1072 this callback is called after the resuming is completed. This
1073 will call the `connect' client operation to the application
1074 since it has not been called yet. */
1076 static void silc_client_resume_session_cb(SilcClient client,
1077 SilcClientConnection conn,
1083 /* Notify application that connection is created to server */
1084 client->internal->ops->connected(client, conn, success ?
1085 SILC_CLIENT_CONN_SUCCESS_RESUME :
1086 SILC_CLIENT_CONN_ERROR_RESUME);
1089 /* Issue INFO command to fetch the real server name and server
1090 information and other stuff. */
1091 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1092 silc_client_command_reply_info_i, 0,
1094 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1095 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1096 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1097 silc_buffer_free(sidp);
1101 /* Removes a client entry from all channels it has joined. */
1103 void silc_client_remove_from_channels(SilcClient client,
1104 SilcClientConnection conn,
1105 SilcClientEntry client_entry)
1107 SilcHashTableList htl;
1108 SilcChannelUser chu;
1110 silc_hash_table_list(client_entry->channels, &htl);
1111 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1112 silc_hash_table_del(chu->client->channels, chu->channel);
1113 silc_hash_table_del(chu->channel->user_list, chu->client);
1117 silc_hash_table_list_reset(&htl);
1120 /* Replaces `old' client entries from all channels to `new' client entry.
1121 This can be called for example when nickname changes and old ID entry
1122 is replaced from ID cache with the new one. If the old ID entry is only
1123 updated, then this fucntion needs not to be called. */
1125 void silc_client_replace_from_channels(SilcClient client,
1126 SilcClientConnection conn,
1127 SilcClientEntry old,
1128 SilcClientEntry new)
1130 SilcHashTableList htl;
1131 SilcChannelUser chu;
1133 silc_hash_table_list(old->channels, &htl);
1134 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1135 /* Replace client entry */
1136 silc_hash_table_del(chu->client->channels, chu->channel);
1137 silc_hash_table_del(chu->channel->user_list, chu->client);
1140 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1141 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1143 silc_hash_table_list_reset(&htl);
1146 /* Registers failure timeout to process the received failure packet
1149 void silc_client_process_failure(SilcClient client,
1150 SilcClientConnection conn,
1151 SilcPacketContext *packet)
1153 SilcUInt32 failure = 0;
1155 if (sock->protocol) {
1156 if (packet->buffer->len >= 4)
1157 SILC_GET32_MSB(failure, packet->buffer->data);
1159 /* Notify application */
1160 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1161 SILC_32_TO_PTR(failure));
1165 /* A timeout callback for the re-key. We will be the initiator of the
1168 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1170 SilcClientConnection conn = (SilcSocketConnection)context;
1171 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1172 SilcClient client = (SilcClient)conn->internal->rekey->context;
1173 SilcProtocol protocol;
1174 SilcClientRekeyInternalContext *proto_ctx;
1176 SILC_LOG_DEBUG(("Start"));
1178 /* If rekey protocol is active already wait for it to finish */
1179 if (sock->protocol && sock->protocol->protocol &&
1180 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
1183 /* Allocate internal protocol context. This is sent as context
1185 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1186 proto_ctx->client = (void *)client;
1187 proto_ctx->sock = silc_socket_dup(sock);
1188 proto_ctx->responder = FALSE;
1189 proto_ctx->pfs = conn->internal->rekey->pfs;
1191 /* Perform rekey protocol. Will call the final callback after the
1192 protocol is over. */
1193 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1194 &protocol, proto_ctx, silc_client_rekey_final);
1195 sock->protocol = protocol;
1197 /* Run the protocol */
1198 silc_protocol_execute(protocol, client->schedule, 0, 0);
1201 /* The final callback for the REKEY protocol. This will actually take the
1202 new key material into use. */
1204 SILC_TASK_CALLBACK(silc_client_rekey_final)
1206 SilcProtocol protocol = (SilcProtocol)context;
1207 SilcClientRekeyInternalContext *ctx =
1208 (SilcClientRekeyInternalContext *)protocol->context;
1209 SilcClient client = (SilcClient)ctx->client;
1210 SilcClientConnection conn = ctx->sock;
1211 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1213 SILC_LOG_DEBUG(("Start"));
1215 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1216 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1217 /* Error occured during protocol */
1218 silc_protocol_cancel(protocol, client->schedule);
1219 silc_protocol_free(protocol);
1220 sock->protocol = NULL;
1222 silc_packet_context_free(ctx->packet);
1224 silc_ske_free(ctx->ske);
1225 silc_socket_free(ctx->sock);
1230 /* Purge the outgoing data queue to assure that all rekey packets really
1231 go to the network before we quit the protocol. */
1232 silc_client_packet_queue_purge(client, sock);
1234 /* Re-register re-key timeout */
1235 if (ctx->responder == FALSE)
1236 silc_schedule_task_add(client->schedule, sock->sock,
1237 silc_client_rekey_callback,
1238 sock, conn->internal->rekey->timeout, 0,
1239 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1242 silc_protocol_free(protocol);
1243 sock->protocol = NULL;
1245 silc_packet_context_free(ctx->packet);
1247 silc_ske_free(ctx->ske);
1248 silc_socket_free(ctx->sock);
1252 /* Processes incoming connection authentication method request packet.
1253 It is a reply to our previously sent request. The packet can be used
1254 to resolve the authentication method for the current session if the
1255 client does not know it beforehand. */
1257 void silc_client_connection_auth_request(SilcClient client,
1258 SilcClientConnection conn,
1259 SilcPacketContext *packet)
1261 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1262 SilcUInt16 conn_type, auth_meth;
1265 /* If we haven't send our request then ignore this one. */
1266 if (!conn->internal->connauth)
1269 /* Parse the payload */
1270 ret = silc_buffer_unformat(packet->buffer,
1271 SILC_STR_UI_SHORT(&conn_type),
1272 SILC_STR_UI_SHORT(&auth_meth),
1275 auth_meth = SILC_AUTH_NONE;
1277 /* Call the request callback to notify application for received
1278 authentication method information. */
1279 if (conn->internal->connauth->callback)
1280 (*conn->internal->connauth->callback)(client, conn, auth_meth,
1281 conn->internal->connauth->context);
1283 silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1285 silc_free(conn->internal->connauth);
1286 conn->internal->connauth = NULL;
1289 /* Timeout task callback called if the server does not reply to our
1290 connection authentication method request in the specified time interval. */
1292 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1294 SilcClientConnection conn = (SilcClientConnection)context;
1295 SilcClient client = conn->client;
1297 if (!conn->internal->connauth)
1300 /* Call the request callback to notify application */
1301 if (conn->internal->connauth->callback)
1302 (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1303 conn->internal->connauth->context);
1305 silc_free(conn->internal->connauth);
1306 conn->internal->connauth = NULL;
1309 /* This function can be used to request the current authentication method
1310 from the server. This may be called when connecting to the server
1311 and the client library requests the authentication data from the
1312 application. If the application does not know the current authentication
1313 method it can request it from the server using this function.
1314 The `callback' with `context' will be called after the server has
1315 replied back with the current authentication method. */
1318 silc_client_request_authentication_method(SilcClient client,
1319 SilcClientConnection conn,
1320 SilcConnectionAuthRequest callback,
1323 SilcClientConnAuthRequest connauth;
1326 assert(client && conn);
1327 connauth = silc_calloc(1, sizeof(*connauth));
1328 connauth->callback = callback;
1329 connauth->context = context;
1331 if (conn->internal->connauth)
1332 silc_free(conn->internal->connauth);
1334 conn->internal->connauth = connauth;
1336 /* Assemble the request packet and send it to the server */
1337 packet = silc_buffer_alloc(4);
1338 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1339 silc_buffer_format(packet,
1340 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1341 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1343 silc_client_packet_send(client, conn->sock,
1344 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1345 NULL, 0, NULL, NULL,
1346 packet->data, packet->len, FALSE);
1347 silc_buffer_free(packet);
1349 /* Register a timeout in case server does not reply anything back. */
1351 silc_schedule_task_add(client->schedule, conn->sock->sock,
1352 silc_client_request_authentication_method_timeout,
1354 client->internal->params->connauth_request_secs, 0,
1355 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1360 /******************************* Client API *********************************/
1362 /* Allocates new client object. This has to be done before client may
1363 work. After calling this one must call silc_client_init to initialize
1364 the client. The `application' is application specific user data pointer
1365 and caller must free it. */
1367 SilcClient silc_client_alloc(SilcClientOperations *ops,
1368 SilcClientParams *params,
1370 const char *version_string)
1372 SilcClient new_client;
1374 new_client = silc_calloc(1, sizeof(*new_client));
1375 new_client->application = application;
1377 new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
1378 new_client->internal->ops = ops;
1379 new_client->internal->params =
1380 silc_calloc(1, sizeof(*new_client->internal->params));
1381 if (!version_string)
1382 version_string = silc_version_string;
1383 new_client->internal->silc_client_version = strdup(version_string);
1386 memcpy(new_client->internal->params, params, sizeof(*params));
1388 if (!new_client->internal->params->task_max)
1389 new_client->internal->params->task_max = 200;
1391 if (!new_client->internal->params->rekey_secs)
1392 new_client->internal->params->rekey_secs = 3600;
1394 if (!new_client->internal->params->connauth_request_secs)
1395 new_client->internal->params->connauth_request_secs = 2;
1397 new_client->internal->params->
1398 nickname_format[sizeof(new_client->internal->
1399 params->nickname_format) - 1] = 0;
1404 /* Frees client object and its internals. */
1406 void silc_client_free(SilcClient client)
1410 silc_rng_free(client->rng);
1412 if (!client->internal->params->dont_register_crypto_library) {
1413 silc_cipher_unregister_all();
1414 silc_pkcs_unregister_all();
1415 silc_hash_unregister_all();
1416 silc_hmac_unregister_all();
1419 silc_hash_free(client->md5hash);
1420 silc_hash_free(client->sha1hash);
1421 silc_hmac_free(client->internal->md5hmac);
1422 silc_hmac_free(client->internal->sha1hmac);
1423 silc_free(client->internal->params);
1424 silc_free(client->internal->silc_client_version);
1425 silc_free(client->internal);
1430 /* Initializes the client. This makes all the necessary steps to make
1431 the client ready to be run. One must call silc_client_run to run the
1432 client. Returns FALSE if error occured, TRUE otherwise. */
1434 SilcBool silc_client_init(SilcClient client)
1436 SILC_LOG_DEBUG(("Initializing client"));
1439 assert(client->username);
1440 assert(client->hostname);
1441 assert(client->realname);
1443 /* Validate essential strings */
1444 if (client->nickname)
1445 if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
1446 SILC_STRING_UTF8, 128)) {
1447 SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
1450 if (!silc_identifier_verify(client->username, strlen(client->username),
1451 SILC_STRING_UTF8, 128)) {
1452 SILC_LOG_ERROR(("Malformed username '%s'", client->username));
1455 if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
1456 SILC_STRING_UTF8, 256)) {
1457 SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
1460 if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
1461 SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
1465 if (!client->internal->params->dont_register_crypto_library) {
1466 /* Initialize the crypto library. If application has done this already
1467 this has no effect. Also, we will not be overriding something
1468 application might have registered earlier. */
1469 silc_cipher_register_default();
1470 silc_pkcs_register_default();
1471 silc_hash_register_default();
1472 silc_hmac_register_default();
1475 /* Initialize hash functions for client to use */
1476 silc_hash_alloc("md5", &client->md5hash);
1477 silc_hash_alloc("sha1", &client->sha1hash);
1479 /* Initialize random number generator */
1480 client->rng = silc_rng_alloc();
1481 silc_rng_init(client->rng);
1482 silc_rng_global_init(client->rng);
1484 /* Initialize the scheduler */
1486 silc_schedule_init(client->internal->params->task_max ?
1487 client->internal->params->task_max : 200, client);
1488 if (!client->schedule)
1491 /* Start packet engine */
1492 client->internal->packet_engine =
1493 silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1495 if (!client->internal->packet_engine)
1498 /* Initialize FSM */
1499 if (!silc_fsm_init(&client->internal->fsm, client, NULL, NULL,
1502 silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1504 /* Allocate client lock */
1505 silc_mutex_alloc(&client->internal->lock);
1507 /* Register commands */
1508 silc_client_commands_register(client);
1513 /* Stops the client. This is called to stop the client and thus to stop
1516 void silc_client_stop(SilcClient client)
1518 SILC_LOG_DEBUG(("Stopping client"));
1520 silc_schedule_stop(client->schedule);
1521 silc_schedule_uninit(client->schedule);
1523 silc_client_commands_unregister(client);
1525 SILC_LOG_DEBUG(("Client stopped"));
1528 /* Starts the SILC client FSM machine and blocks here. When this returns
1529 the client has ended. */
1531 void silc_client_run(SilcClient client)
1533 SILC_LOG_DEBUG(("Starting SILC client"));
1535 /* Start the client */
1536 silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1538 /* Signal the application when we are running */
1539 client->internal->run_callback = TRUE;
1540 SILC_FSM_SEMA_POST(&client->internal->wait_event);
1542 /* Run the scheduler */
1543 silc_schedule(client->schedule);
1546 /* Call scheduler one iteration and return. This cannot be called if threads
1549 void silc_client_run_one(SilcClient client)
1551 silc_schedule_one(client->schedule, -1);