Memory leak fixes.
[silc.git] / lib / silccore / silcpacket.c
1 /*
2
3   silcpacket.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2007 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 /* Per scheduler (which usually means per thread) data.  We put per scheduler
29    data here for accessing without locking.  SILC Schedule dictates that
30    tasks are dispatched in one thread, hence the per scheduler context. */
31 typedef struct {
32   SilcSchedule schedule;                 /* The scheduler */
33   SilcPacketEngine engine;               /* Packet engine */
34   SilcDList inbufs;                      /* Data inbut buffer list */
35   SilcUInt32 stream_count;               /* Number of streams using this */
36 } *SilcPacketEngineContext;
37
38 /* Packet engine */
39 struct SilcPacketEngineStruct {
40   SilcMutex lock;                        /* Engine lock */
41   SilcRng rng;                           /* RNG for engine */
42   SilcHashTable contexts;                /* Per scheduler contexts */
43   SilcPacketCallbacks *callbacks;        /* Packet callbacks */
44   void *callback_context;                /* Context for callbacks */
45   SilcList streams;                      /* All streams in engine */
46   SilcList packet_pool;                  /* Free list for received packets */
47   SilcHashTable udp_remote;              /* UDP remote streams, or NULL */
48   unsigned int local_is_router    : 1;
49 };
50
51 /* Packet processor context */
52 typedef struct SilcPacketProcessStruct {
53   SilcPacketType *types;                 /* Packets to process */
54   SilcPacketCallbacks *callbacks;        /* Callbacks or NULL */
55   void *callback_context;
56   SilcInt32 priority;                    /* Priority */
57 } *SilcPacketProcess;
58
59 /* UDP remote stream tuple */
60 typedef struct {
61   char *remote_ip;                       /* Remote IP address */
62   SilcUInt16 remote_port;                /* Remote port */
63 } *SilcPacketRemoteUDP;
64
65 /* Packet stream */
66 struct SilcPacketStreamStruct {
67   struct SilcPacketStreamStruct *next;
68   SilcPacketEngineContext sc;            /* Per scheduler context */
69   SilcStream stream;                     /* Underlaying stream */
70   SilcMutex lock;                        /* Packet stream lock */
71   SilcDList process;                     /* Packet processors, or NULL */
72   SilcPacketRemoteUDP remote_udp;        /* UDP remote stream tuple, or NULL */
73   void *stream_context;                  /* Stream context */
74   SilcBufferStruct outbuf;               /* Out buffer */
75   SilcBuffer inbuf;                      /* Inbuf from inbuf list or NULL */
76   SilcCipher send_key[2];                /* Sending key */
77   SilcHmac send_hmac[2];                 /* Sending HMAC */
78   SilcCipher receive_key[2];             /* Receiving key */
79   SilcHmac receive_hmac[2];              /* Receiving HMAC */
80   unsigned char *src_id;                 /* Source ID */
81   unsigned char *dst_id;                 /* Destination ID */
82   SilcUInt32 send_psn;                   /* Sending sequence */
83   SilcUInt32 receive_psn;                /* Receiving sequence */
84   SilcAtomic8 refcnt;                    /* Reference counter */
85   SilcUInt8 sid;                         /* Security ID, set if IV included */
86   unsigned int src_id_len  : 6;
87   unsigned int src_id_type : 2;
88   unsigned int dst_id_len  : 6;
89   unsigned int dst_id_type : 2;
90   unsigned int is_router   : 1;          /* Set if router stream */
91   unsigned int destroyed   : 1;          /* Set if destroyed */
92   unsigned int iv_included : 1;          /* Set if IV included */
93   unsigned int udp         : 1;          /* UDP remote stream */
94 };
95
96 /* Initial size of stream buffers */
97 #define SILC_PACKET_DEFAULT_SIZE  1024
98
99 /* Header length without source and destination ID's. */
100 #define SILC_PACKET_HEADER_LEN 10
101
102 /* Minimum length of SILC Packet Header. */
103 #define SILC_PACKET_MIN_HEADER_LEN 16
104 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
105
106 /* Maximum padding length */
107 #define SILC_PACKET_MAX_PADLEN 128
108
109 /* Default padding length */
110 #define SILC_PACKET_DEFAULT_PADLEN 16
111
112 /* Minimum packet length */
113 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
114
115 /* Returns true length of the packet. */
116 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
117 do {                                                                     \
118   SILC_GET16_MSB((__ret_truelen), (__packetdata));                       \
119   (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4];    \
120 } while(0)
121
122 /* Calculates the data length with given header length.  This macro
123    can be used to check whether the data_len with header_len exceeds
124    SILC_PACKET_MAX_LEN.  If it does, this returns the new data_len
125    so that the SILC_PACKET_MAX_LEN is not exceeded.  If the data_len
126    plus header_len fits SILC_PACKET_MAX_LEN the returned data length
127    is the data_len given as argument. */
128 #define SILC_PACKET_DATALEN(data_len, header_len)                         \
129   ((data_len + header_len) > SILC_PACKET_MAX_LEN ?                        \
130    data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
131
132 /* Calculates the length of the padding in the packet. */
133 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen)               \
134 do {                                                                        \
135   __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) %                  \
136               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN));  \
137   if (__padlen < 8)                                                         \
138     __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
139 } while(0)
140
141 /* Returns the length of the padding up to the maximum length, which
142    is 128 bytes.*/
143 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen)          \
144 do {                                                                       \
145   __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) %                     \
146               ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
147 } while(0)
148
149 /* EOS callback */
150 #define SILC_PACKET_CALLBACK_EOS(s)                                     \
151 do {                                                                    \
152   (s)->sc->engine->callbacks->eos((s)->sc->engine, s,                   \
153                                   (s)->sc->engine->callback_context,    \
154                                   (s)->stream_context);                 \
155 } while(0)
156
157 /* Error callback */
158 #define SILC_PACKET_CALLBACK_ERROR(s, err)                              \
159 do {                                                                    \
160   (s)->sc->engine->callbacks->error((s)->sc->engine, s, err,            \
161                                     (s)->sc->engine->callback_context,  \
162                                     (s)->stream_context);               \
163 } while(0)
164
165 static SilcBool silc_packet_dispatch(SilcPacket packet);
166 static void silc_packet_read_process(SilcPacketStream stream);
167 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
168                                             SilcPacketType type,
169                                             SilcPacketFlags flags,
170                                             SilcIdType src_id_type,
171                                             unsigned char *src_id,
172                                             SilcUInt32 src_id_len,
173                                             SilcIdType dst_id_type,
174                                             unsigned char *dst_id,
175                                             SilcUInt32 dst_id_len,
176                                             const unsigned char *data,
177                                             SilcUInt32 data_len,
178                                             SilcCipher cipher,
179                                             SilcHmac hmac);
180
181 /************************ Static utility functions **************************/
182
183 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
184
185 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
186 {
187   SilcPacket packet = context;
188   SilcPacketStream stream = packet->stream;
189
190   SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
191
192   silc_mutex_lock(stream->lock);
193   if (!stream->destroyed)
194     silc_packet_dispatch(packet);
195   silc_mutex_unlock(stream->lock);
196   silc_packet_stream_unref(stream);
197 }
198
199 /* Write data to the stream.  Must be called with ps->lock locked.  Unlocks
200    the lock inside this function, unless no_unlock is TRUE.  Unlocks always
201    in case it returns FALSE. */
202
203 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
204                                                 SilcBool no_unlock)
205 {
206   SilcStream stream;
207   SilcBool connected;
208   int i;
209
210   if (ps->udp)
211     stream = ((SilcPacketStream)ps->stream)->stream;
212   else
213     stream = ps->stream;
214
215   if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
216     if (!connected) {
217       /* Connectionless UDP stream */
218       while (silc_buffer_len(&ps->outbuf) > 0) {
219         i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
220                               ps->remote_udp->remote_port,
221                               ps->outbuf.data, silc_buffer_len(&ps->outbuf));
222         if (silc_unlikely(i == -2)) {
223           /* Error */
224           silc_buffer_reset(&ps->outbuf);
225           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
226           return FALSE;
227         }
228
229         if (silc_unlikely(i == -1)) {
230           /* Cannot write now, write later. */
231           if (!no_unlock)
232             silc_mutex_unlock(ps->lock);
233           return TRUE;
234         }
235
236         /* Wrote data */
237         silc_buffer_pull(&ps->outbuf, i);
238       }
239
240       silc_buffer_reset(&ps->outbuf);
241       if (!no_unlock)
242         silc_mutex_unlock(ps->lock);
243
244       return TRUE;
245     }
246   }
247
248   /* Write the data to the stream */
249   while (silc_buffer_len(&ps->outbuf) > 0) {
250     i = silc_stream_write(stream, ps->outbuf.data,
251                           silc_buffer_len(&ps->outbuf));
252     if (silc_unlikely(i == 0)) {
253       /* EOS */
254       silc_buffer_reset(&ps->outbuf);
255       silc_mutex_unlock(ps->lock);
256       SILC_PACKET_CALLBACK_EOS(ps);
257       return FALSE;
258     }
259
260     if (silc_unlikely(i == -2)) {
261       /* Error */
262       silc_buffer_reset(&ps->outbuf);
263       silc_mutex_unlock(ps->lock);
264       SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
265       return FALSE;
266     }
267
268     if (silc_unlikely(i == -1)) {
269       /* Cannot write now, write later. */
270       if (!no_unlock)
271         silc_mutex_unlock(ps->lock);
272       return TRUE;
273     }
274
275     /* Wrote data */
276     silc_buffer_pull(&ps->outbuf, i);
277   }
278
279   silc_buffer_reset(&ps->outbuf);
280   if (!no_unlock)
281     silc_mutex_unlock(ps->lock);
282
283   return TRUE;
284 }
285
286 /* Reads data from stream.  Must be called with ps->lock locked.  If this
287    returns FALSE the lock has been unlocked.  If this returns packet stream
288    to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
289    It is returned if the stream is UDP and remote UDP stream exists for
290    the sender of the packet. */
291
292 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
293                                                SilcPacketStream *ret_ps)
294 {
295   SilcStream stream = ps->stream;
296   SilcBuffer inbuf;
297   SilcBool connected;
298   int ret;
299
300   /* Get inbuf.  If there is already some data for this stream in the buffer
301      we already have it.  Otherwise get the current one from list, it will
302      include the data. */
303   inbuf = ps->inbuf;
304   if (!inbuf) {
305     silc_dlist_start(ps->sc->inbufs);
306     inbuf = silc_dlist_get(ps->sc->inbufs);
307     if (!inbuf) {
308       /* Allocate new data input buffer */
309       inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
310       if (!inbuf) {
311         silc_mutex_unlock(ps->lock);
312         return FALSE;
313       }
314       silc_buffer_reset(inbuf);
315       silc_dlist_add(ps->sc->inbufs, inbuf);
316     }
317   }
318
319   /* Make sure there is enough room to read */
320   if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
321     silc_buffer_realloc(inbuf, silc_buffer_truelen(inbuf) +
322                         (SILC_PACKET_DEFAULT_SIZE * 2));
323
324   if (silc_socket_stream_is_udp(stream, &connected)) {
325     if (!connected) {
326       /* Connectionless UDP stream, read one UDP packet */
327       char remote_ip[64], tuple[64];
328       int remote_port;
329       SilcPacketStream remote;
330
331       ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
332                                  &remote_port, inbuf->tail,
333                                  silc_buffer_taillen(inbuf));
334
335       if (silc_unlikely(ret < 0)) {
336         silc_mutex_unlock(ps->lock);
337         if (ret == -1) {
338           /* Cannot read now, do it later. */
339           silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
340           return FALSE;
341         }
342
343         /* Error */
344         silc_buffer_reset(inbuf);
345         SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
346         return FALSE;
347       }
348
349       /* See if remote packet stream exist for this sender */
350       silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
351       silc_mutex_lock(ps->sc->engine->lock);
352       if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
353                                (void *)&remote)) {
354         silc_mutex_unlock(ps->sc->engine->lock);
355         SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
356                         remote_port, remote));
357         silc_mutex_unlock(ps->lock);
358         silc_mutex_lock(remote->lock);
359         *ret_ps = remote;
360         return TRUE;
361       }
362       silc_mutex_unlock(ps->sc->engine->lock);
363
364       /* Unknown sender */
365       if (!ps->remote_udp) {
366         ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
367         if (silc_unlikely(!ps->remote_udp)) {
368           silc_mutex_unlock(ps->lock);
369           SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
370           return FALSE;
371         }
372       }
373
374       /* Save sender IP and port */
375       silc_free(ps->remote_udp->remote_ip);
376       ps->remote_udp->remote_ip = strdup(remote_ip);
377       ps->remote_udp->remote_port = remote_port;
378
379       silc_buffer_pull_tail(inbuf, ret);
380       return TRUE;
381     }
382   }
383
384   /* Read data from the stream */
385   ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
386   if (silc_unlikely(ret <= 0)) {
387     silc_mutex_unlock(ps->lock);
388     if (ret == 0) {
389       /* EOS */
390       silc_buffer_reset(inbuf);
391       SILC_PACKET_CALLBACK_EOS(ps);
392       return FALSE;
393     }
394
395     if (ret == -1) {
396       /* Cannot read now, do it later. */
397       silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
398       return FALSE;
399     }
400
401     /* Error */
402     silc_buffer_reset(inbuf);
403     SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
404     return FALSE;
405   }
406
407   silc_buffer_pull_tail(inbuf, ret);
408   return TRUE;
409 }
410
411 /* Our stream IO notifier callback. */
412
413 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
414                                   void *context)
415 {
416   SilcPacketStream remote = NULL, ps = context;
417
418   silc_mutex_lock(ps->lock);
419
420   if (silc_unlikely(ps->destroyed)) {
421     silc_mutex_unlock(ps->lock);
422     return;
423   }
424
425   switch (status) {
426   case SILC_STREAM_CAN_READ:
427     /* Reading is locked also with stream->lock because we may be reading
428        at the same time other thread is writing to same underlaying stream. */
429     SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
430
431     /* Read data from stream */
432     if (!silc_packet_stream_read(ps, &remote))
433       return;
434
435     /* Now process the data */
436     silc_packet_stream_ref(ps);
437     if (!remote) {
438       silc_packet_read_process(ps);
439       silc_mutex_unlock(ps->lock);
440     } else {
441       silc_packet_read_process(remote);
442       silc_mutex_unlock(remote->lock);
443     }
444     silc_packet_stream_unref(ps);
445     break;
446
447   case SILC_STREAM_CAN_WRITE:
448     SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
449                     ps->stream, ps));
450
451     if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
452       silc_mutex_unlock(ps->lock);
453       return;
454     }
455
456     /* Write pending data to stream */
457     silc_packet_stream_write(ps, FALSE);
458     break;
459
460   default:
461     silc_mutex_unlock(ps->lock);
462     break;
463   }
464 }
465
466 /* Allocate packet */
467
468 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
469 {
470   SilcPacket packet;
471
472   SILC_LOG_DEBUG(("Packet pool count %d",
473                   silc_list_count(engine->packet_pool)));
474
475   silc_mutex_lock(engine->lock);
476
477   /* Get packet from freelist or allocate new one. */
478   packet = silc_list_get(engine->packet_pool);
479   if (!packet) {
480     void *tmp;
481
482     silc_mutex_unlock(engine->lock);
483
484     packet = silc_calloc(1, sizeof(*packet));
485     if (silc_unlikely(!packet))
486       return NULL;
487
488     SILC_LOG_DEBUG(("Allocating new packet %p", packet));
489
490     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
491     if (silc_unlikely(!tmp)) {
492       silc_free(packet);
493       return NULL;
494     }
495     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
496     silc_buffer_reset(&packet->buffer);
497
498     return packet;
499   }
500
501   SILC_LOG_DEBUG(("Get packet %p", packet));
502
503   /* Delete from freelist */
504   silc_list_del(engine->packet_pool, packet);
505
506   silc_mutex_unlock(engine->lock);
507
508   return packet;
509 }
510
511 /* UDP remote stream hash table destructor */
512
513 static void silc_packet_engine_hash_destr(void *key, void *context,
514                                           void *user_context)
515 {
516   silc_free(key);
517 }
518
519 /* Per scheduler context hash table destructor */
520
521 static void silc_packet_engine_context_destr(void *key, void *context,
522                                              void *user_context)
523 {
524   SilcPacketEngineContext sc = context;
525   SilcBuffer buffer;
526
527   silc_dlist_start(sc->inbufs);
528   while ((buffer = silc_dlist_get(sc->inbufs))) {
529     silc_buffer_clear(buffer);
530     silc_buffer_free(buffer);
531     silc_dlist_del(sc->inbufs, buffer);
532   }
533
534   silc_dlist_uninit(sc->inbufs);
535   silc_free(sc);
536 }
537
538
539 /******************************** Packet API ********************************/
540
541 /* Allocate new packet engine */
542
543 SilcPacketEngine
544 silc_packet_engine_start(SilcRng rng, SilcBool router,
545                          SilcPacketCallbacks *callbacks,
546                          void *callback_context)
547 {
548   SilcPacketEngine engine;
549   SilcPacket packet;
550   int i;
551   void *tmp;
552
553   SILC_LOG_DEBUG(("Starting new packet engine"));
554
555   if (!callbacks)
556     return NULL;
557   if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
558     return NULL;
559
560   engine = silc_calloc(1, sizeof(*engine));
561   if (!engine)
562     return NULL;
563
564   engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
565                                            silc_packet_engine_context_destr,
566                                            engine, TRUE);
567   if (!engine->contexts) {
568     silc_free(engine);
569     return NULL;
570   }
571
572   engine->rng = rng;
573   engine->local_is_router = router;
574   engine->callbacks = callbacks;
575   engine->callback_context = callback_context;
576   silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
577   silc_mutex_alloc(&engine->lock);
578
579   /* Allocate packet free list */
580   silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
581   for (i = 0; i < 5; i++) {
582     packet = silc_calloc(1, sizeof(*packet));
583     if (!packet) {
584       silc_packet_engine_stop(engine);
585       return NULL;
586     }
587
588     tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
589     if (!tmp) {
590       silc_packet_engine_stop(engine);
591       return NULL;
592     }
593     silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
594     silc_buffer_reset(&packet->buffer);
595
596     silc_list_add(engine->packet_pool, packet);
597   }
598   silc_list_start(engine->packet_pool);
599
600   return engine;
601 }
602
603 /* Stop packet engine */
604
605 void silc_packet_engine_stop(SilcPacketEngine engine)
606 {
607   SilcPacket packet;
608
609   SILC_LOG_DEBUG(("Stopping packet engine"));
610
611   if (!engine)
612     return;
613
614   /* Free packet free list */
615   silc_list_start(engine->packet_pool);
616   while ((packet = silc_list_get(engine->packet_pool))) {
617     silc_buffer_purge(&packet->buffer);
618     silc_free(packet);
619   }
620
621   silc_hash_table_free(engine->contexts);
622   silc_mutex_free(engine->lock);
623   silc_free(engine);
624 }
625
626 /* Create new packet stream */
627
628 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
629                                            SilcSchedule schedule,
630                                            SilcStream stream)
631 {
632   SilcPacketStream ps;
633   SilcBuffer inbuf;
634   void *tmp;
635
636   SILC_LOG_DEBUG(("Creating new packet stream"));
637
638   if (!engine || !stream)
639     return NULL;
640
641   ps = silc_calloc(1, sizeof(*ps));
642   if (!ps)
643     return NULL;
644
645   ps->stream = stream;
646   silc_atomic_init8(&ps->refcnt, 1);
647   silc_mutex_alloc(&ps->lock);
648
649   /* Allocate out buffer */
650   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
651   if (!tmp) {
652     silc_packet_stream_destroy(ps);
653     return NULL;
654   }
655   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
656   silc_buffer_reset(&ps->outbuf);
657
658   /* Initialize packet procesors list */
659   ps->process = silc_dlist_init();
660   if (!ps->process) {
661     silc_packet_stream_destroy(ps);
662     return NULL;
663   }
664
665   silc_mutex_lock(engine->lock);
666
667   /* Add per scheduler context */
668   if (!silc_hash_table_find(engine->contexts, schedule, NULL,
669                             (void *)&ps->sc)) {
670     ps->sc = silc_calloc(1, sizeof(*ps->sc));
671     if (!ps->sc) {
672       silc_packet_stream_destroy(ps);
673       silc_mutex_unlock(engine->lock);
674       return NULL;
675     }
676     ps->sc->engine = engine;
677     ps->sc->schedule = schedule;
678
679     /* Allocate data input buffer */
680     inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
681     if (!inbuf) {
682       silc_free(ps->sc);
683       ps->sc = NULL;
684       silc_packet_stream_destroy(ps);
685       silc_mutex_unlock(engine->lock);
686       return NULL;
687     }
688     silc_buffer_reset(inbuf);
689
690     ps->sc->inbufs = silc_dlist_init();
691     if (!ps->sc->inbufs) {
692       silc_buffer_free(inbuf);
693       silc_free(ps->sc);
694       ps->sc = NULL;
695       silc_packet_stream_destroy(ps);
696       silc_mutex_unlock(engine->lock);
697       return NULL;
698     }
699     silc_dlist_add(ps->sc->inbufs, inbuf);
700
701     /* Add to per scheduler context hash table */
702     if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
703       silc_buffer_free(inbuf);
704       silc_dlist_del(ps->sc->inbufs, inbuf);
705       silc_free(ps->sc);
706       ps->sc = NULL;
707       silc_packet_stream_destroy(ps);
708       silc_mutex_unlock(engine->lock);
709       return NULL;
710     }
711   }
712   ps->sc->stream_count++;
713
714   /* Add the packet stream to engine */
715   silc_list_add(engine->streams, ps);
716
717   /* If this is UDP stream, allocate UDP remote stream hash table */
718   if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
719     engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
720                                                silc_hash_string_compare, NULL,
721                                                silc_packet_engine_hash_destr,
722                                                NULL, TRUE);
723
724   silc_mutex_unlock(engine->lock);
725
726   /* Set IO notifier callback.  This schedules this stream for I/O. */
727   if (!silc_stream_set_notifier(ps->stream, schedule,
728                                 silc_packet_stream_io, ps)) {
729     SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
730     silc_packet_stream_destroy(ps);
731     return NULL;
732   }
733
734   return ps;
735 }
736
737 /* Add new remote packet stream for UDP packet streams */
738
739 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
740                                                const char *remote_ip,
741                                                SilcUInt16 remote_port,
742                                                SilcPacket packet)
743 {
744   SilcPacketEngine engine = stream->sc->engine;
745   SilcPacketStream ps;
746   char *tuple;
747   void *tmp;
748
749   SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
750                   remote_ip, remote_port, stream));
751
752   if (!stream || !remote_ip || !remote_port)
753     return NULL;
754
755   if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
756     SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
757     return NULL;
758   }
759
760   ps = silc_calloc(1, sizeof(*ps));
761   if (!ps)
762     return NULL;
763   ps->sc = stream->sc;
764
765   silc_atomic_init8(&ps->refcnt, 1);
766   silc_mutex_alloc(&ps->lock);
767
768   /* Set the UDP packet stream as underlaying stream */
769   silc_packet_stream_ref(stream);
770   ps->stream = (SilcStream)stream;
771   ps->udp = TRUE;
772
773   /* Allocate out buffer */
774   tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
775   if (!tmp) {
776     silc_packet_stream_destroy(ps);
777     return NULL;
778   }
779   silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
780   silc_buffer_reset(&ps->outbuf);
781
782   /* Initialize packet procesors list */
783   ps->process = silc_dlist_init();
784   if (!ps->process) {
785     silc_packet_stream_destroy(ps);
786     return NULL;
787   }
788
789   /* Add to engine with this IP and port pair */
790   tuple = silc_format("%d%s", remote_port, remote_ip);
791   silc_mutex_lock(engine->lock);
792   if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
793     silc_mutex_unlock(engine->lock);
794     silc_packet_stream_destroy(ps);
795     return NULL;
796   }
797   silc_mutex_unlock(engine->lock);
798
799   /* Save remote IP and port pair */
800   ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
801   if (!ps->remote_udp) {
802     silc_packet_stream_destroy(ps);
803     return NULL;
804   }
805   ps->remote_udp->remote_port = remote_port;
806   ps->remote_udp->remote_ip = strdup(remote_ip);
807   if (!ps->remote_udp->remote_ip) {
808     silc_packet_stream_destroy(ps);
809     return NULL;
810   }
811
812   if (packet) {
813     /* Inject packet to the new stream */
814     packet->stream = ps;
815     silc_packet_stream_ref(ps);
816     silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
817                                    silc_packet_stream_inject_packet, packet,
818                                    0, 0);
819   }
820
821   return ps;
822 }
823
824 /* Destroy packet stream */
825
826 void silc_packet_stream_destroy(SilcPacketStream stream)
827 {
828   if (!stream)
829     return;
830
831   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
832     stream->destroyed = TRUE;
833
834     /* Close the underlaying stream */
835     if (!stream->udp && stream->stream)
836       silc_stream_close(stream->stream);
837     return;
838   }
839
840   SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
841
842   if (!stream->udp) {
843     /* Delete from engine */
844     silc_mutex_lock(stream->sc->engine->lock);
845     silc_list_del(stream->sc->engine->streams, stream);
846
847     /* Remove per scheduler context, if it is not used anymore */
848     if (stream->sc) {
849       stream->sc->stream_count--;
850       if (!stream->sc->stream_count)
851         silc_hash_table_del(stream->sc->engine->contexts,
852                             stream->sc->schedule);
853     }
854     silc_mutex_unlock(stream->sc->engine->lock);
855
856     /* Destroy the underlaying stream */
857     if (stream->stream)
858       silc_stream_destroy(stream->stream);
859   } else {
860     /* Delete from UDP remote hash table */
861     char tuple[64];
862     silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
863              stream->remote_udp->remote_ip);
864     silc_mutex_lock(stream->sc->engine->lock);
865     silc_hash_table_del(stream->sc->engine->udp_remote, tuple);
866     silc_mutex_unlock(stream->sc->engine->lock);
867
868     silc_free(stream->remote_udp->remote_ip);
869     silc_free(stream->remote_udp);
870
871     /* Unreference the underlaying packet stream */
872     silc_packet_stream_unref((SilcPacketStream)stream->stream);
873   }
874
875   /* Clear and free buffers */
876   silc_buffer_clear(&stream->outbuf);
877   silc_buffer_purge(&stream->outbuf);
878
879   if (stream->process) {
880     SilcPacketProcess p;
881     silc_dlist_start(stream->process);
882     while ((p = silc_dlist_get(stream->process))) {
883       silc_free(p->types);
884       silc_free(p);
885       silc_dlist_del(stream->process, p);
886     }
887     silc_dlist_uninit(stream->process);
888   }
889
890   /* Destroy ciphers and HMACs */
891   if (stream->send_key[0])
892     silc_cipher_free(stream->send_key[0]);
893   if (stream->receive_key[0])
894     silc_cipher_free(stream->receive_key[0]);
895   if (stream->send_hmac[0])
896     silc_hmac_free(stream->send_hmac[0]);
897   if (stream->receive_hmac[0])
898     silc_hmac_free(stream->receive_hmac[0]);
899   if (stream->send_key[1])
900     silc_cipher_free(stream->send_key[1]);
901   if (stream->receive_key[1])
902     silc_cipher_free(stream->receive_key[1]);
903   if (stream->send_hmac[1])
904     silc_hmac_free(stream->send_hmac[1]);
905   if (stream->receive_hmac[1])
906     silc_hmac_free(stream->receive_hmac[1]);
907
908   /* Free IDs */
909   silc_free(stream->src_id);
910   silc_free(stream->dst_id);
911
912   silc_atomic_uninit8(&stream->refcnt);
913   silc_mutex_free(stream->lock);
914   silc_free(stream);
915 }
916
917 /* Marks as router stream */
918
919 void silc_packet_stream_set_router(SilcPacketStream stream)
920 {
921   stream->is_router = TRUE;
922 }
923
924 /* Mark to include IV in ciphertext */
925
926 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
927 {
928   stream->iv_included = TRUE;
929 }
930
931 /* Links `callbacks' to `stream' for specified packet types */
932
933 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
934                                            SilcPacketCallbacks *callbacks,
935                                            void *callback_context,
936                                            int priority, va_list ap)
937 {
938   SilcPacketProcess p, e;
939   SilcInt32 packet_type;
940   int i;
941
942   SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
943
944   if (!callbacks)
945     return FALSE;
946   if (!callbacks->packet_receive)
947     return FALSE;
948
949   p = silc_calloc(1, sizeof(*p));
950   if (!p)
951     return FALSE;
952
953   p->priority = priority;
954   p->callbacks = callbacks;
955   p->callback_context = callback_context;
956
957   silc_mutex_lock(stream->lock);
958
959   if (!stream->process) {
960     stream->process = silc_dlist_init();
961     if (!stream->process) {
962       silc_mutex_unlock(stream->lock);
963       return FALSE;
964     }
965   }
966
967   /* According to priority set the procesor to correct position.  First
968      entry has the highest priority */
969   silc_dlist_start(stream->process);
970   while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
971     if (p->priority > e->priority) {
972       silc_dlist_insert(stream->process, p);
973       break;
974     }
975   }
976   if (!e)
977     silc_dlist_add(stream->process, p);
978
979   /* Get packet types to process */
980   i = 1;
981   while (1) {
982     packet_type = va_arg(ap, SilcInt32);
983
984     if (packet_type == SILC_PACKET_ANY)
985       break;
986
987     if (packet_type == -1)
988       break;
989
990     p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
991     if (!p->types) {
992       silc_mutex_unlock(stream->lock);
993       return FALSE;
994     }
995
996     p->types[i - 1] = (SilcPacketType)packet_type;
997     i++;
998   }
999   if (p->types)
1000     p->types[i - 1] = 0;
1001
1002   silc_mutex_unlock(stream->lock);
1003
1004   silc_packet_stream_ref(stream);
1005
1006   return TRUE;
1007 }
1008
1009 /* Links `callbacks' to `stream' for specified packet types */
1010
1011 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1012                                  SilcPacketCallbacks *callbacks,
1013                                  void *callback_context,
1014                                  int priority, ...)
1015 {
1016   va_list ap;
1017   SilcBool ret;
1018
1019   va_start(ap, priority);
1020   ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1021                                    priority, ap);
1022   va_end(ap);
1023
1024   return ret;
1025 }
1026
1027 /* Unlinks `callbacks' from `stream'. */
1028
1029 void silc_packet_stream_unlink(SilcPacketStream stream,
1030                                SilcPacketCallbacks *callbacks,
1031                                void *callback_context)
1032 {
1033   SilcPacketProcess p;
1034
1035   SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1036                   callbacks, stream));
1037
1038   silc_mutex_lock(stream->lock);
1039
1040   silc_dlist_start(stream->process);
1041   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1042     if (p->callbacks == callbacks &&
1043         p->callback_context == callback_context) {
1044       silc_dlist_del(stream->process, p);
1045       silc_free(p->types);
1046       silc_free(p);
1047       break;
1048     }
1049
1050   if (!silc_dlist_count(stream->process)) {
1051     silc_dlist_uninit(stream->process);
1052     stream->process = NULL;
1053   }
1054
1055   silc_mutex_unlock(stream->lock);
1056
1057   silc_packet_stream_unref(stream);
1058 }
1059
1060 /* Returns TRUE if stream is UDP stream */
1061
1062 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1063 {
1064   return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1065 }
1066
1067 /* Return packet sender IP and port for UDP packet stream */
1068
1069 SilcBool silc_packet_get_sender(SilcPacket packet,
1070                                 const char **sender_ip,
1071                                 SilcUInt16 *sender_port)
1072 {
1073   if (!packet->stream->remote_udp)
1074     return FALSE;
1075
1076   *sender_ip = packet->stream->remote_udp->remote_ip;
1077   *sender_port = packet->stream->remote_udp->remote_port;
1078
1079   return TRUE;
1080 }
1081
1082 /* Reference packet stream */
1083
1084 void silc_packet_stream_ref(SilcPacketStream stream)
1085 {
1086   silc_atomic_add_int8(&stream->refcnt, 1);
1087   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1088                   silc_atomic_get_int8(&stream->refcnt) - 1,
1089                   silc_atomic_get_int8(&stream->refcnt)));
1090 }
1091
1092 /* Unreference packet stream */
1093
1094 void silc_packet_stream_unref(SilcPacketStream stream)
1095 {
1096   SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1097                   silc_atomic_get_int8(&stream->refcnt),
1098                   silc_atomic_get_int8(&stream->refcnt) - 1));
1099   if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1100     return;
1101   silc_atomic_add_int8(&stream->refcnt, 1);
1102   silc_packet_stream_destroy(stream);
1103 }
1104
1105 /* Return engine */
1106
1107 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1108 {
1109   return stream->sc->engine;
1110 }
1111
1112 /* Set application context for packet stream */
1113
1114 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1115 {
1116   silc_mutex_lock(stream->lock);
1117   stream->stream_context = stream_context;
1118   silc_mutex_unlock(stream->lock);
1119 }
1120
1121 /* Return application context from packet stream */
1122
1123 void *silc_packet_get_context(SilcPacketStream stream)
1124 {
1125   void *context;
1126   silc_mutex_lock(stream->lock);
1127   context = stream->stream_context;
1128   silc_mutex_unlock(stream->lock);
1129   return context;
1130 }
1131
1132 /* Change underlaying stream */
1133
1134 void silc_packet_stream_set_stream(SilcPacketStream ps,
1135                                    SilcStream stream)
1136 {
1137   if (ps->stream)
1138     silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1139   ps->stream = stream;
1140   silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1141                            ps);
1142 }
1143
1144 /* Return underlaying stream */
1145
1146 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1147 {
1148   return stream->stream;
1149 }
1150
1151 /* Set keys. */
1152
1153 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1154                               SilcCipher receive_key, SilcHmac send_hmac,
1155                               SilcHmac receive_hmac, SilcBool rekey)
1156 {
1157   SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1158
1159   /* If doing rekey, send REKEY_DONE packet */
1160   if (rekey) {
1161     /* This will take stream lock. */
1162     if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1163                               stream->src_id_type, stream->src_id,
1164                               stream->src_id_len, stream->dst_id_type,
1165                               stream->dst_id, stream->dst_id_len,
1166                               NULL, 0, stream->send_key[0],
1167                               stream->send_hmac[0]))
1168       return FALSE;
1169
1170     /* Write the packet to the stream */
1171     if (!silc_packet_stream_write(stream, TRUE))
1172       return FALSE;
1173   } else {
1174     silc_mutex_lock(stream->lock);
1175   }
1176
1177   /* In case IV Included is set, save the old keys */
1178   if (stream->iv_included) {
1179     if (stream->send_key[1] && send_key) {
1180       silc_cipher_free(stream->send_key[1]);
1181       stream->send_key[1] = stream->send_key[0];
1182     }
1183     if (stream->receive_key[1] && receive_key) {
1184       silc_cipher_free(stream->receive_key[1]);
1185       stream->receive_key[1] = stream->receive_key[0];
1186     }
1187     if (stream->send_hmac[1] && send_hmac) {
1188       silc_hmac_free(stream->send_hmac[1]);
1189       stream->send_hmac[1] = stream->send_hmac[0];
1190     }
1191     if (stream->receive_hmac[1] && receive_hmac) {
1192       silc_hmac_free(stream->receive_hmac[1]);
1193       stream->receive_hmac[1] = stream->receive_hmac[0];
1194     }
1195   } else {
1196     if (stream->send_key[0] && send_key)
1197       silc_cipher_free(stream->send_key[0]);
1198     if (stream->receive_key[0] && receive_key)
1199       silc_cipher_free(stream->receive_key[0]);
1200     if (stream->send_hmac[0] && send_hmac)
1201       silc_hmac_free(stream->send_hmac[0]);
1202     if (stream->receive_hmac[0] && receive_hmac)
1203       silc_hmac_free(stream->receive_hmac[0]);
1204   }
1205
1206   /* Set keys */
1207   if (send_key)
1208     stream->send_key[0] = send_key;
1209   if (receive_key)
1210     stream->receive_key[0] = receive_key;
1211   if (send_hmac)
1212     stream->send_hmac[0] = send_hmac;
1213   if (receive_hmac)
1214     stream->receive_hmac[0] = receive_hmac;
1215
1216   silc_mutex_unlock(stream->lock);
1217   return TRUE;
1218 }
1219
1220 /* Return current ciphers from packet stream */
1221
1222 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1223                               SilcCipher *send_key,
1224                               SilcCipher *receive_key,
1225                               SilcHmac *send_hmac,
1226                               SilcHmac *receive_hmac)
1227 {
1228   if (!stream->send_key[0] && !stream->receive_key[0] &&
1229       !stream->send_hmac[0] && !stream->receive_hmac[0])
1230     return FALSE;
1231
1232   silc_mutex_lock(stream->lock);
1233
1234   if (send_key)
1235     *send_key = stream->send_key[0];
1236   if (receive_key)
1237     *receive_key = stream->receive_key[0];
1238   if (send_hmac)
1239     *send_hmac = stream->send_hmac[0];
1240   if (receive_hmac)
1241     *receive_hmac = stream->receive_hmac[0];
1242
1243   silc_mutex_unlock(stream->lock);
1244
1245   return TRUE;
1246 }
1247
1248 /* Set SILC IDs to packet stream */
1249
1250 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1251                              SilcIdType src_id_type, const void *src_id,
1252                              SilcIdType dst_id_type, const void *dst_id)
1253 {
1254   SilcUInt32 len;
1255   unsigned char tmp[32];
1256
1257   if (!src_id && !dst_id)
1258     return FALSE;
1259
1260   SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1261
1262   silc_mutex_lock(stream->lock);
1263
1264   if (src_id) {
1265     silc_free(stream->src_id);
1266     if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1267       silc_mutex_unlock(stream->lock);
1268       return FALSE;
1269     }
1270     stream->src_id = silc_memdup(tmp, len);
1271     if (!stream->src_id) {
1272       silc_mutex_unlock(stream->lock);
1273       return FALSE;
1274     }
1275     stream->src_id_type = src_id_type;
1276     stream->src_id_len = len;
1277   }
1278
1279   if (dst_id) {
1280     silc_free(stream->dst_id);
1281     if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1282       silc_mutex_unlock(stream->lock);
1283       return FALSE;
1284     }
1285     stream->dst_id = silc_memdup(tmp, len);
1286     if (!stream->dst_id) {
1287       silc_mutex_unlock(stream->lock);
1288       return FALSE;
1289     }
1290     stream->dst_id_type = dst_id_type;
1291     stream->dst_id_len = len;
1292   }
1293
1294   silc_mutex_unlock(stream->lock);
1295
1296   return TRUE;
1297 }
1298
1299 /* Adds Security ID (SID) */
1300
1301 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1302 {
1303   if (!stream->iv_included)
1304     return FALSE;
1305
1306   SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1307
1308   stream->sid = sid;
1309   return TRUE;
1310 }
1311
1312 /* Free packet */
1313
1314 void silc_packet_free(SilcPacket packet)
1315 {
1316   SilcPacketStream stream = packet->stream;
1317
1318   SILC_LOG_DEBUG(("Freeing packet %p", packet));
1319
1320   /* Check for double free */
1321   SILC_ASSERT(packet->stream != NULL);
1322
1323   packet->stream = NULL;
1324   packet->src_id = packet->dst_id = NULL;
1325   silc_buffer_reset(&packet->buffer);
1326
1327   silc_mutex_lock(stream->sc->engine->lock);
1328
1329   /* Put the packet back to freelist */
1330   silc_list_add(stream->sc->engine->packet_pool, packet);
1331   if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1332     silc_list_start(stream->sc->engine->packet_pool);
1333
1334   silc_mutex_unlock(stream->sc->engine->lock);
1335 }
1336
1337 /****************************** Packet Sending ******************************/
1338
1339 /* Prepare outgoing data buffer for packet sending.  Returns the
1340    pointer to that buffer into the `packet'. */
1341
1342 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1343                                                 SilcUInt32 totlen,
1344                                                 SilcHmac hmac,
1345                                                 SilcBuffer packet)
1346 {
1347   unsigned char *oldptr;
1348   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1349
1350   totlen += mac_len;
1351
1352   /* Allocate more space if needed */
1353   if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1354     if (!silc_buffer_realloc(&stream->outbuf,
1355                              silc_buffer_truelen(&stream->outbuf) + totlen))
1356       return FALSE;
1357   }
1358
1359   /* Pull data area for the new packet, and return pointer to the start of
1360      the data area and save the pointer in to the `packet'.  MAC is pulled
1361      later after it's computed. */
1362   oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1363   silc_buffer_set(packet, oldptr, totlen);
1364   silc_buffer_push_tail(packet, mac_len);
1365
1366   return TRUE;
1367 }
1368
1369 /* Increments counter when encrypting in counter mode. */
1370
1371 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1372                                                   SilcCipher cipher,
1373                                                   unsigned char *ret_iv)
1374 {
1375   unsigned char *iv = silc_cipher_get_iv(cipher);
1376   SilcUInt32 pc;
1377
1378   /* Increment packet counter */
1379   SILC_GET32_MSB(pc, iv + 8);
1380   pc++;
1381   SILC_PUT32_MSB(pc, iv + 8);
1382
1383   /* Reset block counter */
1384   memset(iv + 12, 0, 4);
1385
1386   /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1387   if (stream->iv_included) {
1388     /* Get new nonce */
1389     ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1390     ret_iv[1] = ret_iv[0] + iv[4];
1391     ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1392     ret_iv[3] = ret_iv[0] + ret_iv[2];
1393     SILC_PUT32_MSB(pc, ret_iv + 4);
1394     SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1395
1396     /* Set new nonce to counter block */
1397     memcpy(iv + 4, ret_iv, 4);
1398   }
1399
1400   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1401 }
1402
1403 /* Internal routine to assemble outgoing packet.  Assembles and encryptes
1404    the packet.  The silc_packet_stream_write needs to be called to send it
1405    after this returns TRUE. */
1406
1407 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1408                                             SilcPacketType type,
1409                                             SilcPacketFlags flags,
1410                                             SilcIdType src_id_type,
1411                                             unsigned char *src_id,
1412                                             SilcUInt32 src_id_len,
1413                                             SilcIdType dst_id_type,
1414                                             unsigned char *dst_id,
1415                                             SilcUInt32 dst_id_len,
1416                                             const unsigned char *data,
1417                                             SilcUInt32 data_len,
1418                                             SilcCipher cipher,
1419                                             SilcHmac hmac)
1420 {
1421   unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1422   int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1423   int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1424   SilcBool ctr;
1425   SilcBufferStruct packet;
1426
1427   SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1428                   "data len %d", silc_get_packet_name(type), stream->send_psn,
1429                   flags, src_id_type, dst_id_type, data_len));
1430
1431   /* Get the true length of the packet. This is saved as payload length
1432      into the packet header.  This does not include the length of the
1433      padding. */
1434   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1435                                             src_id_len + dst_id_len));
1436   enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1437                       src_id_len + dst_id_len);
1438
1439   /* If using CTR mode, increment the counter */
1440   ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1441   if (ctr) {
1442     silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1443
1444     /* If IV is included, the SID, IV and sequence number is added to packet */
1445     if (stream->iv_included && cipher) {
1446       psnlen = sizeof(psn);
1447       ivlen = 8 + 1;
1448       iv[0] = stream->sid;
1449     }
1450   } else {
1451     /* If IV is included, the SID, IV and sequence number is added to packet */
1452     if (stream->iv_included && cipher) {
1453       psnlen = sizeof(psn);
1454       ivlen = block_len + 1;
1455       iv[0] = stream->sid;
1456       memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1457     }
1458   }
1459
1460   /* We automatically figure out the packet structure from the packet
1461      type and flags, and calculate correct length.  Private messages with
1462      private keys and channel messages are special packets as their
1463      payload is encrypted already. */
1464   if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1465        flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1466       type == SILC_PACKET_CHANNEL_MESSAGE) {
1467
1468     /* Padding is calculated from header + IDs */
1469     if (!ctr)
1470       SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1471                           psnlen), block_len, padlen);
1472
1473     /* Length to encrypt, header + IDs + padding. */
1474     enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1475               padlen + psnlen);
1476   } else {
1477
1478     /* Padding is calculated from true length of the packet */
1479     if (flags & SILC_PACKET_FLAG_LONG_PAD)
1480       SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1481     else if (!ctr)
1482       SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1483
1484     enclen += padlen + psnlen;
1485   }
1486
1487   /* Remove implementation specific flags */
1488   flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1489
1490   /* Get random padding */
1491   for (i = 0; i < padlen; i++) tmppad[i] =
1492     silc_rng_get_byte_fast(stream->sc->engine->rng);
1493
1494   silc_mutex_lock(stream->lock);
1495
1496   /* Get packet pointer from the outgoing buffer */
1497   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1498                                               + psnlen, hmac, &packet))) {
1499     silc_mutex_unlock(stream->lock);
1500     return FALSE;
1501   }
1502
1503   SILC_PUT32_MSB(stream->send_psn, psn);
1504
1505   /* Create the packet.  This creates the SILC header, adds padding, and
1506      the actual packet data. */
1507   i = silc_buffer_format(&packet,
1508                          SILC_STR_DATA(iv, ivlen),
1509                          SILC_STR_DATA(psn, psnlen),
1510                          SILC_STR_UI_SHORT(truelen),
1511                          SILC_STR_UI_CHAR(flags),
1512                          SILC_STR_UI_CHAR(type),
1513                          SILC_STR_UI_CHAR(padlen),
1514                          SILC_STR_UI_CHAR(0),
1515                          SILC_STR_UI_CHAR(src_id_len),
1516                          SILC_STR_UI_CHAR(dst_id_len),
1517                          SILC_STR_UI_CHAR(src_id_type),
1518                          SILC_STR_DATA(src_id, src_id_len),
1519                          SILC_STR_UI_CHAR(dst_id_type),
1520                          SILC_STR_DATA(dst_id, dst_id_len),
1521                          SILC_STR_DATA(tmppad, padlen),
1522                          SILC_STR_DATA(data, data_len),
1523                          SILC_STR_END);
1524   if (silc_unlikely(i < 0)) {
1525     silc_mutex_unlock(stream->lock);
1526     return FALSE;
1527   }
1528
1529   SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1530                    silc_buffer_data(&packet), silc_buffer_len(&packet));
1531
1532   /* Encrypt the packet */
1533   if (silc_likely(cipher)) {
1534     SILC_LOG_DEBUG(("Encrypting packet"));
1535     if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1536                                            packet.data + ivlen, enclen,
1537                                            NULL))) {
1538       SILC_LOG_ERROR(("Packet encryption failed"));
1539       silc_mutex_unlock(stream->lock);
1540       return FALSE;
1541     }
1542   }
1543
1544   /* Compute HMAC */
1545   if (silc_likely(hmac)) {
1546     SilcUInt32 mac_len;
1547
1548     /* MAC is computed from the entire encrypted packet data, and put
1549        to the end of the packet. */
1550     silc_hmac_init(hmac);
1551     silc_hmac_update(hmac, psn, sizeof(psn));
1552     silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1553     silc_hmac_final(hmac, packet.tail, &mac_len);
1554     silc_buffer_pull_tail(&packet, mac_len);
1555     stream->send_psn++;
1556   }
1557
1558   return TRUE;
1559 }
1560
1561 /* Sends a packet */
1562
1563 SilcBool silc_packet_send(SilcPacketStream stream,
1564                           SilcPacketType type, SilcPacketFlags flags,
1565                           const unsigned char *data, SilcUInt32 data_len)
1566 {
1567   SilcBool ret;
1568
1569   ret = silc_packet_send_raw(stream, type, flags,
1570                              stream->src_id_type,
1571                              stream->src_id,
1572                              stream->src_id_len,
1573                              stream->dst_id_type,
1574                              stream->dst_id,
1575                              stream->dst_id_len,
1576                              data, data_len,
1577                              stream->send_key[0],
1578                              stream->send_hmac[0]);
1579
1580   /* Write the packet to the stream */
1581   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1582 }
1583
1584 /* Sends a packet, extended routine */
1585
1586 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1587                               SilcPacketType type, SilcPacketFlags flags,
1588                               SilcIdType src_id_type, void *src_id,
1589                               SilcIdType dst_id_type, void *dst_id,
1590                               const unsigned char *data, SilcUInt32 data_len,
1591                               SilcCipher cipher, SilcHmac hmac)
1592 {
1593   unsigned char src_id_data[32], dst_id_data[32];
1594   SilcUInt32 src_id_len, dst_id_len;
1595   SilcBool ret;
1596
1597   if (src_id)
1598     if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1599                         sizeof(src_id_data), &src_id_len))
1600       return FALSE;
1601   if (dst_id)
1602     if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1603                         sizeof(dst_id_data), &dst_id_len))
1604       return FALSE;
1605
1606   ret = silc_packet_send_raw(stream, type, flags,
1607                              src_id ? src_id_type : stream->src_id_type,
1608                              src_id ? src_id_data : stream->src_id,
1609                              src_id ? src_id_len : stream->src_id_len,
1610                              dst_id ? dst_id_type : stream->dst_id_type,
1611                              dst_id ? dst_id_data : stream->dst_id,
1612                              dst_id ? dst_id_len : stream->dst_id_len,
1613                              data, data_len,
1614                              cipher ? cipher : stream->send_key[0],
1615                              hmac ? hmac : stream->send_hmac[0]);
1616
1617   /* Write the packet to the stream */
1618   return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1619 }
1620
1621 /* Sends packet after formatting the arguments to buffer */
1622
1623 SilcBool silc_packet_send_va(SilcPacketStream stream,
1624                              SilcPacketType type, SilcPacketFlags flags, ...)
1625 {
1626   SilcBufferStruct buf;
1627   SilcBool ret;
1628   va_list va;
1629
1630   va_start(va, flags);
1631
1632   memset(&buf, 0, sizeof(buf));
1633   if (silc_buffer_format_vp(&buf, va) < 0) {
1634     va_end(va);
1635     return FALSE;
1636   }
1637
1638   ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1639                          silc_buffer_len(&buf));
1640
1641   silc_buffer_purge(&buf);
1642   va_end(va);
1643
1644   return ret;
1645 }
1646
1647 /* Sends packet after formatting the arguments to buffer, extended routine */
1648
1649 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1650                                  SilcPacketType type, SilcPacketFlags flags,
1651                                  SilcIdType src_id_type, void *src_id,
1652                                  SilcIdType dst_id_type, void *dst_id,
1653                                  SilcCipher cipher, SilcHmac hmac, ...)
1654 {
1655   SilcBufferStruct buf;
1656   SilcBool ret;
1657   va_list va;
1658
1659   va_start(va, hmac);
1660
1661   memset(&buf, 0, sizeof(buf));
1662   if (silc_buffer_format_vp(&buf, va) < 0) {
1663     va_end(va);
1664     return FALSE;
1665   }
1666
1667   ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1668                              dst_id_type, dst_id, silc_buffer_data(&buf),
1669                              silc_buffer_len(&buf), cipher, hmac);
1670
1671   silc_buffer_purge(&buf);
1672   va_end(va);
1673
1674   return TRUE;
1675 }
1676
1677 /***************************** Packet Receiving *****************************/
1678
1679 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1680
1681 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1682                                              const unsigned char *data,
1683                                              SilcUInt32 data_len,
1684                                              const unsigned char *packet_mac,
1685                                              const unsigned char *packet_seq,
1686                                              SilcUInt32 sequence)
1687 {
1688   /* Check MAC */
1689   if (silc_likely(hmac)) {
1690     unsigned char mac[32], psn[4];
1691     SilcUInt32 mac_len;
1692
1693     SILC_LOG_DEBUG(("Verifying MAC"));
1694
1695     /* Compute HMAC of packet */
1696     silc_hmac_init(hmac);
1697
1698     if (!packet_seq) {
1699       SILC_PUT32_MSB(sequence, psn);
1700       silc_hmac_update(hmac, psn, 4);
1701     } else
1702       silc_hmac_update(hmac, packet_seq, 4);
1703
1704     silc_hmac_update(hmac, data, data_len);
1705     silc_hmac_final(hmac, mac, &mac_len);
1706
1707     /* Compare the MAC's */
1708     if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1709       SILC_LOG_DEBUG(("MAC failed"));
1710       return FALSE;
1711     }
1712
1713     SILC_LOG_DEBUG(("MAC is Ok"));
1714   }
1715
1716   return TRUE;
1717 }
1718
1719 /* Increments/sets counter when decrypting in counter mode. */
1720
1721 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1722                                                      unsigned char *iv,
1723                                                      unsigned char *packet_iv)
1724 {
1725   SilcUInt32 pc;
1726
1727   /* If IV Included flag, set the IV from packet to block counter. */
1728   if (stream->iv_included) {
1729     memcpy(iv + 4, packet_iv, 8);
1730   } else {
1731     /* Increment packet counter */
1732     SILC_GET32_MSB(pc, iv + 8);
1733     pc++;
1734     SILC_PUT32_MSB(pc, iv + 8);
1735   }
1736
1737   /* Reset block counter */
1738   memset(iv + 12, 0, 4);
1739
1740   SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1741 }
1742
1743 /* Decrypts SILC packet.  Handles both normal and special packet decryption.
1744    Return 0 when packet is normal and 1 when it it special, -1 on error. */
1745
1746 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1747                                       SilcUInt32 sequence, SilcBuffer buffer,
1748                                       SilcBool normal)
1749 {
1750   if (normal == TRUE) {
1751     if (silc_likely(cipher)) {
1752       /* Decrypt rest of the packet */
1753       SILC_LOG_DEBUG(("Decrypting the packet"));
1754       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1755                                              buffer->data,
1756                                              silc_buffer_len(buffer), NULL)))
1757         return -1;
1758     }
1759     return 0;
1760
1761   } else {
1762     /* Decrypt rest of the header plus padding */
1763     if (silc_likely(cipher)) {
1764       SilcUInt16 len;
1765       SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1766
1767       SILC_LOG_DEBUG(("Decrypting the header"));
1768
1769       /* Padding length + src id len + dst id len + header length - 16
1770          bytes already decrypted, gives the rest of the encrypted packet */
1771       silc_buffer_push(buffer, block_len);
1772       len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1773               (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1774              block_len);
1775       silc_buffer_pull(buffer, block_len);
1776
1777       if (silc_unlikely(len > silc_buffer_len(buffer))) {
1778         SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1779                         "packet dropped"));
1780         return -1;
1781       }
1782       if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1783                                              buffer->data, len, NULL)))
1784         return -1;
1785     }
1786
1787     return 1;
1788   }
1789 }
1790
1791 /* Parses the packet. This is called when a whole packet is ready to be
1792    parsed. The buffer sent must be already decrypted before calling this
1793    function. */
1794
1795 static inline SilcBool silc_packet_parse(SilcPacket packet)
1796 {
1797   SilcBuffer buffer = &packet->buffer;
1798   SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1799   SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1800   int ret;
1801
1802   SILC_LOG_DEBUG(("Parsing incoming packet"));
1803
1804   /* Parse the buffer.  This parses the SILC header of the packet. */
1805   ret = silc_buffer_unformat(buffer,
1806                              SILC_STR_ADVANCE,
1807                              SILC_STR_OFFSET(6),
1808                              SILC_STR_UI_CHAR(&src_id_len),
1809                              SILC_STR_UI_CHAR(&dst_id_len),
1810                              SILC_STR_UI_CHAR(&src_id_type),
1811                              SILC_STR_END);
1812   if (silc_unlikely(ret == -1)) {
1813     if (!packet->stream->udp &&
1814         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1815       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1816     return FALSE;
1817   }
1818
1819   if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1820                     dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1821     if (!packet->stream->udp &&
1822         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1823       SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1824                       packet->src_id_len, packet->dst_id_len));
1825     return FALSE;
1826   }
1827
1828   ret = silc_buffer_unformat(buffer,
1829                              SILC_STR_ADVANCE,
1830                              SILC_STR_DATA(&packet->src_id, src_id_len),
1831                              SILC_STR_UI_CHAR(&dst_id_type),
1832                              SILC_STR_DATA(&packet->dst_id, dst_id_len),
1833                              SILC_STR_OFFSET(padlen),
1834                              SILC_STR_END);
1835   if (silc_unlikely(ret == -1)) {
1836     if (!packet->stream->udp &&
1837         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1838       SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1839     return FALSE;
1840   }
1841
1842   if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1843                     dst_id_type > SILC_ID_CHANNEL)) {
1844     if (!packet->stream->udp &&
1845         !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1846       SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1847                       src_id_type, dst_id_type));
1848     return FALSE;
1849   }
1850
1851   packet->src_id_len = src_id_len;
1852   packet->dst_id_len = dst_id_len;
1853   packet->src_id_type = src_id_type;
1854   packet->dst_id_type = dst_id_type;
1855
1856   SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1857                    silc_buffer_len(buffer)), buffer->head,
1858                    silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1859
1860   SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1861                   silc_get_packet_name(packet->type)));
1862
1863   return TRUE;
1864 }
1865
1866 /* Dispatch packet to application.  Called with stream->lock locked.
1867    Returns FALSE if the stream was destroyed while dispatching a packet. */
1868
1869 static SilcBool silc_packet_dispatch(SilcPacket packet)
1870 {
1871   SilcPacketStream stream = packet->stream;
1872   SilcPacketProcess p;
1873   SilcBool default_sent = FALSE;
1874   SilcPacketType *pt;
1875
1876   /* Dispatch packet to all packet processors that want it */
1877
1878   if (silc_likely(!stream->process)) {
1879     /* Send to default processor as no others exist */
1880     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1881     silc_mutex_unlock(stream->lock);
1882     if (silc_unlikely(!stream->sc->engine->callbacks->
1883                       packet_receive(stream->sc->engine, stream, packet,
1884                                      stream->sc->engine->callback_context,
1885                                      stream->stream_context)))
1886       silc_packet_free(packet);
1887     silc_mutex_lock(stream->lock);
1888     return stream->destroyed == FALSE;
1889   }
1890
1891   silc_dlist_start(stream->process);
1892   while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1893
1894     /* If priority is 0 or less, we send to default processor first
1895        because default processor has 0 priority */
1896     if (!default_sent && p->priority <= 0) {
1897       SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1898       default_sent = TRUE;
1899       silc_mutex_unlock(stream->lock);
1900       if (stream->sc->engine->callbacks->
1901           packet_receive(stream->sc->engine, stream, packet,
1902                          stream->sc->engine->callback_context,
1903                          stream->stream_context)) {
1904         silc_mutex_lock(stream->lock);
1905         return stream->destroyed == FALSE;
1906       }
1907       silc_mutex_lock(stream->lock);
1908     }
1909
1910     /* Send to processor */
1911     if (!p->types) {
1912       /* Send all packet types */
1913       SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1914       silc_mutex_unlock(stream->lock);
1915       if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1916                                        p->callback_context,
1917                                        stream->stream_context)) {
1918         silc_mutex_lock(stream->lock);
1919         return stream->destroyed == FALSE;
1920       }
1921       silc_mutex_lock(stream->lock);
1922     } else {
1923       /* Send specific types */
1924       for (pt = p->types; *pt; pt++) {
1925         if (*pt != packet->type)
1926           continue;
1927         SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1928         silc_mutex_unlock(stream->lock);
1929         if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1930                                          p->callback_context,
1931                                          stream->stream_context)) {
1932           silc_mutex_lock(stream->lock);
1933           return stream->destroyed == FALSE;
1934         }
1935         silc_mutex_lock(stream->lock);
1936         break;
1937       }
1938     }
1939   }
1940
1941   if (!default_sent) {
1942     /* Send to default processor as it has not been sent yet */
1943     SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1944     silc_mutex_unlock(stream->lock);
1945     if (stream->sc->engine->callbacks->
1946         packet_receive(stream->sc->engine, stream, packet,
1947                        stream->sc->engine->callback_context,
1948                        stream->stream_context)) {
1949       silc_mutex_lock(stream->lock);
1950       return stream->destroyed == FALSE;
1951     }
1952     silc_mutex_lock(stream->lock);
1953   }
1954
1955   /* If we got here, no one wanted the packet, so drop it */
1956   silc_packet_free(packet);
1957   return stream->destroyed == FALSE;
1958 }
1959
1960 /* Process incoming data and parse packets.  Called with stream->lock
1961    locked. */
1962
1963 static void silc_packet_read_process(SilcPacketStream stream)
1964 {
1965   SilcBuffer inbuf;
1966   SilcCipher cipher;
1967   SilcHmac hmac;
1968   SilcPacket packet;
1969   SilcUInt8 sid;
1970   SilcUInt16 packetlen;
1971   SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1972   unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1973   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1974   SilcBool normal;
1975   int ret;
1976
1977   /* Get inbuf.  If there is already some data for this stream in the buffer
1978      we already have it.  Otherwise get the current one from list, it will
1979      include the data. */
1980   inbuf = stream->inbuf;
1981   if (!inbuf) {
1982     silc_dlist_start(stream->sc->inbufs);
1983     inbuf = silc_dlist_get(stream->sc->inbufs);
1984   }
1985
1986   /* Parse the packets from the data */
1987   while (silc_buffer_len(inbuf) > 0) {
1988     ivlen = psnlen = 0;
1989     cipher = stream->receive_key[0];
1990     hmac = stream->receive_hmac[0];
1991     normal = FALSE;
1992
1993     if (silc_unlikely(silc_buffer_len(inbuf) <
1994                       (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1995                        SILC_PACKET_MIN_HEADER_LEN))) {
1996       SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1997       silc_dlist_del(stream->sc->inbufs, inbuf);
1998       stream->inbuf = inbuf;
1999       return;
2000     }
2001
2002     if (silc_likely(hmac))
2003       mac_len = silc_hmac_len(hmac);
2004     else
2005       mac_len = 0;
2006
2007     /* Decrypt first block of the packet to get the length field out */
2008     if (silc_likely(cipher)) {
2009       block_len = silc_cipher_get_block_len(cipher);
2010
2011       if (stream->iv_included) {
2012         /* SID, IV and sequence number is included in the ciphertext */
2013         sid = (SilcUInt8)inbuf->data[0];
2014
2015         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2016           /* Set the CTR mode IV from packet to counter block */
2017           memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2018           silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2019           ivlen = 8 + 1;
2020         } else {
2021           /* Get IV from packet */
2022           memcpy(iv, inbuf->data + 1, block_len);
2023           ivlen = block_len + 1;
2024         }
2025         psnlen = 4;
2026
2027         /* Check SID, and get correct decryption key */
2028         if (sid != stream->sid) {
2029           /* If SID is recent get the previous key and use it */
2030           if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2031               stream->receive_key[1] && !stream->receive_hmac[1]) {
2032             cipher = stream->receive_key[1];
2033             hmac = stream->receive_hmac[1];
2034           } else {
2035             /* The SID is unknown, drop rest of the data in buffer */
2036             SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2037                             sid, stream->sid));
2038             silc_mutex_unlock(stream->lock);
2039             SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2040             silc_mutex_lock(stream->lock);
2041             goto out;
2042           }
2043         }
2044       } else {
2045         memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2046
2047         /* If using CTR mode, increment the counter */
2048         if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2049           silc_packet_receive_ctr_increment(stream, iv, NULL);
2050       }
2051
2052       silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp,
2053                           block_len, iv);
2054
2055       header = tmp;
2056       if (stream->iv_included) {
2057         /* Take sequence number from packet */
2058         packet_seq = header;
2059         header += 4;
2060       }
2061     } else {
2062       /* Unencrypted packet */
2063       block_len = SILC_PACKET_MIN_HEADER_LEN;
2064       header = inbuf->data;
2065     }
2066
2067     /* Get packet length and full packet length with padding */
2068     SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2069
2070     /* Sanity checks */
2071     if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2072       if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2073         SILC_LOG_ERROR(("Received too short packet"));
2074       silc_mutex_unlock(stream->lock);
2075       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2076       silc_mutex_lock(stream->lock);
2077       memset(tmp, 0, sizeof(tmp));
2078       goto out;
2079     }
2080
2081     if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2082       SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2083                       "(%d bytes)",
2084                       paddedlen + mac_len - silc_buffer_len(inbuf)));
2085       memset(tmp, 0, sizeof(tmp));
2086       silc_dlist_del(stream->sc->inbufs, inbuf);
2087       stream->inbuf = inbuf;
2088       return;
2089     }
2090
2091     /* Check MAC of the packet */
2092     if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2093                                              paddedlen + ivlen,
2094                                              inbuf->data + ivlen +
2095                                              paddedlen, packet_seq,
2096                                              stream->receive_psn))) {
2097       silc_mutex_unlock(stream->lock);
2098       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2099       silc_mutex_lock(stream->lock);
2100       memset(tmp, 0, sizeof(tmp));
2101       goto out;
2102     }
2103
2104     /* Get packet */
2105     packet = silc_packet_alloc(stream->sc->engine);
2106     if (silc_unlikely(!packet)) {
2107       silc_mutex_unlock(stream->lock);
2108       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2109       silc_mutex_lock(stream->lock);
2110       memset(tmp, 0, sizeof(tmp));
2111       goto out;
2112     }
2113     packet->stream = stream;
2114
2115     /* Allocate more space to packet buffer, if needed */
2116     if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2117       if (!silc_buffer_realloc(&packet->buffer,
2118                                silc_buffer_truelen(&packet->buffer) +
2119                                (paddedlen -
2120                                 silc_buffer_truelen(&packet->buffer)))) {
2121         silc_mutex_unlock(stream->lock);
2122         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2123         silc_mutex_lock(stream->lock);
2124         silc_packet_free(packet);
2125         memset(tmp, 0, sizeof(tmp));
2126         goto out;
2127       }
2128     }
2129
2130     /* Parse packet header */
2131     packet->flags = (SilcPacketFlags)header[2];
2132     packet->type = (SilcPacketType)header[3];
2133
2134     if (stream->sc->engine->local_is_router) {
2135       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2136           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2137         normal = FALSE;
2138       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2139                (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2140                 stream->is_router == TRUE))
2141         normal = TRUE;
2142     } else {
2143       if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2144           (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2145         normal = FALSE;
2146       else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2147         normal = TRUE;
2148     }
2149
2150     SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2151                       stream->receive_psn, paddedlen + ivlen + mac_len),
2152                      inbuf->data, paddedlen + ivlen + mac_len);
2153
2154     /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2155     silc_buffer_pull_tail(&packet->buffer, paddedlen);
2156     silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2157     silc_buffer_pull(&packet->buffer, block_len - psnlen);
2158     silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2159                                       psnlen + (block_len - psnlen)),
2160                     paddedlen - ivlen - psnlen - (block_len - psnlen));
2161     if (silc_likely(cipher)) {
2162       silc_cipher_set_iv(cipher, iv);
2163       ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2164                                 &packet->buffer, normal);
2165       if (silc_unlikely(ret < 0)) {
2166         silc_mutex_unlock(stream->lock);
2167         SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2168         silc_mutex_lock(stream->lock);
2169         silc_packet_free(packet);
2170         memset(tmp, 0, sizeof(tmp));
2171         goto out;
2172       }
2173
2174       stream->receive_psn++;
2175     }
2176     silc_buffer_push(&packet->buffer, block_len);
2177
2178     /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2179     silc_buffer_pull(inbuf, paddedlen + mac_len);
2180
2181     /* Parse the packet */
2182     if (silc_unlikely(!silc_packet_parse(packet))) {
2183       silc_mutex_unlock(stream->lock);
2184       SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2185       silc_mutex_lock(stream->lock);
2186       silc_packet_free(packet);
2187       memset(tmp, 0, sizeof(tmp));
2188       goto out;
2189     }
2190
2191     /* Dispatch the packet to application */
2192     if (!silc_packet_dispatch(packet))
2193       break;
2194   }
2195
2196  out:
2197   /* Add inbuf back to free list, if we owned it. */
2198   if (stream->inbuf) {
2199     silc_dlist_add(stream->sc->inbufs, inbuf);
2200     stream->inbuf = NULL;
2201   }
2202
2203   silc_buffer_reset(inbuf);
2204 }
2205
2206 /****************************** Packet Waiting ******************************/
2207
2208 /* Packet wait receive callback */
2209 static SilcBool
2210 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2211                                 SilcPacketStream stream,
2212                                 SilcPacket packet,
2213                                 void *callback_context,
2214                                 void *stream_context);
2215
2216 /* Packet waiting callbacks */
2217 static SilcPacketCallbacks silc_packet_wait_cbs =
2218 {
2219   silc_packet_wait_packet_receive, NULL, NULL
2220 };
2221
2222 /* Packet waiting context */
2223 typedef struct {
2224   SilcMutex wait_lock;
2225   SilcCond wait_cond;
2226   SilcList packet_queue;
2227   unsigned int stopped     : 1;
2228 } *SilcPacketWait;
2229
2230 /* Packet wait receive callback */
2231
2232 static SilcBool
2233 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2234                                 SilcPacketStream stream,
2235                                 SilcPacket packet,
2236                                 void *callback_context,
2237                                 void *stream_context)
2238 {
2239   SilcPacketWait pw = callback_context;
2240
2241   /* Signal the waiting thread for a new packet */
2242   silc_mutex_lock(pw->wait_lock);
2243
2244   if (silc_unlikely(pw->stopped)) {
2245     silc_mutex_unlock(pw->wait_lock);
2246     return FALSE;
2247   }
2248
2249   silc_list_add(pw->packet_queue, packet);
2250   silc_cond_broadcast(pw->wait_cond);
2251
2252   silc_mutex_unlock(pw->wait_lock);
2253
2254   return TRUE;
2255 }
2256
2257 /* Initialize packet waiting */
2258
2259 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2260 {
2261   SilcPacketWait pw;
2262   SilcBool ret;
2263   va_list ap;
2264
2265   pw = silc_calloc(1, sizeof(*pw));
2266   if (!pw)
2267     return NULL;
2268
2269   /* Allocate mutex and conditional variable */
2270   if (!silc_mutex_alloc(&pw->wait_lock)) {
2271     silc_free(pw);
2272     return NULL;
2273   }
2274   if (!silc_cond_alloc(&pw->wait_cond)) {
2275     silc_mutex_free(pw->wait_lock);
2276     silc_free(pw);
2277     return NULL;
2278   }
2279
2280   /* Link to the packet stream for the requested packet types */
2281   va_start(ap, stream);
2282   ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2283                                    10000000, ap);
2284   va_end(ap);
2285   if (!ret) {
2286     silc_cond_free(pw->wait_cond);
2287     silc_mutex_free(pw->wait_lock);
2288     silc_free(pw);
2289     return NULL;
2290   }
2291
2292   /* Initialize packet queue */
2293   silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2294
2295   return (void *)pw;
2296 }
2297
2298 /* Uninitialize packet waiting */
2299
2300 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2301 {
2302   SilcPacketWait pw = waiter;
2303   SilcPacket packet;
2304
2305   /* Signal any threads to stop waiting */
2306   silc_mutex_lock(pw->wait_lock);
2307   pw->stopped = TRUE;
2308   silc_cond_broadcast(pw->wait_cond);
2309   silc_mutex_unlock(pw->wait_lock);
2310
2311   /* Re-acquire lock and free resources */
2312   silc_mutex_lock(pw->wait_lock);
2313   silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2314
2315   /* Free any remaining packets */
2316   silc_list_start(pw->packet_queue);
2317   while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2318     silc_packet_free(packet);
2319
2320   silc_mutex_unlock(pw->wait_lock);
2321   silc_cond_free(pw->wait_cond);
2322   silc_mutex_free(pw->wait_lock);
2323   silc_free(pw);
2324 }
2325
2326 /* Blocks thread until a packet has been received. */
2327
2328 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2329 {
2330   SilcPacketWait pw = waiter;
2331   SilcBool ret = FALSE;
2332
2333   silc_mutex_lock(pw->wait_lock);
2334
2335   /* Wait here until packet has arrived */
2336   while (silc_list_count(pw->packet_queue) == 0) {
2337     if (silc_unlikely(pw->stopped)) {
2338       silc_mutex_unlock(pw->wait_lock);
2339       return -1;
2340     }
2341     ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2342   }
2343
2344   /* Return packet */
2345   silc_list_start(pw->packet_queue);
2346   *return_packet = silc_list_get(pw->packet_queue);
2347   silc_list_del(pw->packet_queue, *return_packet);
2348
2349   silc_mutex_unlock(pw->wait_lock);
2350
2351   return ret == TRUE ? 1 : 0;
2352 }
2353
2354 /************************** Packet Stream Wrapper ***************************/
2355
2356 /* Packet stream wrapper receive callback */
2357 static SilcBool
2358 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2359                                 SilcPacketStream stream,
2360                                 SilcPacket packet,
2361                                 void *callback_context,
2362                                 void *stream_context);
2363
2364 const SilcStreamOps silc_packet_stream_ops;
2365
2366 /* Packet stream wrapper context */
2367 typedef struct {
2368   const SilcStreamOps *ops;
2369   SilcPacketStream stream;
2370   SilcMutex lock;
2371   void *waiter;                   /* Waiter context in blocking mode */
2372   SilcPacketWrapCoder coder;
2373   void *coder_context;
2374   SilcBuffer encbuf;
2375   SilcStreamNotifier callback;
2376   void *context;
2377   SilcList in_queue;
2378   SilcPacketType type;
2379   SilcPacketFlags flags;
2380   unsigned int closed        : 1;
2381   unsigned int blocking      : 1;
2382   unsigned int read_more     : 1;
2383 } *SilcPacketWrapperStream;
2384
2385 /* Packet wrapper callbacks */
2386 static SilcPacketCallbacks silc_packet_wrap_cbs =
2387 {
2388   silc_packet_wrap_packet_receive, NULL, NULL
2389 };
2390
2391 /* Packet stream wrapper receive callback, non-blocking mode */
2392
2393 static SilcBool
2394 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2395                                 SilcPacketStream stream,
2396                                 SilcPacket packet,
2397                                 void *callback_context,
2398                                 void *stream_context)
2399 {
2400   SilcPacketWrapperStream pws = callback_context;
2401
2402   if (pws->closed || !pws->callback)
2403     return FALSE;
2404
2405   silc_mutex_lock(pws->lock);
2406   silc_list_add(pws->in_queue, packet);
2407   silc_mutex_unlock(pws->lock);
2408
2409   /* Call notifier callback */
2410   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2411
2412   return TRUE;
2413 }
2414
2415 /* Task callback to notify more data is available for reading */
2416
2417 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2418 {
2419   SilcPacketWrapperStream pws = context;
2420
2421   if (pws->closed || !pws->callback)
2422     return;
2423
2424   /* Call notifier callback */
2425   pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2426 }
2427
2428 /* Read SILC packet */
2429
2430 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2431                           SilcUInt32 buf_len)
2432 {
2433   SilcPacketWrapperStream pws = stream;
2434   SilcPacket packet;
2435   SilcBool read_more = FALSE;
2436   int len;
2437
2438   if (pws->closed)
2439     return -2;
2440
2441   if (pws->blocking) {
2442     /* Block until packet is received */
2443     if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2444       return -2;
2445     if (pws->closed)
2446       return -2;
2447   } else {
2448     /* Non-blocking mode */
2449     silc_mutex_lock(pws->lock);
2450     if (!silc_list_count(pws->in_queue)) {
2451       silc_mutex_unlock(pws->lock);
2452       return -1;
2453     }
2454
2455     silc_list_start(pws->in_queue);
2456     packet = silc_list_get(pws->in_queue);
2457     silc_list_del(pws->in_queue, packet);
2458     silc_mutex_unlock(pws->lock);
2459   }
2460
2461   /* Call decoder if set */
2462   if (pws->coder && !pws->read_more)
2463     pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2464                pws->coder_context);
2465
2466   len = silc_buffer_len(&packet->buffer);
2467   if (len > buf_len) {
2468     len = buf_len;
2469     read_more = TRUE;
2470   }
2471
2472   /* Read data */
2473   memcpy(buf, packet->buffer.data, len);
2474
2475   if (read_more && !pws->blocking) {
2476     /* More data will be available (in blocking mode not supported). */
2477     silc_buffer_pull(&packet->buffer, len);
2478     silc_list_insert(pws->in_queue, NULL, packet);
2479     silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2480                                    silc_packet_wrap_read_more, pws, 0, 0);
2481     pws->read_more = TRUE;
2482     return len;
2483   }
2484
2485   pws->read_more = FALSE;
2486   silc_packet_free(packet);
2487   return len;
2488 }
2489
2490 /* Write SILC packet */
2491
2492 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2493                            SilcUInt32 data_len)
2494 {
2495   SilcPacketWrapperStream pws = stream;
2496   SilcBool ret = FALSE;
2497
2498   /* Call decoder if set */
2499   if (pws->coder) {
2500     silc_buffer_reset(pws->encbuf);
2501     ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2502                      pws->coder_context);
2503   }
2504
2505   /* Send the SILC packet */
2506   if (ret) {
2507     if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2508                              SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2509                                            silc_buffer_len(pws->encbuf)),
2510                              SILC_STR_DATA(data, data_len),
2511                              SILC_STR_END))
2512       return -2;
2513   } else {
2514     if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2515       return -2;
2516   }
2517
2518   return data_len;
2519 }
2520
2521 /* Close stream */
2522
2523 SilcBool silc_packet_wrap_close(SilcStream stream)
2524 {
2525   SilcPacketWrapperStream pws = stream;
2526
2527   if (pws->closed)
2528     return TRUE;
2529
2530   if (pws->blocking) {
2531     /* Close packet waiter */
2532     silc_packet_wait_uninit(pws->waiter, pws->stream);
2533   } else {
2534     /* Unlink */
2535     if (pws->callback)
2536       silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2537   }
2538   pws->closed = TRUE;
2539
2540   return TRUE;
2541 }
2542
2543 /* Destroy wrapper stream */
2544
2545 void silc_packet_wrap_destroy(SilcStream stream)
2546
2547 {
2548   SilcPacketWrapperStream pws = stream;
2549   SilcPacket packet;
2550
2551   SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2552
2553   silc_stream_close(stream);
2554   silc_list_start(pws->in_queue);
2555   while ((packet = silc_list_get(pws->in_queue)))
2556     silc_packet_free(packet);
2557   if (pws->lock)
2558     silc_mutex_free(pws->lock);
2559   if (pws->encbuf)
2560     silc_buffer_free(pws->encbuf);
2561   silc_packet_stream_unref(pws->stream);
2562
2563   silc_free(pws);
2564 }
2565
2566 /* Link stream to receive packets */
2567
2568 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2569                                    SilcSchedule schedule,
2570                                    SilcStreamNotifier callback,
2571                                    void *context)
2572 {
2573   SilcPacketWrapperStream pws = stream;
2574
2575   if (pws->closed || pws->blocking)
2576     return FALSE;
2577
2578   /* Link to receive packets */
2579   if (callback)
2580     silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2581                             100000, pws->type, -1);
2582   else
2583     silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2584
2585   pws->callback = callback;
2586   pws->context = context;
2587
2588   return TRUE;
2589 }
2590
2591 /* Return schedule */
2592
2593 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2594 {
2595   return NULL;
2596 }
2597
2598 /* Wraps packet stream into SilcStream. */
2599
2600 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2601                                    SilcPacketType type,
2602                                    SilcPacketFlags flags,
2603                                    SilcBool blocking_mode,
2604                                    SilcPacketWrapCoder coder,
2605                                    void *context)
2606 {
2607   SilcPacketWrapperStream pws;
2608
2609   pws = silc_calloc(1, sizeof(*pws));
2610   if (!pws)
2611     return NULL;
2612
2613   SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2614
2615   pws->ops = &silc_packet_stream_ops;
2616   pws->stream = stream;
2617   pws->type = type;
2618   pws->flags = flags;
2619   pws->blocking = blocking_mode;
2620   pws->coder = coder;
2621   pws->coder_context = context;
2622
2623   /* Allocate small amount for encoder buffer. */
2624   if (pws->coder)
2625     pws->encbuf = silc_buffer_alloc(8);
2626
2627   if (pws->blocking) {
2628     /* Blocking mode.  Use packet waiter to do the thing. */
2629     pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2630     if (!pws->waiter) {
2631       silc_free(pws);
2632       return NULL;
2633     }
2634   } else {
2635     /* Non-blocking mode */
2636     silc_mutex_alloc(&pws->lock);
2637     silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2638   }
2639
2640   silc_packet_stream_ref(stream);
2641
2642   return (SilcStream)pws;
2643 }
2644
2645 const SilcStreamOps silc_packet_stream_ops =
2646 {
2647   silc_packet_wrap_read,
2648   silc_packet_wrap_write,
2649   silc_packet_wrap_close,
2650   silc_packet_wrap_destroy,
2651   silc_packet_wrap_notifier,
2652   silc_packet_wrap_get_schedule,
2653 };