updates.
[silc.git] / lib / silcclient / client.c
1 /*
2
3   client.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "clientlibincludes.h"
23 #include "client_internal.h"
24
25 /* Static task callback prototypes */
26 SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
27 SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
28 SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
29 SILC_TASK_CALLBACK(silc_client_packet_parse_real);
30
31 static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
32 static void silc_client_packet_parse_type(SilcClient client, 
33                                           SilcSocketConnection sock,
34                                           SilcPacketContext *packet);
35
36 /* Allocates new client object. This has to be done before client may
37    work. After calling this one must call silc_client_init to initialize
38    the client. The `application' is application specific user data pointer
39    and caller must free it. */
40
41 SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
42 {
43   SilcClient new_client;
44
45   new_client = silc_calloc(1, sizeof(*new_client));
46   new_client->application = application;
47   new_client->ops = ops;
48
49   return new_client;
50 }
51
52 /* Frees client object and its internals. */
53
54 void silc_client_free(SilcClient client)
55 {
56   if (client) {
57     if (client->rng)
58       silc_rng_free(client->rng);
59
60     silc_free(client);
61   }
62 }
63
64 /* Initializes the client. This makes all the necessary steps to make
65    the client ready to be run. One must call silc_client_run to run the
66    client. Returns FALSE if error occured, TRUE otherwise. */
67
68 int silc_client_init(SilcClient client)
69 {
70   SILC_LOG_DEBUG(("Initializing client"));
71
72   /* Initialize hash functions for client to use */
73   silc_hash_alloc("md5", &client->md5hash);
74   silc_hash_alloc("sha1", &client->sha1hash);
75
76   /* Initialize none cipher */
77   silc_cipher_alloc("none", &client->none_cipher);
78
79   /* Initialize random number generator */
80   client->rng = silc_rng_alloc();
81   silc_rng_init(client->rng);
82   silc_rng_global_init(client->rng);
83
84   /* Register protocols */
85   silc_client_protocols_register();
86
87   /* Initialize the scheduler */
88   silc_schedule_init(&client->io_queue, &client->timeout_queue, 
89                      &client->generic_queue, 5000);
90
91   return TRUE;
92 }
93
94 /* Stops the client. This is called to stop the client and thus to stop
95    the program. */
96
97 void silc_client_stop(SilcClient client)
98 {
99   SILC_LOG_DEBUG(("Stopping client"));
100
101   /* Stop the scheduler, although it might be already stopped. This
102      doesn't hurt anyone. This removes all the tasks and task queues,
103      as well. */
104   silc_schedule_stop();
105   silc_schedule_uninit();
106
107   silc_client_protocols_unregister();
108
109   SILC_LOG_DEBUG(("Client stopped"));
110 }
111
112 /* Runs the client. This starts the scheduler from the utility library.
113    When this functions returns the execution of the appliation is over. */
114
115 void silc_client_run(SilcClient client)
116 {
117   SILC_LOG_DEBUG(("Running client"));
118
119   /* Start the scheduler, the heart of the SILC client. When this returns
120      the program will be terminated. */
121   silc_schedule();
122 }
123
124 /* Allocates and adds new connection to the client. This adds the allocated
125    connection to the connection table and returns a pointer to it. A client
126    can have multiple connections to multiple servers. Every connection must
127    be added to the client using this function. User data `context' may
128    be sent as argument. This function is normally used only if the 
129    application performed the connecting outside the library. The library
130    however may use this internally. */
131
132 SilcClientConnection silc_client_add_connection(SilcClient client,
133                                                 char *hostname,
134                                                 int port,
135                                                 void *context)
136 {
137   SilcClientConnection conn;
138   int i;
139
140   conn = silc_calloc(1, sizeof(*conn));
141
142   /* Initialize ID caches */
143   conn->client_cache = silc_idcache_alloc(0, NULL);
144   conn->channel_cache = silc_idcache_alloc(0, NULL);
145   conn->server_cache = silc_idcache_alloc(0, NULL);
146   conn->client = client;
147   conn->remote_host = strdup(hostname);
148   conn->remote_port = port;
149   conn->context = context;
150   conn->pending_commands = silc_dlist_init();
151
152   /* Add the connection to connections table */
153   for (i = 0; i < client->conns_count; i++)
154     if (client->conns && !client->conns[i]) {
155       client->conns[i] = conn;
156       return conn;
157     }
158
159   client->conns = silc_realloc(client->conns, sizeof(*client->conns)
160                                * (client->conns_count + 1));
161   client->conns[client->conns_count] = conn;
162   client->conns_count++;
163
164   return conn;
165 }
166
167 /* Removes connection from client. Frees all memory. */
168
169 void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
170 {
171   int i;
172
173   for (i = 0; i < client->conns_count; i++)
174     if (client->conns[i] == conn) {
175       if (conn->pending_commands)
176         silc_dlist_uninit(conn->pending_commands);
177       silc_free(conn);
178       client->conns[i] = NULL;
179     }
180 }
181
182 static int 
183 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
184 {
185   int sock;
186
187   /* XXX In the future we should give up this non-blocking connect all
188      together and use threads instead. */
189   /* Create connection to server asynchronously */
190   sock = silc_net_create_connection_async(ctx->port, ctx->host);
191   if (sock < 0)
192     return -1;
193
194   /* Register task that will receive the async connect and will
195      read the result. */
196   ctx->task = silc_task_register(ctx->client->io_queue, sock, 
197                                  silc_client_connect_to_server_start,
198                                  (void *)ctx, 0, 0, 
199                                  SILC_TASK_FD,
200                                  SILC_TASK_PRI_NORMAL);
201   silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
202   silc_schedule_set_listen_fd(sock, ctx->task->iomask);
203
204   ctx->sock = sock;
205
206   return sock;
207 }
208
209 /* Connects to remote server. This is the main routine used to connect
210    to SILC server. Returns -1 on error and the created socket otherwise. 
211    The `context' is user context that is saved into the SilcClientConnection
212    that is created after the connection is created. Note that application
213    may handle the connecting process outside the library. If this is the
214    case then this function is not used at all. When the connecting is
215    done the `connect' client operation is called. */
216
217 int silc_client_connect_to_server(SilcClient client, int port,
218                                   char *host, void *context)
219 {
220   SilcClientInternalConnectContext *ctx;
221   SilcClientConnection conn;
222   int sock;
223
224   SILC_LOG_DEBUG(("Connecting to port %d of server %s",
225                   port, host));
226
227   conn = silc_client_add_connection(client, host, port, context);
228
229   client->ops->say(client, conn, 
230                    "Connecting to port %d of server %s", port, host);
231
232   /* Allocate internal context for connection process. This is
233      needed as we are doing async connecting. */
234   ctx = silc_calloc(1, sizeof(*ctx));
235   ctx->client = client;
236   ctx->conn = conn;
237   ctx->host = strdup(host);
238   ctx->port = port;
239   ctx->tries = 0;
240
241   /* Do the actual connecting process */
242   sock = silc_client_connect_to_server_internal(ctx);
243   if (sock == -1)
244     silc_client_del_connection(client, conn);
245   return sock;
246 }
247
248 /* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
249    key material between client and server.  This function can be called
250    directly if application is performing its own connecting and does not
251    use the connecting provided by this library. This function is normally
252    used only if the application performed the connecting outside the library.
253    The library however may use this internally. */
254
255 int silc_client_start_key_exchange(SilcClient client,
256                                    SilcClientConnection conn,
257                                    int fd)
258 {
259   SilcProtocol protocol;
260   SilcClientKEInternalContext *proto_ctx;
261   void *context;
262
263   /* Allocate new socket connection object */
264   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
265
266   conn->nickname = strdup(client->username);
267   conn->sock->hostname = conn->remote_host;
268   conn->sock->ip = strdup(conn->remote_host);
269   conn->sock->port = conn->remote_port;
270
271   /* Allocate internal Key Exchange context. This is sent to the
272      protocol as context. */
273   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
274   proto_ctx->client = (void *)client;
275   proto_ctx->sock = conn->sock;
276   proto_ctx->rng = client->rng;
277   proto_ctx->responder = FALSE;
278   proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
279   proto_ctx->verify = silc_client_protocol_ke_verify_key;
280
281   /* Perform key exchange protocol. silc_client_connect_to_server_final
282      will be called after the protocol is finished. */
283   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
284                       &protocol, (void *)proto_ctx,
285                       silc_client_connect_to_server_second);
286   if (!protocol) {
287     client->ops->say(client, conn, 
288                      "Error: Could not start authentication protocol");
289     return FALSE;
290   }
291   conn->sock->protocol = protocol;
292
293   /* Register the connection for network input and output. This sets
294      that scheduler will listen for incoming packets for this connection 
295      and sets that outgoing packets may be sent to this connection as well.
296      However, this doesn't set the scheduler for outgoing traffic, it will 
297      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
298      later when outgoing data is available. */
299   context = (void *)client;
300   SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
301
302   /* Execute the protocol */
303   protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
304   return TRUE;
305 }
306
307 /* Start of the connection to the remote server. This is called after
308    succesful TCP/IP connection has been established to the remote host. */
309
310 SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
311 {
312   SilcClientInternalConnectContext *ctx =
313     (SilcClientInternalConnectContext *)context;
314   SilcClient client = ctx->client;
315   SilcClientConnection conn = ctx->conn;
316   int opt, opt_len = sizeof(opt);
317
318   SILC_LOG_DEBUG(("Start"));
319
320   /* Check the socket status as it might be in error */
321   getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
322   if (opt != 0) {
323     if (ctx->tries < 2) {
324       /* Connection failed but lets try again */
325       client->ops->say(client, conn, "Could not connect to server %s: %s",
326                        ctx->host, strerror(opt));
327       client->ops->say(client, conn, 
328                        "Connecting to port %d of server %s resumed", 
329                        ctx->port, ctx->host);
330
331       /* Unregister old connection try */
332       silc_schedule_unset_listen_fd(fd);
333       silc_net_close_connection(fd);
334       silc_task_unregister(client->io_queue, ctx->task);
335
336       /* Try again */
337       silc_client_connect_to_server_internal(ctx);
338       ctx->tries++;
339     } else {
340       /* Connection failed and we won't try anymore */
341       client->ops->say(client, conn, "Could not connect to server %s: %s",
342                        ctx->host, strerror(opt));
343       silc_schedule_unset_listen_fd(fd);
344       silc_net_close_connection(fd);
345       silc_task_unregister(client->io_queue, ctx->task);
346       silc_free(ctx);
347
348       /* Notify application of failure */
349       client->ops->connect(client, conn, FALSE);
350       silc_client_del_connection(client, conn);
351     }
352     return;
353   }
354
355   silc_schedule_unset_listen_fd(fd);
356   silc_task_unregister(client->io_queue, ctx->task);
357   silc_free(ctx);
358
359   if (!silc_client_start_key_exchange(client, conn, fd)) {
360     silc_net_close_connection(fd);
361     client->ops->connect(client, conn, FALSE);
362   }
363 }
364
365 /* Second part of the connecting to the server. This executed 
366    authentication protocol. */
367
368 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
369 {
370   SilcProtocol protocol = (SilcProtocol)context;
371   SilcClientKEInternalContext *ctx = 
372     (SilcClientKEInternalContext *)protocol->context;
373   SilcClient client = (SilcClient)ctx->client;
374   SilcSocketConnection sock = NULL;
375   SilcClientConnAuthInternalContext *proto_ctx;
376
377   SILC_LOG_DEBUG(("Start"));
378
379   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
380       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
381     /* Error occured during protocol */
382     SILC_LOG_DEBUG(("Error during KE protocol"));
383     silc_protocol_free(protocol);
384     silc_ske_free_key_material(ctx->keymat);
385     if (ctx->ske)
386       silc_ske_free(ctx->ske);
387     if (ctx->dest_id)
388       silc_free(ctx->dest_id);
389     ctx->sock->protocol = NULL;
390     silc_task_unregister_by_callback(client->timeout_queue,
391                                      silc_client_failure_callback);
392
393     /* Notify application of failure */
394     client->ops->connect(client, ctx->sock->user_data, FALSE);
395     silc_free(ctx);
396     return;
397   }
398
399   /* We now have the key material as the result of the key exchange
400      protocol. Take the key material into use. Free the raw key material
401      as soon as we've set them into use. */
402   silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
403                                    ctx->ske->prop->cipher,
404                                    ctx->ske->prop->pkcs,
405                                    ctx->ske->prop->hash,
406                                    ctx->ske->prop->hmac);
407   silc_ske_free_key_material(ctx->keymat);
408
409   /* Allocate internal context for the authentication protocol. This
410      is sent as context for the protocol. */
411   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
412   proto_ctx->client = (void *)client;
413   proto_ctx->sock = sock = ctx->sock;
414   proto_ctx->ske = ctx->ske;    /* Save SKE object from previous protocol */
415   proto_ctx->dest_id_type = ctx->dest_id_type;
416   proto_ctx->dest_id = ctx->dest_id;
417
418   /* Resolve the authentication method to be used in this connection */
419   if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
420                                     sock->port, &proto_ctx->auth_meth,
421                                     &proto_ctx->auth_data, 
422                                     &proto_ctx->auth_data_len))
423     {
424       /* XXX do AUTH_REQUEST resolcing with server */
425       proto_ctx->auth_meth = SILC_AUTH_NONE;
426     }
427
428   /* Free old protocol as it is finished now */
429   silc_protocol_free(protocol);
430   if (ctx->packet)
431     silc_packet_context_free(ctx->packet);
432   silc_free(ctx);
433   /* silc_free(ctx->keymat....); */
434   sock->protocol = NULL;
435
436   /* Allocate the authentication protocol. This is allocated here
437      but we won't start it yet. We will be receiving party of this
438      protocol thus we will wait that connecting party will make
439      their first move. */
440   silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
441                       &sock->protocol, (void *)proto_ctx, 
442                       silc_client_connect_to_server_final);
443
444   /* Execute the protocol */
445   sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
446 }
447
448 /* Finalizes the connection to the remote SILC server. This is called
449    after authentication protocol has been completed. This send our
450    user information to the server to receive our client ID from
451    server. */
452
453 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
454 {
455   SilcProtocol protocol = (SilcProtocol)context;
456   SilcClientConnAuthInternalContext *ctx = 
457     (SilcClientConnAuthInternalContext *)protocol->context;
458   SilcClient client = (SilcClient)ctx->client;
459   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
460   SilcBuffer packet;
461
462   SILC_LOG_DEBUG(("Start"));
463
464   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
465       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
466     /* Error occured during protocol */
467     SILC_LOG_DEBUG(("Error during authentication protocol"));
468     silc_protocol_free(protocol);
469     if (ctx->auth_data)
470       silc_free(ctx->auth_data);
471     if (ctx->ske)
472       silc_ske_free(ctx->ske);
473     if (ctx->dest_id)
474       silc_free(ctx->dest_id);
475     conn->sock->protocol = NULL;
476     silc_task_unregister_by_callback(client->timeout_queue,
477                                      silc_client_failure_callback);
478
479     /* Notify application of failure */
480     client->ops->connect(client, ctx->sock->user_data, FALSE);
481     silc_free(ctx);
482     return;
483   }
484
485   /* Send NEW_CLIENT packet to the server. We will become registered
486      to the SILC network after sending this packet and we will receive
487      client ID from the server. */
488   packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
489                              strlen(client->realname));
490   silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
491   silc_buffer_format(packet,
492                      SILC_STR_UI_SHORT(strlen(client->username)),
493                      SILC_STR_UI_XNSTRING(client->username,
494                                           strlen(client->username)),
495                      SILC_STR_UI_SHORT(strlen(client->realname)),
496                      SILC_STR_UI_XNSTRING(client->realname,
497                                           strlen(client->realname)),
498                      SILC_STR_END);
499
500   /* Send the packet */
501   silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
502                           NULL, 0, NULL, NULL, 
503                           packet->data, packet->len, TRUE);
504   silc_buffer_free(packet);
505
506   /* Save remote ID. */
507   conn->remote_id = ctx->dest_id;
508   conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
509   conn->remote_id_data_len = SILC_ID_SERVER_LEN;
510
511   silc_task_unregister_by_callback(client->timeout_queue,
512                                    silc_client_failure_callback);
513   silc_protocol_free(protocol);
514   if (ctx->auth_data)
515     silc_free(ctx->auth_data);
516   if (ctx->ske)
517     silc_ske_free(ctx->ske);
518   silc_free(ctx);
519   conn->sock->protocol = NULL;
520 }
521
522 /* Internal routine that sends packet or marks packet to be sent. This
523    is used directly only in special cases. Normal cases should use
524    silc_server_packet_send. Returns < 0 on error. */
525
526 int silc_client_packet_send_real(SilcClient client,
527                                  SilcSocketConnection sock,
528                                  int force_send)
529 {
530   int ret;
531
532   /* Send the packet */
533   ret = silc_packet_send(sock, force_send);
534   if (ret != -2)
535     return ret;
536
537   /* Mark that there is some outgoing data available for this connection. 
538      This call sets the connection both for input and output (the input
539      is set always and this call keeps the input setting, actually). 
540      Actual data sending is performed by silc_client_packet_process. */
541   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
542
543   /* Mark to socket that data is pending in outgoing buffer. This flag
544      is needed if new data is added to the buffer before the earlier
545      put data is sent to the network. */
546   SILC_SET_OUTBUF_PENDING(sock);
547
548   return 0;
549 }
550
551 /* Packet processing callback. This is used to send and receive packets
552    from network. This is generic task. */
553
554 SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
555 {
556   SilcClient client = (SilcClient)context;
557   SilcSocketConnection sock = NULL;
558   SilcClientConnection conn;
559   int ret;
560
561   SILC_LOG_DEBUG(("Processing packet"));
562
563   SILC_CLIENT_GET_SOCK(client, fd, sock);
564   if (sock == NULL)
565     return;
566
567   conn = (SilcClientConnection)sock->user_data;
568
569   /* Packet sending */
570   if (type == SILC_TASK_WRITE) {
571     SILC_LOG_DEBUG(("Writing data to connection"));
572
573     if (sock->outbuf->data - sock->outbuf->head)
574       silc_buffer_push(sock->outbuf, 
575                        sock->outbuf->data - sock->outbuf->head);
576
577     ret = silc_client_packet_send_real(client, sock, TRUE);
578
579     /* If returned -2 could not write to connection now, will do
580        it later. */
581     if (ret == -2)
582       return;
583     
584     /* The packet has been sent and now it is time to set the connection
585        back to only for input. When there is again some outgoing data 
586        available for this connection it will be set for output as well. 
587        This call clears the output setting and sets it only for input. */
588     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
589     SILC_UNSET_OUTBUF_PENDING(sock);
590
591     silc_buffer_clear(sock->outbuf);
592     return;
593   }
594
595   /* Packet receiving */
596   if (type == SILC_TASK_READ) {
597     SILC_LOG_DEBUG(("Reading data from connection"));
598
599     /* Read data from network */
600     ret = silc_packet_receive(sock);
601     if (ret < 0)
602       return;
603     
604     /* EOF */
605     if (ret == 0) {
606       SILC_LOG_DEBUG(("Read EOF"));
607
608       /* If connection is disconnecting already we will finally
609          close the connection */
610       if (SILC_IS_DISCONNECTING(sock)) {
611         client->ops->disconnect(client, conn);
612         silc_client_close_connection(client, conn);
613         return;
614       }
615       
616       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
617       client->ops->disconnect(client, conn);
618       silc_client_close_connection(client, conn);
619       return;
620     }
621
622     /* Process the packet. This will call the parser that will then
623        decrypt and parse the packet. */
624     silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
625                                 silc_client_packet_parse, client);
626   }
627 }
628
629 /* Callback function that the silc_packet_decrypt will call to make the
630    decision whether the packet is normal or special packet. We will 
631    return TRUE if it is normal and FALSE if it is special */
632
633 static int silc_client_packet_decrypt_check(SilcPacketType packet_type,
634                                             SilcBuffer buffer,
635                                             SilcPacketContext *packet,
636                                             void *context)
637 {
638
639   /* Packet is normal packet, if: 
640
641      1) packet is private message packet and does not have private key set
642      2) is other packet than channel message packet
643
644      all other packets are special packets 
645   */
646   if ((packet_type == SILC_PACKET_PRIVATE_MESSAGE &&
647        !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
648       packet_type != SILC_PACKET_CHANNEL_MESSAGE)
649     return TRUE;
650
651   return FALSE;
652 }
653
654 /* Parses whole packet, received earlier. */
655
656 SILC_TASK_CALLBACK(silc_client_packet_parse_real)
657 {
658   SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
659   SilcClient client = (SilcClient)parse_ctx->context;
660   SilcPacketContext *packet = parse_ctx->packet;
661   SilcBuffer buffer = packet->buffer;
662   SilcSocketConnection sock = parse_ctx->sock;
663   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
664   int ret;
665
666   SILC_LOG_DEBUG(("Start"));
667
668   /* Decrypt the received packet */
669   ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
670                             silc_client_packet_decrypt_check, parse_ctx);
671   if (ret < 0)
672     goto out;
673
674   if (ret == 0) {
675     /* Parse the packet. Packet type is returned. */
676     ret = silc_packet_parse(packet);
677   } else {
678     /* Parse the packet header in special way as this is "special"
679        packet type. */
680     ret = silc_packet_parse_special(packet);
681   }
682
683   if (ret == SILC_PACKET_NONE)
684     goto out;
685
686   /* Parse the incoming packet type */
687   silc_client_packet_parse_type(client, sock, packet);
688
689  out:
690   silc_buffer_clear(sock->inbuf);
691   silc_packet_context_free(packet);
692   silc_free(parse_ctx);
693 }
694
695 /* Parser callback called by silc_packet_receive_process. Thie merely
696    registers timeout that will handle the actual parsing when appropriate. */
697
698 void silc_client_packet_parse(SilcPacketParserContext *parser_context)
699 {
700   SilcClient client = (SilcClient)parser_context->context;
701
702   /* Parse the packet */
703   silc_task_register(client->timeout_queue, parser_context->sock->sock, 
704                      silc_client_packet_parse_real,
705                      (void *)parser_context, 0, 1, 
706                      SILC_TASK_TIMEOUT,
707                      SILC_TASK_PRI_NORMAL);
708 }
709   
710 /* Parses the packet type and calls what ever routines the packet type
711    requires. This is done for all incoming packets. */
712
713 void silc_client_packet_parse_type(SilcClient client, 
714                                    SilcSocketConnection sock,
715                                    SilcPacketContext *packet)
716 {
717   SilcBuffer buffer = packet->buffer;
718   SilcPacketType type = packet->type;
719
720   SILC_LOG_DEBUG(("Parsing packet type %d", type));
721
722   /* Parse the packet type */
723   switch(type) {
724   case SILC_PACKET_DISCONNECT:
725     silc_client_disconnected_by_server(client, sock, buffer);
726     break;
727   case SILC_PACKET_SUCCESS:
728     /*
729      * Success received for something. For now we can have only
730      * one protocol for connection executing at once hence this
731      * success message is for whatever protocol is executing currently.
732      */
733     if (sock->protocol) {
734       sock->protocol->execute(client->timeout_queue, 0,
735                               sock->protocol, sock->sock, 0, 0);
736     }
737     break;
738   case SILC_PACKET_FAILURE:
739     /*
740      * Failure received for some protocol. Set the protocol state to 
741      * error and call the protocol callback. This fill cause error on
742      * protocol and it will call the final callback.
743      */
744     silc_client_process_failure(client, sock, packet);
745     break;
746   case SILC_PACKET_REJECT:
747     break;
748
749   case SILC_PACKET_NOTIFY:
750     /*
751      * Received notify message 
752      */
753     silc_client_notify_by_server(client, sock, packet);
754     break;
755
756   case SILC_PACKET_ERROR:
757     /*
758      * Received error message
759      */
760     silc_client_error_by_server(client, sock, buffer);
761     break;
762
763   case SILC_PACKET_CHANNEL_MESSAGE:
764     /*
765      * Received message to (from, actually) a channel
766      */
767     silc_client_channel_message(client, sock, packet);
768     break;
769   case SILC_PACKET_CHANNEL_KEY:
770     /*
771      * Received key for a channel. By receiving this key the client will be
772      * able to talk to the channel it has just joined. This can also be
773      * a new key for existing channel as keys expire peridiocally.
774      */
775     silc_client_receive_channel_key(client, sock, buffer);
776     break;
777
778   case SILC_PACKET_PRIVATE_MESSAGE:
779     /*
780      * Received private message
781      */
782     silc_client_private_message(client, sock, packet);
783     break;
784   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
785     /*
786      * Received private message key
787      */
788     break;
789
790   case SILC_PACKET_COMMAND_REPLY:
791     /*
792      * Recived reply for a command
793      */
794     silc_client_command_reply_process(client, sock, packet);
795     break;
796
797   case SILC_PACKET_KEY_EXCHANGE:
798     if (sock->protocol) {
799       SilcClientKEInternalContext *proto_ctx = 
800         (SilcClientKEInternalContext *)sock->protocol->context;
801
802       proto_ctx->packet = silc_packet_context_dup(packet);
803       proto_ctx->dest_id_type = packet->src_id_type;
804       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
805                                           packet->src_id_type);
806       if (!proto_ctx->dest_id)
807         break;
808
809       /* Let the protocol handle the packet */
810       sock->protocol->execute(client->timeout_queue, 0,
811                               sock->protocol, sock->sock, 0, 0);
812     } else {
813       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
814                       "protocol active, packet dropped."));
815
816       /* XXX Trigger KE protocol?? Rekey actually! */
817     }
818     break;
819
820   case SILC_PACKET_KEY_EXCHANGE_1:
821     if (sock->protocol) {
822
823     } else {
824       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
825                       "protocol active, packet dropped."));
826     }
827     break;
828   case SILC_PACKET_KEY_EXCHANGE_2:
829     if (sock->protocol) {
830       SilcClientKEInternalContext *proto_ctx = 
831         (SilcClientKEInternalContext *)sock->protocol->context;
832
833       if (proto_ctx->packet)
834         silc_packet_context_free(proto_ctx->packet);
835
836       proto_ctx->packet = silc_packet_context_dup(packet);
837       proto_ctx->dest_id_type = packet->src_id_type;
838       proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
839                                           packet->src_id_type);
840       if (!proto_ctx->dest_id)
841         break;
842
843       /* Let the protocol handle the packet */
844       sock->protocol->execute(client->timeout_queue, 0,
845                               sock->protocol, sock->sock, 0, 0);
846     } else {
847       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
848                       "protocol active, packet dropped."));
849     }
850     break;
851
852   case SILC_PACKET_NEW_ID:
853     {
854       /*
855        * Received new ID from server. This packet is received at
856        * the connection to the server.  New ID is also received when 
857        * user changes nickname but in that case the new ID is received
858        * as command reply and not as this packet type.
859        */
860       SilcIDPayload idp;
861
862       idp = silc_id_payload_parse(buffer);
863       if (!idp)
864         break;
865       if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
866         break;
867
868       silc_client_receive_new_id(client, sock, idp);
869       silc_id_payload_free(idp);
870       break;
871     }
872
873   case SILC_PACKET_HEARTBEAT:
874     /*
875      * Received heartbeat packet
876      */
877     SILC_LOG_DEBUG(("Heartbeat packet"));
878     break;
879
880   case SILC_PACKET_KEY_AGREEMENT:
881     /*
882      * Received key agreement packet
883      */
884     SILC_LOG_DEBUG(("Key agreement packet"));
885     silc_client_key_agreement(client, sock, packet);
886     break;
887
888   default:
889     SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
890     break;
891   }
892 }
893
894 /* Sends packet. This doesn't actually send the packet instead it assembles
895    it and marks it to be sent. However, if force_send is TRUE the packet
896    is sent immediately. if dst_id, cipher and hmac are NULL those parameters
897    will be derived from sock argument. Otherwise the valid arguments sent
898    are used. */
899
900 void silc_client_packet_send(SilcClient client, 
901                              SilcSocketConnection sock,
902                              SilcPacketType type, 
903                              void *dst_id,
904                              SilcIdType dst_id_type,
905                              SilcCipher cipher,
906                              SilcHmac hmac,
907                              unsigned char *data, 
908                              unsigned int data_len, 
909                              int force_send)
910 {
911   SilcPacketContext packetdata;
912
913   SILC_LOG_DEBUG(("Sending packet, type %d", type));
914
915   /* Get data used in the packet sending, keys and stuff */
916   if ((!cipher || !hmac || !dst_id) && sock->user_data) {
917     if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
918       cipher = ((SilcClientConnection)sock->user_data)->send_key;
919
920     if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
921       hmac = ((SilcClientConnection)sock->user_data)->hmac;
922
923     if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
924       dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
925       dst_id_type = SILC_ID_SERVER;
926     }
927   }
928
929   /* Set the packet context pointers */
930   packetdata.flags = 0;
931   packetdata.type = type;
932   if (((SilcClientConnection)sock->user_data)->local_id_data)
933     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
934   else 
935     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
936   packetdata.src_id_len = SILC_ID_CLIENT_LEN;
937   packetdata.src_id_type = SILC_ID_CLIENT;
938   if (dst_id) {
939     packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
940     packetdata.dst_id_len = silc_id_get_len(dst_id_type);
941     packetdata.dst_id_type = dst_id_type;
942   } else {
943     packetdata.dst_id = NULL;
944     packetdata.dst_id_len = 0;
945     packetdata.dst_id_type = SILC_ID_NONE;
946   }
947   packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
948     packetdata.src_id_len + packetdata.dst_id_len;
949   packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
950
951   /* Prepare outgoing data buffer for packet sending */
952   silc_packet_send_prepare(sock, 
953                            SILC_PACKET_HEADER_LEN +
954                            packetdata.src_id_len + 
955                            packetdata.dst_id_len,
956                            packetdata.padlen,
957                            data_len);
958
959   SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
960
961   packetdata.buffer = sock->outbuf;
962
963   /* Put the data to the buffer */
964   if (data && data_len)
965     silc_buffer_put(sock->outbuf, data, data_len);
966
967   /* Create the outgoing packet */
968   silc_packet_assemble(&packetdata);
969
970   /* Encrypt the packet */
971   if (cipher)
972     silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
973
974   SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
975                    sock->outbuf->data, sock->outbuf->len);
976
977   /* Now actually send the packet */
978   silc_client_packet_send_real(client, sock, force_send);
979 }
980
981 /* Closes connection to remote end. Free's all allocated data except
982    for some information such as nickname etc. that are valid at all time. */
983
984 void silc_client_close_connection(SilcClient client,
985                                   SilcClientConnection conn)
986 {
987   SilcSocketConnection sock = conn->sock;
988
989   /* We won't listen for this connection anymore */
990   silc_schedule_unset_listen_fd(sock->sock);
991
992   /* Unregister all tasks */
993   silc_task_unregister_by_fd(client->io_queue, sock->sock);
994   silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
995
996   /* Close the actual connection */
997   silc_net_close_connection(sock->sock);
998
999   client->ops->say(client, sock->user_data,
1000                    "Closed connection to host %s", sock->hostname);
1001
1002   /* Free everything */
1003   if (sock->user_data) {
1004     /* XXX Free all client entries and channel entries. */
1005
1006     /* Clear ID caches */
1007     silc_idcache_del_all(conn->client_cache);
1008     silc_idcache_del_all(conn->channel_cache);
1009
1010     /* Free data */
1011     if (conn->remote_host)
1012       silc_free(conn->remote_host);
1013     if (conn->local_id)
1014       silc_free(conn->local_id);
1015     if (conn->local_id_data)
1016       silc_free(conn->local_id_data);
1017     if (conn->send_key)
1018       silc_cipher_free(conn->send_key);
1019     if (conn->receive_key)
1020       silc_cipher_free(conn->receive_key);
1021     if (conn->hmac)
1022       silc_hmac_free(conn->hmac);
1023     if (conn->hmac_key) {
1024       memset(conn->hmac_key, 0, conn->hmac_key_len);
1025       silc_free(conn->hmac_key);
1026     }
1027     if (conn->pending_commands)
1028       silc_dlist_uninit(conn->pending_commands);
1029
1030     conn->sock = NULL;
1031     conn->remote_port = 0;
1032     conn->remote_type = 0;
1033     conn->send_key = NULL;
1034     conn->receive_key = NULL;
1035     conn->hmac = NULL;
1036     conn->hmac_key = NULL;
1037     conn->hmac_key_len = 0;
1038     conn->local_id = NULL;
1039     conn->local_id_data = NULL;
1040     conn->remote_host = NULL;
1041     conn->current_channel = NULL;
1042     conn->pending_commands = NULL;
1043
1044     silc_client_del_connection(client, conn);
1045   }
1046
1047   if (sock->protocol) {
1048     silc_protocol_free(sock->protocol);
1049     sock->protocol = NULL;
1050   }
1051   silc_socket_free(sock);
1052 }
1053
1054 /* Called when we receive disconnection packet from server. This 
1055    closes our end properly and displays the reason of the disconnection
1056    on the screen. */
1057
1058 void silc_client_disconnected_by_server(SilcClient client,
1059                                         SilcSocketConnection sock,
1060                                         SilcBuffer message)
1061 {
1062   char *msg;
1063
1064   SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
1065
1066   msg = silc_calloc(message->len + 1, sizeof(char));
1067   memcpy(msg, message->data, message->len);
1068   client->ops->say(client, sock->user_data, msg);
1069   silc_free(msg);
1070
1071   SILC_SET_DISCONNECTED(sock);
1072   silc_client_close_connection(client, sock->user_data);
1073 }
1074
1075 /* Received error message from server. Display it on the screen. 
1076    We don't take any action what so ever of the error message. */
1077
1078 void silc_client_error_by_server(SilcClient client,
1079                                  SilcSocketConnection sock,
1080                                  SilcBuffer message)
1081 {
1082   char *msg;
1083
1084   msg = silc_calloc(message->len + 1, sizeof(char));
1085   memcpy(msg, message->data, message->len);
1086   client->ops->say(client, sock->user_data, msg);
1087   silc_free(msg);
1088 }
1089
1090 /* Processes the received new Client ID from server. Old Client ID is
1091    deleted from cache and new one is added. */
1092
1093 void silc_client_receive_new_id(SilcClient client,
1094                                 SilcSocketConnection sock,
1095                                 SilcIDPayload idp)
1096 {
1097   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1098   int connecting = FALSE;
1099
1100   if (!conn->local_entry)
1101     connecting = TRUE;
1102
1103   /* Delete old ID from ID cache */
1104   silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
1105   
1106   /* Save the new ID */
1107   if (conn->local_id)
1108     silc_free(conn->local_id);
1109   if (conn->local_id_data)
1110     silc_free(conn->local_id_data);
1111
1112   conn->local_id = silc_id_payload_get_id(idp);
1113   conn->local_id_data = silc_id_payload_get_data(idp);
1114   conn->local_id_data_len = silc_id_payload_get_len(idp);;
1115
1116   if (!conn->local_entry)
1117     conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
1118
1119   conn->local_entry->nickname = conn->nickname;
1120   if (!conn->local_entry->username) {
1121     conn->local_entry->username = 
1122       silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
1123                   sizeof(conn->local_entry->username));
1124     sprintf(conn->local_entry->username, "%s@%s", client->username,
1125             client->hostname);
1126   }
1127   conn->local_entry->server = strdup(conn->remote_host);
1128   conn->local_entry->id = conn->local_id;
1129   
1130   /* Put it to the ID cache */
1131   silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
1132                    SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
1133                    TRUE, FALSE);
1134
1135   /* Notify application of successful connection. We do it here now that
1136      we've received the Client ID and are allowed to send traffic. */
1137   if (connecting)
1138     client->ops->connect(client, conn, TRUE);
1139 }
1140
1141 /* Processed received Channel ID for a channel. This is called when client
1142    joins to channel and server replies with channel ID. The ID is cached. 
1143    Returns the created channel entry. */
1144
1145 SilcChannelEntry silc_client_new_channel_id(SilcClient client,
1146                                             SilcSocketConnection sock,
1147                                             char *channel_name,
1148                                             unsigned int mode, 
1149                                             SilcIDPayload idp)
1150 {
1151   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
1152   SilcChannelEntry channel;
1153
1154   SILC_LOG_DEBUG(("New channel ID"));
1155
1156   channel = silc_calloc(1, sizeof(*channel));
1157   channel->channel_name = channel_name;
1158   channel->id = silc_id_payload_get_id(idp);
1159   channel->mode = mode;
1160   silc_list_init(channel->clients, struct SilcChannelUserStruct, next);
1161
1162   conn->current_channel = channel;
1163
1164   /* Put it to the ID cache */
1165   silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
1166                    SILC_ID_CHANNEL, (void *)channel->id, (void *)channel, 
1167                    TRUE, FALSE);
1168
1169   return channel;
1170 }
1171
1172 /* Removes a client entry from all channel it has joined. This really is
1173    a performance killer (client_entry should have pointers to channel 
1174    entry list). */
1175
1176 void silc_client_remove_from_channels(SilcClient client,
1177                                       SilcClientConnection conn,
1178                                       SilcClientEntry client_entry)
1179 {
1180   SilcIDCacheEntry id_cache;
1181   SilcIDCacheList list;
1182   SilcChannelEntry channel;
1183   SilcChannelUser chu;
1184
1185   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1186                                SILC_ID_CHANNEL, &list))
1187     return;
1188
1189   silc_idcache_list_first(list, &id_cache);
1190   channel = (SilcChannelEntry)id_cache->context;
1191   
1192   while (channel) {
1193     
1194     /* Remove client from channel */
1195     silc_list_start(channel->clients);
1196     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1197       if (chu->client == client_entry) {
1198         silc_list_del(channel->clients, chu);
1199         silc_free(chu);
1200         break;
1201       }
1202     }
1203
1204     if (!silc_idcache_list_next(list, &id_cache))
1205       break;
1206     
1207     channel = (SilcChannelEntry)id_cache->context;
1208   }
1209
1210   silc_idcache_list_free(list);
1211 }
1212
1213 /* Replaces `old' client entries from all channels to `new' client entry.
1214    This can be called for example when nickname changes and old ID entry
1215    is replaced from ID cache with the new one. If the old ID entry is only
1216    updated, then this fucntion needs not to be called. */
1217
1218 void silc_client_replace_from_channels(SilcClient client, 
1219                                        SilcClientConnection conn,
1220                                        SilcClientEntry old,
1221                                        SilcClientEntry new)
1222 {
1223   SilcIDCacheEntry id_cache;
1224   SilcIDCacheList list;
1225   SilcChannelEntry channel;
1226   SilcChannelUser chu;
1227
1228   if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
1229                                SILC_ID_CHANNEL, &list))
1230     return;
1231
1232   silc_idcache_list_first(list, &id_cache);
1233   channel = (SilcChannelEntry)id_cache->context;
1234   
1235   while (channel) {
1236     
1237     /* Replace client entry */
1238     silc_list_start(channel->clients);
1239     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1240       if (chu->client == old) {
1241         chu->client = new;
1242         break;
1243       }
1244     }
1245
1246     if (!silc_idcache_list_next(list, &id_cache))
1247       break;
1248     
1249     channel = (SilcChannelEntry)id_cache->context;
1250   }
1251
1252   silc_idcache_list_free(list);
1253 }
1254
1255 /* Parses mode mask and returns the mode as string. */
1256
1257 char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
1258 {
1259   char string[100];
1260
1261   if (!mode)
1262     return NULL;
1263
1264   memset(string, 0, sizeof(string));
1265
1266   if (mode & SILC_CHANNEL_MODE_PRIVATE)
1267     strncat(string, "p", 1);
1268
1269   if (mode & SILC_CHANNEL_MODE_SECRET)
1270     strncat(string, "s", 1);
1271
1272   if (mode & SILC_CHANNEL_MODE_PRIVKEY)
1273     strncat(string, "k", 1);
1274
1275   if (mode & SILC_CHANNEL_MODE_INVITE)
1276     strncat(string, "i", 1);
1277
1278   if (mode & SILC_CHANNEL_MODE_TOPIC)
1279     strncat(string, "t", 1);
1280
1281   if (mode & SILC_CHANNEL_MODE_ULIMIT)
1282     strncat(string, "l", 1);
1283
1284   if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
1285     strncat(string, "a", 1);
1286
1287   if (mode & SILC_CHANNEL_MODE_CIPHER) {
1288     char cipher[30];
1289     memset(cipher, 0, sizeof(cipher));
1290     snprintf(cipher, sizeof(cipher), " c (%s)", 
1291              channel->channel_key->cipher->name);
1292     strncat(string, cipher, strlen(cipher));
1293   }
1294
1295   if (mode & SILC_CHANNEL_MODE_HMAC) {
1296     char hmac[30];
1297     memset(hmac, 0, sizeof(hmac));
1298     snprintf(hmac, sizeof(hmac), " h (%s)", 
1299              channel->hmac->hmac->name);
1300     strncat(string, hmac, strlen(hmac));
1301   }
1302
1303   /* Rest of mode is ignored */
1304
1305   return strdup(string);
1306 }
1307
1308 /* Parses channel user mode mask and returns te mode as string */
1309
1310 char *silc_client_chumode(unsigned int mode)
1311 {
1312   char string[4];
1313
1314   if (!mode)
1315     return NULL;
1316
1317   memset(string, 0, sizeof(string));
1318
1319   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1320     strncat(string, "f", 1);
1321
1322   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1323     strncat(string, "o", 1);
1324
1325   return strdup(string);
1326 }
1327
1328 /* Parses channel user mode and returns it as special mode character. */
1329
1330 char *silc_client_chumode_char(unsigned int mode)
1331 {
1332   char string[4];
1333
1334   if (!mode)
1335     return NULL;
1336
1337   memset(string, 0, sizeof(string));
1338
1339   if (mode & SILC_CHANNEL_UMODE_CHANFO)
1340     strncat(string, "*", 1);
1341
1342   if (mode & SILC_CHANNEL_UMODE_CHANOP)
1343     strncat(string, "@", 1);
1344
1345   return strdup(string);
1346 }
1347
1348 /* Failure timeout callback. If this is called then we will immediately
1349    process the received failure. We always process the failure with timeout
1350    since we do not want to blindly trust to received failure packets. 
1351    This won't be called (the timeout is cancelled) if the failure was
1352    bogus (it is bogus if remote does not close the connection after sending
1353    the failure). */
1354
1355 SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
1356 {
1357   SilcClientFailureContext *f = (SilcClientFailureContext *)context;
1358
1359   if (f->sock->protocol) {
1360     f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
1361     f->sock->protocol->execute(f->client->timeout_queue, 0,
1362                                f->sock->protocol, f->sock->sock, 0, 0);
1363     
1364     /* Notify application */
1365     f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
1366                             (void *)f->failure);
1367   }
1368
1369   silc_free(f);
1370 }
1371
1372 /* Registers failure timeout to process the received failure packet
1373    with timeout. */
1374
1375 void silc_client_process_failure(SilcClient client,
1376                                  SilcSocketConnection sock,
1377                                  SilcPacketContext *packet)
1378 {
1379   SilcClientFailureContext *f;
1380   unsigned int failure = 0;
1381
1382   if (sock->protocol) {
1383     if (packet->buffer->len >= 4)
1384       SILC_GET32_MSB(failure, packet->buffer->data);
1385
1386     f = silc_calloc(1, sizeof(*f));
1387     f->client = client;
1388     f->sock = sock;
1389     f->failure = failure;
1390
1391     /* We will wait 5 seconds to process this failure packet */
1392     silc_task_register(client->timeout_queue, sock->sock,
1393                        silc_client_failure_callback, (void *)f, 5, 0,
1394                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1395   }
1396 }