Fixed silc_client_run_one.
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2006 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27
28 /************************ Static utility functions **************************/
29
30 /* Connection machine FSM destructor.  This will finish the thread where
31    the machine was running and deletes the connection context. */
32
33 static void silc_client_connection_destructor(SilcFSM fsm,
34                                               void *fsm_context,
35                                               void *destructor_context)
36 {
37   SilcClientConnection conn = fsm_context;
38   SilcFSMThread thread = destructor_context;
39
40   /* Delete connection */
41   silc_client_del_connection(conn->client, conn);
42
43   /* Finish the thread were this machine was running */
44   silc_fsm_finish(thread);
45 }
46
47 /* Packet FSM thread destructor */
48
49 static void silc_client_packet_destructor(SilcFSMThread thread,
50                                           void *thread_context,
51                                           void *destructor_context)
52 {
53   SilcClientConnection conn = thread_context;
54
55   /* Add thread back to thread pool */
56   silc_list_add(conn->internal->thread_pool, thread);
57   if (silc_list_count(conn->internal->thread_pool) == 1)
58     silc_list_start(conn->internal->thread_pool);
59 }
60
61 /* Packet engine callback to receive a packet */
62
63 static SilcBool silc_client_packet_receive(SilcPacketEngine engine,
64                                            SilcPacketStream stream,
65                                            SilcPacket packet,
66                                            void *callback_context,
67                                            void *stream_context)
68 {
69   SilcClientConnection conn = stream_context;
70   SilcFSMThread thread;
71
72   /* Packets we do not handle */
73   switch (packet->type) {
74   case SILC_PACKET_HEARTBEAT:
75   case SILC_PACKET_SUCCESS:
76   case SILC_PACKET_FAILURE:
77   case SILC_PACKET_REJECT:
78   case SILC_PACKET_KEY_EXCHANGE:
79   case SILC_PACKET_KEY_EXCHANGE_1:
80   case SILC_PACKET_KEY_EXCHANGE_2:
81   case SILC_PACKET_REKEY:
82   case SILC_PACKET_REKEY_DONE:
83   case SILC_PACKET_CONNECTION_AUTH:
84   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
85     return FALSE;
86     break;
87   }
88
89   /* Get packet processing thread */
90   thread = silc_list_get(conn->internal->thread_pool);
91   if (!thread) {
92     thread = silc_fsm_thread_alloc(&conn->internal->fsm, conn,
93                                    silc_client_packet_destructor, NULL, FALSE);
94     if (!thread)
95       return FALSE;
96   } else {
97     silc_list_del(conn->internal->thread_pool, thread);
98     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
99                          silc_client_packet_destructor, NULL, FALSE);
100   }
101
102   /* Process packet in thread */
103   silc_fsm_set_state_context(thread, packet);
104   silc_fsm_start_sync(thread, silc_client_connection_st_packet);
105
106   return TRUE;
107 }
108
109 /* Packet engine callback to indicate end of stream */
110
111 static void silc_client_packet_eos(SilcPacketEngine engine,
112                                    SilcPacketStream stream,
113                                    void *callback_context,
114                                    void *stream_context)
115 {
116   SILC_LOG_DEBUG(("End of stream received"));
117 }
118
119 /* Packet engine callback to indicate error */
120
121 static void silc_client_packet_error(SilcPacketEngine engine,
122                                      SilcPacketStream stream,
123                                      SilcPacketError error,
124                                      void *callback_context,
125                                      void *stream_context)
126 {
127
128 }
129
130 /* Packet stream callbacks */
131 static SilcPacketCallbacks silc_client_stream_cbs =
132 {
133   silc_client_packet_receive,
134   silc_client_packet_eos,
135   silc_client_packet_error
136 };
137
138 /* FSM destructor */
139
140 void silc_client_fsm_destructor(SilcFSM fsm, void *fsm_context,
141                                 void *destructor_context)
142 {
143   silc_fsm_free(fsm);
144 }
145
146
147 /************************** Connection's machine ****************************/
148
149 /* Start the connection's state machine.  If threads are in use the machine
150    is always executed in a real thread. */
151
152 SILC_FSM_STATE(silc_client_connection_st_start)
153 {
154   SilcClientConnection conn = fsm_context;
155   SilcFSM connfsm;
156
157   /* Take scheduler for connection */
158   conn->internal->schedule = silc_fsm_get_schedule(fsm);
159
160   /*** Run connection machine */
161   connfsm = &conn->internal->fsm;
162   silc_fsm_init(connfsm, conn, silc_client_connection_destructor,
163                 fsm, conn->internal->schedule);
164   silc_fsm_sema_init(&conn->internal->wait_event, connfsm, 0);
165   silc_fsm_start_sync(connfsm, silc_client_connection_st_run);
166
167   /* Schedule any events set in initialization */
168   if (conn->internal->connect)
169     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
170   if (conn->internal->key_exchange)
171     SILC_FSM_SEMA_POST(&conn->internal->wait_event);
172
173   /* Wait until this thread is terminated from the machine destructor */
174   return SILC_FSM_WAIT;
175 }
176
177 /* Connection machine main state.  This handles various connection related
178    events, but not packet processing.  It's done in dedicated packet
179    processing FSM thread. */
180
181 SILC_FSM_STATE(silc_client_connection_st_run)
182 {
183   SilcClientConnection conn = fsm_context;
184   SilcFSMThread thread;
185
186   /* Wait for events */
187   SILC_FSM_SEMA_WAIT(&conn->internal->wait_event);
188
189   /* Process events */
190   thread = &conn->internal->event_thread;
191
192   if (conn->internal->connect) {
193     SILC_LOG_DEBUG(("Event: connect"));
194     conn->internal->connect = FALSE;
195
196     /*** Event: connect */
197     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
198                          NULL, NULL, FALSE);
199     silc_fsm_start_sync(thread, silc_client_st_connect);
200     return SILC_FSM_CONTINUE;
201   }
202
203   if (conn->internal->key_exchange) {
204     SILC_LOG_DEBUG(("Event: key exchange"));
205     conn->internal->key_exchange = FALSE;
206
207     /*** Event: key exchange */
208     silc_fsm_thread_init(thread, &conn->internal->fsm, conn,
209                          NULL, NULL, FALSE);
210     silc_fsm_start_sync(thread, silc_client_st_connect_set_stream);
211     return SILC_FSM_CONTINUE;
212   }
213
214   if (conn->internal->disconnected) {
215     /** Event: disconnected */
216     SILC_LOG_DEBUG(("Event: disconnected"));
217     conn->internal->disconnected = FALSE;
218     silc_fsm_next(fsm, silc_client_connection_st_close);
219     return SILC_FSM_CONTINUE;
220   }
221
222   /* NOT REACHED */
223   SILC_ASSERT(FALSE);
224   return SILC_FSM_CONTINUE;
225 }
226
227 /* Packet processor thread.  Each incoming packet is processed in FSM
228    thread in this state.  The thread is run in the connection machine. */
229
230 SILC_FSM_STATE(silc_client_connection_st_packet)
231 {
232   SilcPacket packet = state_context;
233
234   SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(packet->type)));
235
236   switch (packet->type) {
237
238   case SILC_PACKET_PRIVATE_MESSAGE:
239     /** Private message */
240     silc_fsm_next(fsm, silc_client_private_message);
241     break;
242
243   case SILC_PACKET_CHANNEL_MESSAGE:
244     /** Channel message */
245     silc_fsm_next(fsm, silc_client_channel_message);
246     break;
247
248   case SILC_PACKET_FTP:
249     /* File transfer packet */
250     //    silc_client_ftp(client, conn, packet);
251     break;
252
253   case SILC_PACKET_CHANNEL_KEY:
254     /** Channel key */
255     silc_fsm_next(fsm, silc_client_channel_key);
256     break;
257
258   case SILC_PACKET_COMMAND_REPLY:
259     /** Command reply */
260     silc_fsm_next(fsm, silc_client_command_reply);
261     break;
262
263   case SILC_PACKET_NOTIFY:
264     /** Notify */
265     silc_fsm_next(fsm, silc_client_notify);
266     break;
267
268   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
269     /* Private message key indicator */
270     silc_fsm_next(fsm, silc_client_private_message_key);
271     break;
272
273   case SILC_PACKET_DISCONNECT:
274     /** Disconnect */
275     silc_fsm_next(fsm, silc_client_disconnect);
276     break;
277
278   case SILC_PACKET_ERROR:
279     /* Error by server */
280     silc_fsm_next(fsm, silc_client_error);
281     break;
282
283   case SILC_PACKET_KEY_AGREEMENT:
284     /* Key agreement */
285     //    silc_client_key_agreement(client, conn, packet);
286     break;
287
288   case SILC_PACKET_COMMAND:
289     /** Command packet */
290     silc_fsm_next(fsm, silc_client_command);
291     break;
292
293   case SILC_PACKET_NEW_ID:
294     /** New ID */
295     silc_fsm_next(fsm, silc_client_new_id);
296
297   case SILC_PACKET_CONNECTION_AUTH_REQUEST:
298     /* Reply to connection authentication request to resolve authentication
299        method from server. */
300     //    silc_client_connection_auth_request(client, conn, packet);
301     break;
302
303   default:
304     silc_packet_free(packet);
305     return SILC_FSM_FINISH;
306     break;
307   }
308
309   return SILC_FSM_CONTINUE;
310 }
311
312 /* Disconnection even to close remote connection.  We close the connection
313    and finish the connection machine in this state.  The connection context
314    is deleted in the machine destructor.  The connection callback must be
315    already called back to application before getting here. */
316
317 SILC_FSM_STATE(silc_client_connection_st_close)
318 {
319   SilcClientConnection conn = fsm_context;
320
321   SILC_LOG_DEBUG(("Closing remote connection"));
322
323   /* XXX abort any ongoing events (protocols) */
324
325   /* Close connection */
326   silc_packet_stream_destroy(conn->stream);
327
328   SILC_LOG_DEBUG(("Finishing connection machine"));
329
330   return SILC_FSM_FINISH;
331 }
332
333 /* Received error packet from server.  Send it to application. */
334
335 SILC_FSM_STATE(silc_client_error)
336 {
337   SilcClientConnection conn = fsm_context;
338   SilcClient client = conn->client;
339   SilcPacket packet = state_context;
340   char *msg;
341
342   msg = silc_memdup(silc_buffer_data(&packet->buffer),
343                     silc_buffer_len(&packet->buffer));
344   if (msg)
345     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, msg);
346
347   silc_free(msg);
348   silc_packet_free(packet);
349
350   return SILC_FSM_FINISH;
351 }
352
353 /* Received disconnect packet from server.  We close the connection and
354    send the disconnect message to application. */
355
356 SILC_FSM_STATE(silc_client_disconnect)
357 {
358   SilcClientConnection conn = fsm_context;
359   SilcClient client = conn->client;
360   SilcPacket packet = state_context;
361   SilcStatus status;
362   char *message = NULL;
363
364   SILC_LOG_DEBUG(("Server disconnected"));
365
366   if (silc_buffer_len(&packet->buffer) < 1) {
367     silc_packet_free(packet);
368     return SILC_FSM_FINISH;
369   }
370
371   status = (SilcStatus)packet->buffer.data[0];
372
373   silc_buffer_pull(&packet->buffer, 1);
374   if (silc_buffer_len(&packet->buffer) > 1 &&
375       silc_utf8_valid(silc_buffer_data(&packet->buffer),
376                       silc_buffer_len(&packet->buffer)))
377     message = silc_memdup(silc_buffer_data(&packet->buffer),
378                           silc_buffer_len(&packet->buffer));
379
380   /* Call connection callback */
381   conn->callback(client, conn, SILC_CLIENT_CONN_DISCONNECTED, status,
382                  message, conn->callback_context);
383
384   silc_free(message);
385   silc_packet_free(packet);
386
387   /* Signal to close connection */
388   conn->internal->disconnected = TRUE;
389   SILC_FSM_SEMA_POST(&conn->internal->wait_event);
390
391   return SILC_FSM_FINISH;
392 }
393
394 /*************************** Main client machine ****************************/
395
396 /* The client's main state where we wait for various events */
397
398 SILC_FSM_STATE(silc_client_st_run)
399 {
400   SilcClient client = fsm_context;
401
402   /* Wait for events */
403   SILC_FSM_SEMA_WAIT(&client->internal->wait_event);
404
405   /* Process events */
406
407   if (client->internal->run_callback && client->internal->ops->running) {
408     /* Call running callbcak back to application */
409     client->internal->run_callback = FALSE;
410     client->internal->ops->running(client, client->application);
411     return SILC_FSM_CONTINUE;
412   }
413
414   /* NOT REACHED */
415   SILC_ASSERT(FALSE);
416   return SILC_FSM_CONTINUE;
417 }
418
419 /******************************* Private API ********************************/
420
421 /* Adds new connection.  Creates the connection context and returns it. */
422
423 static SilcClientConnection
424 silc_client_add_connection(SilcClient client,
425                            SilcConnectionType conn_type,
426                            SilcClientConnectionParams *params,
427                            SilcPublicKey public_key,
428                            SilcPrivateKey private_key,
429                            char *remote_host, int port,
430                            SilcClientConnectCallback callback,
431                            void *context)
432 {
433   SilcClientConnection conn;
434   SilcFSMThread thread;
435
436   if (!callback)
437     return NULL;
438
439   SILC_LOG_DEBUG(("Adding new connection to %s:%d", remote_host, port));
440
441   conn = silc_calloc(1, sizeof(*conn));
442   if (!conn)
443     return NULL;
444
445   conn->client = client;
446   conn->public_key = public_key;
447   conn->private_key = private_key;
448   conn->remote_host = strdup(remote_host);
449   conn->remote_port = port ? port : 706;
450   conn->type = conn_type;
451   conn->callback = callback;
452   conn->callback_context = context;
453
454   conn->internal = silc_calloc(1, sizeof(*conn->internal));
455   if (!conn->internal) {
456     silc_free(conn);
457     return NULL;
458   }
459
460   if (!silc_hash_alloc("sha1", &conn->internal->sha1hash)) {
461     silc_free(conn);
462     silc_free(conn->internal);
463     return NULL;
464   }
465   if (params)
466     conn->internal->params = *params;
467   conn->internal->verbose = TRUE;
468   silc_list_init(conn->internal->pending_commands,
469                  struct SilcClientCommandContextStruct, next);
470   silc_list_init(conn->internal->thread_pool, SilcFSMThreadStruct, next);
471
472   conn->internal->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT,
473                                                     NULL, NULL);
474   conn->internal->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL,
475                                                      NULL, NULL);
476   conn->internal->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER,
477                                                     NULL, NULL);
478   if (!conn->internal->client_cache || !conn->internal->channel_cache ||
479       !conn->internal->server_cache) {
480     silc_client_del_connection(client, conn);
481     return NULL;
482   }
483
484   conn->internal->ftp_sessions = silc_dlist_init();
485
486   /* Run the connection state machine.  If threads are in use the machine
487      is always run in a real thread. */
488   thread = silc_fsm_thread_alloc(&client->internal->fsm, conn,
489                                  silc_client_fsm_destructor, NULL,
490                                  client->internal->params->threads);
491   if (!thread) {
492     silc_client_del_connection(client, conn);
493     return NULL;
494   }
495   silc_fsm_start(thread, silc_client_connection_st_start);
496
497   return conn;
498 }
499
500 /* Removes connection from client. Frees all memory. */
501
502 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
503 {
504 #if 0
505   SilcClientConnection c;
506   SilcIDCacheList list;
507   SilcIDCacheEntry entry;
508   SilcClientCommandPending *r;
509   SilcBool ret;
510
511   silc_dlist_start(client->internal->conns);
512   while ((c = silc_dlist_get(client->internal->conns)) != SILC_LIST_END) {
513     if (c != conn)
514       continue;
515
516     /* Free all cache entries */
517     if (silc_idcache_get_all(conn->internal->client_cache, &list)) {
518       ret = silc_idcache_list_first(list, &entry);
519       while (ret) {
520         silc_client_del_client(client, conn, entry->context);
521         ret = silc_idcache_list_next(list, &entry);
522       }
523       silc_idcache_list_free(list);
524     }
525
526     if (silc_idcache_get_all(conn->internal->channel_cache, &list)) {
527       ret = silc_idcache_list_first(list, &entry);
528       while (ret) {
529         silc_client_del_channel(client, conn, entry->context);
530         ret = silc_idcache_list_next(list, &entry);
531       }
532       silc_idcache_list_free(list);
533     }
534
535     if (silc_idcache_get_all(conn->internal->server_cache, &list)) {
536       ret = silc_idcache_list_first(list, &entry);
537       while (ret) {
538         silc_client_del_server(client, conn, entry->context);
539         ret = silc_idcache_list_next(list, &entry);
540       }
541       silc_idcache_list_free(list);
542     }
543
544     /* Clear ID caches */
545     if (conn->internal->client_cache)
546       silc_idcache_free(conn->internal->client_cache);
547     if (conn->internal->channel_cache)
548       silc_idcache_free(conn->internal->channel_cache);
549     if (conn->internal->server_cache)
550       silc_idcache_free(conn->internal->server_cache);
551
552     /* Free data (my ID is freed in above silc_client_del_client).
553        conn->nickname is freed when freeing the local_entry->nickname. */
554     silc_free(conn->remote_host);
555     silc_free(conn->local_id_data);
556     if (conn->internal->send_key)
557       silc_cipher_free(conn->internal->send_key);
558     if (conn->internal->receive_key)
559       silc_cipher_free(conn->internal->receive_key);
560     if (conn->internal->hmac_send)
561       silc_hmac_free(conn->internal->hmac_send);
562     if (conn->internal->hmac_receive)
563       silc_hmac_free(conn->internal->hmac_receive);
564     silc_free(conn->internal->rekey);
565
566     if (conn->internal->active_session) {
567       if (conn->sock)
568         conn->sock->user_data = NULL;
569       silc_client_ftp_session_free(conn->internal->active_session);
570       conn->internal->active_session = NULL;
571     }
572
573     silc_client_ftp_free_sessions(client, conn);
574
575     if (conn->internal->pending_commands) {
576       silc_dlist_start(conn->internal->pending_commands);
577       while ((r = silc_dlist_get(conn->internal->pending_commands))
578              != SILC_LIST_END)
579         silc_dlist_del(conn->internal->pending_commands, r);
580       silc_dlist_uninit(conn->internal->pending_commands);
581     }
582
583     silc_free(conn->internal);
584     memset(conn, 0, sizeof(*conn));
585     silc_free(conn);
586
587     silc_dlist_del(client->internal->conns, conn);
588   }
589 #endif /* 0 */
590 }
591
592
593 /******************************* Client API *********************************/
594
595 /* Connects to remote server.  This is the main routine used to connect
596    to remote SILC server.  Performs key exchange also.  Returns the
597    connection context to the connection callback. */
598
599 SilcBool silc_client_connect_to_server(SilcClient client,
600                                        SilcClientConnectionParams *params,
601                                        SilcPublicKey public_key,
602                                        SilcPrivateKey private_key,
603                                        char *remote_host, int port,
604                                        SilcClientConnectCallback callback,
605                                        void *context)
606 {
607   SilcClientConnection conn;
608
609   if (!client || !remote_host)
610     return FALSE;
611
612   /* Add new connection */
613   conn = silc_client_add_connection(client, SILC_CONN_SERVER, params,
614                                     public_key, private_key, remote_host,
615                                     port, callback, context);
616   if (!conn) {
617     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
618     return FALSE;
619   }
620
621   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
622                              "Connecting to port %d of server %s",
623                              port, remote_host);
624
625   /* Signal connection machine to start connecting */
626   conn->internal->connect = TRUE;
627   return TRUE;
628 }
629
630 /* Connects to remote client.  Performs key exchange also.  Returns the
631    connection context to the connection callback. */
632
633 SilcBool silc_client_connect_to_client(SilcClient client,
634                                        SilcClientConnectionParams *params,
635                                        SilcPublicKey public_key,
636                                        SilcPrivateKey private_key,
637                                        char *remote_host, int port,
638                                        SilcClientConnectCallback callback,
639                                        void *context)
640 {
641   SilcClientConnection conn;
642
643   if (!client || !remote_host)
644     return FALSE;
645
646   /* Add new connection */
647   conn = silc_client_add_connection(client, SILC_CONN_CLIENT, params,
648                                     public_key, private_key, remote_host,
649                                     port, callback, context);
650   if (!conn) {
651     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
652     return FALSE;
653   }
654
655   client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
656                              "Connecting to port %d of client host %s",
657                              port, remote_host);
658
659   /* Signal connection machine to start connecting */
660   conn->internal->connect = TRUE;
661   return TRUE;
662 }
663
664 /* Starts key exchange in the remote stream indicated by `stream'.  This
665    creates the connection context and returns it in the connection callback. */
666
667 SilcBool silc_client_key_exchange(SilcClient client,
668                                   SilcClientConnectionParams *params,
669                                   SilcPublicKey public_key,
670                                   SilcPrivateKey private_key,
671                                   SilcStream stream,
672                                   SilcConnectionType conn_type,
673                                   SilcClientConnectCallback callback,
674                                   void *context)
675 {
676   SilcClientConnection conn;
677   const char *host;
678   SilcUInt16 port;
679
680   if (!client || !stream)
681     return FALSE;
682
683   if (!silc_socket_stream_get_info(stream, NULL, &host, NULL, &port))
684     return FALSE;
685
686   /* Add new connection */
687   conn = silc_client_add_connection(client, conn_type, params,
688                                     public_key, private_key,
689                                     (char *)host, port, callback, context);
690   if (!conn) {
691     callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL, context);
692     return FALSE;
693   }
694   conn->stream = (void *)stream;
695
696   /* Signal connection to start key exchange */
697   conn->internal->key_exchange = TRUE;
698   return TRUE;
699 }
700
701 /* Closes remote connection */
702
703 void silc_client_close_connection(SilcClient client,
704                                   SilcClientConnection conn)
705 {
706
707 }
708
709 #if 0
710 /* Finalizes the connection to the remote SILC server. This is called
711    after authentication protocol has been completed. This send our
712    user information to the server to receive our client ID from
713    server. */
714
715 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
716 {
717   SilcProtocol protocol = (SilcProtocol)context;
718   SilcClientConnAuthInternalContext *ctx =
719     (SilcClientConnAuthInternalContext *)protocol->context;
720   SilcClient client = (SilcClient)ctx->client;
721   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
722   SilcBuffer packet;
723
724   SILC_LOG_DEBUG(("Start"));
725
726   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
727       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
728     /* Error occured during protocol */
729     SILC_LOG_DEBUG(("Error during authentication protocol"));
730     ctx->status = SILC_CLIENT_CONN_ERROR_AUTH;
731     goto err;
732   }
733
734   if (conn->internal->params.detach_data) {
735     /* Send RESUME_CLIENT packet to the server, which is used to resume
736        old detached session back. */
737     SilcBuffer auth;
738     SilcClientID *old_client_id;
739     unsigned char *old_id;
740     SilcUInt16 old_id_len;
741
742     if (!silc_client_process_detach_data(client, conn, &old_id, &old_id_len)) {
743       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
744       goto err;
745     }
746
747     old_client_id = silc_id_str2id(old_id, old_id_len, SILC_ID_CLIENT);
748     if (!old_client_id) {
749       silc_free(old_id);
750       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
751       goto err;
752     }
753
754     /* Generate authentication data that server will verify */
755     auth = silc_auth_public_key_auth_generate(client->public_key,
756                                               client->private_key,
757                                               client->rng,
758                                               conn->internal->hash,
759                                               old_client_id, SILC_ID_CLIENT);
760     if (!auth) {
761       silc_free(old_client_id);
762       silc_free(old_id);
763       ctx->status = SILC_CLIENT_CONN_ERROR_RESUME;
764       goto err;
765     }
766
767     packet = silc_buffer_alloc_size(2 + old_id_len + auth->len);
768     silc_buffer_format(packet,
769                        SILC_STR_UI_SHORT(old_id_len),
770                        SILC_STR_UI_XNSTRING(old_id, old_id_len),
771                        SILC_STR_UI_XNSTRING(auth->data, auth->len),
772                        SILC_STR_END);
773
774     /* Send the packet */
775     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
776                             NULL, 0, NULL, NULL,
777                             packet->data, packet->len, TRUE);
778     silc_buffer_free(packet);
779     silc_buffer_free(auth);
780     silc_free(old_client_id);
781     silc_free(old_id);
782   } else {
783     /* Send NEW_CLIENT packet to the server. We will become registered
784        to the SILC network after sending this packet and we will receive
785        client ID from the server. */
786     packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
787                                strlen(client->realname));
788     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
789     silc_buffer_format(packet,
790                        SILC_STR_UI_SHORT(strlen(client->username)),
791                        SILC_STR_UI_XNSTRING(client->username,
792                                             strlen(client->username)),
793                        SILC_STR_UI_SHORT(strlen(client->realname)),
794                        SILC_STR_UI_XNSTRING(client->realname,
795                                             strlen(client->realname)),
796                        SILC_STR_END);
797
798     /* Send the packet */
799     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
800                             NULL, 0, NULL, NULL,
801                             packet->data, packet->len, TRUE);
802     silc_buffer_free(packet);
803   }
804
805   /* Save remote ID. */
806   conn->remote_id = ctx->dest_id;
807   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
808   conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
809
810   /* Register re-key timeout */
811   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
812   conn->internal->rekey->context = (void *)client;
813   silc_schedule_task_add(client->schedule, conn->sock->sock,
814                          silc_client_rekey_callback,
815                          (void *)conn->sock, conn->internal->rekey->timeout, 0,
816                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
817
818   silc_protocol_free(protocol);
819   silc_free(ctx->auth_data);
820   if (ctx->ske)
821     silc_ske_free(ctx->ske);
822   silc_socket_free(ctx->sock);
823   silc_free(ctx);
824   conn->sock->protocol = NULL;
825   return;
826
827  err:
828   silc_protocol_free(protocol);
829   silc_free(ctx->auth_data);
830   silc_free(ctx->dest_id);
831   if (ctx->ske)
832     silc_ske_free(ctx->ske);
833   conn->sock->protocol = NULL;
834   silc_socket_free(ctx->sock);
835
836   /* Notify application of failure */
837   silc_schedule_task_add(client->schedule, ctx->sock->sock,
838                          silc_client_connect_failure_auth, ctx,
839                          0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
840 }
841
842 /* Client session resuming callback.  If the session was resumed
843    this callback is called after the resuming is completed.  This
844    will call the `connect' client operation to the application
845    since it has not been called yet. */
846
847 static void silc_client_resume_session_cb(SilcClient client,
848                                           SilcClientConnection conn,
849                                           SilcBool success,
850                                           void *context)
851 {
852   SilcBuffer sidp;
853
854   /* Notify application that connection is created to server */
855   client->internal->ops->connected(client, conn, success ?
856                                    SILC_CLIENT_CONN_SUCCESS_RESUME :
857                                    SILC_CLIENT_CONN_ERROR_RESUME);
858
859   if (success) {
860     /* Issue INFO command to fetch the real server name and server
861        information and other stuff. */
862     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
863                                  silc_client_command_reply_info_i, 0,
864                                  ++conn->cmd_ident);
865     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
866     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
867                              conn->cmd_ident, 1, 2, sidp->data, sidp->len);
868     silc_buffer_free(sidp);
869   }
870 }
871
872 /* Processes incoming connection authentication method request packet.
873    It is a reply to our previously sent request. The packet can be used
874    to resolve the authentication method for the current session if the
875    client does not know it beforehand. */
876
877 void silc_client_connection_auth_request(SilcClient client,
878                                          SilcClientConnection conn,
879                                          SilcPacketContext *packet)
880 {
881   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
882   SilcUInt16 conn_type, auth_meth;
883   int ret;
884
885   /* If we haven't send our request then ignore this one. */
886   if (!conn->internal->connauth)
887     return;
888
889   /* Parse the payload */
890   ret = silc_buffer_unformat(packet->buffer,
891                              SILC_STR_UI_SHORT(&conn_type),
892                              SILC_STR_UI_SHORT(&auth_meth),
893                              SILC_STR_END);
894   if (ret == -1)
895     auth_meth = SILC_AUTH_NONE;
896
897   /* Call the request callback to notify application for received
898      authentication method information. */
899   if (conn->internal->connauth->callback)
900     (*conn->internal->connauth->callback)(client, conn, auth_meth,
901                                           conn->internal->connauth->context);
902
903   silc_schedule_task_del(client->schedule, conn->internal->connauth->timeout);
904
905   silc_free(conn->internal->connauth);
906   conn->internal->connauth = NULL;
907 }
908
909 /* Timeout task callback called if the server does not reply to our
910    connection authentication method request in the specified time interval. */
911
912 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
913 {
914   SilcClientConnection conn = (SilcClientConnection)context;
915   SilcClient client = conn->client;
916
917   if (!conn->internal->connauth)
918     return;
919
920   /* Call the request callback to notify application */
921   if (conn->internal->connauth->callback)
922     (*conn->internal->connauth->callback)(client, conn, SILC_AUTH_NONE,
923                                           conn->internal->connauth->context);
924
925   silc_free(conn->internal->connauth);
926   conn->internal->connauth = NULL;
927 }
928
929 /* This function can be used to request the current authentication method
930    from the server. This may be called when connecting to the server
931    and the client library requests the authentication data from the
932    application. If the application does not know the current authentication
933    method it can request it from the server using this function.
934    The `callback' with `context' will be called after the server has
935    replied back with the current authentication method. */
936
937 void
938 silc_client_request_authentication_method(SilcClient client,
939                                           SilcClientConnection conn,
940                                           SilcConnectionAuthRequest callback,
941                                           void *context)
942 {
943   SilcClientConnAuthRequest connauth;
944   SilcBuffer packet;
945
946   assert(client && conn);
947   connauth = silc_calloc(1, sizeof(*connauth));
948   connauth->callback = callback;
949   connauth->context = context;
950
951   if (conn->internal->connauth)
952     silc_free(conn->internal->connauth);
953
954   conn->internal->connauth = connauth;
955
956   /* Assemble the request packet and send it to the server */
957   packet = silc_buffer_alloc(4);
958   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
959   silc_buffer_format(packet,
960                      SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
961                      SILC_STR_UI_SHORT(SILC_AUTH_NONE),
962                      SILC_STR_END);
963   silc_client_packet_send(client, conn->sock,
964                           SILC_PACKET_CONNECTION_AUTH_REQUEST,
965                           NULL, 0, NULL, NULL,
966                           packet->data, packet->len, FALSE);
967   silc_buffer_free(packet);
968
969   /* Register a timeout in case server does not reply anything back. */
970   connauth->timeout =
971     silc_schedule_task_add(client->schedule, conn->sock->sock,
972                            silc_client_request_authentication_method_timeout,
973                            conn,
974                            client->internal->params->connauth_request_secs, 0,
975                            SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
976 }
977 #endif /* 0 */
978
979
980 /* Allocates new client object. This has to be done before client may
981    work. After calling this one must call silc_client_init to initialize
982    the client. The `application' is application specific user data pointer
983    and caller must free it. */
984
985 SilcClient silc_client_alloc(SilcClientOperations *ops,
986                              SilcClientParams *params,
987                              void *application,
988                              const char *version_string)
989 {
990   SilcClient new_client;
991
992   new_client = silc_calloc(1, sizeof(*new_client));
993   if (!new_client)
994     return NULL;
995   new_client->application = application;
996
997   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
998   if (!new_client->internal) {
999     silc_free(new_client);
1000     return NULL;
1001   }
1002   new_client->internal->ops = ops;
1003   new_client->internal->params =
1004     silc_calloc(1, sizeof(*new_client->internal->params));
1005   if (!version_string)
1006     version_string = silc_version_string;
1007   new_client->internal->silc_client_version = strdup(version_string);
1008
1009   if (params)
1010     memcpy(new_client->internal->params, params, sizeof(*params));
1011
1012   if (!new_client->internal->params->task_max)
1013     new_client->internal->params->task_max = 200;
1014
1015   if (!new_client->internal->params->rekey_secs)
1016     new_client->internal->params->rekey_secs = 3600;
1017
1018   if (!new_client->internal->params->connauth_request_secs)
1019     new_client->internal->params->connauth_request_secs = 2;
1020
1021   new_client->internal->params->
1022     nickname_format[sizeof(new_client->internal->
1023                            params->nickname_format) - 1] = 0;
1024
1025   return new_client;
1026 }
1027
1028 /* Frees client object and its internals. */
1029
1030 void silc_client_free(SilcClient client)
1031 {
1032   if (client) {
1033     if (client->rng)
1034       silc_rng_free(client->rng);
1035
1036     if (!client->internal->params->dont_register_crypto_library) {
1037       silc_cipher_unregister_all();
1038       silc_pkcs_unregister_all();
1039       silc_hash_unregister_all();
1040       silc_hmac_unregister_all();
1041     }
1042
1043     silc_free(client->internal->params);
1044     silc_free(client->internal->silc_client_version);
1045     silc_free(client->internal);
1046     silc_free(client);
1047   }
1048 }
1049
1050 /* Initializes the client. This makes all the necessary steps to make
1051    the client ready to be run. One must call silc_client_run to run the
1052    client. Returns FALSE if error occured, TRUE otherwise. */
1053
1054 SilcBool silc_client_init(SilcClient client, const char *username,
1055                           const char *hostname, const char *realname)
1056 {
1057   SILC_LOG_DEBUG(("Initializing client"));
1058
1059   if (!client)
1060     return FALSE;
1061
1062   if (!username || !hostname || !realname) {
1063     SILC_LOG_ERROR(("Username, hostname and realname must be given to "
1064                     "silc_client_init"));
1065     return FALSE;
1066   }
1067
1068   /* Validate essential strings */
1069   if (!silc_identifier_verify(username, strlen(username),
1070                               SILC_STRING_UTF8, 128)) {
1071     SILC_LOG_ERROR(("Malformed username '%s'. Username must be UTF-8 string",
1072                     client->username));
1073     return FALSE;
1074   }
1075   if (!silc_identifier_verify(hostname, strlen(hostname),
1076                               SILC_STRING_UTF8, 256)) {
1077     SILC_LOG_ERROR(("Malformed hostname '%s'. Hostname must be UTF-8 string",
1078                     client->hostname));
1079     return FALSE;
1080   }
1081   if (!silc_utf8_valid(realname, strlen(realname))) {
1082     SILC_LOG_ERROR(("Malformed realname '%s'. Realname must be UTF-8 string",
1083                     client->realname));
1084     return FALSE;
1085   }
1086
1087   /* Take the name strings */
1088   client->username = strdup(username);
1089   client->hostname = strdup(hostname);
1090   client->realname = strdup(realname);
1091   if (!username || !hostname || !realname)
1092     return FALSE;
1093
1094   if (!client->internal->params->dont_register_crypto_library) {
1095     /* Initialize the crypto library.  If application has done this already
1096        this has no effect.  Also, we will not be overriding something
1097        application might have registered earlier. */
1098     silc_cipher_register_default();
1099     silc_pkcs_register_default();
1100     silc_hash_register_default();
1101     silc_hmac_register_default();
1102   }
1103
1104   /* Initialize random number generator */
1105   client->rng = silc_rng_alloc();
1106   silc_rng_init(client->rng);
1107   silc_rng_global_init(client->rng);
1108
1109   /* Initialize the scheduler */
1110   client->schedule =
1111     silc_schedule_init(client->internal->params->task_max ?
1112                        client->internal->params->task_max : 0, client);
1113   if (!client->schedule)
1114     return FALSE;
1115
1116   /* Start packet engine */
1117   client->internal->packet_engine =
1118     silc_packet_engine_start(client->rng, FALSE, &silc_client_stream_cbs,
1119                              client);
1120   if (!client->internal->packet_engine)
1121     return FALSE;
1122
1123   /* Initialize FSM */
1124   if (!silc_fsm_init(&client->internal->fsm, client, NULL, NULL,
1125                      client->schedule))
1126     return FALSE;
1127   silc_fsm_sema_init(&client->internal->wait_event, &client->internal->fsm, 0);
1128
1129   /* Allocate client lock */
1130   silc_mutex_alloc(&client->internal->lock);
1131
1132   /* Register commands */
1133   silc_client_commands_register(client);
1134
1135   /* Start the client machine */
1136   silc_fsm_start_sync(&client->internal->fsm, silc_client_st_run);
1137
1138   /* Signal the application when we are running */
1139   client->internal->run_callback = TRUE;
1140   SILC_FSM_SEMA_POST(&client->internal->wait_event);
1141
1142   return TRUE;
1143 }
1144
1145 /* Stops the client. This is called to stop the client and thus to stop
1146    the program. */
1147
1148 void silc_client_stop(SilcClient client)
1149 {
1150   SILC_LOG_DEBUG(("Stopping client"));
1151
1152   silc_schedule_stop(client->schedule);
1153   silc_schedule_uninit(client->schedule);
1154   silc_client_commands_unregister(client);
1155
1156   SILC_LOG_DEBUG(("Client stopped"));
1157 }
1158
1159 /* Starts the SILC client FSM machine and blocks here.  When this returns
1160    the client has ended. */
1161
1162 void silc_client_run(SilcClient client)
1163 {
1164   SILC_LOG_DEBUG(("Starting SILC client"));
1165
1166   /* Run the scheduler */
1167   silc_schedule(client->schedule);
1168 }
1169
1170 /* Call scheduler one iteration and return.  This cannot be called if threads
1171    are in use. */
1172
1173 void silc_client_run_one(SilcClient client)
1174 {
1175   silc_schedule_one(client->schedule, 0);
1176 }