5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 * Created: Fri Jul 25 18:52:14 1997
26 /************************** Types and definitions ***************************/
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. */
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;
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;
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 */
59 /* UDP remote stream tuple */
61 char *remote_ip; /* Remote IP address */
62 SilcUInt16 remote_port; /* Remote port */
63 } *SilcPacketRemoteUDP;
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 */
96 /* Initial size of stream buffers */
97 #define SILC_PACKET_DEFAULT_SIZE 1024
99 /* Header length without source and destination ID's. */
100 #define SILC_PACKET_HEADER_LEN 10
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
106 /* Maximum padding length */
107 #define SILC_PACKET_MAX_PADLEN 128
109 /* Default padding length */
110 #define SILC_PACKET_DEFAULT_PADLEN 16
112 /* Minimum packet length */
113 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
115 /* Returns true length of the packet. */
116 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
118 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
119 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
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)
132 /* Calculates the length of the padding in the packet. */
133 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
135 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
136 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
138 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
141 /* Returns the length of the padding up to the maximum length, which
143 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
145 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
146 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
150 #define SILC_PACKET_CALLBACK_EOS(s) \
152 (s)->sc->engine->callbacks->eos((s)->sc->engine, s, \
153 (s)->sc->engine->callback_context, \
154 (s)->stream_context); \
158 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
160 (s)->sc->engine->callbacks->error((s)->sc->engine, s, err, \
161 (s)->sc->engine->callback_context, \
162 (s)->stream_context); \
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,
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,
181 /************************ Static utility functions **************************/
183 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
185 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
187 SilcPacket packet = context;
188 SilcPacketStream stream = packet->stream;
190 SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
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);
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. */
203 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
211 stream = ((SilcPacketStream)ps->stream)->stream;
215 if (ps->udp && silc_socket_stream_is_udp(stream, &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)) {
224 silc_buffer_reset(&ps->outbuf);
225 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
229 if (silc_unlikely(i == -1)) {
230 /* Cannot write now, write later. */
232 silc_mutex_unlock(ps->lock);
237 silc_buffer_pull(&ps->outbuf, i);
240 silc_buffer_reset(&ps->outbuf);
242 silc_mutex_unlock(ps->lock);
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)) {
254 silc_buffer_reset(&ps->outbuf);
255 silc_mutex_unlock(ps->lock);
256 SILC_PACKET_CALLBACK_EOS(ps);
260 if (silc_unlikely(i == -2)) {
262 silc_buffer_reset(&ps->outbuf);
263 silc_mutex_unlock(ps->lock);
264 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
268 if (silc_unlikely(i == -1)) {
269 /* Cannot write now, write later. */
271 silc_mutex_unlock(ps->lock);
276 silc_buffer_pull(&ps->outbuf, i);
279 silc_buffer_reset(&ps->outbuf);
281 silc_mutex_unlock(ps->lock);
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. */
292 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
293 SilcPacketStream *ret_ps)
295 SilcStream stream = ps->stream;
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
305 silc_dlist_start(ps->sc->inbufs);
306 inbuf = silc_dlist_get(ps->sc->inbufs);
308 /* Allocate new data input buffer */
309 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
311 silc_mutex_unlock(ps->lock);
314 silc_buffer_reset(inbuf);
315 silc_dlist_add(ps->sc->inbufs, inbuf);
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));
324 if (silc_socket_stream_is_udp(stream, &connected)) {
326 /* Connectionless UDP stream, read one UDP packet */
327 char remote_ip[64], tuple[64];
329 SilcPacketStream remote;
331 ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
332 &remote_port, inbuf->tail,
333 silc_buffer_taillen(inbuf));
335 if (silc_unlikely(ret < 0)) {
336 silc_mutex_unlock(ps->lock);
338 /* Cannot read now, do it later. */
339 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
344 silc_buffer_reset(inbuf);
345 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
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,
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);
362 silc_mutex_unlock(ps->sc->engine->lock);
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);
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;
379 silc_buffer_pull_tail(inbuf, ret);
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);
390 silc_buffer_reset(inbuf);
391 SILC_PACKET_CALLBACK_EOS(ps);
396 /* Cannot read now, do it later. */
397 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
402 silc_buffer_reset(inbuf);
403 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
407 silc_buffer_pull_tail(inbuf, ret);
411 /* Our stream IO notifier callback. */
413 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
416 SilcPacketStream remote = NULL, ps = context;
418 silc_mutex_lock(ps->lock);
420 if (silc_unlikely(ps->destroyed)) {
421 silc_mutex_unlock(ps->lock);
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));
431 /* Read data from stream */
432 if (!silc_packet_stream_read(ps, &remote))
435 /* Now process the data */
436 silc_packet_stream_ref(ps);
438 silc_packet_read_process(ps);
439 silc_mutex_unlock(ps->lock);
441 silc_packet_read_process(remote);
442 silc_mutex_unlock(remote->lock);
444 silc_packet_stream_unref(ps);
447 case SILC_STREAM_CAN_WRITE:
448 SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
451 if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
452 silc_mutex_unlock(ps->lock);
456 /* Write pending data to stream */
457 silc_packet_stream_write(ps, FALSE);
461 silc_mutex_unlock(ps->lock);
466 /* Allocate packet */
468 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
472 SILC_LOG_DEBUG(("Packet pool count %d",
473 silc_list_count(engine->packet_pool)));
475 silc_mutex_lock(engine->lock);
477 /* Get packet from freelist or allocate new one. */
478 packet = silc_list_get(engine->packet_pool);
482 silc_mutex_unlock(engine->lock);
484 packet = silc_calloc(1, sizeof(*packet));
485 if (silc_unlikely(!packet))
488 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
490 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
491 if (silc_unlikely(!tmp)) {
495 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
496 silc_buffer_reset(&packet->buffer);
501 SILC_LOG_DEBUG(("Get packet %p", packet));
503 /* Delete from freelist */
504 silc_list_del(engine->packet_pool, packet);
506 silc_mutex_unlock(engine->lock);
511 /* UDP remote stream hash table destructor */
513 static void silc_packet_engine_hash_destr(void *key, void *context,
519 /* Per scheduler context hash table destructor */
521 static void silc_packet_engine_context_destr(void *key, void *context,
524 SilcPacketEngineContext sc = context;
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);
534 silc_dlist_uninit(sc->inbufs);
539 /******************************** Packet API ********************************/
541 /* Allocate new packet engine */
544 silc_packet_engine_start(SilcRng rng, SilcBool router,
545 SilcPacketCallbacks *callbacks,
546 void *callback_context)
548 SilcPacketEngine engine;
553 SILC_LOG_DEBUG(("Starting new packet engine"));
557 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
560 engine = silc_calloc(1, sizeof(*engine));
564 engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
565 silc_packet_engine_context_destr,
567 if (!engine->contexts) {
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);
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));
584 silc_packet_engine_stop(engine);
588 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
590 silc_packet_engine_stop(engine);
593 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
594 silc_buffer_reset(&packet->buffer);
596 silc_list_add(engine->packet_pool, packet);
598 silc_list_start(engine->packet_pool);
603 /* Stop packet engine */
605 void silc_packet_engine_stop(SilcPacketEngine engine)
608 SILC_LOG_DEBUG(("Stopping packet engine"));
618 /* Create new packet stream */
620 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
621 SilcSchedule schedule,
628 SILC_LOG_DEBUG(("Creating new packet stream"));
630 if (!engine || !stream)
633 ps = silc_calloc(1, sizeof(*ps));
638 silc_atomic_init8(&ps->refcnt, 1);
639 silc_mutex_alloc(&ps->lock);
641 /* Allocate out buffer */
642 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
644 silc_packet_stream_destroy(ps);
647 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
648 silc_buffer_reset(&ps->outbuf);
650 /* Initialize packet procesors list */
651 ps->process = silc_dlist_init();
653 silc_packet_stream_destroy(ps);
657 silc_mutex_lock(engine->lock);
659 /* Add per scheduler context */
660 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
662 ps->sc = silc_calloc(1, sizeof(*ps->sc));
664 silc_packet_stream_destroy(ps);
665 silc_mutex_unlock(engine->lock);
668 ps->sc->engine = engine;
669 ps->sc->schedule = schedule;
671 /* Allocate data input buffer */
672 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
676 silc_packet_stream_destroy(ps);
677 silc_mutex_unlock(engine->lock);
680 silc_buffer_reset(inbuf);
682 ps->sc->inbufs = silc_dlist_init();
683 if (!ps->sc->inbufs) {
684 silc_buffer_free(inbuf);
687 silc_packet_stream_destroy(ps);
688 silc_mutex_unlock(engine->lock);
691 silc_dlist_add(ps->sc->inbufs, inbuf);
693 /* Add to per scheduler context hash table */
694 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
695 silc_buffer_free(inbuf);
696 silc_dlist_del(ps->sc->inbufs, inbuf);
699 silc_packet_stream_destroy(ps);
700 silc_mutex_unlock(engine->lock);
704 ps->sc->stream_count++;
706 /* Add the packet stream to engine */
707 silc_list_add(engine->streams, ps);
709 /* If this is UDP stream, allocate UDP remote stream hash table */
710 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
711 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
712 silc_hash_string_compare, NULL,
713 silc_packet_engine_hash_destr,
716 silc_mutex_unlock(engine->lock);
718 /* Set IO notifier callback. This schedules this stream for I/O. */
719 if (!silc_stream_set_notifier(ps->stream, schedule,
720 silc_packet_stream_io, ps)) {
721 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
722 silc_packet_stream_destroy(ps);
729 /* Add new remote packet stream for UDP packet streams */
731 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
732 const char *remote_ip,
733 SilcUInt16 remote_port,
736 SilcPacketEngine engine = stream->sc->engine;
741 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
742 remote_ip, remote_port, stream));
744 if (!stream || !remote_ip || !remote_port)
747 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
748 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
752 ps = silc_calloc(1, sizeof(*ps));
757 silc_atomic_init8(&ps->refcnt, 1);
758 silc_mutex_alloc(&ps->lock);
760 /* Set the UDP packet stream as underlaying stream */
761 silc_packet_stream_ref(stream);
762 ps->stream = (SilcStream)stream;
765 /* Allocate out buffer */
766 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
768 silc_packet_stream_destroy(ps);
771 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
772 silc_buffer_reset(&ps->outbuf);
774 /* Initialize packet procesors list */
775 ps->process = silc_dlist_init();
777 silc_packet_stream_destroy(ps);
781 /* Add to engine with this IP and port pair */
782 tuple = silc_format("%d%s", remote_port, remote_ip);
783 silc_mutex_lock(engine->lock);
784 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
785 silc_mutex_unlock(engine->lock);
786 silc_packet_stream_destroy(ps);
789 silc_mutex_unlock(engine->lock);
791 /* Save remote IP and port pair */
792 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
793 if (!ps->remote_udp) {
794 silc_packet_stream_destroy(ps);
797 ps->remote_udp->remote_port = remote_port;
798 ps->remote_udp->remote_ip = strdup(remote_ip);
799 if (!ps->remote_udp->remote_ip) {
800 silc_packet_stream_destroy(ps);
805 /* Inject packet to the new stream */
807 silc_packet_stream_ref(ps);
808 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
809 silc_packet_stream_inject_packet, packet,
816 /* Destroy packet stream */
818 void silc_packet_stream_destroy(SilcPacketStream stream)
823 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
824 stream->destroyed = TRUE;
826 /* Close the underlaying stream */
827 if (!stream->udp && stream->stream)
828 silc_stream_close(stream->stream);
832 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
835 /* Delete from engine */
836 silc_mutex_lock(stream->sc->engine->lock);
837 silc_list_del(stream->sc->engine->streams, stream);
839 /* Remove per scheduler context, if it is not used anymore */
841 stream->sc->stream_count--;
842 if (!stream->sc->stream_count)
843 silc_hash_table_del(stream->sc->engine->contexts,
844 stream->sc->schedule);
846 silc_mutex_unlock(stream->sc->engine->lock);
848 /* Destroy the underlaying stream */
850 silc_stream_destroy(stream->stream);
852 /* Delete from UDP remote hash table */
854 silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
855 stream->remote_udp->remote_ip);
856 silc_mutex_lock(stream->sc->engine->lock);
857 silc_hash_table_del(stream->sc->engine->udp_remote, tuple);
858 silc_mutex_unlock(stream->sc->engine->lock);
860 silc_free(stream->remote_udp->remote_ip);
861 silc_free(stream->remote_udp);
863 /* Unreference the underlaying packet stream */
864 silc_packet_stream_unref((SilcPacketStream)stream->stream);
867 /* Clear and free buffers */
868 silc_buffer_clear(&stream->outbuf);
869 silc_buffer_purge(&stream->outbuf);
871 if (stream->process) {
873 silc_dlist_start(stream->process);
874 while ((p = silc_dlist_get(stream->process))) {
877 silc_dlist_del(stream->process, p);
879 silc_dlist_uninit(stream->process);
884 silc_atomic_uninit8(&stream->refcnt);
885 silc_mutex_free(stream->lock);
889 /* Marks as router stream */
891 void silc_packet_stream_set_router(SilcPacketStream stream)
893 stream->is_router = TRUE;
896 /* Mark to include IV in ciphertext */
898 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
900 stream->iv_included = TRUE;
903 /* Links `callbacks' to `stream' for specified packet types */
905 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
906 SilcPacketCallbacks *callbacks,
907 void *callback_context,
908 int priority, va_list ap)
910 SilcPacketProcess p, e;
911 SilcInt32 packet_type;
914 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
918 if (!callbacks->packet_receive)
921 p = silc_calloc(1, sizeof(*p));
925 p->priority = priority;
926 p->callbacks = callbacks;
927 p->callback_context = callback_context;
929 silc_mutex_lock(stream->lock);
931 if (!stream->process) {
932 stream->process = silc_dlist_init();
933 if (!stream->process) {
934 silc_mutex_unlock(stream->lock);
939 /* According to priority set the procesor to correct position. First
940 entry has the highest priority */
941 silc_dlist_start(stream->process);
942 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
943 if (p->priority > e->priority) {
944 silc_dlist_insert(stream->process, p);
949 silc_dlist_add(stream->process, p);
951 /* Get packet types to process */
954 packet_type = va_arg(ap, SilcInt32);
956 if (packet_type == SILC_PACKET_ANY)
959 if (packet_type == -1)
962 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
964 silc_mutex_unlock(stream->lock);
968 p->types[i - 1] = (SilcPacketType)packet_type;
974 silc_mutex_unlock(stream->lock);
976 silc_packet_stream_ref(stream);
981 /* Links `callbacks' to `stream' for specified packet types */
983 SilcBool silc_packet_stream_link(SilcPacketStream stream,
984 SilcPacketCallbacks *callbacks,
985 void *callback_context,
991 va_start(ap, priority);
992 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
999 /* Unlinks `callbacks' from `stream'. */
1001 void silc_packet_stream_unlink(SilcPacketStream stream,
1002 SilcPacketCallbacks *callbacks,
1003 void *callback_context)
1005 SilcPacketProcess p;
1007 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1008 callbacks, stream));
1010 silc_mutex_lock(stream->lock);
1012 silc_dlist_start(stream->process);
1013 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1014 if (p->callbacks == callbacks &&
1015 p->callback_context == callback_context) {
1016 silc_dlist_del(stream->process, p);
1017 silc_free(p->types);
1022 if (!silc_dlist_count(stream->process)) {
1023 silc_dlist_uninit(stream->process);
1024 stream->process = NULL;
1027 silc_mutex_unlock(stream->lock);
1029 silc_packet_stream_unref(stream);
1032 /* Returns TRUE if stream is UDP stream */
1034 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1036 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1039 /* Return packet sender IP and port for UDP packet stream */
1041 SilcBool silc_packet_get_sender(SilcPacket packet,
1042 const char **sender_ip,
1043 SilcUInt16 *sender_port)
1045 if (!packet->stream->remote_udp)
1048 *sender_ip = packet->stream->remote_udp->remote_ip;
1049 *sender_port = packet->stream->remote_udp->remote_port;
1054 /* Reference packet stream */
1056 void silc_packet_stream_ref(SilcPacketStream stream)
1058 silc_atomic_add_int8(&stream->refcnt, 1);
1059 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1060 silc_atomic_get_int8(&stream->refcnt) - 1,
1061 silc_atomic_get_int8(&stream->refcnt)));
1064 /* Unreference packet stream */
1066 void silc_packet_stream_unref(SilcPacketStream stream)
1068 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1069 silc_atomic_get_int8(&stream->refcnt),
1070 silc_atomic_get_int8(&stream->refcnt) - 1));
1071 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1073 silc_atomic_add_int8(&stream->refcnt, 1);
1074 silc_packet_stream_destroy(stream);
1079 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1081 return stream->sc->engine;
1084 /* Set application context for packet stream */
1086 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1088 silc_mutex_lock(stream->lock);
1089 stream->stream_context = stream_context;
1090 silc_mutex_unlock(stream->lock);
1093 /* Return application context from packet stream */
1095 void *silc_packet_get_context(SilcPacketStream stream)
1098 silc_mutex_lock(stream->lock);
1099 context = stream->stream_context;
1100 silc_mutex_unlock(stream->lock);
1104 /* Change underlaying stream */
1106 void silc_packet_stream_set_stream(SilcPacketStream ps,
1110 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1111 ps->stream = stream;
1112 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1116 /* Return underlaying stream */
1118 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1120 return stream->stream;
1125 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1126 SilcCipher receive_key, SilcHmac send_hmac,
1127 SilcHmac receive_hmac, SilcBool rekey)
1129 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1131 /* If doing rekey, send REKEY_DONE packet */
1133 /* This will take stream lock. */
1134 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1135 stream->src_id_type, stream->src_id,
1136 stream->src_id_len, stream->dst_id_type,
1137 stream->dst_id, stream->dst_id_len,
1138 NULL, 0, stream->send_key[0],
1139 stream->send_hmac[0]))
1142 /* Write the packet to the stream */
1143 if (!silc_packet_stream_write(stream, TRUE))
1146 silc_mutex_lock(stream->lock);
1149 /* In case IV Included is set, save the old keys */
1150 if (stream->iv_included) {
1151 if (stream->send_key[1] && send_key) {
1152 silc_cipher_free(stream->send_key[1]);
1153 stream->send_key[1] = stream->send_key[0];
1155 if (stream->receive_key[1] && receive_key) {
1156 silc_cipher_free(stream->receive_key[1]);
1157 stream->receive_key[1] = stream->receive_key[0];
1159 if (stream->send_hmac[1] && send_hmac) {
1160 silc_hmac_free(stream->send_hmac[1]);
1161 stream->send_hmac[1] = stream->send_hmac[0];
1163 if (stream->receive_hmac[1] && receive_hmac) {
1164 silc_hmac_free(stream->receive_hmac[1]);
1165 stream->receive_hmac[1] = stream->receive_hmac[0];
1168 if (stream->send_key[0] && send_key)
1169 silc_cipher_free(stream->send_key[0]);
1170 if (stream->send_key[1] && receive_key)
1171 silc_cipher_free(stream->receive_key[0]);
1172 if (stream->send_hmac[0] && send_hmac)
1173 silc_hmac_free(stream->send_hmac[0]);
1174 if (stream->receive_hmac[0] && receive_hmac)
1175 silc_hmac_free(stream->receive_hmac[0]);
1180 stream->send_key[0] = send_key;
1182 stream->receive_key[0] = receive_key;
1184 stream->send_hmac[0] = send_hmac;
1186 stream->receive_hmac[0] = receive_hmac;
1188 silc_mutex_unlock(stream->lock);
1192 /* Return current ciphers from packet stream */
1194 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1195 SilcCipher *send_key,
1196 SilcCipher *receive_key,
1197 SilcHmac *send_hmac,
1198 SilcHmac *receive_hmac)
1200 if (!stream->send_key[0] && !stream->receive_key[0] &&
1201 !stream->send_hmac[0] && !stream->receive_hmac[0])
1204 silc_mutex_lock(stream->lock);
1207 *send_key = stream->send_key[0];
1209 *receive_key = stream->receive_key[0];
1211 *send_hmac = stream->send_hmac[0];
1213 *receive_hmac = stream->receive_hmac[0];
1215 silc_mutex_unlock(stream->lock);
1220 /* Set SILC IDs to packet stream */
1222 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1223 SilcIdType src_id_type, const void *src_id,
1224 SilcIdType dst_id_type, const void *dst_id)
1227 unsigned char tmp[32];
1229 if (!src_id && !dst_id)
1232 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1234 silc_mutex_lock(stream->lock);
1237 silc_free(stream->src_id);
1238 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1239 silc_mutex_unlock(stream->lock);
1242 stream->src_id = silc_memdup(tmp, len);
1243 if (!stream->src_id) {
1244 silc_mutex_unlock(stream->lock);
1247 stream->src_id_type = src_id_type;
1248 stream->src_id_len = len;
1252 silc_free(stream->dst_id);
1253 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1254 silc_mutex_unlock(stream->lock);
1257 stream->dst_id = silc_memdup(tmp, len);
1258 if (!stream->dst_id) {
1259 silc_mutex_unlock(stream->lock);
1262 stream->dst_id_type = dst_id_type;
1263 stream->dst_id_len = len;
1266 silc_mutex_unlock(stream->lock);
1271 /* Adds Security ID (SID) */
1273 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1275 if (!stream->iv_included)
1278 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1286 void silc_packet_free(SilcPacket packet)
1288 SilcPacketStream stream = packet->stream;
1290 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1292 /* Check for double free */
1293 SILC_ASSERT(packet->stream != NULL);
1295 packet->stream = NULL;
1296 packet->src_id = packet->dst_id = NULL;
1297 silc_buffer_reset(&packet->buffer);
1299 silc_mutex_lock(stream->sc->engine->lock);
1301 /* Put the packet back to freelist */
1302 silc_list_add(stream->sc->engine->packet_pool, packet);
1303 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1304 silc_list_start(stream->sc->engine->packet_pool);
1306 silc_mutex_unlock(stream->sc->engine->lock);
1309 /****************************** Packet Sending ******************************/
1311 /* Prepare outgoing data buffer for packet sending. Returns the
1312 pointer to that buffer into the `packet'. */
1314 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1319 unsigned char *oldptr;
1320 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1324 /* Allocate more space if needed */
1325 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1326 if (!silc_buffer_realloc(&stream->outbuf,
1327 silc_buffer_truelen(&stream->outbuf) + totlen))
1331 /* Pull data area for the new packet, and return pointer to the start of
1332 the data area and save the pointer in to the `packet'. MAC is pulled
1333 later after it's computed. */
1334 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1335 silc_buffer_set(packet, oldptr, totlen);
1336 silc_buffer_push_tail(packet, mac_len);
1341 /* Increments counter when encrypting in counter mode. */
1343 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1345 unsigned char *ret_iv)
1347 unsigned char *iv = silc_cipher_get_iv(cipher);
1350 /* Increment packet counter */
1351 SILC_GET32_MSB(pc, iv + 8);
1353 SILC_PUT32_MSB(pc, iv + 8);
1355 /* Reset block counter */
1356 memset(iv + 12, 0, 4);
1358 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1359 if (stream->iv_included) {
1361 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1362 ret_iv[1] = ret_iv[0] + iv[4];
1363 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1364 ret_iv[3] = ret_iv[0] + ret_iv[2];
1365 SILC_PUT32_MSB(pc, ret_iv + 4);
1366 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1368 /* Set new nonce to counter block */
1369 memcpy(iv + 4, ret_iv, 4);
1372 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1375 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1376 the packet. The silc_packet_stream_write needs to be called to send it
1377 after this returns TRUE. */
1379 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1380 SilcPacketType type,
1381 SilcPacketFlags flags,
1382 SilcIdType src_id_type,
1383 unsigned char *src_id,
1384 SilcUInt32 src_id_len,
1385 SilcIdType dst_id_type,
1386 unsigned char *dst_id,
1387 SilcUInt32 dst_id_len,
1388 const unsigned char *data,
1389 SilcUInt32 data_len,
1393 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1394 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1395 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1397 SilcBufferStruct packet;
1399 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1400 "data len %d", silc_get_packet_name(type), stream->send_psn,
1401 flags, src_id_type, dst_id_type, data_len));
1403 /* Get the true length of the packet. This is saved as payload length
1404 into the packet header. This does not include the length of the
1406 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1407 src_id_len + dst_id_len));
1408 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1409 src_id_len + dst_id_len);
1411 /* If using CTR mode, increment the counter */
1412 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1414 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1416 /* If IV is included, the SID, IV and sequence number is added to packet */
1417 if (stream->iv_included && cipher) {
1418 psnlen = sizeof(psn);
1420 iv[0] = stream->sid;
1423 /* If IV is included, the SID, IV and sequence number is added to packet */
1424 if (stream->iv_included && cipher) {
1425 psnlen = sizeof(psn);
1426 ivlen = block_len + 1;
1427 iv[0] = stream->sid;
1428 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1432 /* We automatically figure out the packet structure from the packet
1433 type and flags, and calculate correct length. Private messages with
1434 private keys and channel messages are special packets as their
1435 payload is encrypted already. */
1436 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1437 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1438 type == SILC_PACKET_CHANNEL_MESSAGE) {
1440 /* Padding is calculated from header + IDs */
1442 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1443 psnlen), block_len, padlen);
1445 /* Length to encrypt, header + IDs + padding. */
1446 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1450 /* Padding is calculated from true length of the packet */
1451 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1452 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1454 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1456 enclen += padlen + psnlen;
1459 /* Remove implementation specific flags */
1460 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1462 /* Get random padding */
1463 for (i = 0; i < padlen; i++) tmppad[i] =
1464 silc_rng_get_byte_fast(stream->sc->engine->rng);
1466 silc_mutex_lock(stream->lock);
1468 /* Get packet pointer from the outgoing buffer */
1469 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1470 + psnlen, hmac, &packet))) {
1471 silc_mutex_unlock(stream->lock);
1475 SILC_PUT32_MSB(stream->send_psn, psn);
1477 /* Create the packet. This creates the SILC header, adds padding, and
1478 the actual packet data. */
1479 i = silc_buffer_format(&packet,
1480 SILC_STR_DATA(iv, ivlen),
1481 SILC_STR_DATA(psn, psnlen),
1482 SILC_STR_UI_SHORT(truelen),
1483 SILC_STR_UI_CHAR(flags),
1484 SILC_STR_UI_CHAR(type),
1485 SILC_STR_UI_CHAR(padlen),
1486 SILC_STR_UI_CHAR(0),
1487 SILC_STR_UI_CHAR(src_id_len),
1488 SILC_STR_UI_CHAR(dst_id_len),
1489 SILC_STR_UI_CHAR(src_id_type),
1490 SILC_STR_DATA(src_id, src_id_len),
1491 SILC_STR_UI_CHAR(dst_id_type),
1492 SILC_STR_DATA(dst_id, dst_id_len),
1493 SILC_STR_DATA(tmppad, padlen),
1494 SILC_STR_DATA(data, data_len),
1496 if (silc_unlikely(i < 0)) {
1497 silc_mutex_unlock(stream->lock);
1501 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1502 silc_buffer_data(&packet), silc_buffer_len(&packet));
1504 /* Encrypt the packet */
1505 if (silc_likely(cipher)) {
1506 SILC_LOG_DEBUG(("Encrypting packet"));
1507 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1508 packet.data + ivlen, enclen,
1510 SILC_LOG_ERROR(("Packet encryption failed"));
1511 silc_mutex_unlock(stream->lock);
1517 if (silc_likely(hmac)) {
1520 /* MAC is computed from the entire encrypted packet data, and put
1521 to the end of the packet. */
1522 silc_hmac_init(hmac);
1523 silc_hmac_update(hmac, psn, sizeof(psn));
1524 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1525 silc_hmac_final(hmac, packet.tail, &mac_len);
1526 silc_buffer_pull_tail(&packet, mac_len);
1533 /* Sends a packet */
1535 SilcBool silc_packet_send(SilcPacketStream stream,
1536 SilcPacketType type, SilcPacketFlags flags,
1537 const unsigned char *data, SilcUInt32 data_len)
1541 ret = silc_packet_send_raw(stream, type, flags,
1542 stream->src_id_type,
1545 stream->dst_id_type,
1549 stream->send_key[0],
1550 stream->send_hmac[0]);
1552 /* Write the packet to the stream */
1553 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1556 /* Sends a packet, extended routine */
1558 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1559 SilcPacketType type, SilcPacketFlags flags,
1560 SilcIdType src_id_type, void *src_id,
1561 SilcIdType dst_id_type, void *dst_id,
1562 const unsigned char *data, SilcUInt32 data_len,
1563 SilcCipher cipher, SilcHmac hmac)
1565 unsigned char src_id_data[32], dst_id_data[32];
1566 SilcUInt32 src_id_len, dst_id_len;
1570 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1571 sizeof(src_id_data), &src_id_len))
1574 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1575 sizeof(dst_id_data), &dst_id_len))
1578 ret = silc_packet_send_raw(stream, type, flags,
1579 src_id ? src_id_type : stream->src_id_type,
1580 src_id ? src_id_data : stream->src_id,
1581 src_id ? src_id_len : stream->src_id_len,
1582 dst_id ? dst_id_type : stream->dst_id_type,
1583 dst_id ? dst_id_data : stream->dst_id,
1584 dst_id ? dst_id_len : stream->dst_id_len,
1586 cipher ? cipher : stream->send_key[0],
1587 hmac ? hmac : stream->send_hmac[0]);
1589 /* Write the packet to the stream */
1590 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1593 /* Sends packet after formatting the arguments to buffer */
1595 SilcBool silc_packet_send_va(SilcPacketStream stream,
1596 SilcPacketType type, SilcPacketFlags flags, ...)
1598 SilcBufferStruct buf;
1602 va_start(va, flags);
1604 memset(&buf, 0, sizeof(buf));
1605 if (silc_buffer_format_vp(&buf, va) < 0) {
1610 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1611 silc_buffer_len(&buf));
1613 silc_buffer_purge(&buf);
1619 /* Sends packet after formatting the arguments to buffer, extended routine */
1621 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1622 SilcPacketType type, SilcPacketFlags flags,
1623 SilcIdType src_id_type, void *src_id,
1624 SilcIdType dst_id_type, void *dst_id,
1625 SilcCipher cipher, SilcHmac hmac, ...)
1627 SilcBufferStruct buf;
1633 memset(&buf, 0, sizeof(buf));
1634 if (silc_buffer_format_vp(&buf, va) < 0) {
1639 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1640 dst_id_type, dst_id, silc_buffer_data(&buf),
1641 silc_buffer_len(&buf), cipher, hmac);
1643 silc_buffer_purge(&buf);
1649 /***************************** Packet Receiving *****************************/
1651 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1653 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1654 const unsigned char *data,
1655 SilcUInt32 data_len,
1656 const unsigned char *packet_mac,
1657 const unsigned char *packet_seq,
1658 SilcUInt32 sequence)
1661 if (silc_likely(hmac)) {
1662 unsigned char mac[32], psn[4];
1665 SILC_LOG_DEBUG(("Verifying MAC"));
1667 /* Compute HMAC of packet */
1668 silc_hmac_init(hmac);
1671 SILC_PUT32_MSB(sequence, psn);
1672 silc_hmac_update(hmac, psn, 4);
1674 silc_hmac_update(hmac, packet_seq, 4);
1676 silc_hmac_update(hmac, data, data_len);
1677 silc_hmac_final(hmac, mac, &mac_len);
1679 /* Compare the MAC's */
1680 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1681 SILC_LOG_DEBUG(("MAC failed"));
1685 SILC_LOG_DEBUG(("MAC is Ok"));
1691 /* Increments/sets counter when decrypting in counter mode. */
1693 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1695 unsigned char *packet_iv)
1699 /* If IV Included flag, set the IV from packet to block counter. */
1700 if (stream->iv_included) {
1701 memcpy(iv + 4, packet_iv, 8);
1703 /* Increment packet counter */
1704 SILC_GET32_MSB(pc, iv + 8);
1706 SILC_PUT32_MSB(pc, iv + 8);
1709 /* Reset block counter */
1710 memset(iv + 12, 0, 4);
1712 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1715 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1716 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1718 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1719 SilcUInt32 sequence, SilcBuffer buffer,
1722 if (normal == TRUE) {
1723 if (silc_likely(cipher)) {
1724 /* Decrypt rest of the packet */
1725 SILC_LOG_DEBUG(("Decrypting the packet"));
1726 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1728 silc_buffer_len(buffer), NULL)))
1734 /* Decrypt rest of the header plus padding */
1735 if (silc_likely(cipher)) {
1737 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1739 SILC_LOG_DEBUG(("Decrypting the header"));
1741 /* Padding length + src id len + dst id len + header length - 16
1742 bytes already decrypted, gives the rest of the encrypted packet */
1743 silc_buffer_push(buffer, block_len);
1744 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1745 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1747 silc_buffer_pull(buffer, block_len);
1749 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1750 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1754 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1755 buffer->data, len, NULL)))
1763 /* Parses the packet. This is called when a whole packet is ready to be
1764 parsed. The buffer sent must be already decrypted before calling this
1767 static inline SilcBool silc_packet_parse(SilcPacket packet)
1769 SilcBuffer buffer = &packet->buffer;
1770 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1771 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1774 SILC_LOG_DEBUG(("Parsing incoming packet"));
1776 /* Parse the buffer. This parses the SILC header of the packet. */
1777 ret = silc_buffer_unformat(buffer,
1780 SILC_STR_UI_CHAR(&src_id_len),
1781 SILC_STR_UI_CHAR(&dst_id_len),
1782 SILC_STR_UI_CHAR(&src_id_type),
1784 if (silc_unlikely(ret == -1)) {
1785 if (!packet->stream->udp &&
1786 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1787 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1791 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1792 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1793 if (!packet->stream->udp &&
1794 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1795 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1796 packet->src_id_len, packet->dst_id_len));
1800 ret = silc_buffer_unformat(buffer,
1802 SILC_STR_DATA(&packet->src_id, src_id_len),
1803 SILC_STR_UI_CHAR(&dst_id_type),
1804 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1805 SILC_STR_OFFSET(padlen),
1807 if (silc_unlikely(ret == -1)) {
1808 if (!packet->stream->udp &&
1809 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1810 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1814 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1815 dst_id_type > SILC_ID_CHANNEL)) {
1816 if (!packet->stream->udp &&
1817 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1818 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1819 src_id_type, dst_id_type));
1823 packet->src_id_len = src_id_len;
1824 packet->dst_id_len = dst_id_len;
1825 packet->src_id_type = src_id_type;
1826 packet->dst_id_type = dst_id_type;
1828 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1829 silc_buffer_len(buffer)), buffer->head,
1830 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1832 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1833 silc_get_packet_name(packet->type)));
1838 /* Dispatch packet to application. Called with stream->lock locked.
1839 Returns FALSE if the stream was destroyed while dispatching a packet. */
1841 static SilcBool silc_packet_dispatch(SilcPacket packet)
1843 SilcPacketStream stream = packet->stream;
1844 SilcPacketProcess p;
1845 SilcBool default_sent = FALSE;
1848 /* Dispatch packet to all packet processors that want it */
1850 if (silc_likely(!stream->process)) {
1851 /* Send to default processor as no others exist */
1852 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1853 silc_mutex_unlock(stream->lock);
1854 if (silc_unlikely(!stream->sc->engine->callbacks->
1855 packet_receive(stream->sc->engine, stream, packet,
1856 stream->sc->engine->callback_context,
1857 stream->stream_context)))
1858 silc_packet_free(packet);
1859 silc_mutex_lock(stream->lock);
1860 return stream->destroyed == FALSE;
1863 silc_dlist_start(stream->process);
1864 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1866 /* If priority is 0 or less, we send to default processor first
1867 because default processor has 0 priority */
1868 if (!default_sent && p->priority <= 0) {
1869 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1870 default_sent = TRUE;
1871 silc_mutex_unlock(stream->lock);
1872 if (stream->sc->engine->callbacks->
1873 packet_receive(stream->sc->engine, stream, packet,
1874 stream->sc->engine->callback_context,
1875 stream->stream_context)) {
1876 silc_mutex_lock(stream->lock);
1877 return stream->destroyed == FALSE;
1879 silc_mutex_lock(stream->lock);
1882 /* Send to processor */
1884 /* Send all packet types */
1885 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1886 silc_mutex_unlock(stream->lock);
1887 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1888 p->callback_context,
1889 stream->stream_context)) {
1890 silc_mutex_lock(stream->lock);
1891 return stream->destroyed == FALSE;
1893 silc_mutex_lock(stream->lock);
1895 /* Send specific types */
1896 for (pt = p->types; *pt; pt++) {
1897 if (*pt != packet->type)
1899 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1900 silc_mutex_unlock(stream->lock);
1901 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1902 p->callback_context,
1903 stream->stream_context)) {
1904 silc_mutex_lock(stream->lock);
1905 return stream->destroyed == FALSE;
1907 silc_mutex_lock(stream->lock);
1913 if (!default_sent) {
1914 /* Send to default processor as it has not been sent yet */
1915 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1916 silc_mutex_unlock(stream->lock);
1917 if (stream->sc->engine->callbacks->
1918 packet_receive(stream->sc->engine, stream, packet,
1919 stream->sc->engine->callback_context,
1920 stream->stream_context)) {
1921 silc_mutex_lock(stream->lock);
1922 return stream->destroyed == FALSE;
1924 silc_mutex_lock(stream->lock);
1927 /* If we got here, no one wanted the packet, so drop it */
1928 silc_packet_free(packet);
1929 return stream->destroyed == FALSE;
1932 /* Process incoming data and parse packets. Called with stream->lock
1935 static void silc_packet_read_process(SilcPacketStream stream)
1942 SilcUInt16 packetlen;
1943 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1944 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1945 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1949 /* Get inbuf. If there is already some data for this stream in the buffer
1950 we already have it. Otherwise get the current one from list, it will
1951 include the data. */
1952 inbuf = stream->inbuf;
1954 silc_dlist_start(stream->sc->inbufs);
1955 inbuf = silc_dlist_get(stream->sc->inbufs);
1958 /* Parse the packets from the data */
1959 while (silc_buffer_len(inbuf) > 0) {
1961 cipher = stream->receive_key[0];
1962 hmac = stream->receive_hmac[0];
1965 if (silc_unlikely(silc_buffer_len(inbuf) <
1966 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1967 SILC_PACKET_MIN_HEADER_LEN))) {
1968 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1969 silc_dlist_del(stream->sc->inbufs, inbuf);
1970 stream->inbuf = inbuf;
1974 if (silc_likely(hmac))
1975 mac_len = silc_hmac_len(hmac);
1979 /* Decrypt first block of the packet to get the length field out */
1980 if (silc_likely(cipher)) {
1981 block_len = silc_cipher_get_block_len(cipher);
1983 if (stream->iv_included) {
1984 /* SID, IV and sequence number is included in the ciphertext */
1985 sid = (SilcUInt8)inbuf->data[0];
1987 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
1988 /* Set the CTR mode IV from packet to counter block */
1989 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1990 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
1993 /* Get IV from packet */
1994 memcpy(iv, inbuf->data + 1, block_len);
1995 ivlen = block_len + 1;
1999 /* Check SID, and get correct decryption key */
2000 if (sid != stream->sid) {
2001 /* If SID is recent get the previous key and use it */
2002 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2003 stream->receive_key[1] && !stream->receive_hmac[1]) {
2004 cipher = stream->receive_key[1];
2005 hmac = stream->receive_hmac[1];
2007 /* The SID is unknown, drop rest of the data in buffer */
2008 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2010 silc_mutex_unlock(stream->lock);
2011 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2012 silc_mutex_lock(stream->lock);
2017 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2019 /* If using CTR mode, increment the counter */
2020 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2021 silc_packet_receive_ctr_increment(stream, iv, NULL);
2024 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp,
2028 if (stream->iv_included) {
2029 /* Take sequence number from packet */
2030 packet_seq = header;
2034 /* Unencrypted packet */
2035 block_len = SILC_PACKET_MIN_HEADER_LEN;
2036 header = inbuf->data;
2039 /* Get packet length and full packet length with padding */
2040 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2043 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2044 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2045 SILC_LOG_ERROR(("Received too short packet"));
2046 silc_mutex_unlock(stream->lock);
2047 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2048 silc_mutex_lock(stream->lock);
2049 memset(tmp, 0, sizeof(tmp));
2053 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2054 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2056 paddedlen + mac_len - silc_buffer_len(inbuf)));
2057 memset(tmp, 0, sizeof(tmp));
2058 silc_dlist_del(stream->sc->inbufs, inbuf);
2059 stream->inbuf = inbuf;
2063 /* Check MAC of the packet */
2064 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2066 inbuf->data + ivlen +
2067 paddedlen, packet_seq,
2068 stream->receive_psn))) {
2069 silc_mutex_unlock(stream->lock);
2070 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2071 silc_mutex_lock(stream->lock);
2072 memset(tmp, 0, sizeof(tmp));
2077 packet = silc_packet_alloc(stream->sc->engine);
2078 if (silc_unlikely(!packet)) {
2079 silc_mutex_unlock(stream->lock);
2080 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2081 silc_mutex_lock(stream->lock);
2082 memset(tmp, 0, sizeof(tmp));
2085 packet->stream = stream;
2087 /* Allocate more space to packet buffer, if needed */
2088 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2089 if (!silc_buffer_realloc(&packet->buffer,
2090 silc_buffer_truelen(&packet->buffer) +
2092 silc_buffer_truelen(&packet->buffer)))) {
2093 silc_mutex_unlock(stream->lock);
2094 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2095 silc_mutex_lock(stream->lock);
2096 silc_packet_free(packet);
2097 memset(tmp, 0, sizeof(tmp));
2102 /* Parse packet header */
2103 packet->flags = (SilcPacketFlags)header[2];
2104 packet->type = (SilcPacketType)header[3];
2106 if (stream->sc->engine->local_is_router) {
2107 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2108 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2110 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2111 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2112 stream->is_router == TRUE))
2115 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2116 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2118 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2122 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2123 stream->receive_psn, paddedlen + ivlen + mac_len),
2124 inbuf->data, paddedlen + ivlen + mac_len);
2126 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2127 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2128 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2129 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2130 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2131 psnlen + (block_len - psnlen)),
2132 paddedlen - ivlen - psnlen - (block_len - psnlen));
2133 if (silc_likely(cipher)) {
2134 silc_cipher_set_iv(cipher, iv);
2135 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2136 &packet->buffer, normal);
2137 if (silc_unlikely(ret < 0)) {
2138 silc_mutex_unlock(stream->lock);
2139 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2140 silc_mutex_lock(stream->lock);
2141 silc_packet_free(packet);
2142 memset(tmp, 0, sizeof(tmp));
2146 stream->receive_psn++;
2148 silc_buffer_push(&packet->buffer, block_len);
2150 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2151 silc_buffer_pull(inbuf, paddedlen + mac_len);
2153 /* Parse the packet */
2154 if (silc_unlikely(!silc_packet_parse(packet))) {
2155 silc_mutex_unlock(stream->lock);
2156 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2157 silc_mutex_lock(stream->lock);
2158 silc_packet_free(packet);
2159 memset(tmp, 0, sizeof(tmp));
2163 /* Dispatch the packet to application */
2164 if (!silc_packet_dispatch(packet))
2169 /* Add inbuf back to free list, if we owned it. */
2170 if (stream->inbuf) {
2171 silc_dlist_add(stream->sc->inbufs, inbuf);
2172 stream->inbuf = NULL;
2175 silc_buffer_reset(inbuf);
2178 /****************************** Packet Waiting ******************************/
2180 /* Packet wait receive callback */
2182 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2183 SilcPacketStream stream,
2185 void *callback_context,
2186 void *stream_context);
2188 /* Packet waiting callbacks */
2189 static SilcPacketCallbacks silc_packet_wait_cbs =
2191 silc_packet_wait_packet_receive, NULL, NULL
2194 /* Packet waiting context */
2196 SilcMutex wait_lock;
2198 SilcList packet_queue;
2199 unsigned int stopped : 1;
2202 /* Packet wait receive callback */
2205 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2206 SilcPacketStream stream,
2208 void *callback_context,
2209 void *stream_context)
2211 SilcPacketWait pw = callback_context;
2213 /* Signal the waiting thread for a new packet */
2214 silc_mutex_lock(pw->wait_lock);
2216 if (silc_unlikely(pw->stopped)) {
2217 silc_mutex_unlock(pw->wait_lock);
2221 silc_list_add(pw->packet_queue, packet);
2222 silc_cond_broadcast(pw->wait_cond);
2224 silc_mutex_unlock(pw->wait_lock);
2229 /* Initialize packet waiting */
2231 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2237 pw = silc_calloc(1, sizeof(*pw));
2241 /* Allocate mutex and conditional variable */
2242 if (!silc_mutex_alloc(&pw->wait_lock)) {
2246 if (!silc_cond_alloc(&pw->wait_cond)) {
2247 silc_mutex_free(pw->wait_lock);
2252 /* Link to the packet stream for the requested packet types */
2253 va_start(ap, stream);
2254 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2258 silc_cond_free(pw->wait_cond);
2259 silc_mutex_free(pw->wait_lock);
2264 /* Initialize packet queue */
2265 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2270 /* Uninitialize packet waiting */
2272 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2274 SilcPacketWait pw = waiter;
2277 /* Signal any threads to stop waiting */
2278 silc_mutex_lock(pw->wait_lock);
2280 silc_cond_broadcast(pw->wait_cond);
2281 silc_mutex_unlock(pw->wait_lock);
2283 /* Re-acquire lock and free resources */
2284 silc_mutex_lock(pw->wait_lock);
2285 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2287 /* Free any remaining packets */
2288 silc_list_start(pw->packet_queue);
2289 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2290 silc_packet_free(packet);
2292 silc_mutex_unlock(pw->wait_lock);
2293 silc_cond_free(pw->wait_cond);
2294 silc_mutex_free(pw->wait_lock);
2298 /* Blocks thread until a packet has been received. */
2300 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2302 SilcPacketWait pw = waiter;
2303 SilcBool ret = FALSE;
2305 silc_mutex_lock(pw->wait_lock);
2307 /* Wait here until packet has arrived */
2308 while (silc_list_count(pw->packet_queue) == 0) {
2309 if (silc_unlikely(pw->stopped)) {
2310 silc_mutex_unlock(pw->wait_lock);
2313 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2317 silc_list_start(pw->packet_queue);
2318 *return_packet = silc_list_get(pw->packet_queue);
2319 silc_list_del(pw->packet_queue, *return_packet);
2321 silc_mutex_unlock(pw->wait_lock);
2323 return ret == TRUE ? 1 : 0;
2326 /************************** Packet Stream Wrapper ***************************/
2328 /* Packet stream wrapper receive callback */
2330 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2331 SilcPacketStream stream,
2333 void *callback_context,
2334 void *stream_context);
2336 const SilcStreamOps silc_packet_stream_ops;
2338 /* Packet stream wrapper context */
2340 const SilcStreamOps *ops;
2341 SilcPacketStream stream;
2343 void *waiter; /* Waiter context in blocking mode */
2344 SilcPacketWrapCoder coder;
2345 void *coder_context;
2347 SilcStreamNotifier callback;
2350 SilcPacketType type;
2351 SilcPacketFlags flags;
2352 unsigned int closed : 1;
2353 unsigned int blocking : 1;
2354 unsigned int read_more : 1;
2355 } *SilcPacketWrapperStream;
2357 /* Packet wrapper callbacks */
2358 static SilcPacketCallbacks silc_packet_wrap_cbs =
2360 silc_packet_wrap_packet_receive, NULL, NULL
2363 /* Packet stream wrapper receive callback, non-blocking mode */
2366 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2367 SilcPacketStream stream,
2369 void *callback_context,
2370 void *stream_context)
2372 SilcPacketWrapperStream pws = callback_context;
2374 if (pws->closed || !pws->callback)
2377 silc_mutex_lock(pws->lock);
2378 silc_list_add(pws->in_queue, packet);
2379 silc_mutex_unlock(pws->lock);
2381 /* Call notifier callback */
2382 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2387 /* Task callback to notify more data is available for reading */
2389 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2391 SilcPacketWrapperStream pws = context;
2393 if (pws->closed || !pws->callback)
2396 /* Call notifier callback */
2397 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2400 /* Read SILC packet */
2402 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2405 SilcPacketWrapperStream pws = stream;
2407 SilcBool read_more = FALSE;
2413 if (pws->blocking) {
2414 /* Block until packet is received */
2415 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2420 /* Non-blocking mode */
2421 silc_mutex_lock(pws->lock);
2422 if (!silc_list_count(pws->in_queue)) {
2423 silc_mutex_unlock(pws->lock);
2427 silc_list_start(pws->in_queue);
2428 packet = silc_list_get(pws->in_queue);
2429 silc_list_del(pws->in_queue, packet);
2430 silc_mutex_unlock(pws->lock);
2433 /* Call decoder if set */
2434 if (pws->coder && !pws->read_more)
2435 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2436 pws->coder_context);
2438 len = silc_buffer_len(&packet->buffer);
2439 if (len > buf_len) {
2445 memcpy(buf, packet->buffer.data, len);
2447 if (read_more && !pws->blocking) {
2448 /* More data will be available (in blocking mode not supported). */
2449 silc_buffer_pull(&packet->buffer, len);
2450 silc_list_insert(pws->in_queue, NULL, packet);
2451 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2452 silc_packet_wrap_read_more, pws, 0, 0);
2453 pws->read_more = TRUE;
2457 pws->read_more = FALSE;
2458 silc_packet_free(packet);
2462 /* Write SILC packet */
2464 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2465 SilcUInt32 data_len)
2467 SilcPacketWrapperStream pws = stream;
2468 SilcBool ret = FALSE;
2470 /* Call decoder if set */
2472 silc_buffer_reset(pws->encbuf);
2473 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2474 pws->coder_context);
2477 /* Send the SILC packet */
2479 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2480 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2481 silc_buffer_len(pws->encbuf)),
2482 SILC_STR_DATA(data, data_len),
2486 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2495 SilcBool silc_packet_wrap_close(SilcStream stream)
2497 SilcPacketWrapperStream pws = stream;
2502 if (pws->blocking) {
2503 /* Close packet waiter */
2504 silc_packet_wait_uninit(pws->waiter, pws->stream);
2508 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2515 /* Destroy wrapper stream */
2517 void silc_packet_wrap_destroy(SilcStream stream)
2520 SilcPacketWrapperStream pws = stream;
2523 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2525 silc_stream_close(stream);
2526 silc_list_start(pws->in_queue);
2527 while ((packet = silc_list_get(pws->in_queue)))
2528 silc_packet_free(packet);
2530 silc_mutex_free(pws->lock);
2532 silc_buffer_free(pws->encbuf);
2533 silc_packet_stream_unref(pws->stream);
2538 /* Link stream to receive packets */
2540 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2541 SilcSchedule schedule,
2542 SilcStreamNotifier callback,
2545 SilcPacketWrapperStream pws = stream;
2547 if (pws->closed || pws->blocking)
2550 /* Link to receive packets */
2552 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2553 100000, pws->type, -1);
2555 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2557 pws->callback = callback;
2558 pws->context = context;
2563 /* Return schedule */
2565 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2570 /* Wraps packet stream into SilcStream. */
2572 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2573 SilcPacketType type,
2574 SilcPacketFlags flags,
2575 SilcBool blocking_mode,
2576 SilcPacketWrapCoder coder,
2579 SilcPacketWrapperStream pws;
2581 pws = silc_calloc(1, sizeof(*pws));
2585 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2587 pws->ops = &silc_packet_stream_ops;
2588 pws->stream = stream;
2591 pws->blocking = blocking_mode;
2593 pws->coder_context = context;
2595 /* Allocate small amount for encoder buffer. */
2597 pws->encbuf = silc_buffer_alloc(8);
2599 if (pws->blocking) {
2600 /* Blocking mode. Use packet waiter to do the thing. */
2601 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2607 /* Non-blocking mode */
2608 if (!silc_mutex_alloc(&pws->lock)) {
2613 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2616 silc_packet_stream_ref(stream);
2618 return (SilcStream)pws;
2621 const SilcStreamOps silc_packet_stream_ops =
2623 silc_packet_wrap_read,
2624 silc_packet_wrap_write,
2625 silc_packet_wrap_close,
2626 silc_packet_wrap_destroy,
2627 silc_packet_wrap_notifier,
2628 silc_packet_wrap_get_schedule,