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 SilcClient client = callback_context;
42 SilcClientConnection conn = stream_context;
44 /* Packets we do not handle */
45 switch (packet->type) {
46 case SILC_PACKET_HEARTBEAT:
47 case SILC_PACKET_SUCCESS:
48 case SILC_PACKET_FAILURE:
49 case SILC_PACKET_REJECT:
50 case SILC_PACKET_KEY_EXCHANGE:
51 case SILC_PACKET_KEY_EXCHANGE_1:
52 case SILC_PACKET_KEY_EXCHANGE_2:
53 case SILC_PACKET_REKEY:
54 case SILC_PACKET_REKEY_DONE:
55 case SILC_PACKET_CONNECTION_AUTH:
56 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
61 /* Signal packet processor thread for a new packet */
62 conn->internal->new_packet = TRUE;
63 silc_fsm_set_state_context(&conn->internal->packet_thread, packet);
64 silc_fsm_continue_sync(&conn->internal->packet_thread);
69 /* Packet engine callback to indicate end of stream */
71 static void silc_client_packet_eos(SilcPacketEngine engine,
72 SilcPacketStream stream,
73 void *callback_context,
76 SILC_LOG_DEBUG(("End of stream received"));
79 /* Packet engine callback to indicate error */
81 static void silc_client_packet_error(SilcPacketEngine engine,
82 SilcPacketStream stream,
83 SilcPacketError error,
84 void *callback_context,
90 /* Packet stream callbacks */
91 static SilcPacketCallbacks silc_client_stream_cbs =
93 silc_client_packet_receive,
94 silc_client_packet_eos,
95 silc_client_packet_error
100 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
101 void *destructor_context)
107 /************************** Connection's machine ****************************/
109 /* Start the connection's state machine. If threads are in use the machine
110 is always executed in a real thread. */
112 SILC_FSM_STATE(silc_client_connection_st_start)
114 SilcClientConnection conn = fsm_context;
116 /* Take scheduler for connection */
117 conn->internal->schedule = silc_fsm_get_schedule(fsm);
119 /*** Run connection machine */
120 silc_fsm_init(&conn->internal->fsm, conn, NULL, NULL,
121 conn->internal->schedule);
122 silc_fsm_sema_init(&conn->internal->wait_event, &conn->internal->fsm, 0);
123 silc_fsm_start_sync(&conn->internal->fsm, silc_client_connection_st_run);
125 /*** Run packet processor FSM thread */
126 silc_fsm_thread_init(&conn->internal->packet_thread, &conn->internal->fsm,
127 conn, silc_client_fsm_destructor, NULL, FALSE);
128 silc_fsm_start_sync(&conn->internal->packet_thread,
129 silc_client_connection_st_packet);
131 /* Schedule any events set in initialization */
132 if (conn->internal->connect)
133 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
134 if (conn->internal->key_exchange)
135 SILC_FSM_SEMA_POST(&conn->internal->wait_event);
137 /* Wait until this thread is terminated */
138 return SILC_FSM_WAIT;
141 /* Connection machine main state. */
143 SILC_FSM_STATE(silc_client_connection_st_run)
145 SilcClientConnection conn = fsm_context;
147 /* Wait for events */
148 SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
152 if (conn->internal->connect) {
153 SILC_LOG_DEBUG(("Event: connect"));
154 conn->internal->connect = FALSE;
156 /** Connect remote host */
157 silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
158 conn, NULL, NULL, FALSE);
159 silc_fsm_start_sync(&conn->internal->event_thread, silc_client_st_connect);
160 return SILC_FSM_CONTINUE;
163 if (conn->internal->key_exchange) {
164 SILC_LOG_DEBUG(("Event: key exchange"));
165 conn->internal->key_exchange = FALSE;
167 /** Start key exchange */
168 silc_fsm_thread_init(&conn->internal->event_thread, &conn->internal->fsm,
169 conn, NULL, NULL, FALSE);
170 silc_fsm_start_sync(&conn->internal->event_thread,
171 silc_client_st_connect_key_exchange);
172 return SILC_FSM_CONTINUE;
175 if (conn->internal->disconnected) {
176 SILC_LOG_DEBUG(("Event: disconnected"));
177 conn->internal->disconnected = FALSE;
179 return SILC_FSM_CONTINUE;
183 #if defined(SILC_DEBUG)
185 #endif /* SILC_DEBUG */
186 return SILC_FSM_CONTINUE;
189 /* Connection's packet processor main state. Packet processor thread waits
190 here for a new packet and processes received packets. */
192 SILC_FSM_STATE(silc_client_connection_st_packet)
194 SilcClientConnection conn = fsm_context;
195 SilcClient client = conn->client;
196 SilcPacket packet = state_context;
198 /* Wait for packet to arrive */
199 if (!conn->internal->new_packet) {
200 SILC_LOG_DEBUG(("Wait for packet"));
201 return SILC_FSM_WAIT;
203 conn->internal->new_packet = FALSE;
205 SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
207 switch (packet->type) {
209 case SILC_PACKET_PRIVATE_MESSAGE:
210 /** Private message */
211 silc_fsm_next(fsm, silc_client_private_message);
214 case SILC_PACKET_CHANNEL_MESSAGE:
215 /* Channel message */
216 // silc_client_channel_message(client, conn, packet);
219 case SILC_PACKET_FTP:
220 /* File transfer packet */
221 // silc_client_ftp(client, conn, packet);
224 case SILC_PACKET_CHANNEL_KEY:
225 /* Received channel key */
226 // silc_client_channel_key(client, conn, packet);
229 case SILC_PACKET_COMMAND_REPLY:
231 silc_fsm_next(fsm, silc_client_command_reply);
234 case SILC_PACKET_NOTIFY:
236 // silc_client_notify(client, conn, packet);
239 case SILC_PACKET_PRIVATE_MESSAGE_KEY:
240 /* Private message key indicator */
241 // silc_client_private_message_key(client, conn, packet);
244 case SILC_PACKET_DISCONNECT:
245 /* Server disconnects */
246 // silc_client_disconnect(client, conn, packet);
249 case SILC_PACKET_ERROR:
250 /* Error by server */
251 // silc_client_error(client, conn, packet);
254 case SILC_PACKET_KEY_AGREEMENT:
256 // silc_client_key_agreement(client, conn, packet);
259 case SILC_PACKET_COMMAND:
260 /** Command packet */
261 silc_fsm_next(fsm, silc_client_command);
264 case SILC_PACKET_NEW_ID:
266 silc_fsm_next(fsm, silc_client_new_id);
268 case SILC_PACKET_CONNECTION_AUTH_REQUEST:
269 /* Reply to connection authentication request to resolve authentication
270 method from server. */
271 // silc_client_connection_auth_request(client, conn, packet);
275 silc_packet_free(packet);
279 return SILC_FSM_CONTINUE;
283 /*************************** Main client machine ****************************/
285 /* The client's main state where we wait for various events */
287 SILC_FSM_STATE(silc_client_st_run)
289 SilcClient client = fsm_context;
291 /* Wait for events */
292 SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
296 if (client->internal->run_callback && client->internal->ops->running) {
297 /* Call running callbcak back to application */
298 client->internal->run_callback = FALSE;
299 client->internal->ops->running(client, client->application);
300 return SILC_FSM_CONTINUE;
304 #if defined(SILC_DEBUG)
306 #endif /* SILC_DEBUG */
307 return SILC_FSM_CONTINUE;
311 /**************************** Packet Processing *****************************/
313 /* Received new ID from server during registering to SILC network */
315 SILC_FSM_STATE(silc_client_new_id)
317 SilcClientConnection conn = fsm_context;
318 SilcClient client = conn->client;
319 SilcPacket packet = state_context;
325 SILC_LOG_DEBUG(("New ID received from server"));
327 if (!silc_id_payload_parse_id(silc_buffer_data(&packet->buffer),
328 silc_buffer_len(&packet->buffer), &id))
331 /* Create local client entry */
332 conn->local_entry = silc_client_add_client(client, conn, (client->nickname ?
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 /* Processes the received new Client ID from server. Old Client ID is
1102 deleted from cache and new one is added. */
1104 void silc_client_receive_new_id(SilcClient client,
1105 SilcClientConnection conn,
1108 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1109 int connecting = FALSE;
1110 SilcClientID *client_id = silc_id_payload_get_id(idp);
1113 if (!conn->local_entry)
1116 /* Delete old ID from ID cache */
1117 if (conn->local_id) {
1118 /* Check whether they are different */
1119 if (SILC_ID_CLIENT_COMPARE(conn->local_id, client_id)) {
1120 silc_free(client_id);
1124 silc_idcache_del_by_context(conn->internal->client_cache,
1126 silc_free(conn->local_id);
1129 /* Save the new ID */
1131 if (conn->local_id_data)
1132 silc_free(conn->local_id_data);
1134 conn->local_id = client_id;
1135 conn->local_id_data = silc_id_payload_get_data(idp);
1136 conn->local_id_data_len = silc_id_payload_get_len(idp);;
1138 if (!conn->local_entry)
1139 conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1141 conn->local_entry->nickname = conn->nickname;
1142 if (!conn->local_entry->username)
1143 conn->local_entry->username = strdup(client->username);
1144 if (!conn->local_entry->server)
1145 conn->local_entry->server = strdup(conn->remote_host);
1146 conn->local_entry->id = conn->local_id;
1147 conn->local_entry->valid = TRUE;
1148 if (!conn->local_entry->channels)
1149 conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
1154 /* Normalize nickname */
1155 nickname = silc_identifier_check(conn->nickname, strlen(conn->nickname),
1156 SILC_STRING_UTF8, 128, NULL);
1160 /* Put it to the ID cache */
1161 silc_idcache_add(conn->internal->client_cache, nickname, conn->local_id,
1162 (void *)conn->local_entry, 0, NULL);
1168 /* Issue IDENTIFY command for itself to get resolved hostname
1169 correctly from server. */
1170 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
1171 silc_client_command_reply_identify_i, 0,
1173 sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
1174 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
1175 conn->cmd_ident, 1, 5, sidp->data, sidp->len);
1176 silc_buffer_free(sidp);
1178 if (!conn->internal->params.detach_data) {
1179 /* Send NICK command if the nickname was set by the application (and is
1180 not same as the username). Send this with little timeout. */
1181 if (client->nickname &&
1182 !silc_utf8_strcasecmp(client->nickname, client->username))
1183 silc_schedule_task_add(client->schedule, 0,
1184 silc_client_send_auto_nick, conn,
1185 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1187 /* Notify application of successful connection. We do it here now that
1188 we've received the Client ID and are allowed to send traffic. */
1189 client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_SUCCESS);
1191 /* Issue INFO command to fetch the real server name and server
1192 information and other stuff. */
1193 silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
1194 silc_client_command_reply_info_i, 0,
1196 sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
1197 silc_client_command_send(client, conn, SILC_COMMAND_INFO,
1198 conn->cmd_ident, 1, 2, sidp->data, sidp->len);
1199 silc_buffer_free(sidp);
1201 /* We are resuming session. Start resolving informations from the
1202 server we need to set the client libary in the state before
1203 detaching the session. The connect client operation is called
1204 after this is successfully completed */
1205 silc_client_resume_session(client, conn, silc_client_resume_session_cb,
1212 /* Removes a client entry from all channels it has joined. */
1214 void silc_client_remove_from_channels(SilcClient client,
1215 SilcClientConnection conn,
1216 SilcClientEntry client_entry)
1218 SilcHashTableList htl;
1219 SilcChannelUser chu;
1221 silc_hash_table_list(client_entry->channels, &htl);
1222 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1223 silc_hash_table_del(chu->client->channels, chu->channel);
1224 silc_hash_table_del(chu->channel->user_list, chu->client);
1228 silc_hash_table_list_reset(&htl);
1231 /* Replaces `old' client entries from all channels to `new' client entry.
1232 This can be called for example when nickname changes and old ID entry
1233 is replaced from ID cache with the new one. If the old ID entry is only
1234 updated, then this fucntion needs not to be called. */
1236 void silc_client_replace_from_channels(SilcClient client,
1237 SilcClientConnection conn,
1238 SilcClientEntry old,
1239 SilcClientEntry new)
1241 SilcHashTableList htl;
1242 SilcChannelUser chu;
1244 silc_hash_table_list(old->channels, &htl);
1245 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1246 /* Replace client entry */
1247 silc_hash_table_del(chu->client->channels, chu->channel);
1248 silc_hash_table_del(chu->channel->user_list, chu->client);
1251 silc_hash_table_add(chu->channel->user_list, chu->client, chu);
1252 silc_hash_table_add(chu->client->channels, chu->channel, chu);
1254 silc_hash_table_list_reset(&htl);
1257 /* Registers failure timeout to process the received failure packet
1260 void silc_client_process_failure(SilcClient client,
1261 SilcClientConnection conn,
1262 SilcPacketContext *packet)
1264 SilcUInt32 failure = 0;
1266 if (sock->protocol) {
1267 if (packet->buffer->len >= 4)
1268 SILC_GET32_MSB(failure, packet->buffer->data);
1270 /* Notify application */
1271 client->internal->ops->failure(client, sock->user_data, sock->protocol,
1272 SILC_32_TO_PTR(failure));
1276 /* A timeout callback for the re-key. We will be the initiator of the
1279 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
1281 SilcClientConnection conn = (SilcSocketConnection)context;
1282 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1283 SilcClient client = (SilcClient)conn->internal->rekey->context;
1284 SilcProtocol protocol;
1285 SilcClientRekeyInternalContext *proto_ctx;
1287 SILC_LOG_DEBUG(("Start"));
1289 /* If rekey protocol is active already wait for it to finish */
1290 if (sock->protocol && sock->protocol->protocol &&
1291 sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
1294 /* Allocate internal protocol context. This is sent as context
1296 proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
1297 proto_ctx->client = (void *)client;
1298 proto_ctx->sock = silc_socket_dup(sock);
1299 proto_ctx->responder = FALSE;
1300 proto_ctx->pfs = conn->internal->rekey->pfs;
1302 /* Perform rekey protocol. Will call the final callback after the
1303 protocol is over. */
1304 silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
1305 &protocol, proto_ctx, silc_client_rekey_final);
1306 sock->protocol = protocol;
1308 /* Run the protocol */
1309 silc_protocol_execute(protocol, client->schedule, 0, 0);
1312 /* The final callback for the REKEY protocol. This will actually take the
1313 new key material into use. */
1315 SILC_TASK_CALLBACK(silc_client_rekey_final)
1317 SilcProtocol protocol = (SilcProtocol)context;
1318 SilcClientRekeyInternalContext *ctx =
1319 (SilcClientRekeyInternalContext *)protocol->context;
1320 SilcClient client = (SilcClient)ctx->client;
1321 SilcClientConnection conn = ctx->sock;
1322 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1324 SILC_LOG_DEBUG(("Start"));
1326 if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
1327 protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
1328 /* Error occured during protocol */
1329 silc_protocol_cancel(protocol, client->schedule);
1330 silc_protocol_free(protocol);
1331 sock->protocol = NULL;
1333 silc_packet_context_free(ctx->packet);
1335 silc_ske_free(ctx->ske);
1336 silc_socket_free(ctx->sock);
1341 /* Purge the outgoing data queue to assure that all rekey packets really
1342 go to the network before we quit the protocol. */
1343 silc_client_packet_queue_purge(client, sock);
1345 /* Re-register re-key timeout */
1346 if (ctx->responder == FALSE)
1347 silc_schedule_task_add(client->schedule, sock->sock,
1348 silc_client_rekey_callback,
1349 sock, conn->internal->rekey->timeout, 0,
1350 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1353 silc_protocol_free(protocol);
1354 sock->protocol = NULL;
1356 silc_packet_context_free(ctx->packet);
1358 silc_ske_free(ctx->ske);
1359 silc_socket_free(ctx->sock);
1363 /* Processes incoming connection authentication method request packet.
1364 It is a reply to our previously sent request. The packet can be used
1365 to resolve the authentication method for the current session if the
1366 client does not know it beforehand. */
1368 void silc_client_connection_auth_request(SilcClient client,
1369 SilcClientConnection conn,
1370 SilcPacketContext *packet)
1372 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1373 SilcUInt16 conn_type, auth_meth;
1376 /* If we haven't send our request then ignore this one. */
1377 if (!conn->internal->connauth)
1380 /* Parse the payload */
1381 ret = silc_buffer_unformat(packet->buffer,
1382 SILC_STR_UI_SHORT(&conn_type),
1383 SILC_STR_UI_SHORT(&auth_meth),
1386 auth_meth = SILC_AUTH_NONE;
1388 /* Call the request callback to notify application for received
1389 authentication method information. */
1390 if (conn->internal->connauth->callback)
1391 (*conn->internal->connauth->callback)(client, conn, auth_meth,
1392 conn->internal->connauth->context);
1394 silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
1396 silc_free(conn->internal->connauth);
1397 conn->internal->connauth = NULL;
1400 /* Timeout task callback called if the server does not reply to our
1401 connection authentication method request in the specified time interval. */
1403 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
1405 SilcClientConnection conn = (SilcClientConnection)context;
1406 SilcClient client = conn->client;
1408 if (!conn->internal->connauth)
1411 /* Call the request callback to notify application */
1412 if (conn->internal->connauth->callback)
1413 (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
1414 conn->internal->connauth->context);
1416 silc_free(conn->internal->connauth);
1417 conn->internal->connauth = NULL;
1420 /* This function can be used to request the current authentication method
1421 from the server. This may be called when connecting to the server
1422 and the client library requests the authentication data from the
1423 application. If the application does not know the current authentication
1424 method it can request it from the server using this function.
1425 The `callback' with `context' will be called after the server has
1426 replied back with the current authentication method. */
1429 silc_client_request_authentication_method(SilcClient client,
1430 SilcClientConnection conn,
1431 SilcConnectionAuthRequest callback,
1434 SilcClientConnAuthRequest connauth;
1437 assert(client && conn);
1438 connauth = silc_calloc(1, sizeof(*connauth));
1439 connauth->callback = callback;
1440 connauth->context = context;
1442 if (conn->internal->connauth)
1443 silc_free(conn->internal->connauth);
1445 conn->internal->connauth = connauth;
1447 /* Assemble the request packet and send it to the server */
1448 packet = silc_buffer_alloc(4);
1449 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1450 silc_buffer_format(packet,
1451 SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
1452 SILC_STR_UI_SHORT(SILC_AUTH_NONE),
1454 silc_client_packet_send(client, conn->sock,
1455 SILC_PACKET_CONNECTION_AUTH_REQUEST,
1456 NULL, 0, NULL, NULL,
1457 packet->data, packet->len, FALSE);
1458 silc_buffer_free(packet);
1460 /* Register a timeout in case server does not reply anything back. */
1462 silc_schedule_task_add(client->schedule, conn->sock->sock,
1463 silc_client_request_authentication_method_timeout,
1465 client->internal->params->connauth_request_secs, 0,
1466 SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1471 /******************************* Client API *********************************/
1473 /* Allocates new client object. This has to be done before client may
1474 work. After calling this one must call silc_client_init to initialize
1475 the client. The `application' is application specific user data pointer
1476 and caller must free it. */
1478 SilcClient silc_client_alloc(SilcClientOperations *ops,
1479 SilcClientParams *params,
1481 const char *version_string)
1483 SilcClient new_client;
1485 new_client = silc_calloc(1, sizeof(*new_client));
1486 new_client->application = application;
1488 new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
1489 new_client->internal->ops = ops;
1490 new_client->internal->params =
1491 silc_calloc(1, sizeof(*new_client->internal->params));
1492 if (!version_string)
1493 version_string = silc_version_string;
1494 new_client->internal->silc_client_version = strdup(version_string);
1497 memcpy(new_client->internal->params, params, sizeof(*params));
1499 if (!new_client->internal->params->task_max)
1500 new_client->internal->params->task_max = 200;
1502 if (!new_client->internal->params->rekey_secs)
1503 new_client->internal->params->rekey_secs = 3600;
1505 if (!new_client->internal->params->connauth_request_secs)
1506 new_client->internal->params->connauth_request_secs = 2;
1508 new_client->internal->params->
1509 nickname_format[sizeof(new_client->internal->
1510 params->nickname_format) - 1] = 0;
1515 /* Frees client object and its internals. */
1517 void silc_client_free(SilcClient client)
1521 silc_rng_free(client->rng);
1523 if (!client->internal->params->dont_register_crypto_library) {
1524 silc_cipher_unregister_all();
1525 silc_pkcs_unregister_all();
1526 silc_hash_unregister_all();
1527 silc_hmac_unregister_all();
1530 silc_hash_free(client->md5hash);
1531 silc_hash_free(client->sha1hash);
1532 silc_hmac_free(client->internal->md5hmac);
1533 silc_hmac_free(client->internal->sha1hmac);
1534 silc_free(client->internal->params);
1535 silc_free(client->internal->silc_client_version);
1536 silc_free(client->internal);
1541 /* Initializes the client. This makes all the necessary steps to make
1542 the client ready to be run. One must call silc_client_run to run the
1543 client. Returns FALSE if error occured, TRUE otherwise. */
1545 SilcBool silc_client_init(SilcClient client)
1547 SILC_LOG_DEBUG(("Initializing client"));
1550 assert(client->username);
1551 assert(client->hostname);
1552 assert(client->realname);
1554 /* Validate essential strings */
1555 if (client->nickname)
1556 if (!silc_identifier_verify(client->nickname, strlen(client->nickname),
1557 SILC_STRING_UTF8, 128)) {
1558 SILC_LOG_ERROR(("Malformed nickname '%s'", client->nickname));
1561 if (!silc_identifier_verify(client->username, strlen(client->username),
1562 SILC_STRING_UTF8, 128)) {
1563 SILC_LOG_ERROR(("Malformed username '%s'", client->username));
1566 if (!silc_identifier_verify(client->hostname, strlen(client->hostname),
1567 SILC_STRING_UTF8, 256)) {
1568 SILC_LOG_ERROR(("Malformed hostname '%s'", client->hostname));
1571 if (!silc_utf8_valid(client->realname, strlen(client->realname))) {
1572 SILC_LOG_ERROR(("Malformed realname '%s'", client->realname));
1576 if (!client->internal->params->dont_register_crypto_library) {
1577 /* Initialize the crypto library. If application has done this already
1578 this has no effect. Also, we will not be overriding something
1579 application might have registered earlier. */
1580 silc_cipher_register_default();
1581 silc_pkcs_register_default();
1582 silc_hash_register_default();
1583 silc_hmac_register_default();
1586 /* Initialize hash functions for client to use */
1587 silc_hash_alloc("md5", &client->md5hash);
1588 silc_hash_alloc("sha1", &client->sha1hash);
1590 /* Initialize random number generator */
1591 client->rng = silc_rng_alloc();
1592 silc_rng_init(client->rng);
1593 silc_rng_global_init(client->rng);
1595 /* Initialize the scheduler */
1597 silc_schedule_init(client->internal->params->task_max ?
1598 client->internal->params->task_max : 200, client);
1599 if (!client->schedule)
1602 /* Start packet engine */
1603 client->internal->packet_engine =
1604 silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1606 if (!client->internal->packet_engine)
1609 /* Initialize FSM */
1610 if (!silc_fsm_init(&client->internal->fsm, client, NULL, NULL,
1613 silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1615 /* Allocate client lock */
1616 silc_mutex_alloc(&client->internal->lock);
1618 /* Register commands */
1619 silc_client_commands_register(client);
1624 /* Stops the client. This is called to stop the client and thus to stop
1627 void silc_client_stop(SilcClient client)
1629 SILC_LOG_DEBUG(("Stopping client"));
1631 silc_schedule_stop(client->schedule);
1632 silc_schedule_uninit(client->schedule);
1634 silc_client_commands_unregister(client);
1636 SILC_LOG_DEBUG(("Client stopped"));
1639 /* Starts the SILC client FSM machine and blocks here. When this returns
1640 the client has ended. */
1642 void silc_client_run(SilcClient client)
1644 SILC_LOG_DEBUG(("Starting SILC client"));
1646 /* Start the client */
1647 silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1649 /* Signal the application when we are running */
1650 client->internal->run_callback = TRUE;
1651 SILC_FSM_SEMA_POST(&client->internal->wait_event);
1653 /* Run the scheduler */
1654 silc_schedule(client->schedule);
1657 /* Call scheduler one iteration and return. This cannot be called if threads
1660 void silc_client_run_one(SilcClient client)
1662 silc_schedule_one(client->schedule, -1);