Added silc_packet_stream_is_udp
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.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 /*
20  * Created: Fri Jul 25 18:52:14 1997
21  */
22 /* $Id$ */
23
24 #include "silc.h"
25
26 /************************** Types and definitions ***************************/
27
28 /* Packet engine */
29 struct SilcPacketEngineStruct {
30   SilcRng rng;                           /* RNG for engine */
31   SilcPacketCallbacks *callbacks;        /* Packet callbacks */
32   void *callback_context;                /* Context for callbacks */
33   SilcList streams;                      /* All streams in engine */
34   SilcList packet_pool;                  /* Free list for received packets */
35   SilcMutex lock;                        /* Engine lock */
36   SilcHashTable udp_remote;              /* UDP remote streams, or NULL */
37   SilcBool local_is_router;
38 };
39
40 /* Packet processor context */
41 typedef struct SilcPacketProcessStruct {
42   SilcInt32 priority;                    /* Priority */
43   SilcPacketType *types;                 /* Packets to process */
44   SilcPacketCallbacks *callbacks;        /* Callbacks or NULL */
45   void *callback_context;
46 } *SilcPacketProcess;
47
48 /* UDP remote stream tuple */
49 typedef struct {
50   char *remote_ip;                       /* Remote IP address */
51   SilcUInt16 remote_port;                /* Remote port */
52 } *SilcPacketRemoteUDP;
53
54 /* Packet stream */
55 struct SilcPacketStreamStruct {
56   struct SilcPacketStreamStruct *next;
57   SilcPacketEngine engine;               /* Packet engine */
58   SilcStream stream;                     /* Underlaying stream */
59   SilcMutex lock;                        /* Stream lock */
60   SilcDList process;                     /* Packet processors, or NULL */
61   SilcPacketRemoteUDP remote_udp;        /* UDP remote stream tuple, or NULL */
62   void *stream_context;                  /* Stream context */
63   SilcBufferStruct inbuf;                /* In buffer */
64   SilcBufferStruct outbuf;               /* Out buffer */
65   SilcCipher send_key[2];                /* Sending key */
66   SilcHmac send_hmac[2];                 /* Sending HMAC */
67   SilcCipher receive_key[2];             /* Receiving key */
68   SilcHmac receive_hmac[2];              /* Receiving HMAC */
69   unsigned char *src_id;                 /* Source ID */
70   unsigned char *dst_id;                 /* Destination ID */
71   SilcUInt32 send_psn;                   /* Sending sequence */
72   SilcUInt32 receive_psn;                /* Receiving sequence */
73   SilcAtomic8 refcnt;                    /* Reference counter */
74   SilcUInt8 sid;                         /* Security ID, set if IV included */
75   unsigned int src_id_len  : 6;
76   unsigned int src_id_type : 2;
77   unsigned int dst_id_len  : 6;
78   unsigned int dst_id_type : 2;
79   unsigned int is_router   : 1;          /* Set if router stream */
80   unsigned int destroyed   : 1;          /* Set if destroyed */
81   unsigned int iv_included : 1;          /* Set if IV included */
82   unsigned int udp         : 1;          /* UDP remote stream */
83 };
84
85 /* Initial size of stream buffers */
86 #define SILC_PACKET_DEFAULT_SIZE  1024
87
88 /* Header length without source and destination ID's. */
89 #define SILC_PACKET_HEADER_LEN 10
90
91 /* Minimum length of SILC Packet Header. */
92 #define SILC_PACKET_MIN_HEADER_LEN 16
93 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
94
95 /* Maximum padding length */
96 #define SILC_PACKET_MAX_PADLEN 128
97
98 /* Default padding length */
99 #define SILC_PACKET_DEFAULT_PADLEN 16
100
101 /* Minimum packet length */
102 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
103
104 /* Returns true length of the packet. */
105 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
106 do {                                                                     \
107   SILC_GET16_MSB((__ret_truelen), (__packetdata));                       \
108   (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4];    \
109 } while(0)
110
111 /* Calculates the data length with given header length.  This macro
112    can be used to check whether the data_len with header_len exceeds
113    SILC_PACKET_MAX_LEN.  If it does, this returns the new data_len
114    so that the SILC_PACKET_MAX_LEN is not exceeded.  If the data_len
115    plus header_len fits SILC_PACKET_MAX_LEN the returned data length
116    is the data_len given as argument. */
117 #define SILC_PACKET_DATALEN(data_len, header_len)                         \
118   ((data_len + header_len) > SILC_PACKET_MAX_LEN ?                        \
119    data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
120
121 /* Calculates the length of the padding in the packet. */
122 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)               \
123 do {                                                                        \
124   __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                  \
125               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
126   if (__padlen < 8)                                                         \
127     __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
128 } while(0)
129
130 /* Returns the length of the padding up to the maximum length, which
131    is 128 bytes.*/
132 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen)          \
133 do {                                                                       \
134   __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
135               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
136 } while(0)
137
138 /* EOS callback */
139 #define SILC_PACKET_CALLBACK_EOS(s)                                     \
140 do {                                                                    \
141   (s)->engine->callbacks->eos((s)->engine, s,                           \
142                               (s)->engine->callback_context,            \
143                               (s)->stream_context);                     \
144 } while(0)
145
146 /* Error callback */
147 #define SILC_PACKET_CALLBACK_ERROR(s, err)                              \
148 do {                                                                    \
149   (s)->engine->callbacks->error((s)->engine, s, err,                    \
150                                 (s)->engine->callback_context,          \
151                                 (s)->stream_context);                   \
152 } while(0)
153
154 static void silc_packet_dispatch(SilcPacket packet);
155 static void silc_packet_read_process(SilcPacketStream stream);
156
157 /************************ Static utility functions **************************/
158
159 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
160
161 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
162 {
163   SilcPacket packet = context;
164   SilcPacketStream stream = packet->stream;
165
166   SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
167
168   silc_mutex_lock(stream->lock);
169   silc_packet_dispatch(packet);
170   silc_mutex_unlock(stream->lock);
171 }
172
173 /* Write data to the stream.  Must be called with ps->lock locked.  Unlocks
174    the lock inside this function. */
175
176 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps)
177 {
178   SilcStream stream;
179   SilcBool connected;
180   int i;
181
182   if (ps->udp)
183     stream = ((SilcPacketStream)ps->stream)->stream;
184   else
185     stream = ps->stream;
186
187   if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
188     if (!connected) {
189       /* Connectionless UDP stream */
190       while (silc_buffer_len(&ps->outbuf) > 0) {
191         i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
192                               ps->remote_udp->remote_port,
193                               ps->outbuf.data, silc_buffer_len(&ps->outbuf));
194         if (i == -2) {
195           /* Error */
196           silc_buffer_reset(&ps->outbuf);
197           silc_mutex_unlock(ps->lock);
198           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
199           return FALSE;
200         }
201
202         if (i == -1) {
203           /* Cannot write now, write later. */
204           silc_mutex_unlock(ps->lock);
205           return TRUE;
206         }
207
208         /* Wrote data */
209         silc_buffer_pull(&ps->outbuf, i);
210       }
211
212       silc_buffer_reset(&ps->outbuf);
213       silc_mutex_unlock(ps->lock);
214
215       return TRUE;
216     }
217   }
218
219   /* Write the data to the stream */
220   while (silc_buffer_len(&ps->outbuf) > 0) {
221     i = silc_stream_write(stream, ps->outbuf.data,
222                           silc_buffer_len(&ps->outbuf));
223     if (i == 0) {
224       /* EOS */
225       silc_buffer_reset(&ps->outbuf);
226       silc_mutex_unlock(ps->lock);
227       SILC_PACKET_CALLBACK_EOS(ps);
228       return FALSE;
229     }
230
231     if (i == -2) {
232       /* Error */
233       silc_buffer_reset(&ps->outbuf);
234       silc_mutex_unlock(ps->lock);
235       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
236       return FALSE;
237     }
238
239     if (i == -1) {
240       /* Cannot write now, write later. */
241       silc_mutex_unlock(ps->lock);
242       return TRUE;
243     }
244
245     /* Wrote data */
246     silc_buffer_pull(&ps->outbuf, i);
247   }
248
249   silc_buffer_reset(&ps->outbuf);
250   silc_mutex_unlock(ps->lock);
251
252   return TRUE;
253 }
254
255 /* Reads data from stream.  Must be called with the ps->lock locked.  If this
256    returns FALSE the lock has been unlocked.  If this returns packet stream
257    to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
258    It is returned if the stream is UDP and remote UDP stream exists for
259    the sender of the packet. */
260
261 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
262                                                SilcPacketStream *ret_ps)
263 {
264   SilcStream stream;
265   SilcBool connected;
266   int ret;
267
268   stream = ps->stream;
269
270   /* Make sure we have fair amount of free space in inbuf */
271   if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
272     if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
273                              SILC_PACKET_DEFAULT_SIZE * 2)) {
274       silc_mutex_unlock(ps->lock);
275       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
276       return FALSE;
277     }
278
279   if (silc_socket_stream_is_udp(stream, &connected)) {
280     if (!connected) {
281       /* Connectionless UDP stream, read one UDP packet */
282       char remote_ip[64], tuple[64];
283       int remote_port;
284       SilcPacketStream remote;
285
286       ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
287                                  &remote_port, ps->inbuf.tail,
288                                  silc_buffer_taillen(&ps->inbuf));
289       if (ret == -2) {
290         /* Error */
291         silc_buffer_reset(&ps->inbuf);
292         silc_mutex_unlock(ps->lock);
293         SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
294         return FALSE;
295       }
296
297       if (ret == -1) {
298         /* Cannot read now, do it later. */
299         silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
300         silc_mutex_unlock(ps->lock);
301         return FALSE;
302       }
303
304       /* See if remote packet stream exist for this sender */
305       snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
306       silc_mutex_lock(ps->engine->lock);
307       if (silc_hash_table_find(ps->engine->udp_remote, tuple, NULL,
308                                (void *)&remote)) {
309         /* Found packet stream for this sender, copy the packet */
310         silc_mutex_unlock(ps->engine->lock);
311
312         SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p",
313                         remote_ip, remote_port, remote));
314
315         silc_mutex_lock(remote->lock);
316         if (ret > silc_buffer_taillen(&remote->inbuf))
317           if (!silc_buffer_realloc(&remote->inbuf, ret)) {
318             silc_mutex_unlock(remote->lock);
319             silc_mutex_unlock(ps->lock);
320             SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
321             return FALSE;
322           }
323
324         silc_buffer_put_tail(&remote->inbuf, ps->inbuf.tail, ret);
325         silc_buffer_pull_tail(&remote->inbuf, ret);
326         *ret_ps = remote;
327
328         silc_buffer_reset(&ps->inbuf);
329         silc_mutex_unlock(ps->lock);
330         return TRUE;
331       }
332       silc_mutex_unlock(ps->engine->lock);
333
334       /* Unknown sender */
335       if (!ps->remote_udp) {
336         ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
337         if (!ps->remote_udp) {
338           silc_mutex_unlock(ps->lock);
339           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
340           return FALSE;
341         }
342       }
343
344       /* Save sender IP and port */
345       silc_free(ps->remote_udp->remote_ip);
346       ps->remote_udp->remote_ip = strdup(remote_ip);
347       ps->remote_udp->remote_port = remote_port;
348
349       silc_buffer_pull_tail(&ps->inbuf, ret);
350       return TRUE;
351     }
352   }
353
354   /* Read data from the stream */
355   ret = silc_stream_read(ps->stream, ps->inbuf.tail,
356                          silc_buffer_taillen(&ps->inbuf));
357
358   if (ret == 0) {
359     /* EOS */
360     silc_buffer_reset(&ps->inbuf);
361     silc_mutex_unlock(ps->lock);
362     SILC_PACKET_CALLBACK_EOS(ps);
363     return FALSE;
364   }
365
366   if (ret == -2) {
367     /* Error */
368     silc_buffer_reset(&ps->inbuf);
369     silc_mutex_unlock(ps->lock);
370     SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
371     return FALSE;
372   }
373
374   if (ret == -1) {
375     /* Cannot read now, do it later. */
376     silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
377     silc_mutex_unlock(ps->lock);
378     return FALSE;
379   }
380
381   silc_buffer_pull_tail(&ps->inbuf, ret);
382   return TRUE;
383 }
384
385 /* Our stream IO notifier callback. */
386
387 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
388                                   void *context)
389 {
390   SilcPacketStream remote = NULL, ps = context;
391
392   silc_mutex_lock(ps->lock);
393
394   if (ps->destroyed) {
395     silc_mutex_unlock(ps->lock);
396     return;
397   }
398
399   switch (status) {
400
401   case SILC_STREAM_CAN_WRITE:
402     SILC_LOG_DEBUG(("Writing pending data to stream"));
403
404     if (!silc_buffer_headlen(&ps->outbuf)) {
405       silc_mutex_unlock(ps->lock);
406       return;
407     }
408
409     /* Write pending data to stream */
410     silc_packet_stream_write(ps);
411     break;
412
413   case SILC_STREAM_CAN_READ:
414     SILC_LOG_DEBUG(("Reading data from stream"));
415
416     /* Read data from stream */
417     if (!silc_packet_stream_read(ps, &remote))
418       return;
419
420     /* Now process the data */
421     if (!remote) {
422       silc_packet_read_process(ps);
423       silc_mutex_unlock(ps->lock);
424     } else {
425       silc_packet_read_process(remote);
426       silc_mutex_unlock(remote->lock);
427     }
428     break;
429
430   default:
431     silc_mutex_unlock(ps->lock);
432     break;
433   }
434 }
435
436 /* Allocate packet */
437
438 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
439 {
440   SilcPacket packet;
441
442   SILC_LOG_DEBUG(("Packet pool count %d",
443                   silc_list_count(engine->packet_pool)));
444
445   silc_mutex_lock(engine->lock);
446
447   /* Get packet from freelist or allocate new one. */
448   packet = silc_list_get(engine->packet_pool);
449   if (!packet) {
450     void *tmp;
451
452     silc_mutex_unlock(engine->lock);
453
454     packet = silc_calloc(1, sizeof(*packet));
455     if (!packet)
456       return NULL;
457
458     SILC_LOG_DEBUG(("Allocating new packet %p", packet));
459
460     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
461     if (!tmp) {
462       silc_free(packet);
463       return NULL;
464     }
465     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
466     silc_buffer_reset(&packet->buffer);
467
468     return packet;
469   }
470
471   SILC_LOG_DEBUG(("Get packet %p", packet));
472
473   /* Delete from freelist */
474   silc_list_del(engine->packet_pool, packet);
475
476   silc_mutex_unlock(engine->lock);
477
478   return packet;
479 }
480
481 /* UDP remote stream hash table destructor */
482
483 static void silc_packet_engine_hash_destr(void *key, void *context,
484                                           void *user_context)
485 {
486   silc_free(key);
487 }
488
489
490 /******************************** Packet API ********************************/
491
492 /* Allocate new packet engine */
493
494 SilcPacketEngine
495 silc_packet_engine_start(SilcRng rng, SilcBool router,
496                          SilcPacketCallbacks *callbacks,
497                          void *callback_context)
498 {
499   SilcPacketEngine engine;
500   SilcPacket packet;
501   int i;
502   void *tmp;
503
504   SILC_LOG_DEBUG(("Starting new packet engine"));
505
506   if (!callbacks)
507     return NULL;
508   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
509     return NULL;
510
511   engine = silc_calloc(1, sizeof(*engine));
512   if (!engine)
513     return NULL;
514
515   engine->rng = rng;
516   engine->local_is_router = router;
517   engine->callbacks = callbacks;
518   engine->callback_context = callback_context;
519   silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
520   silc_mutex_alloc(&engine->lock);
521
522   /* Allocate packet free list */
523   silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
524   for (i = 0; i < 5; i++) {
525     packet = silc_calloc(1, sizeof(*packet));
526     if (!packet) {
527       silc_packet_engine_stop(engine);
528       return NULL;
529     }
530
531     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
532     if (!tmp) {
533       silc_packet_engine_stop(engine);
534       return NULL;
535     }
536     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
537     silc_buffer_reset(&packet->buffer);
538
539     silc_list_add(engine->packet_pool, packet);
540   }
541   silc_list_start(engine->packet_pool);
542
543   return engine;
544 }
545
546 /* Stop packet engine */
547
548 void silc_packet_engine_stop(SilcPacketEngine engine)
549 {
550
551   SILC_LOG_DEBUG(("Stopping packet engine"));
552
553   if (!engine)
554     return;
555
556   /* XXX */
557
558   silc_free(engine);
559 }
560
561 /* Create new packet stream */
562
563 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
564                                            SilcSchedule schedule,
565                                            SilcStream stream)
566 {
567   SilcPacketStream ps;
568   void *tmp;
569
570   SILC_LOG_DEBUG(("Creating new packet stream"));
571
572   if (!engine || !stream)
573     return NULL;
574
575   ps = silc_calloc(1, sizeof(*ps));
576   if (!ps)
577     return NULL;
578
579   ps->engine = engine;
580   ps->stream = stream;
581   silc_atomic_init8(&ps->refcnt, 1);
582   silc_mutex_alloc(&ps->lock);
583
584   /* Allocate buffers */
585   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
586   if (!tmp) {
587     silc_packet_stream_destroy(ps);
588     return NULL;
589   }
590   silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
591   silc_buffer_reset(&ps->inbuf);
592   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
593   if (!tmp) {
594     silc_packet_stream_destroy(ps);
595     return NULL;
596   }
597   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
598   silc_buffer_reset(&ps->outbuf);
599
600   /* Initialize packet procesors list */
601   ps->process = silc_dlist_init();
602   if (!ps->process) {
603     silc_packet_stream_destroy(ps);
604     return NULL;
605   }
606
607   /* Set IO notifier callback */
608   silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
609
610   /* Add to engine */
611   silc_mutex_lock(engine->lock);
612   silc_list_add(engine->streams, ps);
613   silc_mutex_unlock(engine->lock);
614
615   /* If this is UDP stream, allocate UDP remote stream hash table */
616   if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
617     engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
618                                                silc_hash_string_compare, NULL,
619                                                silc_packet_engine_hash_destr,
620                                                NULL, TRUE);
621
622   return ps;
623 }
624
625 /* Add new remote packet stream for UDP packet streams */
626
627 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
628                                                const char *remote_ip,
629                                                SilcUInt16 remote_port,
630                                                SilcPacket packet)
631 {
632   SilcPacketEngine engine = stream->engine;
633   SilcPacketStream ps;
634   char *tuple;
635   void *tmp;
636
637   SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
638                   remote_ip, remote_port, stream));
639
640   if (!stream || !remote_ip || !remote_port)
641     return NULL;
642
643   if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
644     SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
645     return NULL;
646   }
647
648   ps = silc_calloc(1, sizeof(*ps));
649   if (!ps)
650     return NULL;
651
652   ps->engine = engine;
653   silc_atomic_init8(&ps->refcnt, 1);
654   silc_mutex_alloc(&ps->lock);
655
656   /* Set the UDP packet stream as underlaying stream */
657   silc_packet_stream_ref(stream);
658   ps->stream = (SilcStream)stream;
659   ps->udp = TRUE;
660
661   /* Allocate buffers */
662   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
663   if (!tmp) {
664     silc_packet_stream_destroy(ps);
665     return NULL;
666   }
667   silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
668   silc_buffer_reset(&ps->inbuf);
669   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
670   if (!tmp) {
671     silc_packet_stream_destroy(ps);
672     return NULL;
673   }
674   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
675   silc_buffer_reset(&ps->outbuf);
676
677   /* Initialize packet procesors list */
678   ps->process = silc_dlist_init();
679   if (!ps->process) {
680     silc_packet_stream_destroy(ps);
681     return NULL;
682   }
683
684   /* Add to engine with this IP and port pair */
685   tuple = silc_format("%d%s", remote_port, remote_ip);
686   silc_mutex_lock(engine->lock);
687   if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
688     silc_mutex_unlock(engine->lock);
689     silc_packet_stream_destroy(ps);
690     return NULL;
691   }
692   silc_mutex_unlock(engine->lock);
693
694   /* Save remote IP and port pair */
695   ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
696   if (!ps->remote_udp) {
697     silc_packet_stream_destroy(ps);
698     return NULL;
699   }
700   ps->remote_udp->remote_port = remote_port;
701   ps->remote_udp->remote_ip = strdup(remote_ip);
702   if (!ps->remote_udp->remote_ip) {
703     silc_packet_stream_destroy(ps);
704     return NULL;
705   }
706
707   if (packet) {
708     /* Inject packet to the new stream */
709     packet->stream = ps;
710     silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
711                                    silc_packet_stream_inject_packet, packet,
712                                    0, 0);
713   }
714
715   return ps;
716 }
717
718 /* Destroy packet stream */
719
720 void silc_packet_stream_destroy(SilcPacketStream stream)
721 {
722   if (!stream)
723     return;
724
725   if (silc_atomic_get_int8(&stream->refcnt) > 1) {
726     stream->destroyed = TRUE;
727     return;
728   }
729
730   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
731
732   if (!stream->udp) {
733     /* Delete from engine */
734     silc_mutex_lock(stream->engine->lock);
735     silc_list_del(stream->engine->streams, stream);
736     silc_mutex_unlock(stream->engine->lock);
737
738     /* Destroy the underlaying stream */
739     if (stream->stream)
740       silc_stream_destroy(stream->stream);
741   } else {
742     /* Delete from UDP remote hash table */
743     char tuple[64];
744     snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
745              stream->remote_udp->remote_ip);
746     silc_mutex_lock(stream->engine->lock);
747     silc_hash_table_del(stream->engine->udp_remote, tuple);
748     silc_mutex_unlock(stream->engine->lock);
749
750     silc_free(stream->remote_udp->remote_ip);
751     silc_free(stream->remote_udp);
752
753     /* Unreference the underlaying packet stream */
754     silc_packet_stream_unref((SilcPacketStream)stream->stream);
755   }
756
757   /* Clear and free buffers */
758   silc_buffer_clear(&stream->inbuf);
759   silc_buffer_clear(&stream->outbuf);
760   silc_buffer_purge(&stream->inbuf);
761   silc_buffer_purge(&stream->outbuf);
762
763   if (stream->process) {
764     SilcPacketProcess p;
765     silc_dlist_start(stream->process);
766     while ((p = silc_dlist_get(stream->process))) {
767       silc_free(p->types);
768       silc_free(p);
769       silc_dlist_del(stream->process, p);
770     }
771     silc_dlist_uninit(stream->process);
772   }
773
774   /* XXX */
775
776   silc_atomic_uninit8(&stream->refcnt);
777   silc_mutex_free(stream->lock);
778   silc_free(stream);
779 }
780
781 /* Marks as router stream */
782
783 void silc_packet_stream_set_router(SilcPacketStream stream)
784 {
785   stream->is_router = TRUE;
786 }
787
788 /* Mark to include IV in ciphertext */
789
790 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
791 {
792   stream->iv_included = TRUE;
793 }
794
795 /* Links `callbacks' to `stream' for specified packet types */
796
797 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
798                                            SilcPacketCallbacks *callbacks,
799                                            void *callback_context,
800                                            int priority, va_list ap)
801 {
802   SilcPacketProcess p, e;
803   SilcInt32 packet_type;
804   int i;
805
806   SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
807
808   if (!callbacks)
809     return FALSE;
810   if (!callbacks->packet_receive)
811     return FALSE;
812
813   p = silc_calloc(1, sizeof(*p));
814   if (!p)
815     return FALSE;
816
817   p->priority = priority;
818   p->callbacks = callbacks;
819   p->callback_context = callback_context;
820
821   silc_mutex_lock(stream->lock);
822
823   if (!stream->process) {
824     stream->process = silc_dlist_init();
825     if (!stream->process) {
826       silc_mutex_unlock(stream->lock);
827       return FALSE;
828     }
829   }
830
831   /* According to priority set the procesor to correct position.  First
832      entry has the highest priority */
833   silc_dlist_start(stream->process);
834   while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
835     if (p->priority > e->priority) {
836       silc_dlist_insert(stream->process, p);
837       break;
838     }
839   }
840   if (!e)
841     silc_dlist_add(stream->process, p);
842
843   /* Get packet types to process */
844   i = 1;
845   while (1) {
846     packet_type = va_arg(ap, SilcInt32);
847
848     if (packet_type == SILC_PACKET_ANY)
849       break;
850
851     if (packet_type == -1)
852       break;
853
854     p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
855     if (!p->types) {
856       silc_mutex_unlock(stream->lock);
857       return FALSE;
858     }
859
860     p->types[i - 1] = (SilcPacketType)packet_type;
861     i++;
862   }
863   if (p->types)
864     p->types[i - 1] = 0;
865
866   silc_mutex_unlock(stream->lock);
867
868   silc_packet_stream_ref(stream);
869
870   return TRUE;
871 }
872
873 /* Links `callbacks' to `stream' for specified packet types */
874
875 SilcBool silc_packet_stream_link(SilcPacketStream stream,
876                                  SilcPacketCallbacks *callbacks,
877                                  void *callback_context,
878                                  int priority, ...)
879 {
880   va_list ap;
881   SilcBool ret;
882
883   va_start(ap, priority);
884   ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
885                                    priority, ap);
886   va_end(ap);
887
888   return ret;
889 }
890
891 /* Unlinks `callbacks' from `stream'. */
892
893 void silc_packet_stream_unlink(SilcPacketStream stream,
894                                SilcPacketCallbacks *callbacks,
895                                void *callback_context)
896 {
897   SilcPacketProcess p;
898
899   SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
900                   callbacks, stream));
901
902   silc_mutex_lock(stream->lock);
903
904   silc_dlist_start(stream->process);
905   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
906     if (p->callbacks == callbacks &&
907         p->callback_context == callback_context) {
908       silc_dlist_del(stream->process, p);
909       silc_free(p->types);
910       silc_free(p);
911       break;
912     }
913
914   if (!silc_dlist_count(stream->process)) {
915     silc_dlist_uninit(stream->process);
916     stream->process = NULL;
917   }
918
919   silc_mutex_unlock(stream->lock);
920
921   silc_packet_stream_unref(stream);
922 }
923
924 /* Returns TRUE if stream is UDP stream */
925
926 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
927 {
928   return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
929 }
930
931 /* Return packet sender IP and port for UDP packet stream */
932
933 SilcBool silc_packet_get_sender(SilcPacket packet,
934                                 const char **sender_ip,
935                                 SilcUInt16 *sender_port)
936 {
937   if (!packet->stream->remote_udp)
938     return FALSE;
939
940   *sender_ip = packet->stream->remote_udp->remote_ip;
941   *sender_port = packet->stream->remote_udp->remote_port;
942
943   return TRUE;
944 }
945
946 /* Reference packet stream */
947
948 void silc_packet_stream_ref(SilcPacketStream stream)
949 {
950   silc_atomic_add_int8(&stream->refcnt, 1);
951 }
952
953 /* Unreference packet stream */
954
955 void silc_packet_stream_unref(SilcPacketStream stream)
956 {
957   if (silc_atomic_sub_int8(&stream->refcnt, 1) == 0)
958     silc_packet_stream_destroy(stream);
959 }
960
961 /* Return engine */
962
963 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
964 {
965   return stream->engine;
966 }
967
968 /* Set application context for packet stream */
969
970 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
971 {
972   silc_mutex_lock(stream->lock);
973   stream->stream_context = stream_context;
974   silc_mutex_unlock(stream->lock);
975 }
976
977 /* Return application context from packet stream */
978
979 void *silc_packet_get_context(SilcPacketStream stream)
980 {
981   void *context;
982   silc_mutex_lock(stream->lock);
983   context = stream->stream_context;
984   silc_mutex_unlock(stream->lock);
985   return context;
986 }
987
988 /* Change underlaying stream */
989
990 void silc_packet_stream_set_stream(SilcPacketStream ps,
991                                    SilcStream stream,
992                                    SilcSchedule schedule)
993 {
994   if (ps->stream)
995     silc_stream_set_notifier(ps->stream, schedule, NULL, NULL);
996   ps->stream = stream;
997   silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
998 }
999
1000 /* Return underlaying stream */
1001
1002 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1003 {
1004   return stream->stream;
1005 }
1006
1007 /* Set ciphers for packet stream */
1008
1009 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
1010                              SilcCipher receive)
1011 {
1012   SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
1013
1014   silc_mutex_lock(stream->lock);
1015
1016   /* In case IV Included is set, save the old key */
1017   if (stream->iv_included) {
1018     if (stream->send_key[1]) {
1019       silc_cipher_free(stream->send_key[1]);
1020       stream->send_key[1] = stream->send_key[0];
1021     }
1022     if (stream->receive_key[1]) {
1023       silc_cipher_free(stream->receive_key[1]);
1024       stream->receive_key[1] = stream->receive_key[0];
1025     }
1026   } else {
1027     if (stream->send_key[0])
1028       silc_cipher_free(stream->send_key[0]);
1029     if (stream->send_key[1])
1030       silc_cipher_free(stream->receive_key[0]);
1031   }
1032
1033   stream->send_key[0] = send;
1034   stream->receive_key[0] = receive;
1035
1036   silc_mutex_unlock(stream->lock);
1037 }
1038
1039 /* Return current ciphers from packet stream */
1040
1041 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
1042                                  SilcCipher *receive)
1043 {
1044   if (!stream->send_key[0] && !stream->receive_key[0])
1045     return FALSE;
1046
1047   silc_mutex_lock(stream->lock);
1048
1049   if (send)
1050     *send = stream->send_key[0];
1051   if (receive)
1052     *receive = stream->receive_key[0];
1053
1054   silc_mutex_unlock(stream->lock);
1055
1056   return TRUE;
1057 }
1058
1059 /* Set HMACs for packet stream */
1060
1061 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
1062                            SilcHmac receive)
1063 {
1064   SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
1065
1066   silc_mutex_lock(stream->lock);
1067
1068   /* In case IV Included is set, save the old HMAC */
1069   if (stream->iv_included) {
1070     if (stream->send_hmac[1]) {
1071       silc_hmac_free(stream->send_hmac[1]);
1072       stream->send_hmac[1] = stream->send_hmac[0];
1073     }
1074     if (stream->receive_hmac[1]) {
1075       silc_hmac_free(stream->receive_hmac[1]);
1076       stream->receive_hmac[1] = stream->receive_hmac[0];
1077     }
1078   } else {
1079     if (stream->send_hmac[0])
1080       silc_hmac_free(stream->send_hmac[0]);
1081     if (stream->receive_hmac[0])
1082       silc_hmac_free(stream->receive_hmac[0]);
1083   }
1084
1085   stream->send_hmac[0] = send;
1086   stream->receive_hmac[0] = receive;
1087
1088   silc_mutex_unlock(stream->lock);
1089 }
1090
1091 /* Return current HMACs from packet stream */
1092
1093 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
1094                                SilcHmac *receive)
1095 {
1096   if (!stream->send_hmac[0] && !stream->receive_hmac[0])
1097     return FALSE;
1098
1099   silc_mutex_lock(stream->lock);
1100
1101   if (send)
1102     *send = stream->send_hmac[0];
1103   if (receive)
1104     *receive = stream->receive_hmac[0];
1105
1106   silc_mutex_unlock(stream->lock);
1107
1108   return TRUE;
1109 }
1110
1111 /* Set SILC IDs to packet stream */
1112
1113 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1114                              SilcIdType src_id_type, const void *src_id,
1115                              SilcIdType dst_id_type, const void *dst_id)
1116 {
1117   SilcUInt32 len;
1118   unsigned char tmp[32];
1119
1120   if (!src_id && !dst_id)
1121     return FALSE;
1122
1123   SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1124
1125   silc_mutex_lock(stream->lock);
1126
1127   if (src_id) {
1128     silc_free(stream->src_id);
1129     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1130       silc_mutex_unlock(stream->lock);
1131       return FALSE;
1132     }
1133     stream->src_id = silc_memdup(tmp, len);
1134     if (!stream->src_id) {
1135       silc_mutex_unlock(stream->lock);
1136       return FALSE;
1137     }
1138     stream->src_id_type = src_id_type;
1139     stream->src_id_len = len;
1140   }
1141
1142   if (dst_id) {
1143     silc_free(stream->dst_id);
1144     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1145       silc_mutex_unlock(stream->lock);
1146       return FALSE;
1147     }
1148     stream->dst_id = silc_memdup(tmp, len);
1149     if (!stream->dst_id) {
1150       silc_mutex_unlock(stream->lock);
1151       return FALSE;
1152     }
1153     stream->dst_id_type = dst_id_type;
1154     stream->dst_id_len = len;
1155   }
1156
1157   silc_mutex_unlock(stream->lock);
1158
1159   return TRUE;
1160 }
1161
1162 /* Adds Security ID (SID) */
1163
1164 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1165 {
1166   if (!stream->iv_included)
1167     return FALSE;
1168
1169   SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1170
1171   stream->sid = sid;
1172   return TRUE;
1173 }
1174
1175 /* Free packet */
1176
1177 void silc_packet_free(SilcPacket packet)
1178 {
1179   SilcPacketStream stream = packet->stream;
1180
1181   SILC_LOG_DEBUG(("Freeing packet %p", packet));
1182
1183   /* Check for double free */
1184   SILC_ASSERT(packet->stream != NULL);
1185
1186   packet->stream = NULL;
1187   packet->src_id = packet->dst_id = NULL;
1188   silc_buffer_reset(&packet->buffer);
1189
1190   silc_mutex_lock(stream->engine->lock);
1191
1192   /* Put the packet back to freelist */
1193   silc_list_add(stream->engine->packet_pool, packet);
1194   if (silc_list_count(stream->engine->packet_pool) == 1)
1195     silc_list_start(stream->engine->packet_pool);
1196
1197   silc_mutex_unlock(stream->engine->lock);
1198 }
1199
1200 /****************************** Packet Sending ******************************/
1201
1202 /* Prepare outgoing data buffer for packet sending.  Returns the
1203    pointer to that buffer into the `packet'. */
1204
1205 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1206                                          SilcUInt32 totlen,
1207                                          SilcHmac hmac,
1208                                          SilcBuffer packet)
1209 {
1210   unsigned char *oldptr;
1211   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1212
1213   totlen += mac_len;
1214
1215   /* Allocate more space if needed */
1216   if (silc_buffer_taillen(&stream->outbuf) < totlen) {
1217     if (!silc_buffer_realloc(&stream->outbuf,
1218                              silc_buffer_truelen(&stream->outbuf) + totlen))
1219       return FALSE;
1220   }
1221
1222   /* Pull data area for the new packet, and return pointer to the start of
1223      the data area and save the pointer in to the `packet'.  MAC is pulled
1224      later after it's computed. */
1225   oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1226   silc_buffer_set(packet, oldptr, totlen);
1227   silc_buffer_push_tail(packet, mac_len);
1228
1229   return TRUE;
1230 }
1231
1232 /* Internal routine to send packet */
1233
1234 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
1235                                      SilcPacketType type,
1236                                      SilcPacketFlags flags,
1237                                      SilcIdType src_id_type,
1238                                      unsigned char *src_id,
1239                                      SilcUInt32 src_id_len,
1240                                      SilcIdType dst_id_type,
1241                                      unsigned char *dst_id,
1242                                      SilcUInt32 dst_id_len,
1243                                      const unsigned char *data,
1244                                      SilcUInt32 data_len,
1245                                      SilcCipher cipher,
1246                                      SilcHmac hmac)
1247 {
1248   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1249   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1250   int i, enclen, truelen, padlen, ivlen = 0, psnlen = 0;
1251   SilcBufferStruct packet;
1252
1253   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1254                   "data len %d", silc_get_packet_name(type), stream->send_psn,
1255                   flags, src_id_type, dst_id_type, data_len));
1256
1257   /* Get the true length of the packet. This is saved as payload length
1258      into the packet header.  This does not include the length of the
1259      padding. */
1260   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1261                                             src_id_len + dst_id_len));
1262   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1263                       src_id_len + dst_id_len);
1264
1265   /* If IV is included, the SID, IV and sequence number is added to packet */
1266   if (stream->iv_included && cipher) {
1267     psnlen = sizeof(psn);
1268     ivlen = block_len + 1;
1269     iv[0] = stream->sid;
1270     memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1271   }
1272
1273   /* We automatically figure out the packet structure from the packet
1274      type and flags, and calculate correct length.  Private messages with
1275      private keys and channel messages are special packets as their
1276      payload is encrypted already. */
1277   if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1278        flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1279       type == SILC_PACKET_CHANNEL_MESSAGE) {
1280
1281     /* Padding is calculated from header + IDs */
1282     SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1283                         psnlen), block_len, padlen);
1284
1285     /* Length to encrypt, header + IDs + padding. */
1286     enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1287               padlen + psnlen);
1288   } else {
1289
1290     /* Padding is calculated from true length of the packet */
1291     if (flags & SILC_PACKET_FLAG_LONG_PAD)
1292       SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1293     else
1294       SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1295
1296     enclen += padlen + psnlen;
1297   }
1298
1299   /* Remove implementation specific flags */
1300   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1301
1302   /* Get random padding */
1303   for (i = 0; i < padlen; i++) tmppad[i] =
1304                                  silc_rng_get_byte_fast(stream->engine->rng);
1305
1306   silc_mutex_lock(stream->lock);
1307
1308   /* Get packet pointer from the outgoing buffer */
1309   if (!silc_packet_send_prepare(stream, truelen + padlen + ivlen + psnlen,
1310                                 hmac, &packet)) {
1311     silc_mutex_unlock(stream->lock);
1312     return FALSE;
1313   }
1314
1315   SILC_PUT32_MSB(stream->send_psn, psn);
1316
1317   /* Create the packet.  This creates the SILC header, adds padding, and
1318      the actual packet data. */
1319   i = silc_buffer_format(&packet,
1320                          SILC_STR_DATA(iv, ivlen),
1321                          SILC_STR_DATA(psn, psnlen),
1322                          SILC_STR_UI_SHORT(truelen),
1323                          SILC_STR_UI_CHAR(flags),
1324                          SILC_STR_UI_CHAR(type),
1325                          SILC_STR_UI_CHAR(padlen),
1326                          SILC_STR_UI_CHAR(0),
1327                          SILC_STR_UI_CHAR(src_id_len),
1328                          SILC_STR_UI_CHAR(dst_id_len),
1329                          SILC_STR_UI_CHAR(src_id_type),
1330                          SILC_STR_DATA(src_id, src_id_len),
1331                          SILC_STR_UI_CHAR(dst_id_type),
1332                          SILC_STR_DATA(dst_id, dst_id_len),
1333                          SILC_STR_DATA(tmppad, padlen),
1334                          SILC_STR_DATA(data, data_len),
1335                          SILC_STR_END);
1336   if (i < 0) {
1337     silc_mutex_unlock(stream->lock);
1338     return FALSE;
1339   }
1340
1341   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1342                    silc_buffer_data(&packet), silc_buffer_len(&packet));
1343
1344   /* Encrypt the packet */
1345   if (cipher) {
1346     SILC_LOG_DEBUG(("Encrypting packet"));
1347     if (!silc_cipher_encrypt(cipher, packet.data + ivlen,
1348                              packet.data + ivlen, enclen, NULL)) {
1349       SILC_LOG_ERROR(("Packet encryption failed"));
1350       silc_mutex_unlock(stream->lock);
1351       return FALSE;
1352     }
1353   }
1354
1355   /* Compute HMAC */
1356   if (hmac) {
1357     SilcUInt32 mac_len;
1358
1359     /* MAC is computed from the entire encrypted packet data, and put
1360        to the end of the packet. */
1361     silc_hmac_init(hmac);
1362     silc_hmac_update(hmac, psn, sizeof(psn));
1363     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1364     silc_hmac_final(hmac, packet.tail, &mac_len);
1365     silc_buffer_pull_tail(&packet, mac_len);
1366     stream->send_psn++;
1367   }
1368
1369   /* Write the packet to the stream */
1370   return silc_packet_stream_write(stream);
1371 }
1372
1373 /* Sends a packet */
1374
1375 SilcBool silc_packet_send(SilcPacketStream stream,
1376                           SilcPacketType type, SilcPacketFlags flags,
1377                           const unsigned char *data, SilcUInt32 data_len)
1378 {
1379   return silc_packet_send_raw(stream, type, flags,
1380                               stream->src_id_type,
1381                               stream->src_id,
1382                               stream->src_id_len,
1383                               stream->dst_id_type,
1384                               stream->dst_id,
1385                               stream->dst_id_len,
1386                               data, data_len,
1387                               stream->send_key[0],
1388                               stream->send_hmac[0]);
1389 }
1390
1391 /* Sends a packet, extended routine */
1392
1393 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1394                               SilcPacketType type, SilcPacketFlags flags,
1395                               SilcIdType src_id_type, void *src_id,
1396                               SilcIdType dst_id_type, void *dst_id,
1397                               const unsigned char *data, SilcUInt32 data_len,
1398                               SilcCipher cipher, SilcHmac hmac)
1399 {
1400   unsigned char src_id_data[32], dst_id_data[32];
1401   SilcUInt32 src_id_len, dst_id_len;
1402
1403   if (src_id)
1404     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1405                         sizeof(src_id_data), &src_id_len))
1406       return FALSE;
1407   if (dst_id)
1408     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1409                         sizeof(dst_id_data), &dst_id_len))
1410       return FALSE;
1411
1412   return silc_packet_send_raw(stream, type, flags,
1413                               src_id ? src_id_type : stream->src_id_type,
1414                               src_id ? src_id_data : stream->src_id,
1415                               src_id ? src_id_len : stream->src_id_len,
1416                               dst_id ? dst_id_type : stream->dst_id_type,
1417                               dst_id ? dst_id_data : stream->dst_id,
1418                               dst_id ? dst_id_len : stream->dst_id_len,
1419                               data, data_len,
1420                               cipher ? cipher : stream->send_key[0],
1421                               hmac ? hmac : stream->send_hmac[0]);
1422 }
1423
1424 /* Sends packet after formatting the arguments to buffer */
1425
1426 SilcBool silc_packet_send_va(SilcPacketStream stream,
1427                              SilcPacketType type, SilcPacketFlags flags, ...)
1428 {
1429   SilcBufferStruct buf;
1430   SilcBool ret;
1431   va_list va;
1432
1433   va_start(va, flags);
1434
1435   memset(&buf, 0, sizeof(buf));
1436   if (silc_buffer_format_vp(&buf, va) < 0) {
1437     va_end(va);
1438     return FALSE;
1439   }
1440
1441   ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1442                          silc_buffer_len(&buf));
1443
1444   silc_buffer_purge(&buf);
1445   va_end(va);
1446
1447   return ret;
1448 }
1449
1450 /* Sends packet after formatting the arguments to buffer, extended routine */
1451
1452 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1453                                  SilcPacketType type, SilcPacketFlags flags,
1454                                  SilcIdType src_id_type, void *src_id,
1455                                  SilcIdType dst_id_type, void *dst_id,
1456                                  SilcCipher cipher, SilcHmac hmac, ...)
1457 {
1458   SilcBufferStruct buf;
1459   SilcBool ret;
1460   va_list va;
1461
1462   va_start(va, hmac);
1463
1464   memset(&buf, 0, sizeof(buf));
1465   if (silc_buffer_format_vp(&buf, va) < 0) {
1466     va_end(va);
1467     return FALSE;
1468   }
1469
1470   ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1471                              dst_id_type, dst_id, silc_buffer_data(&buf),
1472                              silc_buffer_len(&buf), cipher, hmac);
1473
1474   silc_buffer_purge(&buf);
1475   va_end(va);
1476
1477   return TRUE;
1478 }
1479
1480 /***************************** Packet Receiving *****************************/
1481
1482 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1483
1484 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1485                                              const unsigned char *data,
1486                                              SilcUInt32 data_len,
1487                                              const unsigned char *packet_mac,
1488                                              const unsigned char *packet_seq,
1489                                              SilcUInt32 sequence)
1490 {
1491   /* Check MAC */
1492   if (hmac) {
1493     unsigned char mac[32], psn[4];
1494     SilcUInt32 mac_len;
1495
1496     SILC_LOG_DEBUG(("Verifying MAC"));
1497
1498     /* Compute HMAC of packet */
1499     silc_hmac_init(hmac);
1500
1501     if (!packet_seq) {
1502       SILC_PUT32_MSB(sequence, psn);
1503       silc_hmac_update(hmac, psn, 4);
1504     } else
1505       silc_hmac_update(hmac, packet_seq, 4);
1506
1507     silc_hmac_update(hmac, data, data_len);
1508     silc_hmac_final(hmac, mac, &mac_len);
1509
1510     /* Compare the MAC's */
1511     if (memcmp(packet_mac, mac, mac_len)) {
1512       SILC_LOG_DEBUG(("MAC failed"));
1513       return FALSE;
1514     }
1515
1516     SILC_LOG_DEBUG(("MAC is Ok"));
1517   }
1518
1519   return TRUE;
1520 }
1521
1522 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1523    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1524
1525 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1526                                       SilcUInt32 sequence, SilcBuffer buffer,
1527                                       SilcBool normal)
1528 {
1529   if (normal == TRUE) {
1530     if (cipher) {
1531       /* Decrypt rest of the packet */
1532       SILC_LOG_DEBUG(("Decrypting the packet"));
1533       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1534                                silc_buffer_len(buffer), NULL))
1535         return -1;
1536     }
1537     return 0;
1538
1539   } else {
1540     /* Decrypt rest of the header plus padding */
1541     if (cipher) {
1542       SilcUInt16 len;
1543       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1544
1545       SILC_LOG_DEBUG(("Decrypting the header"));
1546
1547       /* Padding length + src id len + dst id len + header length - 16
1548          bytes already decrypted, gives the rest of the encrypted packet */
1549       silc_buffer_push(buffer, block_len);
1550       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1551               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1552              block_len);
1553       silc_buffer_pull(buffer, block_len);
1554
1555       if (len > silc_buffer_len(buffer)) {
1556         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1557                         "packet dropped"));
1558         return -1;
1559       }
1560       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1561                                len, NULL))
1562         return -1;
1563     }
1564
1565     return 1;
1566   }
1567 }
1568
1569 /* Parses the packet. This is called when a whole packet is ready to be
1570    parsed. The buffer sent must be already decrypted before calling this
1571    function. */
1572
1573 static inline SilcBool silc_packet_parse(SilcPacket packet)
1574 {
1575   SilcBuffer buffer = &packet->buffer;
1576   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1577   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1578   int ret;
1579
1580   SILC_LOG_DEBUG(("Parsing incoming packet"));
1581
1582   /* Parse the buffer.  This parses the SILC header of the packet. */
1583   ret = silc_buffer_unformat(buffer,
1584                              SILC_STR_ADVANCE,
1585                              SILC_STR_OFFSET(6),
1586                              SILC_STR_UI_CHAR(&src_id_len),
1587                              SILC_STR_UI_CHAR(&dst_id_len),
1588                              SILC_STR_UI_CHAR(&src_id_type),
1589                              SILC_STR_END);
1590   if (ret == -1) {
1591     if (!packet->stream->udp &&
1592         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1593       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1594     return FALSE;
1595   }
1596
1597   if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1598       dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1599     if (!packet->stream->udp &&
1600         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1601       SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1602                       packet->src_id_len, packet->dst_id_len));
1603     return FALSE;
1604   }
1605
1606   ret = silc_buffer_unformat(buffer,
1607                              SILC_STR_ADVANCE,
1608                              SILC_STR_DATA(&packet->src_id, src_id_len),
1609                              SILC_STR_UI_CHAR(&dst_id_type),
1610                              SILC_STR_DATA(&packet->dst_id, dst_id_len),
1611                              SILC_STR_OFFSET(padlen),
1612                              SILC_STR_END);
1613   if (ret == -1) {
1614     if (!packet->stream->udp &&
1615         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1616       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1617     return FALSE;
1618   }
1619
1620   if (src_id_type > SILC_ID_CHANNEL ||
1621       dst_id_type > SILC_ID_CHANNEL) {
1622     if (!packet->stream->udp &&
1623         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1624       SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1625                       src_id_type, dst_id_type));
1626     return FALSE;
1627   }
1628
1629   packet->src_id_len = src_id_len;
1630   packet->dst_id_len = dst_id_len;
1631   packet->src_id_type = src_id_type;
1632   packet->dst_id_type = dst_id_type;
1633
1634   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1635                    silc_buffer_len(buffer)), buffer->head,
1636                    silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1637
1638   SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1639                   silc_get_packet_name(packet->type)));
1640
1641   return TRUE;
1642 }
1643
1644 /* Dispatch packet to application.  Called with stream->lock locked. */
1645
1646 static void silc_packet_dispatch(SilcPacket packet)
1647 {
1648   SilcPacketStream stream = packet->stream;
1649   SilcPacketProcess p;
1650   SilcBool default_sent = FALSE;
1651   SilcPacketType *pt;
1652
1653   /* Dispatch packet to all packet processors that want it */
1654
1655   if (!stream->process) {
1656     /* Send to default processor as no others exist */
1657     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1658     silc_mutex_unlock(stream->lock);
1659     if (!stream->engine->callbacks->
1660         packet_receive(stream->engine, stream, packet,
1661                        stream->engine->callback_context,
1662                        stream->stream_context))
1663       silc_packet_free(packet);
1664     silc_mutex_lock(stream->lock);
1665     return;
1666   }
1667
1668   silc_dlist_start(stream->process);
1669   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1670
1671     /* If priority is 0 or less, we send to default processor first
1672        because default processor has 0 priority */
1673     if (!default_sent && p->priority <= 0) {
1674       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1675       default_sent = TRUE;
1676       silc_mutex_unlock(stream->lock);
1677       if (stream->engine->callbacks->
1678           packet_receive(stream->engine, stream, packet,
1679                          stream->engine->callback_context,
1680                          stream->stream_context)) {
1681         silc_mutex_lock(stream->lock);
1682         return;
1683       }
1684       silc_mutex_lock(stream->lock);
1685     }
1686
1687     /* Send to processor */
1688     if (!p->types) {
1689       /* Send all packet types */
1690       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1691       silc_mutex_unlock(stream->lock);
1692       if (p->callbacks->packet_receive(stream->engine, stream, packet,
1693                                        p->callback_context,
1694                                        stream->stream_context)) {
1695         silc_mutex_lock(stream->lock);
1696         return;
1697       }
1698       silc_mutex_lock(stream->lock);
1699     } else {
1700       /* Send specific types */
1701       for (pt = p->types; *pt; pt++) {
1702         if (*pt != packet->type)
1703           continue;
1704         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1705         silc_mutex_unlock(stream->lock);
1706         if (p->callbacks->packet_receive(stream->engine, stream, packet,
1707                                          p->callback_context,
1708                                          stream->stream_context)) {
1709           silc_mutex_lock(stream->lock);
1710           return;
1711         }
1712         silc_mutex_lock(stream->lock);
1713         break;
1714       }
1715     }
1716   }
1717
1718   if (!default_sent) {
1719     /* Send to default processor as it has not been sent yet */
1720     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1721     silc_mutex_unlock(stream->lock);
1722     if (stream->engine->callbacks->
1723         packet_receive(stream->engine, stream, packet,
1724                        stream->engine->callback_context,
1725                        stream->stream_context)) {
1726       silc_mutex_lock(stream->lock);
1727       return;
1728     }
1729     silc_mutex_lock(stream->lock);
1730   }
1731
1732   /* If we got here, no one wanted the packet, so drop it */
1733   silc_packet_free(packet);
1734 }
1735
1736 /* Process incoming data and parse packets.  Called with stream->lock
1737    locked. */
1738
1739 static void silc_packet_read_process(SilcPacketStream stream)
1740 {
1741   SilcCipher cipher;
1742   SilcHmac hmac;
1743   SilcPacket packet;
1744   SilcUInt8 sid;
1745   SilcUInt16 packetlen;
1746   SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1747   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1748   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1749   SilcBool normal;
1750   int ret;
1751
1752   /* Parse the packets from the data */
1753   while (silc_buffer_len(&stream->inbuf) > 0) {
1754     ivlen = psnlen = 0;
1755     cipher = stream->receive_key[0];
1756     hmac = stream->receive_hmac[0];
1757     normal = FALSE;
1758
1759     if (silc_buffer_len(&stream->inbuf) <
1760         (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1761          SILC_PACKET_MIN_HEADER_LEN)) {
1762       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1763       return;
1764     }
1765
1766     if (hmac)
1767       mac_len = silc_hmac_len(hmac);
1768     else
1769       mac_len = 0;
1770
1771     /* Decrypt first block of the packet to get the length field out */
1772     if (cipher) {
1773       block_len = silc_cipher_get_block_len(cipher);
1774
1775       if (stream->iv_included) {
1776         /* SID, IV and sequence number is included in the ciphertext */
1777         sid = (SilcUInt8)stream->inbuf.data[0];
1778         memcpy(iv, stream->inbuf.data + 1, block_len);
1779         ivlen = block_len + 1;
1780         psnlen = 4;
1781
1782         /* Check SID, and get correct decryption key */
1783         if (sid != stream->sid) {
1784           /* If SID is recent get the previous key and use it */
1785           if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1786               stream->receive_key[1] && !stream->receive_hmac[1]) {
1787             cipher = stream->receive_key[1];
1788             hmac = stream->receive_hmac[1];
1789           } else {
1790             /* The SID is unknown, drop rest of the data in buffer */
1791             SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1792                             sid, stream->sid));
1793             silc_mutex_unlock(stream->lock);
1794             SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1795             silc_mutex_lock(stream->lock);
1796             silc_buffer_reset(&stream->inbuf);
1797             return;
1798           }
1799         }
1800       } else {
1801         memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1802       }
1803
1804       silc_cipher_decrypt(cipher, stream->inbuf.data + ivlen, tmp,
1805                           block_len, iv);
1806
1807       header = tmp;
1808       if (stream->iv_included) {
1809         /* Take sequence number from packet */
1810         packet_seq = header;
1811         header += 4;
1812       }
1813     } else {
1814       block_len = SILC_PACKET_MIN_HEADER_LEN;
1815       header = stream->inbuf.data;
1816     }
1817
1818     /* Get packet length and full packet length with padding */
1819     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1820
1821     /* Sanity checks */
1822     if (packetlen < SILC_PACKET_MIN_LEN) {
1823       if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
1824         SILC_LOG_ERROR(("Received too short packet"));
1825       silc_mutex_unlock(stream->lock);
1826       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1827       silc_mutex_lock(stream->lock);
1828       memset(tmp, 0, sizeof(tmp));
1829       silc_buffer_reset(&stream->inbuf);
1830       return;
1831     }
1832
1833     if (silc_buffer_len(&stream->inbuf) < paddedlen + ivlen + mac_len) {
1834       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1835                       "(%d bytes)",
1836                       paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1837       memset(tmp, 0, sizeof(tmp));
1838       return;
1839     }
1840
1841     /* Check MAC of the packet */
1842     if (!silc_packet_check_mac(hmac, stream->inbuf.data,
1843                                paddedlen + ivlen,
1844                                stream->inbuf.data + ivlen + paddedlen,
1845                                packet_seq, stream->receive_psn)) {
1846       silc_mutex_unlock(stream->lock);
1847       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1848       silc_mutex_lock(stream->lock);
1849       memset(tmp, 0, sizeof(tmp));
1850       silc_buffer_reset(&stream->inbuf);
1851       return;
1852     }
1853
1854     /* Get packet */
1855     packet = silc_packet_alloc(stream->engine);
1856     if (!packet) {
1857       silc_mutex_unlock(stream->lock);
1858       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1859       silc_mutex_lock(stream->lock);
1860       memset(tmp, 0, sizeof(tmp));
1861       silc_buffer_reset(&stream->inbuf);
1862       return;
1863     }
1864     packet->stream = stream;
1865
1866     /* Allocate more space to packet buffer, if needed */
1867     if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1868       if (!silc_buffer_realloc(&packet->buffer,
1869                                silc_buffer_truelen(&packet->buffer) +
1870                                (paddedlen -
1871                                 silc_buffer_truelen(&packet->buffer)))) {
1872         silc_mutex_unlock(stream->lock);
1873         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1874         silc_mutex_lock(stream->lock);
1875         silc_packet_free(packet);
1876         memset(tmp, 0, sizeof(tmp));
1877         silc_buffer_reset(&stream->inbuf);
1878         return;
1879       }
1880     }
1881
1882     /* Parse packet header */
1883     packet->flags = (SilcPacketFlags)header[2];
1884     packet->type = (SilcPacketType)header[3];
1885
1886     if (stream->engine->local_is_router) {
1887       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1888           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1889         normal = FALSE;
1890       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1891                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1892                 stream->is_router == TRUE))
1893         normal = TRUE;
1894     } else {
1895       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1896           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1897         normal = FALSE;
1898       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1899         normal = TRUE;
1900     }
1901
1902     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1903                       stream->receive_psn, paddedlen + ivlen + mac_len),
1904                      stream->inbuf.data, paddedlen + ivlen + mac_len);
1905
1906     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1907     silc_buffer_pull_tail(&packet->buffer, paddedlen);
1908     silc_buffer_put(&packet->buffer, header, block_len - psnlen);
1909     silc_buffer_pull(&packet->buffer, block_len - psnlen);
1910     silc_buffer_put(&packet->buffer, (stream->inbuf.data + ivlen +
1911                                       psnlen + (block_len - psnlen)),
1912                     paddedlen - ivlen - psnlen - (block_len - psnlen));
1913     if (cipher) {
1914       silc_cipher_set_iv(cipher, iv);
1915       ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
1916                                 &packet->buffer, normal);
1917       if (ret < 0) {
1918         silc_mutex_unlock(stream->lock);
1919         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1920         silc_mutex_lock(stream->lock);
1921         silc_packet_free(packet);
1922         memset(tmp, 0, sizeof(tmp));
1923         return;
1924       }
1925
1926       stream->receive_psn++;
1927     }
1928     silc_buffer_push(&packet->buffer, block_len);
1929
1930     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1931     silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1932
1933     /* Parse the packet */
1934     if (!silc_packet_parse(packet)) {
1935       silc_mutex_unlock(stream->lock);
1936       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1937       silc_mutex_lock(stream->lock);
1938       silc_packet_free(packet);
1939       memset(tmp, 0, sizeof(tmp));
1940       return;
1941     }
1942
1943     /* Dispatch the packet to application */
1944     silc_packet_dispatch(packet);
1945   }
1946
1947   silc_buffer_reset(&stream->inbuf);
1948 }
1949
1950
1951 /****************************** Packet Waiting ******************************/
1952
1953 /* Packet wait receive callback */
1954 static SilcBool
1955 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1956                                 SilcPacketStream stream,
1957                                 SilcPacket packet,
1958                                 void *callback_context,
1959                                 void *stream_context);
1960
1961 /* Packet waiting callbacks */
1962 static SilcPacketCallbacks silc_packet_wait_cbs =
1963 {
1964   silc_packet_wait_packet_receive, NULL, NULL
1965 };
1966
1967 /* Packet waiting context */
1968 typedef struct {
1969   SilcMutex wait_lock;
1970   SilcCond wait_cond;
1971   SilcList packet_queue;
1972   unsigned int stopped     : 1;
1973 } *SilcPacketWait;
1974
1975 /* Packet wait receive callback */
1976
1977 static SilcBool
1978 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1979                                 SilcPacketStream stream,
1980                                 SilcPacket packet,
1981                                 void *callback_context,
1982                                 void *stream_context)
1983 {
1984   SilcPacketWait pw = callback_context;
1985
1986   /* Signal the waiting thread for a new packet */
1987   silc_mutex_lock(pw->wait_lock);
1988
1989   if (pw->stopped) {
1990     silc_mutex_unlock(pw->wait_lock);
1991     return FALSE;
1992   }
1993
1994   silc_list_add(pw->packet_queue, packet);
1995   silc_cond_broadcast(pw->wait_cond);
1996
1997   silc_mutex_unlock(pw->wait_lock);
1998
1999   return TRUE;
2000 }
2001
2002 /* Initialize packet waiting */
2003
2004 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2005 {
2006   SilcPacketWait pw;
2007   SilcBool ret;
2008   va_list ap;
2009
2010   pw = silc_calloc(1, sizeof(*pw));
2011   if (!pw)
2012     return NULL;
2013
2014   /* Allocate mutex and conditional variable */
2015   if (!silc_mutex_alloc(&pw->wait_lock)) {
2016     silc_free(pw);
2017     return NULL;
2018   }
2019   if (!silc_cond_alloc(&pw->wait_cond)) {
2020     silc_mutex_free(pw->wait_lock);
2021     silc_free(pw);
2022     return NULL;
2023   }
2024
2025   /* Link to the packet stream for the requested packet types */
2026   va_start(ap, stream);
2027   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2028                                    10000000, ap);
2029   va_end(ap);
2030   if (!ret) {
2031     silc_cond_free(pw->wait_cond);
2032     silc_mutex_free(pw->wait_lock);
2033     silc_free(pw);
2034     return NULL;
2035   }
2036
2037   /* Initialize packet queue */
2038   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2039
2040   return (void *)pw;
2041 }
2042
2043 /* Uninitialize packet waiting */
2044
2045 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2046 {
2047   SilcPacketWait pw = waiter;
2048   SilcPacket packet;
2049
2050   /* Signal any threads to stop waiting */
2051   silc_mutex_lock(pw->wait_lock);
2052   pw->stopped = TRUE;
2053   silc_cond_broadcast(pw->wait_cond);
2054   silc_mutex_unlock(pw->wait_lock);
2055
2056   /* Re-acquire lock and free resources */
2057   silc_mutex_lock(pw->wait_lock);
2058   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2059
2060   /* Free any remaining packets */
2061   silc_list_start(pw->packet_queue);
2062   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2063     silc_packet_free(packet);
2064
2065   silc_mutex_unlock(pw->wait_lock);
2066   silc_cond_free(pw->wait_cond);
2067   silc_mutex_free(pw->wait_lock);
2068   silc_free(pw);
2069 }
2070
2071 /* Blocks thread until a packet has been received. */
2072
2073 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2074 {
2075   SilcPacketWait pw = waiter;
2076   SilcBool ret = FALSE;
2077
2078   silc_mutex_lock(pw->wait_lock);
2079
2080   /* Wait here until packet has arrived */
2081   while (silc_list_count(pw->packet_queue) == 0) {
2082     if (pw->stopped) {
2083       silc_mutex_unlock(pw->wait_lock);
2084       return -1;
2085     }
2086     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2087   }
2088
2089   /* Return packet */
2090   silc_list_start(pw->packet_queue);
2091   *return_packet = silc_list_get(pw->packet_queue);
2092   silc_list_del(pw->packet_queue, *return_packet);
2093
2094   silc_mutex_unlock(pw->wait_lock);
2095
2096   return ret == TRUE ? 1 : 0;
2097 }