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 SilcBufferStruct inbuf; /* Data input buffer */
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 SilcCipher send_key[2]; /* Sending key */
76 SilcHmac send_hmac[2]; /* Sending HMAC */
77 SilcCipher receive_key[2]; /* Receiving key */
78 SilcHmac receive_hmac[2]; /* Receiving HMAC */
79 unsigned char *src_id; /* Source ID */
80 unsigned char *dst_id; /* Destination ID */
81 SilcUInt32 send_psn; /* Sending sequence */
82 SilcUInt32 receive_psn; /* Receiving sequence */
83 SilcAtomic8 refcnt; /* Reference counter */
84 SilcUInt8 sid; /* Security ID, set if IV included */
85 unsigned int src_id_len : 6;
86 unsigned int src_id_type : 2;
87 unsigned int dst_id_len : 6;
88 unsigned int dst_id_type : 2;
89 unsigned int is_router : 1; /* Set if router stream */
90 unsigned int destroyed : 1; /* Set if destroyed */
91 unsigned int iv_included : 1; /* Set if IV included */
92 unsigned int udp : 1; /* UDP remote stream */
95 /* Initial size of stream buffers */
96 #define SILC_PACKET_DEFAULT_SIZE 1024
98 /* Header length without source and destination ID's. */
99 #define SILC_PACKET_HEADER_LEN 10
101 /* Minimum length of SILC Packet Header. */
102 #define SILC_PACKET_MIN_HEADER_LEN 16
103 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
105 /* Maximum padding length */
106 #define SILC_PACKET_MAX_PADLEN 128
108 /* Default padding length */
109 #define SILC_PACKET_DEFAULT_PADLEN 16
111 /* Minimum packet length */
112 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
114 /* Returns true length of the packet. */
115 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
117 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
118 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
121 /* Calculates the data length with given header length. This macro
122 can be used to check whether the data_len with header_len exceeds
123 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
124 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
125 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
126 is the data_len given as argument. */
127 #define SILC_PACKET_DATALEN(data_len, header_len) \
128 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
129 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
131 /* Calculates the length of the padding in the packet. */
132 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
134 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
135 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
137 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
140 /* Returns the length of the padding up to the maximum length, which
142 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
144 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
145 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
149 #define SILC_PACKET_CALLBACK_EOS(s) \
151 (s)->sc->engine->callbacks->eos((s)->sc->engine, s, \
152 (s)->sc->engine->callback_context, \
153 (s)->stream_context); \
157 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
159 (s)->sc->engine->callbacks->error((s)->sc->engine, s, err, \
160 (s)->sc->engine->callback_context, \
161 (s)->stream_context); \
164 static SilcBool silc_packet_dispatch(SilcPacket packet);
165 static void silc_packet_read_process(SilcPacketStream stream);
166 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
168 SilcPacketFlags flags,
169 SilcIdType src_id_type,
170 unsigned char *src_id,
171 SilcUInt32 src_id_len,
172 SilcIdType dst_id_type,
173 unsigned char *dst_id,
174 SilcUInt32 dst_id_len,
175 const unsigned char *data,
180 /************************ Static utility functions **************************/
182 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
184 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
186 SilcPacket packet = context;
187 SilcPacketStream stream = packet->stream;
189 SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
191 silc_mutex_lock(stream->lock);
192 if (!stream->destroyed)
193 silc_packet_dispatch(packet);
194 silc_mutex_unlock(stream->lock);
195 silc_packet_stream_unref(stream);
198 /* Write data to the stream. Must be called with ps->lock locked. Unlocks
199 the lock inside this function, unless no_unlock is TRUE. Unlocks always
200 in case it returns FALSE. */
202 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
210 stream = ((SilcPacketStream)ps->stream)->stream;
214 if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
216 /* Connectionless UDP stream */
217 while (silc_buffer_len(&ps->outbuf) > 0) {
218 i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
219 ps->remote_udp->remote_port,
220 ps->outbuf.data, silc_buffer_len(&ps->outbuf));
221 if (silc_unlikely(i == -2)) {
223 silc_buffer_reset(&ps->outbuf);
224 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
228 if (silc_unlikely(i == -1)) {
229 /* Cannot write now, write later. */
231 silc_mutex_unlock(ps->lock);
236 silc_buffer_pull(&ps->outbuf, i);
239 silc_buffer_reset(&ps->outbuf);
241 silc_mutex_unlock(ps->lock);
247 /* Write the data to the stream */
248 while (silc_buffer_len(&ps->outbuf) > 0) {
249 i = silc_stream_write(stream, ps->outbuf.data,
250 silc_buffer_len(&ps->outbuf));
251 if (silc_unlikely(i == 0)) {
253 silc_buffer_reset(&ps->outbuf);
254 silc_mutex_unlock(ps->lock);
255 SILC_PACKET_CALLBACK_EOS(ps);
259 if (silc_unlikely(i == -2)) {
261 silc_buffer_reset(&ps->outbuf);
262 silc_mutex_unlock(ps->lock);
263 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
267 if (silc_unlikely(i == -1)) {
268 /* Cannot write now, write later. */
270 silc_mutex_unlock(ps->lock);
275 silc_buffer_pull(&ps->outbuf, i);
278 silc_buffer_reset(&ps->outbuf);
280 silc_mutex_unlock(ps->lock);
285 /* Reads data from stream. Must be called with ps->lock locked. If this
286 returns FALSE the lock has been unlocked. If this returns packet stream
287 to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
288 It is returned if the stream is UDP and remote UDP stream exists for
289 the sender of the packet. */
291 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
292 SilcPacketStream *ret_ps)
300 inbuf = &ps->sc->inbuf;
302 if (silc_socket_stream_is_udp(stream, &connected)) {
304 /* Connectionless UDP stream, read one UDP packet */
305 char remote_ip[64], tuple[64];
307 SilcPacketStream remote;
309 ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
310 &remote_port, inbuf->tail,
311 silc_buffer_taillen(inbuf));
313 if (silc_unlikely(ret < 0)) {
314 silc_mutex_unlock(ps->lock);
316 /* Cannot read now, do it later. */
317 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
322 silc_buffer_reset(inbuf);
323 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
327 /* See if remote packet stream exist for this sender */
328 silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
329 silc_mutex_lock(ps->sc->engine->lock);
330 if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
332 silc_mutex_unlock(ps->sc->engine->lock);
333 SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
334 remote_port, remote));
335 silc_mutex_unlock(ps->lock);
336 silc_mutex_lock(remote->lock);
340 silc_mutex_unlock(ps->sc->engine->lock);
343 if (!ps->remote_udp) {
344 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
345 if (silc_unlikely(!ps->remote_udp)) {
346 silc_mutex_unlock(ps->lock);
347 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
352 /* Save sender IP and port */
353 silc_free(ps->remote_udp->remote_ip);
354 ps->remote_udp->remote_ip = strdup(remote_ip);
355 ps->remote_udp->remote_port = remote_port;
357 silc_buffer_pull_tail(inbuf, ret);
362 /* Read data from the stream */
363 ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
364 if (silc_unlikely(ret <= 0)) {
365 silc_mutex_unlock(ps->lock);
368 silc_buffer_reset(inbuf);
369 SILC_PACKET_CALLBACK_EOS(ps);
374 /* Cannot read now, do it later. */
375 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
380 silc_buffer_reset(inbuf);
381 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
385 silc_buffer_pull_tail(inbuf, ret);
389 /* Our stream IO notifier callback. */
391 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
394 SilcPacketStream remote = NULL, ps = context;
396 silc_mutex_lock(ps->lock);
398 if (silc_unlikely(ps->destroyed)) {
399 silc_mutex_unlock(ps->lock);
404 case SILC_STREAM_CAN_READ:
405 /* Reading is locked also with stream->lock because we may be reading
406 at the same time other thread is writing to same underlaying stream. */
407 SILC_LOG_DEBUG(("Reading data from stream"));
409 /* Read data from stream */
410 if (!silc_packet_stream_read(ps, &remote))
413 /* Now process the data */
414 silc_packet_stream_ref(ps);
416 silc_packet_read_process(ps);
417 silc_mutex_unlock(ps->lock);
419 silc_packet_read_process(remote);
420 silc_mutex_unlock(remote->lock);
422 silc_packet_stream_unref(ps);
425 case SILC_STREAM_CAN_WRITE:
426 SILC_LOG_DEBUG(("Writing pending data to stream"));
428 if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
429 silc_mutex_unlock(ps->lock);
433 /* Write pending data to stream */
434 silc_packet_stream_write(ps, FALSE);
438 silc_mutex_unlock(ps->lock);
443 /* Allocate packet */
445 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
449 SILC_LOG_DEBUG(("Packet pool count %d",
450 silc_list_count(engine->packet_pool)));
452 silc_mutex_lock(engine->lock);
454 /* Get packet from freelist or allocate new one. */
455 packet = silc_list_get(engine->packet_pool);
459 silc_mutex_unlock(engine->lock);
461 packet = silc_calloc(1, sizeof(*packet));
462 if (silc_unlikely(!packet))
465 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
467 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
468 if (silc_unlikely(!tmp)) {
472 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
473 silc_buffer_reset(&packet->buffer);
478 SILC_LOG_DEBUG(("Get packet %p", packet));
480 /* Delete from freelist */
481 silc_list_del(engine->packet_pool, packet);
483 silc_mutex_unlock(engine->lock);
488 /* UDP remote stream hash table destructor */
490 static void silc_packet_engine_hash_destr(void *key, void *context,
496 /* Per scheduler context hash table destructor */
498 static void silc_packet_engine_context_destr(void *key, void *context,
501 SilcPacketEngineContext sc = context;
502 silc_buffer_clear(&sc->inbuf);
503 silc_buffer_purge(&sc->inbuf);
508 /******************************** Packet API ********************************/
510 /* Allocate new packet engine */
513 silc_packet_engine_start(SilcRng rng, SilcBool router,
514 SilcPacketCallbacks *callbacks,
515 void *callback_context)
517 SilcPacketEngine engine;
522 SILC_LOG_DEBUG(("Starting new packet engine"));
526 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
529 engine = silc_calloc(1, sizeof(*engine));
533 engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
534 silc_packet_engine_context_destr,
536 if (!engine->contexts) {
542 engine->local_is_router = router;
543 engine->callbacks = callbacks;
544 engine->callback_context = callback_context;
545 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
546 silc_mutex_alloc(&engine->lock);
548 /* Allocate packet free list */
549 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
550 for (i = 0; i < 5; i++) {
551 packet = silc_calloc(1, sizeof(*packet));
553 silc_packet_engine_stop(engine);
557 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
559 silc_packet_engine_stop(engine);
562 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
563 silc_buffer_reset(&packet->buffer);
565 silc_list_add(engine->packet_pool, packet);
567 silc_list_start(engine->packet_pool);
572 /* Stop packet engine */
574 void silc_packet_engine_stop(SilcPacketEngine engine)
577 SILC_LOG_DEBUG(("Stopping packet engine"));
587 /* Create new packet stream */
589 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
590 SilcSchedule schedule,
596 SILC_LOG_DEBUG(("Creating new packet stream"));
598 if (!engine || !stream)
601 ps = silc_calloc(1, sizeof(*ps));
606 silc_atomic_init8(&ps->refcnt, 1);
607 silc_mutex_alloc(&ps->lock);
609 /* Allocate out buffer */
610 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
612 silc_packet_stream_destroy(ps);
615 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
616 silc_buffer_reset(&ps->outbuf);
618 /* Initialize packet procesors list */
619 ps->process = silc_dlist_init();
621 silc_packet_stream_destroy(ps);
625 silc_mutex_lock(engine->lock);
627 /* Add per scheduler context */
628 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
630 ps->sc = silc_calloc(1, sizeof(*ps->sc));
632 silc_packet_stream_destroy(ps);
633 silc_mutex_unlock(engine->lock);
636 ps->sc->engine = engine;
637 ps->sc->schedule = schedule;
639 /* Allocate data input buffer */
640 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE * 31);
644 silc_packet_stream_destroy(ps);
645 silc_mutex_unlock(engine->lock);
648 silc_buffer_set(&ps->sc->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE * 31);
649 silc_buffer_reset(&ps->sc->inbuf);
651 /* Add to per scheduler context hash table */
652 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
653 silc_buffer_purge(&ps->sc->inbuf);
656 silc_packet_stream_destroy(ps);
657 silc_mutex_unlock(engine->lock);
661 ps->sc->stream_count++;
663 /* Add the packet stream to engine */
664 silc_list_add(engine->streams, ps);
666 /* If this is UDP stream, allocate UDP remote stream hash table */
667 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
668 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
669 silc_hash_string_compare, NULL,
670 silc_packet_engine_hash_destr,
673 silc_mutex_unlock(engine->lock);
675 /* Set IO notifier callback. This schedules this stream for I/O. */
676 if (!silc_stream_set_notifier(ps->stream, schedule,
677 silc_packet_stream_io, ps)) {
678 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
679 silc_packet_stream_destroy(ps);
686 /* Add new remote packet stream for UDP packet streams */
688 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
689 const char *remote_ip,
690 SilcUInt16 remote_port,
693 SilcPacketEngine engine = stream->sc->engine;
698 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
699 remote_ip, remote_port, stream));
701 if (!stream || !remote_ip || !remote_port)
704 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
705 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
709 ps = silc_calloc(1, sizeof(*ps));
714 silc_atomic_init8(&ps->refcnt, 1);
715 silc_mutex_alloc(&ps->lock);
717 /* Set the UDP packet stream as underlaying stream */
718 silc_packet_stream_ref(stream);
719 ps->stream = (SilcStream)stream;
722 /* Allocate out buffer */
723 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
725 silc_packet_stream_destroy(ps);
728 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
729 silc_buffer_reset(&ps->outbuf);
731 /* Initialize packet procesors list */
732 ps->process = silc_dlist_init();
734 silc_packet_stream_destroy(ps);
738 /* Add to engine with this IP and port pair */
739 tuple = silc_format("%d%s", remote_port, remote_ip);
740 silc_mutex_lock(engine->lock);
741 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
742 silc_mutex_unlock(engine->lock);
743 silc_packet_stream_destroy(ps);
746 silc_mutex_unlock(engine->lock);
748 /* Save remote IP and port pair */
749 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
750 if (!ps->remote_udp) {
751 silc_packet_stream_destroy(ps);
754 ps->remote_udp->remote_port = remote_port;
755 ps->remote_udp->remote_ip = strdup(remote_ip);
756 if (!ps->remote_udp->remote_ip) {
757 silc_packet_stream_destroy(ps);
762 /* Inject packet to the new stream */
764 silc_packet_stream_ref(ps);
765 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
766 silc_packet_stream_inject_packet, packet,
773 /* Destroy packet stream */
775 void silc_packet_stream_destroy(SilcPacketStream stream)
780 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
781 stream->destroyed = TRUE;
783 /* Close the underlaying stream */
784 if (!stream->udp && stream->stream)
785 silc_stream_close(stream->stream);
789 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
792 /* Delete from engine */
793 silc_mutex_lock(stream->sc->engine->lock);
794 silc_list_del(stream->sc->engine->streams, stream);
796 /* Remove per scheduler context, if it is not used anymore */
798 stream->sc->stream_count--;
799 if (!stream->sc->stream_count)
800 silc_hash_table_del(stream->sc->engine->contexts,
801 stream->sc->schedule);
803 silc_mutex_unlock(stream->sc->engine->lock);
805 /* Destroy the underlaying stream */
807 silc_stream_destroy(stream->stream);
809 /* Delete from UDP remote hash table */
811 silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
812 stream->remote_udp->remote_ip);
813 silc_mutex_lock(stream->sc->engine->lock);
814 silc_hash_table_del(stream->sc->engine->udp_remote, tuple);
815 silc_mutex_unlock(stream->sc->engine->lock);
817 silc_free(stream->remote_udp->remote_ip);
818 silc_free(stream->remote_udp);
820 /* Unreference the underlaying packet stream */
821 silc_packet_stream_unref((SilcPacketStream)stream->stream);
824 /* Clear and free buffers */
825 silc_buffer_clear(&stream->outbuf);
826 silc_buffer_purge(&stream->outbuf);
828 if (stream->process) {
830 silc_dlist_start(stream->process);
831 while ((p = silc_dlist_get(stream->process))) {
834 silc_dlist_del(stream->process, p);
836 silc_dlist_uninit(stream->process);
841 silc_atomic_uninit8(&stream->refcnt);
842 silc_mutex_free(stream->lock);
846 /* Marks as router stream */
848 void silc_packet_stream_set_router(SilcPacketStream stream)
850 stream->is_router = TRUE;
853 /* Mark to include IV in ciphertext */
855 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
857 stream->iv_included = TRUE;
860 /* Links `callbacks' to `stream' for specified packet types */
862 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
863 SilcPacketCallbacks *callbacks,
864 void *callback_context,
865 int priority, va_list ap)
867 SilcPacketProcess p, e;
868 SilcInt32 packet_type;
871 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
875 if (!callbacks->packet_receive)
878 p = silc_calloc(1, sizeof(*p));
882 p->priority = priority;
883 p->callbacks = callbacks;
884 p->callback_context = callback_context;
886 silc_mutex_lock(stream->lock);
888 if (!stream->process) {
889 stream->process = silc_dlist_init();
890 if (!stream->process) {
891 silc_mutex_unlock(stream->lock);
896 /* According to priority set the procesor to correct position. First
897 entry has the highest priority */
898 silc_dlist_start(stream->process);
899 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
900 if (p->priority > e->priority) {
901 silc_dlist_insert(stream->process, p);
906 silc_dlist_add(stream->process, p);
908 /* Get packet types to process */
911 packet_type = va_arg(ap, SilcInt32);
913 if (packet_type == SILC_PACKET_ANY)
916 if (packet_type == -1)
919 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
921 silc_mutex_unlock(stream->lock);
925 p->types[i - 1] = (SilcPacketType)packet_type;
931 silc_mutex_unlock(stream->lock);
933 silc_packet_stream_ref(stream);
938 /* Links `callbacks' to `stream' for specified packet types */
940 SilcBool silc_packet_stream_link(SilcPacketStream stream,
941 SilcPacketCallbacks *callbacks,
942 void *callback_context,
948 va_start(ap, priority);
949 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
956 /* Unlinks `callbacks' from `stream'. */
958 void silc_packet_stream_unlink(SilcPacketStream stream,
959 SilcPacketCallbacks *callbacks,
960 void *callback_context)
964 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
967 silc_mutex_lock(stream->lock);
969 silc_dlist_start(stream->process);
970 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
971 if (p->callbacks == callbacks &&
972 p->callback_context == callback_context) {
973 silc_dlist_del(stream->process, p);
979 if (!silc_dlist_count(stream->process)) {
980 silc_dlist_uninit(stream->process);
981 stream->process = NULL;
984 silc_mutex_unlock(stream->lock);
986 silc_packet_stream_unref(stream);
989 /* Returns TRUE if stream is UDP stream */
991 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
993 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
996 /* Return packet sender IP and port for UDP packet stream */
998 SilcBool silc_packet_get_sender(SilcPacket packet,
999 const char **sender_ip,
1000 SilcUInt16 *sender_port)
1002 if (!packet->stream->remote_udp)
1005 *sender_ip = packet->stream->remote_udp->remote_ip;
1006 *sender_port = packet->stream->remote_udp->remote_port;
1011 /* Reference packet stream */
1013 void silc_packet_stream_ref(SilcPacketStream stream)
1015 silc_atomic_add_int8(&stream->refcnt, 1);
1016 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1017 silc_atomic_get_int8(&stream->refcnt) - 1,
1018 silc_atomic_get_int8(&stream->refcnt)));
1021 /* Unreference packet stream */
1023 void silc_packet_stream_unref(SilcPacketStream stream)
1025 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1026 silc_atomic_get_int8(&stream->refcnt),
1027 silc_atomic_get_int8(&stream->refcnt) - 1));
1028 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1030 silc_atomic_add_int8(&stream->refcnt, 1);
1031 silc_packet_stream_destroy(stream);
1036 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1038 return stream->sc->engine;
1041 /* Set application context for packet stream */
1043 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1045 silc_mutex_lock(stream->lock);
1046 stream->stream_context = stream_context;
1047 silc_mutex_unlock(stream->lock);
1050 /* Return application context from packet stream */
1052 void *silc_packet_get_context(SilcPacketStream stream)
1055 silc_mutex_lock(stream->lock);
1056 context = stream->stream_context;
1057 silc_mutex_unlock(stream->lock);
1061 /* Change underlaying stream */
1063 void silc_packet_stream_set_stream(SilcPacketStream ps,
1067 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1068 ps->stream = stream;
1069 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1073 /* Return underlaying stream */
1075 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1077 return stream->stream;
1082 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1083 SilcCipher receive_key, SilcHmac send_hmac,
1084 SilcHmac receive_hmac, SilcBool rekey)
1086 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1088 /* If doing rekey, send REKEY_DONE packet */
1090 /* This will take stream lock. */
1091 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1092 stream->src_id_type, stream->src_id,
1093 stream->src_id_len, stream->dst_id_type,
1094 stream->dst_id, stream->dst_id_len,
1095 NULL, 0, stream->send_key[0],
1096 stream->send_hmac[0]))
1099 /* Write the packet to the stream */
1100 if (!silc_packet_stream_write(stream, TRUE))
1103 silc_mutex_lock(stream->lock);
1106 /* In case IV Included is set, save the old keys */
1107 if (stream->iv_included) {
1108 if (stream->send_key[1] && send_key) {
1109 silc_cipher_free(stream->send_key[1]);
1110 stream->send_key[1] = stream->send_key[0];
1112 if (stream->receive_key[1] && receive_key) {
1113 silc_cipher_free(stream->receive_key[1]);
1114 stream->receive_key[1] = stream->receive_key[0];
1116 if (stream->send_hmac[1] && send_hmac) {
1117 silc_hmac_free(stream->send_hmac[1]);
1118 stream->send_hmac[1] = stream->send_hmac[0];
1120 if (stream->receive_hmac[1] && receive_hmac) {
1121 silc_hmac_free(stream->receive_hmac[1]);
1122 stream->receive_hmac[1] = stream->receive_hmac[0];
1125 if (stream->send_key[0] && send_key)
1126 silc_cipher_free(stream->send_key[0]);
1127 if (stream->send_key[1] && receive_key)
1128 silc_cipher_free(stream->receive_key[0]);
1129 if (stream->send_hmac[0] && send_hmac)
1130 silc_hmac_free(stream->send_hmac[0]);
1131 if (stream->receive_hmac[0] && receive_hmac)
1132 silc_hmac_free(stream->receive_hmac[0]);
1137 stream->send_key[0] = send_key;
1139 stream->receive_key[0] = receive_key;
1141 stream->send_hmac[0] = send_hmac;
1143 stream->receive_hmac[0] = receive_hmac;
1145 silc_mutex_unlock(stream->lock);
1149 /* Return current ciphers from packet stream */
1151 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1152 SilcCipher *send_key,
1153 SilcCipher *receive_key,
1154 SilcHmac *send_hmac,
1155 SilcHmac *receive_hmac)
1157 if (!stream->send_key[0] && !stream->receive_key[0] &&
1158 !stream->send_hmac[0] && !stream->receive_hmac[0])
1161 silc_mutex_lock(stream->lock);
1164 *send_key = stream->send_key[0];
1166 *receive_key = stream->receive_key[0];
1168 *send_hmac = stream->send_hmac[0];
1170 *receive_hmac = stream->receive_hmac[0];
1172 silc_mutex_unlock(stream->lock);
1177 /* Set SILC IDs to packet stream */
1179 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1180 SilcIdType src_id_type, const void *src_id,
1181 SilcIdType dst_id_type, const void *dst_id)
1184 unsigned char tmp[32];
1186 if (!src_id && !dst_id)
1189 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1191 silc_mutex_lock(stream->lock);
1194 silc_free(stream->src_id);
1195 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1196 silc_mutex_unlock(stream->lock);
1199 stream->src_id = silc_memdup(tmp, len);
1200 if (!stream->src_id) {
1201 silc_mutex_unlock(stream->lock);
1204 stream->src_id_type = src_id_type;
1205 stream->src_id_len = len;
1209 silc_free(stream->dst_id);
1210 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1211 silc_mutex_unlock(stream->lock);
1214 stream->dst_id = silc_memdup(tmp, len);
1215 if (!stream->dst_id) {
1216 silc_mutex_unlock(stream->lock);
1219 stream->dst_id_type = dst_id_type;
1220 stream->dst_id_len = len;
1223 silc_mutex_unlock(stream->lock);
1228 /* Adds Security ID (SID) */
1230 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1232 if (!stream->iv_included)
1235 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1243 void silc_packet_free(SilcPacket packet)
1245 SilcPacketStream stream = packet->stream;
1247 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1249 /* Check for double free */
1250 SILC_ASSERT(packet->stream != NULL);
1252 packet->stream = NULL;
1253 packet->src_id = packet->dst_id = NULL;
1254 silc_buffer_reset(&packet->buffer);
1256 silc_mutex_lock(stream->sc->engine->lock);
1258 /* Put the packet back to freelist */
1259 silc_list_add(stream->sc->engine->packet_pool, packet);
1260 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1261 silc_list_start(stream->sc->engine->packet_pool);
1263 silc_mutex_unlock(stream->sc->engine->lock);
1266 /****************************** Packet Sending ******************************/
1268 /* Prepare outgoing data buffer for packet sending. Returns the
1269 pointer to that buffer into the `packet'. */
1271 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1276 unsigned char *oldptr;
1277 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1281 /* Allocate more space if needed */
1282 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1283 if (!silc_buffer_realloc(&stream->outbuf,
1284 silc_buffer_truelen(&stream->outbuf) + totlen))
1288 /* Pull data area for the new packet, and return pointer to the start of
1289 the data area and save the pointer in to the `packet'. MAC is pulled
1290 later after it's computed. */
1291 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1292 silc_buffer_set(packet, oldptr, totlen);
1293 silc_buffer_push_tail(packet, mac_len);
1298 /* Increments counter when encrypting in counter mode. */
1300 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1302 unsigned char *ret_iv)
1304 unsigned char *iv = silc_cipher_get_iv(cipher);
1307 /* Increment packet counter */
1308 SILC_GET32_MSB(pc, iv + 8);
1310 SILC_PUT32_MSB(pc, iv + 8);
1312 /* Reset block counter */
1313 memset(iv + 12, 0, 4);
1315 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1316 if (stream->iv_included) {
1318 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1319 ret_iv[1] = ret_iv[0] + iv[4];
1320 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1321 ret_iv[3] = ret_iv[0] + ret_iv[2];
1322 SILC_PUT32_MSB(pc, ret_iv + 4);
1323 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1325 /* Set new nonce to counter block */
1326 memcpy(iv + 4, ret_iv, 4);
1329 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1332 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1333 the packet. The silc_packet_stream_write needs to be called to send it
1334 after this returns TRUE. */
1336 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1337 SilcPacketType type,
1338 SilcPacketFlags flags,
1339 SilcIdType src_id_type,
1340 unsigned char *src_id,
1341 SilcUInt32 src_id_len,
1342 SilcIdType dst_id_type,
1343 unsigned char *dst_id,
1344 SilcUInt32 dst_id_len,
1345 const unsigned char *data,
1346 SilcUInt32 data_len,
1350 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1351 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1352 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1354 SilcBufferStruct packet;
1356 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1357 "data len %d", silc_get_packet_name(type), stream->send_psn,
1358 flags, src_id_type, dst_id_type, data_len));
1360 /* Get the true length of the packet. This is saved as payload length
1361 into the packet header. This does not include the length of the
1363 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1364 src_id_len + dst_id_len));
1365 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1366 src_id_len + dst_id_len);
1368 /* If using CTR mode, increment the counter */
1369 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1371 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1373 /* If IV is included, the SID, IV and sequence number is added to packet */
1374 if (stream->iv_included && cipher) {
1375 psnlen = sizeof(psn);
1377 iv[0] = stream->sid;
1380 /* If IV is included, the SID, IV and sequence number is added to packet */
1381 if (stream->iv_included && cipher) {
1382 psnlen = sizeof(psn);
1383 ivlen = block_len + 1;
1384 iv[0] = stream->sid;
1385 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1389 /* We automatically figure out the packet structure from the packet
1390 type and flags, and calculate correct length. Private messages with
1391 private keys and channel messages are special packets as their
1392 payload is encrypted already. */
1393 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1394 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1395 type == SILC_PACKET_CHANNEL_MESSAGE) {
1397 /* Padding is calculated from header + IDs */
1399 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1400 psnlen), block_len, padlen);
1402 /* Length to encrypt, header + IDs + padding. */
1403 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1407 /* Padding is calculated from true length of the packet */
1408 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1409 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1411 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1413 enclen += padlen + psnlen;
1416 /* Remove implementation specific flags */
1417 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1419 /* Get random padding */
1420 for (i = 0; i < padlen; i++) tmppad[i] =
1421 silc_rng_get_byte_fast(stream->sc->engine->rng);
1423 silc_mutex_lock(stream->lock);
1425 /* Get packet pointer from the outgoing buffer */
1426 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1427 + psnlen, hmac, &packet))) {
1428 silc_mutex_unlock(stream->lock);
1432 SILC_PUT32_MSB(stream->send_psn, psn);
1434 /* Create the packet. This creates the SILC header, adds padding, and
1435 the actual packet data. */
1436 i = silc_buffer_format(&packet,
1437 SILC_STR_DATA(iv, ivlen),
1438 SILC_STR_DATA(psn, psnlen),
1439 SILC_STR_UI_SHORT(truelen),
1440 SILC_STR_UI_CHAR(flags),
1441 SILC_STR_UI_CHAR(type),
1442 SILC_STR_UI_CHAR(padlen),
1443 SILC_STR_UI_CHAR(0),
1444 SILC_STR_UI_CHAR(src_id_len),
1445 SILC_STR_UI_CHAR(dst_id_len),
1446 SILC_STR_UI_CHAR(src_id_type),
1447 SILC_STR_DATA(src_id, src_id_len),
1448 SILC_STR_UI_CHAR(dst_id_type),
1449 SILC_STR_DATA(dst_id, dst_id_len),
1450 SILC_STR_DATA(tmppad, padlen),
1451 SILC_STR_DATA(data, data_len),
1453 if (silc_unlikely(i < 0)) {
1454 silc_mutex_unlock(stream->lock);
1458 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1459 silc_buffer_data(&packet), silc_buffer_len(&packet));
1461 /* Encrypt the packet */
1462 if (silc_likely(cipher)) {
1463 SILC_LOG_DEBUG(("Encrypting packet"));
1464 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1465 packet.data + ivlen, enclen,
1467 SILC_LOG_ERROR(("Packet encryption failed"));
1468 silc_mutex_unlock(stream->lock);
1474 if (silc_likely(hmac)) {
1477 /* MAC is computed from the entire encrypted packet data, and put
1478 to the end of the packet. */
1479 silc_hmac_init(hmac);
1480 silc_hmac_update(hmac, psn, sizeof(psn));
1481 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1482 silc_hmac_final(hmac, packet.tail, &mac_len);
1483 silc_buffer_pull_tail(&packet, mac_len);
1490 /* Sends a packet */
1492 SilcBool silc_packet_send(SilcPacketStream stream,
1493 SilcPacketType type, SilcPacketFlags flags,
1494 const unsigned char *data, SilcUInt32 data_len)
1498 ret = silc_packet_send_raw(stream, type, flags,
1499 stream->src_id_type,
1502 stream->dst_id_type,
1506 stream->send_key[0],
1507 stream->send_hmac[0]);
1509 /* Write the packet to the stream */
1510 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1513 /* Sends a packet, extended routine */
1515 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1516 SilcPacketType type, SilcPacketFlags flags,
1517 SilcIdType src_id_type, void *src_id,
1518 SilcIdType dst_id_type, void *dst_id,
1519 const unsigned char *data, SilcUInt32 data_len,
1520 SilcCipher cipher, SilcHmac hmac)
1522 unsigned char src_id_data[32], dst_id_data[32];
1523 SilcUInt32 src_id_len, dst_id_len;
1527 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1528 sizeof(src_id_data), &src_id_len))
1531 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1532 sizeof(dst_id_data), &dst_id_len))
1535 ret = silc_packet_send_raw(stream, type, flags,
1536 src_id ? src_id_type : stream->src_id_type,
1537 src_id ? src_id_data : stream->src_id,
1538 src_id ? src_id_len : stream->src_id_len,
1539 dst_id ? dst_id_type : stream->dst_id_type,
1540 dst_id ? dst_id_data : stream->dst_id,
1541 dst_id ? dst_id_len : stream->dst_id_len,
1543 cipher ? cipher : stream->send_key[0],
1544 hmac ? hmac : stream->send_hmac[0]);
1546 /* Write the packet to the stream */
1547 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1550 /* Sends packet after formatting the arguments to buffer */
1552 SilcBool silc_packet_send_va(SilcPacketStream stream,
1553 SilcPacketType type, SilcPacketFlags flags, ...)
1555 SilcBufferStruct buf;
1559 va_start(va, flags);
1561 memset(&buf, 0, sizeof(buf));
1562 if (silc_buffer_format_vp(&buf, va) < 0) {
1567 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1568 silc_buffer_len(&buf));
1570 silc_buffer_purge(&buf);
1576 /* Sends packet after formatting the arguments to buffer, extended routine */
1578 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1579 SilcPacketType type, SilcPacketFlags flags,
1580 SilcIdType src_id_type, void *src_id,
1581 SilcIdType dst_id_type, void *dst_id,
1582 SilcCipher cipher, SilcHmac hmac, ...)
1584 SilcBufferStruct buf;
1590 memset(&buf, 0, sizeof(buf));
1591 if (silc_buffer_format_vp(&buf, va) < 0) {
1596 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1597 dst_id_type, dst_id, silc_buffer_data(&buf),
1598 silc_buffer_len(&buf), cipher, hmac);
1600 silc_buffer_purge(&buf);
1606 /***************************** Packet Receiving *****************************/
1608 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1610 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1611 const unsigned char *data,
1612 SilcUInt32 data_len,
1613 const unsigned char *packet_mac,
1614 const unsigned char *packet_seq,
1615 SilcUInt32 sequence)
1618 if (silc_likely(hmac)) {
1619 unsigned char mac[32], psn[4];
1622 SILC_LOG_DEBUG(("Verifying MAC"));
1624 /* Compute HMAC of packet */
1625 silc_hmac_init(hmac);
1628 SILC_PUT32_MSB(sequence, psn);
1629 silc_hmac_update(hmac, psn, 4);
1631 silc_hmac_update(hmac, packet_seq, 4);
1633 silc_hmac_update(hmac, data, data_len);
1634 silc_hmac_final(hmac, mac, &mac_len);
1636 /* Compare the MAC's */
1637 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1638 SILC_LOG_DEBUG(("MAC failed"));
1642 SILC_LOG_DEBUG(("MAC is Ok"));
1648 /* Increments/sets counter when decrypting in counter mode. */
1650 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1652 unsigned char *packet_iv)
1656 /* If IV Included flag, set the IV from packet to block counter. */
1657 if (stream->iv_included) {
1658 memcpy(iv + 4, packet_iv, 8);
1660 /* Increment packet counter */
1661 SILC_GET32_MSB(pc, iv + 8);
1663 SILC_PUT32_MSB(pc, iv + 8);
1666 /* Reset block counter */
1667 memset(iv + 12, 0, 4);
1669 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1672 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1673 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1675 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1676 SilcUInt32 sequence, SilcBuffer buffer,
1679 if (normal == TRUE) {
1680 if (silc_likely(cipher)) {
1681 /* Decrypt rest of the packet */
1682 SILC_LOG_DEBUG(("Decrypting the packet"));
1683 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1685 silc_buffer_len(buffer), NULL)))
1691 /* Decrypt rest of the header plus padding */
1692 if (silc_likely(cipher)) {
1694 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1696 SILC_LOG_DEBUG(("Decrypting the header"));
1698 /* Padding length + src id len + dst id len + header length - 16
1699 bytes already decrypted, gives the rest of the encrypted packet */
1700 silc_buffer_push(buffer, block_len);
1701 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1702 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1704 silc_buffer_pull(buffer, block_len);
1706 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1707 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1711 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1712 buffer->data, len, NULL)))
1720 /* Parses the packet. This is called when a whole packet is ready to be
1721 parsed. The buffer sent must be already decrypted before calling this
1724 static inline SilcBool silc_packet_parse(SilcPacket packet)
1726 SilcBuffer buffer = &packet->buffer;
1727 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1728 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1731 SILC_LOG_DEBUG(("Parsing incoming packet"));
1733 /* Parse the buffer. This parses the SILC header of the packet. */
1734 ret = silc_buffer_unformat(buffer,
1737 SILC_STR_UI_CHAR(&src_id_len),
1738 SILC_STR_UI_CHAR(&dst_id_len),
1739 SILC_STR_UI_CHAR(&src_id_type),
1741 if (silc_unlikely(ret == -1)) {
1742 if (!packet->stream->udp &&
1743 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1744 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1748 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1749 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1750 if (!packet->stream->udp &&
1751 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1752 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1753 packet->src_id_len, packet->dst_id_len));
1757 ret = silc_buffer_unformat(buffer,
1759 SILC_STR_DATA(&packet->src_id, src_id_len),
1760 SILC_STR_UI_CHAR(&dst_id_type),
1761 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1762 SILC_STR_OFFSET(padlen),
1764 if (silc_unlikely(ret == -1)) {
1765 if (!packet->stream->udp &&
1766 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1767 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1771 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1772 dst_id_type > SILC_ID_CHANNEL)) {
1773 if (!packet->stream->udp &&
1774 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1775 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1776 src_id_type, dst_id_type));
1780 packet->src_id_len = src_id_len;
1781 packet->dst_id_len = dst_id_len;
1782 packet->src_id_type = src_id_type;
1783 packet->dst_id_type = dst_id_type;
1785 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1786 silc_buffer_len(buffer)), buffer->head,
1787 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1789 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1790 silc_get_packet_name(packet->type)));
1795 /* Dispatch packet to application. Called with stream->lock locked.
1796 Returns FALSE if the stream was destroyed while dispatching a packet. */
1798 static SilcBool silc_packet_dispatch(SilcPacket packet)
1800 SilcPacketStream stream = packet->stream;
1801 SilcPacketProcess p;
1802 SilcBool default_sent = FALSE;
1805 /* Dispatch packet to all packet processors that want it */
1807 if (silc_likely(!stream->process)) {
1808 /* Send to default processor as no others exist */
1809 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1810 silc_mutex_unlock(stream->lock);
1811 if (silc_unlikely(!stream->sc->engine->callbacks->
1812 packet_receive(stream->sc->engine, stream, packet,
1813 stream->sc->engine->callback_context,
1814 stream->stream_context)))
1815 silc_packet_free(packet);
1816 silc_mutex_lock(stream->lock);
1817 return stream->destroyed == FALSE;
1820 silc_dlist_start(stream->process);
1821 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1823 /* If priority is 0 or less, we send to default processor first
1824 because default processor has 0 priority */
1825 if (!default_sent && p->priority <= 0) {
1826 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1827 default_sent = TRUE;
1828 silc_mutex_unlock(stream->lock);
1829 if (stream->sc->engine->callbacks->
1830 packet_receive(stream->sc->engine, stream, packet,
1831 stream->sc->engine->callback_context,
1832 stream->stream_context)) {
1833 silc_mutex_lock(stream->lock);
1834 return stream->destroyed == FALSE;
1836 silc_mutex_lock(stream->lock);
1839 /* Send to processor */
1841 /* Send all packet types */
1842 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1843 silc_mutex_unlock(stream->lock);
1844 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1845 p->callback_context,
1846 stream->stream_context)) {
1847 silc_mutex_lock(stream->lock);
1848 return stream->destroyed == FALSE;
1850 silc_mutex_lock(stream->lock);
1852 /* Send specific types */
1853 for (pt = p->types; *pt; pt++) {
1854 if (*pt != packet->type)
1856 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1857 silc_mutex_unlock(stream->lock);
1858 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1859 p->callback_context,
1860 stream->stream_context)) {
1861 silc_mutex_lock(stream->lock);
1862 return stream->destroyed == FALSE;
1864 silc_mutex_lock(stream->lock);
1870 if (!default_sent) {
1871 /* Send to default processor as it has not been sent yet */
1872 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1873 silc_mutex_unlock(stream->lock);
1874 if (stream->sc->engine->callbacks->
1875 packet_receive(stream->sc->engine, stream, packet,
1876 stream->sc->engine->callback_context,
1877 stream->stream_context)) {
1878 silc_mutex_lock(stream->lock);
1879 return stream->destroyed == FALSE;
1881 silc_mutex_lock(stream->lock);
1884 /* If we got here, no one wanted the packet, so drop it */
1885 silc_packet_free(packet);
1886 return stream->destroyed == FALSE;
1889 /* Process incoming data and parse packets. Called with stream->lock
1892 static void silc_packet_read_process(SilcPacketStream stream)
1894 SilcBuffer inbuf = &stream->sc->inbuf;
1899 SilcUInt16 packetlen;
1900 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1901 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1902 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1906 /* Parse the packets from the data */
1907 while (silc_buffer_len(inbuf) > 0) {
1909 cipher = stream->receive_key[0];
1910 hmac = stream->receive_hmac[0];
1913 if (silc_unlikely(silc_buffer_len(inbuf) <
1914 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1915 SILC_PACKET_MIN_HEADER_LEN))) {
1916 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1920 if (silc_likely(hmac))
1921 mac_len = silc_hmac_len(hmac);
1925 /* Decrypt first block of the packet to get the length field out */
1926 if (silc_likely(cipher)) {
1927 block_len = silc_cipher_get_block_len(cipher);
1929 if (stream->iv_included) {
1930 /* SID, IV and sequence number is included in the ciphertext */
1931 sid = (SilcUInt8)inbuf->data[0];
1933 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
1934 /* Set the CTR mode IV from packet to counter block */
1935 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1936 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
1939 /* Get IV from packet */
1940 memcpy(iv, inbuf->data + 1, block_len);
1941 ivlen = block_len + 1;
1945 /* Check SID, and get correct decryption key */
1946 if (sid != stream->sid) {
1947 /* If SID is recent get the previous key and use it */
1948 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1949 stream->receive_key[1] && !stream->receive_hmac[1]) {
1950 cipher = stream->receive_key[1];
1951 hmac = stream->receive_hmac[1];
1953 /* The SID is unknown, drop rest of the data in buffer */
1954 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1956 silc_mutex_unlock(stream->lock);
1957 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1958 silc_mutex_lock(stream->lock);
1959 silc_buffer_reset(inbuf);
1964 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1966 /* If using CTR mode, increment the counter */
1967 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
1968 silc_packet_receive_ctr_increment(stream, iv, NULL);
1971 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp,
1975 if (stream->iv_included) {
1976 /* Take sequence number from packet */
1977 packet_seq = header;
1981 /* Unencrypted packet */
1982 block_len = SILC_PACKET_MIN_HEADER_LEN;
1983 header = inbuf->data;
1986 /* Get packet length and full packet length with padding */
1987 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1990 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
1991 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
1992 SILC_LOG_ERROR(("Received too short packet"));
1993 silc_mutex_unlock(stream->lock);
1994 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1995 silc_mutex_lock(stream->lock);
1996 memset(tmp, 0, sizeof(tmp));
1997 silc_buffer_reset(inbuf);
2001 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2002 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2004 paddedlen + mac_len - silc_buffer_len(inbuf)));
2005 memset(tmp, 0, sizeof(tmp));
2009 /* Check MAC of the packet */
2010 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2012 inbuf->data + ivlen +
2013 paddedlen, packet_seq,
2014 stream->receive_psn))) {
2015 silc_mutex_unlock(stream->lock);
2016 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2017 silc_mutex_lock(stream->lock);
2018 memset(tmp, 0, sizeof(tmp));
2019 silc_buffer_reset(inbuf);
2024 packet = silc_packet_alloc(stream->sc->engine);
2025 if (silc_unlikely(!packet)) {
2026 silc_mutex_unlock(stream->lock);
2027 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2028 silc_mutex_lock(stream->lock);
2029 memset(tmp, 0, sizeof(tmp));
2030 silc_buffer_reset(inbuf);
2033 packet->stream = stream;
2035 /* Allocate more space to packet buffer, if needed */
2036 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2037 if (!silc_buffer_realloc(&packet->buffer,
2038 silc_buffer_truelen(&packet->buffer) +
2040 silc_buffer_truelen(&packet->buffer)))) {
2041 silc_mutex_unlock(stream->lock);
2042 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2043 silc_mutex_lock(stream->lock);
2044 silc_packet_free(packet);
2045 memset(tmp, 0, sizeof(tmp));
2046 silc_buffer_reset(inbuf);
2051 /* Parse packet header */
2052 packet->flags = (SilcPacketFlags)header[2];
2053 packet->type = (SilcPacketType)header[3];
2055 if (stream->sc->engine->local_is_router) {
2056 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2057 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2059 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2060 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2061 stream->is_router == TRUE))
2064 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2065 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2067 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2071 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2072 stream->receive_psn, paddedlen + ivlen + mac_len),
2073 inbuf->data, paddedlen + ivlen + mac_len);
2075 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2076 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2077 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2078 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2079 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2080 psnlen + (block_len - psnlen)),
2081 paddedlen - ivlen - psnlen - (block_len - psnlen));
2082 if (silc_likely(cipher)) {
2083 silc_cipher_set_iv(cipher, iv);
2084 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2085 &packet->buffer, normal);
2086 if (silc_unlikely(ret < 0)) {
2087 silc_mutex_unlock(stream->lock);
2088 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2089 silc_mutex_lock(stream->lock);
2090 silc_packet_free(packet);
2091 memset(tmp, 0, sizeof(tmp));
2095 stream->receive_psn++;
2097 silc_buffer_push(&packet->buffer, block_len);
2099 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2100 silc_buffer_pull(inbuf, paddedlen + mac_len);
2102 /* Parse the packet */
2103 if (silc_unlikely(!silc_packet_parse(packet))) {
2104 silc_mutex_unlock(stream->lock);
2105 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2106 silc_mutex_lock(stream->lock);
2107 silc_packet_free(packet);
2108 memset(tmp, 0, sizeof(tmp));
2112 /* Dispatch the packet to application */
2113 if (!silc_packet_dispatch(packet))
2117 silc_buffer_reset(inbuf);
2120 /****************************** Packet Waiting ******************************/
2122 /* Packet wait receive callback */
2124 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2125 SilcPacketStream stream,
2127 void *callback_context,
2128 void *stream_context);
2130 /* Packet waiting callbacks */
2131 static SilcPacketCallbacks silc_packet_wait_cbs =
2133 silc_packet_wait_packet_receive, NULL, NULL
2136 /* Packet waiting context */
2138 SilcMutex wait_lock;
2140 SilcList packet_queue;
2141 unsigned int stopped : 1;
2144 /* Packet wait receive callback */
2147 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2148 SilcPacketStream stream,
2150 void *callback_context,
2151 void *stream_context)
2153 SilcPacketWait pw = callback_context;
2155 /* Signal the waiting thread for a new packet */
2156 silc_mutex_lock(pw->wait_lock);
2158 if (silc_unlikely(pw->stopped)) {
2159 silc_mutex_unlock(pw->wait_lock);
2163 silc_list_add(pw->packet_queue, packet);
2164 silc_cond_broadcast(pw->wait_cond);
2166 silc_mutex_unlock(pw->wait_lock);
2171 /* Initialize packet waiting */
2173 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2179 pw = silc_calloc(1, sizeof(*pw));
2183 /* Allocate mutex and conditional variable */
2184 if (!silc_mutex_alloc(&pw->wait_lock)) {
2188 if (!silc_cond_alloc(&pw->wait_cond)) {
2189 silc_mutex_free(pw->wait_lock);
2194 /* Link to the packet stream for the requested packet types */
2195 va_start(ap, stream);
2196 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2200 silc_cond_free(pw->wait_cond);
2201 silc_mutex_free(pw->wait_lock);
2206 /* Initialize packet queue */
2207 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2212 /* Uninitialize packet waiting */
2214 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2216 SilcPacketWait pw = waiter;
2219 /* Signal any threads to stop waiting */
2220 silc_mutex_lock(pw->wait_lock);
2222 silc_cond_broadcast(pw->wait_cond);
2223 silc_mutex_unlock(pw->wait_lock);
2225 /* Re-acquire lock and free resources */
2226 silc_mutex_lock(pw->wait_lock);
2227 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2229 /* Free any remaining packets */
2230 silc_list_start(pw->packet_queue);
2231 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2232 silc_packet_free(packet);
2234 silc_mutex_unlock(pw->wait_lock);
2235 silc_cond_free(pw->wait_cond);
2236 silc_mutex_free(pw->wait_lock);
2240 /* Blocks thread until a packet has been received. */
2242 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2244 SilcPacketWait pw = waiter;
2245 SilcBool ret = FALSE;
2247 silc_mutex_lock(pw->wait_lock);
2249 /* Wait here until packet has arrived */
2250 while (silc_list_count(pw->packet_queue) == 0) {
2251 if (silc_unlikely(pw->stopped)) {
2252 silc_mutex_unlock(pw->wait_lock);
2255 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2259 silc_list_start(pw->packet_queue);
2260 *return_packet = silc_list_get(pw->packet_queue);
2261 silc_list_del(pw->packet_queue, *return_packet);
2263 silc_mutex_unlock(pw->wait_lock);
2265 return ret == TRUE ? 1 : 0;
2268 /************************** Packet Stream Wrapper ***************************/
2270 /* Packet stream wrapper receive callback */
2272 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2273 SilcPacketStream stream,
2275 void *callback_context,
2276 void *stream_context);
2278 const SilcStreamOps silc_packet_stream_ops;
2280 /* Packet stream wrapper context */
2282 const SilcStreamOps *ops;
2283 SilcPacketStream stream;
2285 void *waiter; /* Waiter context in blocking mode */
2286 SilcStreamNotifier callback;
2289 SilcPacketType type;
2290 SilcPacketFlags flags;
2291 unsigned int closed : 1;
2292 unsigned int blocking : 1;
2293 } *SilcPacketWrapperStream;
2295 /* Packet wrapper callbacks */
2296 static SilcPacketCallbacks silc_packet_wrap_cbs =
2298 silc_packet_wrap_packet_receive, NULL, NULL
2301 /* Packet stream wrapper receive callback, non-blocking mode */
2304 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2305 SilcPacketStream stream,
2307 void *callback_context,
2308 void *stream_context)
2310 SilcPacketWrapperStream pws = callback_context;
2312 if (!pws->closed || !pws->callback)
2315 silc_mutex_lock(pws->lock);
2316 silc_list_add(pws->in_queue, packet);
2317 silc_mutex_unlock(pws->lock);
2319 /* Call notifier callback */
2320 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2325 /* Read SILC packet */
2327 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2330 SilcPacketWrapperStream pws = stream;
2337 if (pws->blocking) {
2338 /* Block until packet is received */
2339 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2344 /* Non-blocking mode */
2345 silc_mutex_lock(pws->lock);
2346 if (!silc_list_count(pws->in_queue)) {
2347 silc_mutex_unlock(pws->lock);
2351 silc_list_start(pws->in_queue);
2352 packet = silc_list_get(pws->in_queue);
2353 silc_list_del(pws->in_queue, packet);
2354 silc_mutex_unlock(pws->lock);
2357 len = silc_buffer_len(&packet->buffer);
2361 memcpy(buf, packet->buffer.data, len);
2363 silc_packet_free(packet);
2367 /* Write SILC packet */
2369 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2370 SilcUInt32 data_len)
2372 SilcPacketWrapperStream pws = stream;
2374 /* Send the SILC packet */
2375 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2383 SilcBool silc_packet_wrap_close(SilcStream stream)
2385 SilcPacketWrapperStream pws = stream;
2390 if (pws->blocking) {
2391 /* Close packet waiter */
2392 silc_packet_wait_uninit(pws->waiter, pws->stream);
2396 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2403 /* Destroy wrapper stream */
2405 void silc_packet_wrap_destroy(SilcStream stream)
2408 SilcPacketWrapperStream pws = stream;
2411 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2413 silc_stream_close(stream);
2414 silc_list_start(pws->in_queue);
2415 while ((packet = silc_list_get(pws->in_queue)))
2416 silc_packet_free(packet);
2418 silc_mutex_free(pws->lock);
2419 silc_packet_stream_unref(pws->stream);
2424 /* Link stream to receive packets */
2426 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2427 SilcSchedule schedule,
2428 SilcStreamNotifier callback,
2431 SilcPacketWrapperStream pws = stream;
2433 if (pws->closed || pws->blocking)
2436 /* Link to receive packets */
2438 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2439 100000, pws->type, -1);
2441 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2443 pws->callback = callback;
2444 pws->context = context;
2449 /* Return schedule */
2451 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2456 /* Wraps packet stream into SilcStream. */
2458 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2459 SilcPacketType type,
2460 SilcPacketFlags flags,
2461 SilcBool blocking_mode)
2463 SilcPacketWrapperStream pws;
2465 pws = silc_calloc(1, sizeof(*pws));
2469 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2471 pws->ops = &silc_packet_stream_ops;
2472 pws->stream = stream;
2475 pws->blocking = blocking_mode;
2477 if (pws->blocking) {
2478 /* Blocking mode. Use packet waiter to do the thing. */
2479 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2485 /* Non-blocking mode */
2486 if (!silc_mutex_alloc(&pws->lock)) {
2491 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2494 silc_packet_stream_ref(stream);
2496 return (SilcStream)pws;
2499 const SilcStreamOps silc_packet_stream_ops =
2501 silc_packet_wrap_read,
2502 silc_packet_wrap_write,
2503 silc_packet_wrap_close,
2504 silc_packet_wrap_destroy,
2505 silc_packet_wrap_notifier,
2506 silc_packet_wrap_get_schedule,