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)
609 SILC_LOG_DEBUG(("Stopping packet engine"));
614 /* Free packet free list */
615 silc_list_start(engine->packet_pool);
616 while ((packet = silc_list_get(engine->packet_pool))) {
617 silc_buffer_purge(&packet->buffer);
621 silc_hash_table_free(engine->contexts);
622 silc_mutex_free(engine->lock);
626 /* Create new packet stream */
628 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
629 SilcSchedule schedule,
636 SILC_LOG_DEBUG(("Creating new packet stream"));
638 if (!engine || !stream)
641 ps = silc_calloc(1, sizeof(*ps));
646 silc_atomic_init8(&ps->refcnt, 1);
647 silc_mutex_alloc(&ps->lock);
649 /* Allocate out buffer */
650 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
652 silc_packet_stream_destroy(ps);
655 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
656 silc_buffer_reset(&ps->outbuf);
658 /* Initialize packet procesors list */
659 ps->process = silc_dlist_init();
661 silc_packet_stream_destroy(ps);
665 silc_mutex_lock(engine->lock);
667 /* Add per scheduler context */
668 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
670 ps->sc = silc_calloc(1, sizeof(*ps->sc));
672 silc_packet_stream_destroy(ps);
673 silc_mutex_unlock(engine->lock);
676 ps->sc->engine = engine;
677 ps->sc->schedule = schedule;
679 /* Allocate data input buffer */
680 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
684 silc_packet_stream_destroy(ps);
685 silc_mutex_unlock(engine->lock);
688 silc_buffer_reset(inbuf);
690 ps->sc->inbufs = silc_dlist_init();
691 if (!ps->sc->inbufs) {
692 silc_buffer_free(inbuf);
695 silc_packet_stream_destroy(ps);
696 silc_mutex_unlock(engine->lock);
699 silc_dlist_add(ps->sc->inbufs, inbuf);
701 /* Add to per scheduler context hash table */
702 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
703 silc_buffer_free(inbuf);
704 silc_dlist_del(ps->sc->inbufs, inbuf);
707 silc_packet_stream_destroy(ps);
708 silc_mutex_unlock(engine->lock);
712 ps->sc->stream_count++;
714 /* Add the packet stream to engine */
715 silc_list_add(engine->streams, ps);
717 /* If this is UDP stream, allocate UDP remote stream hash table */
718 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
719 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
720 silc_hash_string_compare, NULL,
721 silc_packet_engine_hash_destr,
724 silc_mutex_unlock(engine->lock);
726 /* Set IO notifier callback. This schedules this stream for I/O. */
727 if (!silc_stream_set_notifier(ps->stream, schedule,
728 silc_packet_stream_io, ps)) {
729 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
730 silc_packet_stream_destroy(ps);
737 /* Add new remote packet stream for UDP packet streams */
739 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
740 const char *remote_ip,
741 SilcUInt16 remote_port,
744 SilcPacketEngine engine = stream->sc->engine;
749 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
750 remote_ip, remote_port, stream));
752 if (!stream || !remote_ip || !remote_port)
755 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
756 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
760 ps = silc_calloc(1, sizeof(*ps));
765 silc_atomic_init8(&ps->refcnt, 1);
766 silc_mutex_alloc(&ps->lock);
768 /* Set the UDP packet stream as underlaying stream */
769 silc_packet_stream_ref(stream);
770 ps->stream = (SilcStream)stream;
773 /* Allocate out buffer */
774 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
776 silc_packet_stream_destroy(ps);
779 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
780 silc_buffer_reset(&ps->outbuf);
782 /* Initialize packet procesors list */
783 ps->process = silc_dlist_init();
785 silc_packet_stream_destroy(ps);
789 /* Add to engine with this IP and port pair */
790 tuple = silc_format("%d%s", remote_port, remote_ip);
791 silc_mutex_lock(engine->lock);
792 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
793 silc_mutex_unlock(engine->lock);
794 silc_packet_stream_destroy(ps);
797 silc_mutex_unlock(engine->lock);
799 /* Save remote IP and port pair */
800 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
801 if (!ps->remote_udp) {
802 silc_packet_stream_destroy(ps);
805 ps->remote_udp->remote_port = remote_port;
806 ps->remote_udp->remote_ip = strdup(remote_ip);
807 if (!ps->remote_udp->remote_ip) {
808 silc_packet_stream_destroy(ps);
813 /* Inject packet to the new stream */
815 silc_packet_stream_ref(ps);
816 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
817 silc_packet_stream_inject_packet, packet,
824 /* Destroy packet stream */
826 void silc_packet_stream_destroy(SilcPacketStream stream)
831 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
832 stream->destroyed = TRUE;
834 /* Close the underlaying stream */
835 if (!stream->udp && stream->stream)
836 silc_stream_close(stream->stream);
840 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
843 /* Delete from engine */
844 silc_mutex_lock(stream->sc->engine->lock);
845 silc_list_del(stream->sc->engine->streams, stream);
847 /* Remove per scheduler context, if it is not used anymore */
849 stream->sc->stream_count--;
850 if (!stream->sc->stream_count)
851 silc_hash_table_del(stream->sc->engine->contexts,
852 stream->sc->schedule);
854 silc_mutex_unlock(stream->sc->engine->lock);
856 /* Destroy the underlaying stream */
858 silc_stream_destroy(stream->stream);
860 /* Delete from UDP remote hash table */
862 silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
863 stream->remote_udp->remote_ip);
864 silc_mutex_lock(stream->sc->engine->lock);
865 silc_hash_table_del(stream->sc->engine->udp_remote, tuple);
866 silc_mutex_unlock(stream->sc->engine->lock);
868 silc_free(stream->remote_udp->remote_ip);
869 silc_free(stream->remote_udp);
871 /* Unreference the underlaying packet stream */
872 silc_packet_stream_unref((SilcPacketStream)stream->stream);
875 /* Clear and free buffers */
876 silc_buffer_clear(&stream->outbuf);
877 silc_buffer_purge(&stream->outbuf);
879 if (stream->process) {
881 silc_dlist_start(stream->process);
882 while ((p = silc_dlist_get(stream->process))) {
885 silc_dlist_del(stream->process, p);
887 silc_dlist_uninit(stream->process);
890 /* Destroy ciphers and HMACs */
891 if (stream->send_key[0])
892 silc_cipher_free(stream->send_key[0]);
893 if (stream->receive_key[0])
894 silc_cipher_free(stream->receive_key[0]);
895 if (stream->send_hmac[0])
896 silc_hmac_free(stream->send_hmac[0]);
897 if (stream->receive_hmac[0])
898 silc_hmac_free(stream->receive_hmac[0]);
899 if (stream->send_key[1])
900 silc_cipher_free(stream->send_key[1]);
901 if (stream->receive_key[1])
902 silc_cipher_free(stream->receive_key[1]);
903 if (stream->send_hmac[1])
904 silc_hmac_free(stream->send_hmac[1]);
905 if (stream->receive_hmac[1])
906 silc_hmac_free(stream->receive_hmac[1]);
909 silc_free(stream->src_id);
910 silc_free(stream->dst_id);
912 silc_atomic_uninit8(&stream->refcnt);
913 silc_mutex_free(stream->lock);
917 /* Marks as router stream */
919 void silc_packet_stream_set_router(SilcPacketStream stream)
921 stream->is_router = TRUE;
924 /* Mark to include IV in ciphertext */
926 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
928 stream->iv_included = TRUE;
931 /* Links `callbacks' to `stream' for specified packet types */
933 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
934 SilcPacketCallbacks *callbacks,
935 void *callback_context,
936 int priority, va_list ap)
938 SilcPacketProcess p, e;
939 SilcInt32 packet_type;
942 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
946 if (!callbacks->packet_receive)
949 p = silc_calloc(1, sizeof(*p));
953 p->priority = priority;
954 p->callbacks = callbacks;
955 p->callback_context = callback_context;
957 silc_mutex_lock(stream->lock);
959 if (!stream->process) {
960 stream->process = silc_dlist_init();
961 if (!stream->process) {
962 silc_mutex_unlock(stream->lock);
967 /* According to priority set the procesor to correct position. First
968 entry has the highest priority */
969 silc_dlist_start(stream->process);
970 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
971 if (p->priority > e->priority) {
972 silc_dlist_insert(stream->process, p);
977 silc_dlist_add(stream->process, p);
979 /* Get packet types to process */
982 packet_type = va_arg(ap, SilcInt32);
984 if (packet_type == SILC_PACKET_ANY)
987 if (packet_type == -1)
990 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
992 silc_mutex_unlock(stream->lock);
996 p->types[i - 1] = (SilcPacketType)packet_type;
1000 p->types[i - 1] = 0;
1002 silc_mutex_unlock(stream->lock);
1004 silc_packet_stream_ref(stream);
1009 /* Links `callbacks' to `stream' for specified packet types */
1011 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1012 SilcPacketCallbacks *callbacks,
1013 void *callback_context,
1019 va_start(ap, priority);
1020 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1027 /* Unlinks `callbacks' from `stream'. */
1029 void silc_packet_stream_unlink(SilcPacketStream stream,
1030 SilcPacketCallbacks *callbacks,
1031 void *callback_context)
1033 SilcPacketProcess p;
1035 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1036 callbacks, stream));
1038 silc_mutex_lock(stream->lock);
1040 silc_dlist_start(stream->process);
1041 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1042 if (p->callbacks == callbacks &&
1043 p->callback_context == callback_context) {
1044 silc_dlist_del(stream->process, p);
1045 silc_free(p->types);
1050 if (!silc_dlist_count(stream->process)) {
1051 silc_dlist_uninit(stream->process);
1052 stream->process = NULL;
1055 silc_mutex_unlock(stream->lock);
1057 silc_packet_stream_unref(stream);
1060 /* Returns TRUE if stream is UDP stream */
1062 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1064 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1067 /* Return packet sender IP and port for UDP packet stream */
1069 SilcBool silc_packet_get_sender(SilcPacket packet,
1070 const char **sender_ip,
1071 SilcUInt16 *sender_port)
1073 if (!packet->stream->remote_udp)
1076 *sender_ip = packet->stream->remote_udp->remote_ip;
1077 *sender_port = packet->stream->remote_udp->remote_port;
1082 /* Reference packet stream */
1084 void silc_packet_stream_ref(SilcPacketStream stream)
1086 silc_atomic_add_int8(&stream->refcnt, 1);
1087 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1088 silc_atomic_get_int8(&stream->refcnt) - 1,
1089 silc_atomic_get_int8(&stream->refcnt)));
1092 /* Unreference packet stream */
1094 void silc_packet_stream_unref(SilcPacketStream stream)
1096 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1097 silc_atomic_get_int8(&stream->refcnt),
1098 silc_atomic_get_int8(&stream->refcnt) - 1));
1099 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1101 silc_atomic_add_int8(&stream->refcnt, 1);
1102 silc_packet_stream_destroy(stream);
1107 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1109 return stream->sc->engine;
1112 /* Set application context for packet stream */
1114 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1116 silc_mutex_lock(stream->lock);
1117 stream->stream_context = stream_context;
1118 silc_mutex_unlock(stream->lock);
1121 /* Return application context from packet stream */
1123 void *silc_packet_get_context(SilcPacketStream stream)
1126 silc_mutex_lock(stream->lock);
1127 context = stream->stream_context;
1128 silc_mutex_unlock(stream->lock);
1132 /* Change underlaying stream */
1134 void silc_packet_stream_set_stream(SilcPacketStream ps,
1138 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1139 ps->stream = stream;
1140 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1144 /* Return underlaying stream */
1146 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1148 return stream->stream;
1153 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1154 SilcCipher receive_key, SilcHmac send_hmac,
1155 SilcHmac receive_hmac, SilcBool rekey)
1157 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1159 /* If doing rekey, send REKEY_DONE packet */
1161 /* This will take stream lock. */
1162 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1163 stream->src_id_type, stream->src_id,
1164 stream->src_id_len, stream->dst_id_type,
1165 stream->dst_id, stream->dst_id_len,
1166 NULL, 0, stream->send_key[0],
1167 stream->send_hmac[0]))
1170 /* Write the packet to the stream */
1171 if (!silc_packet_stream_write(stream, TRUE))
1174 silc_mutex_lock(stream->lock);
1177 /* In case IV Included is set, save the old keys */
1178 if (stream->iv_included) {
1179 if (stream->send_key[1] && send_key) {
1180 silc_cipher_free(stream->send_key[1]);
1181 stream->send_key[1] = stream->send_key[0];
1183 if (stream->receive_key[1] && receive_key) {
1184 silc_cipher_free(stream->receive_key[1]);
1185 stream->receive_key[1] = stream->receive_key[0];
1187 if (stream->send_hmac[1] && send_hmac) {
1188 silc_hmac_free(stream->send_hmac[1]);
1189 stream->send_hmac[1] = stream->send_hmac[0];
1191 if (stream->receive_hmac[1] && receive_hmac) {
1192 silc_hmac_free(stream->receive_hmac[1]);
1193 stream->receive_hmac[1] = stream->receive_hmac[0];
1196 if (stream->send_key[0] && send_key)
1197 silc_cipher_free(stream->send_key[0]);
1198 if (stream->receive_key[0] && receive_key)
1199 silc_cipher_free(stream->receive_key[0]);
1200 if (stream->send_hmac[0] && send_hmac)
1201 silc_hmac_free(stream->send_hmac[0]);
1202 if (stream->receive_hmac[0] && receive_hmac)
1203 silc_hmac_free(stream->receive_hmac[0]);
1208 stream->send_key[0] = send_key;
1210 stream->receive_key[0] = receive_key;
1212 stream->send_hmac[0] = send_hmac;
1214 stream->receive_hmac[0] = receive_hmac;
1216 silc_mutex_unlock(stream->lock);
1220 /* Return current ciphers from packet stream */
1222 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1223 SilcCipher *send_key,
1224 SilcCipher *receive_key,
1225 SilcHmac *send_hmac,
1226 SilcHmac *receive_hmac)
1228 if (!stream->send_key[0] && !stream->receive_key[0] &&
1229 !stream->send_hmac[0] && !stream->receive_hmac[0])
1232 silc_mutex_lock(stream->lock);
1235 *send_key = stream->send_key[0];
1237 *receive_key = stream->receive_key[0];
1239 *send_hmac = stream->send_hmac[0];
1241 *receive_hmac = stream->receive_hmac[0];
1243 silc_mutex_unlock(stream->lock);
1248 /* Set SILC IDs to packet stream */
1250 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1251 SilcIdType src_id_type, const void *src_id,
1252 SilcIdType dst_id_type, const void *dst_id)
1255 unsigned char tmp[32];
1257 if (!src_id && !dst_id)
1260 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1262 silc_mutex_lock(stream->lock);
1265 silc_free(stream->src_id);
1266 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1267 silc_mutex_unlock(stream->lock);
1270 stream->src_id = silc_memdup(tmp, len);
1271 if (!stream->src_id) {
1272 silc_mutex_unlock(stream->lock);
1275 stream->src_id_type = src_id_type;
1276 stream->src_id_len = len;
1280 silc_free(stream->dst_id);
1281 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1282 silc_mutex_unlock(stream->lock);
1285 stream->dst_id = silc_memdup(tmp, len);
1286 if (!stream->dst_id) {
1287 silc_mutex_unlock(stream->lock);
1290 stream->dst_id_type = dst_id_type;
1291 stream->dst_id_len = len;
1294 silc_mutex_unlock(stream->lock);
1299 /* Adds Security ID (SID) */
1301 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1303 if (!stream->iv_included)
1306 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1314 void silc_packet_free(SilcPacket packet)
1316 SilcPacketStream stream = packet->stream;
1318 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1320 /* Check for double free */
1321 SILC_ASSERT(packet->stream != NULL);
1323 packet->stream = NULL;
1324 packet->src_id = packet->dst_id = NULL;
1325 silc_buffer_reset(&packet->buffer);
1327 silc_mutex_lock(stream->sc->engine->lock);
1329 /* Put the packet back to freelist */
1330 silc_list_add(stream->sc->engine->packet_pool, packet);
1331 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1332 silc_list_start(stream->sc->engine->packet_pool);
1334 silc_mutex_unlock(stream->sc->engine->lock);
1337 /****************************** Packet Sending ******************************/
1339 /* Prepare outgoing data buffer for packet sending. Returns the
1340 pointer to that buffer into the `packet'. */
1342 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1347 unsigned char *oldptr;
1348 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1352 /* Allocate more space if needed */
1353 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1354 if (!silc_buffer_realloc(&stream->outbuf,
1355 silc_buffer_truelen(&stream->outbuf) + totlen))
1359 /* Pull data area for the new packet, and return pointer to the start of
1360 the data area and save the pointer in to the `packet'. MAC is pulled
1361 later after it's computed. */
1362 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1363 silc_buffer_set(packet, oldptr, totlen);
1364 silc_buffer_push_tail(packet, mac_len);
1369 /* Increments counter when encrypting in counter mode. */
1371 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1373 unsigned char *ret_iv)
1375 unsigned char *iv = silc_cipher_get_iv(cipher);
1376 SilcUInt32 pc1, pc2;
1378 /* Increment 64-bit packet counter.*/
1379 SILC_GET32_MSB(pc1, iv + 4);
1380 SILC_GET32_MSB(pc2, iv + 8);
1383 SILC_PUT32_MSB(pc1, iv + 4);
1384 SILC_PUT32_MSB(pc2, iv + 8);
1386 /* Reset block counter */
1387 memset(iv + 12, 0, 4);
1389 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1390 if (stream->iv_included) {
1392 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1393 ret_iv[1] = ret_iv[0] + iv[4];
1394 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1395 ret_iv[3] = ret_iv[0] + ret_iv[2];
1396 SILC_PUT32_MSB(pc2, ret_iv + 4);
1397 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1399 /* Set new nonce to counter block */
1400 memcpy(iv + 4, ret_iv, 4);
1403 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1406 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1407 the packet. The silc_packet_stream_write needs to be called to send it
1408 after this returns TRUE. */
1410 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1411 SilcPacketType type,
1412 SilcPacketFlags flags,
1413 SilcIdType src_id_type,
1414 unsigned char *src_id,
1415 SilcUInt32 src_id_len,
1416 SilcIdType dst_id_type,
1417 unsigned char *dst_id,
1418 SilcUInt32 dst_id_len,
1419 const unsigned char *data,
1420 SilcUInt32 data_len,
1424 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1425 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1426 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1428 SilcBufferStruct packet;
1430 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1431 "data len %d", silc_get_packet_name(type), stream->send_psn,
1432 flags, src_id_type, dst_id_type, data_len));
1434 /* Get the true length of the packet. This is saved as payload length
1435 into the packet header. This does not include the length of the
1437 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1438 src_id_len + dst_id_len));
1439 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1440 src_id_len + dst_id_len);
1442 /* If using CTR mode, increment the counter */
1443 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1445 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1447 /* If IV is included, the SID, IV and sequence number is added to packet */
1448 if (stream->iv_included && cipher) {
1449 psnlen = sizeof(psn);
1451 iv[0] = stream->sid;
1454 /* If IV is included, the SID, IV and sequence number is added to packet */
1455 if (stream->iv_included && cipher) {
1456 psnlen = sizeof(psn);
1457 ivlen = block_len + 1;
1458 iv[0] = stream->sid;
1459 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1463 /* We automatically figure out the packet structure from the packet
1464 type and flags, and calculate correct length. Private messages with
1465 private keys and channel messages are special packets as their
1466 payload is encrypted already. */
1467 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1468 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1469 type == SILC_PACKET_CHANNEL_MESSAGE) {
1471 /* Padding is calculated from header + IDs */
1473 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1474 psnlen), block_len, padlen);
1476 /* Length to encrypt, header + IDs + padding. */
1477 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1481 /* Padding is calculated from true length of the packet */
1482 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1483 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1485 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1487 enclen += padlen + psnlen;
1490 /* Remove implementation specific flags */
1491 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1493 /* Get random padding */
1494 for (i = 0; i < padlen; i++) tmppad[i] =
1495 silc_rng_get_byte_fast(stream->sc->engine->rng);
1497 silc_mutex_lock(stream->lock);
1499 /* Get packet pointer from the outgoing buffer */
1500 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1501 + psnlen, hmac, &packet))) {
1502 silc_mutex_unlock(stream->lock);
1506 SILC_PUT32_MSB(stream->send_psn, psn);
1508 /* Create the packet. This creates the SILC header, adds padding, and
1509 the actual packet data. */
1510 i = silc_buffer_format(&packet,
1511 SILC_STR_DATA(iv, ivlen),
1512 SILC_STR_DATA(psn, psnlen),
1513 SILC_STR_UI_SHORT(truelen),
1514 SILC_STR_UI_CHAR(flags),
1515 SILC_STR_UI_CHAR(type),
1516 SILC_STR_UI_CHAR(padlen),
1517 SILC_STR_UI_CHAR(0),
1518 SILC_STR_UI_CHAR(src_id_len),
1519 SILC_STR_UI_CHAR(dst_id_len),
1520 SILC_STR_UI_CHAR(src_id_type),
1521 SILC_STR_DATA(src_id, src_id_len),
1522 SILC_STR_UI_CHAR(dst_id_type),
1523 SILC_STR_DATA(dst_id, dst_id_len),
1524 SILC_STR_DATA(tmppad, padlen),
1525 SILC_STR_DATA(data, data_len),
1527 if (silc_unlikely(i < 0)) {
1528 silc_mutex_unlock(stream->lock);
1532 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1533 silc_buffer_data(&packet), silc_buffer_len(&packet));
1535 /* Encrypt the packet */
1536 if (silc_likely(cipher)) {
1537 SILC_LOG_DEBUG(("Encrypting packet"));
1538 silc_cipher_set_iv(cipher, NULL);
1539 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1540 packet.data + ivlen, enclen,
1542 SILC_LOG_ERROR(("Packet encryption failed"));
1543 silc_mutex_unlock(stream->lock);
1549 if (silc_likely(hmac)) {
1552 /* MAC is computed from the entire encrypted packet data, and put
1553 to the end of the packet. */
1554 silc_hmac_init(hmac);
1555 silc_hmac_update(hmac, psn, sizeof(psn));
1556 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1557 silc_hmac_final(hmac, packet.tail, &mac_len);
1558 silc_buffer_pull_tail(&packet, mac_len);
1565 /* Sends a packet */
1567 SilcBool silc_packet_send(SilcPacketStream stream,
1568 SilcPacketType type, SilcPacketFlags flags,
1569 const unsigned char *data, SilcUInt32 data_len)
1573 ret = silc_packet_send_raw(stream, type, flags,
1574 stream->src_id_type,
1577 stream->dst_id_type,
1581 stream->send_key[0],
1582 stream->send_hmac[0]);
1584 /* Write the packet to the stream */
1585 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1588 /* Sends a packet, extended routine */
1590 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1591 SilcPacketType type, SilcPacketFlags flags,
1592 SilcIdType src_id_type, void *src_id,
1593 SilcIdType dst_id_type, void *dst_id,
1594 const unsigned char *data, SilcUInt32 data_len,
1595 SilcCipher cipher, SilcHmac hmac)
1597 unsigned char src_id_data[32], dst_id_data[32];
1598 SilcUInt32 src_id_len, dst_id_len;
1602 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1603 sizeof(src_id_data), &src_id_len))
1606 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1607 sizeof(dst_id_data), &dst_id_len))
1610 ret = silc_packet_send_raw(stream, type, flags,
1611 src_id ? src_id_type : stream->src_id_type,
1612 src_id ? src_id_data : stream->src_id,
1613 src_id ? src_id_len : stream->src_id_len,
1614 dst_id ? dst_id_type : stream->dst_id_type,
1615 dst_id ? dst_id_data : stream->dst_id,
1616 dst_id ? dst_id_len : stream->dst_id_len,
1618 cipher ? cipher : stream->send_key[0],
1619 hmac ? hmac : stream->send_hmac[0]);
1621 /* Write the packet to the stream */
1622 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1625 /* Sends packet after formatting the arguments to buffer */
1627 SilcBool silc_packet_send_va(SilcPacketStream stream,
1628 SilcPacketType type, SilcPacketFlags flags, ...)
1630 SilcBufferStruct buf;
1634 va_start(va, flags);
1636 memset(&buf, 0, sizeof(buf));
1637 if (silc_buffer_format_vp(&buf, va) < 0) {
1642 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1643 silc_buffer_len(&buf));
1645 silc_buffer_purge(&buf);
1651 /* Sends packet after formatting the arguments to buffer, extended routine */
1653 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1654 SilcPacketType type, SilcPacketFlags flags,
1655 SilcIdType src_id_type, void *src_id,
1656 SilcIdType dst_id_type, void *dst_id,
1657 SilcCipher cipher, SilcHmac hmac, ...)
1659 SilcBufferStruct buf;
1665 memset(&buf, 0, sizeof(buf));
1666 if (silc_buffer_format_vp(&buf, va) < 0) {
1671 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1672 dst_id_type, dst_id, silc_buffer_data(&buf),
1673 silc_buffer_len(&buf), cipher, hmac);
1675 silc_buffer_purge(&buf);
1681 /***************************** Packet Receiving *****************************/
1683 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1685 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1686 const unsigned char *data,
1687 SilcUInt32 data_len,
1688 const unsigned char *packet_mac,
1689 const unsigned char *packet_seq,
1690 SilcUInt32 sequence)
1693 if (silc_likely(hmac)) {
1694 unsigned char mac[32], psn[4];
1697 SILC_LOG_DEBUG(("Verifying MAC"));
1699 /* Compute HMAC of packet */
1700 silc_hmac_init(hmac);
1703 SILC_PUT32_MSB(sequence, psn);
1704 silc_hmac_update(hmac, psn, 4);
1706 silc_hmac_update(hmac, packet_seq, 4);
1708 silc_hmac_update(hmac, data, data_len);
1709 silc_hmac_final(hmac, mac, &mac_len);
1711 /* Compare the MAC's */
1712 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1713 SILC_LOG_DEBUG(("MAC failed"));
1717 SILC_LOG_DEBUG(("MAC is Ok"));
1723 /* Increments/sets counter when decrypting in counter mode. */
1725 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1727 unsigned char *packet_iv)
1729 SilcUInt32 pc1, pc2;
1731 /* If IV Included flag, set the IV from packet to block counter. */
1732 if (stream->iv_included) {
1733 memcpy(iv + 4, packet_iv, 8);
1735 /* Increment 64-bit packet counter. */
1736 SILC_GET32_MSB(pc1, iv + 4);
1737 SILC_GET32_MSB(pc2, iv + 8);
1740 SILC_PUT32_MSB(pc1, iv + 4);
1741 SILC_PUT32_MSB(pc2, iv + 8);
1744 /* Reset block counter */
1745 memset(iv + 12, 0, 4);
1747 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1750 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1751 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1753 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1754 SilcUInt32 sequence, SilcBuffer buffer,
1757 if (normal == TRUE) {
1758 if (silc_likely(cipher)) {
1759 /* Decrypt rest of the packet */
1760 SILC_LOG_DEBUG(("Decrypting the packet"));
1761 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1763 silc_buffer_len(buffer), NULL)))
1769 /* Decrypt rest of the header plus padding */
1770 if (silc_likely(cipher)) {
1772 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1774 SILC_LOG_DEBUG(("Decrypting the header"));
1776 /* Padding length + src id len + dst id len + header length - 16
1777 bytes already decrypted, gives the rest of the encrypted packet */
1778 silc_buffer_push(buffer, block_len);
1779 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1780 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1782 silc_buffer_pull(buffer, block_len);
1784 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1785 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1789 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1790 buffer->data, len, NULL)))
1798 /* Parses the packet. This is called when a whole packet is ready to be
1799 parsed. The buffer sent must be already decrypted before calling this
1802 static inline SilcBool silc_packet_parse(SilcPacket packet)
1804 SilcBuffer buffer = &packet->buffer;
1805 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1806 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1809 SILC_LOG_DEBUG(("Parsing incoming packet"));
1811 /* Parse the buffer. This parses the SILC header of the packet. */
1812 ret = silc_buffer_unformat(buffer,
1815 SILC_STR_UI_CHAR(&src_id_len),
1816 SILC_STR_UI_CHAR(&dst_id_len),
1817 SILC_STR_UI_CHAR(&src_id_type),
1819 if (silc_unlikely(ret == -1)) {
1820 if (!packet->stream->udp &&
1821 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1822 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1826 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1827 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1828 if (!packet->stream->udp &&
1829 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1830 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1831 packet->src_id_len, packet->dst_id_len));
1835 ret = silc_buffer_unformat(buffer,
1837 SILC_STR_DATA(&packet->src_id, src_id_len),
1838 SILC_STR_UI_CHAR(&dst_id_type),
1839 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1840 SILC_STR_OFFSET(padlen),
1842 if (silc_unlikely(ret == -1)) {
1843 if (!packet->stream->udp &&
1844 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1845 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1849 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1850 dst_id_type > SILC_ID_CHANNEL)) {
1851 if (!packet->stream->udp &&
1852 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1853 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1854 src_id_type, dst_id_type));
1858 packet->src_id_len = src_id_len;
1859 packet->dst_id_len = dst_id_len;
1860 packet->src_id_type = src_id_type;
1861 packet->dst_id_type = dst_id_type;
1863 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1864 silc_buffer_len(buffer)), buffer->head,
1865 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1867 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1868 silc_get_packet_name(packet->type)));
1873 /* Dispatch packet to application. Called with stream->lock locked.
1874 Returns FALSE if the stream was destroyed while dispatching a packet. */
1876 static SilcBool silc_packet_dispatch(SilcPacket packet)
1878 SilcPacketStream stream = packet->stream;
1879 SilcPacketProcess p;
1880 SilcBool default_sent = FALSE;
1883 /* Dispatch packet to all packet processors that want it */
1885 if (silc_likely(!stream->process)) {
1886 /* Send to default processor as no others exist */
1887 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1888 silc_mutex_unlock(stream->lock);
1889 if (silc_unlikely(!stream->sc->engine->callbacks->
1890 packet_receive(stream->sc->engine, stream, packet,
1891 stream->sc->engine->callback_context,
1892 stream->stream_context)))
1893 silc_packet_free(packet);
1894 silc_mutex_lock(stream->lock);
1895 return stream->destroyed == FALSE;
1898 silc_dlist_start(stream->process);
1899 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1901 /* If priority is 0 or less, we send to default processor first
1902 because default processor has 0 priority */
1903 if (!default_sent && p->priority <= 0) {
1904 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1905 default_sent = TRUE;
1906 silc_mutex_unlock(stream->lock);
1907 if (stream->sc->engine->callbacks->
1908 packet_receive(stream->sc->engine, stream, packet,
1909 stream->sc->engine->callback_context,
1910 stream->stream_context)) {
1911 silc_mutex_lock(stream->lock);
1912 return stream->destroyed == FALSE;
1914 silc_mutex_lock(stream->lock);
1917 /* Send to processor */
1919 /* Send all packet types */
1920 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1921 silc_mutex_unlock(stream->lock);
1922 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1923 p->callback_context,
1924 stream->stream_context)) {
1925 silc_mutex_lock(stream->lock);
1926 return stream->destroyed == FALSE;
1928 silc_mutex_lock(stream->lock);
1930 /* Send specific types */
1931 for (pt = p->types; *pt; pt++) {
1932 if (*pt != packet->type)
1934 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1935 silc_mutex_unlock(stream->lock);
1936 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1937 p->callback_context,
1938 stream->stream_context)) {
1939 silc_mutex_lock(stream->lock);
1940 return stream->destroyed == FALSE;
1942 silc_mutex_lock(stream->lock);
1948 if (!default_sent) {
1949 /* Send to default processor as it has not been sent yet */
1950 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1951 silc_mutex_unlock(stream->lock);
1952 if (stream->sc->engine->callbacks->
1953 packet_receive(stream->sc->engine, stream, packet,
1954 stream->sc->engine->callback_context,
1955 stream->stream_context)) {
1956 silc_mutex_lock(stream->lock);
1957 return stream->destroyed == FALSE;
1959 silc_mutex_lock(stream->lock);
1962 /* If we got here, no one wanted the packet, so drop it */
1963 silc_packet_free(packet);
1964 return stream->destroyed == FALSE;
1967 /* Process incoming data and parse packets. Called with stream->lock
1970 static void silc_packet_read_process(SilcPacketStream stream)
1977 SilcUInt16 packetlen;
1978 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1979 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1980 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1984 /* Get inbuf. If there is already some data for this stream in the buffer
1985 we already have it. Otherwise get the current one from list, it will
1986 include the data. */
1987 inbuf = stream->inbuf;
1989 silc_dlist_start(stream->sc->inbufs);
1990 inbuf = silc_dlist_get(stream->sc->inbufs);
1993 /* Parse the packets from the data */
1994 while (silc_buffer_len(inbuf) > 0) {
1996 cipher = stream->receive_key[0];
1997 hmac = stream->receive_hmac[0];
2000 if (silc_unlikely(silc_buffer_len(inbuf) <
2001 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2002 SILC_PACKET_MIN_HEADER_LEN))) {
2003 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2004 silc_dlist_del(stream->sc->inbufs, inbuf);
2005 stream->inbuf = inbuf;
2009 if (silc_likely(hmac))
2010 mac_len = silc_hmac_len(hmac);
2014 /* Decrypt first block of the packet to get the length field out */
2015 if (silc_likely(cipher)) {
2016 block_len = silc_cipher_get_block_len(cipher);
2018 if (stream->iv_included) {
2019 /* SID, IV and sequence number is included in the ciphertext */
2020 sid = (SilcUInt8)inbuf->data[0];
2022 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2023 /* Set the CTR mode IV from packet to counter block */
2024 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2025 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2028 /* Get IV from packet */
2029 memcpy(iv, inbuf->data + 1, block_len);
2030 ivlen = block_len + 1;
2034 /* Check SID, and get correct decryption key */
2035 if (sid != stream->sid) {
2036 /* If SID is recent get the previous key and use it */
2037 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2038 stream->receive_key[1] && !stream->receive_hmac[1]) {
2039 cipher = stream->receive_key[1];
2040 hmac = stream->receive_hmac[1];
2042 /* The SID is unknown, drop rest of the data in buffer */
2043 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2045 silc_mutex_unlock(stream->lock);
2046 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2047 silc_mutex_lock(stream->lock);
2052 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2054 /* If using CTR mode, increment the counter */
2055 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2056 silc_packet_receive_ctr_increment(stream, iv, NULL);
2059 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2060 silc_cipher_set_iv(cipher, NULL);
2061 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2064 if (stream->iv_included) {
2065 /* Take sequence number from packet */
2066 packet_seq = header;
2070 /* Unencrypted packet */
2071 block_len = SILC_PACKET_MIN_HEADER_LEN;
2072 header = inbuf->data;
2075 /* Get packet length and full packet length with padding */
2076 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2079 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2080 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2081 SILC_LOG_ERROR(("Received too short packet"));
2082 silc_mutex_unlock(stream->lock);
2083 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2084 silc_mutex_lock(stream->lock);
2085 memset(tmp, 0, sizeof(tmp));
2089 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2090 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2092 paddedlen + mac_len - silc_buffer_len(inbuf)));
2093 memset(tmp, 0, sizeof(tmp));
2094 silc_dlist_del(stream->sc->inbufs, inbuf);
2095 stream->inbuf = inbuf;
2099 /* Check MAC of the packet */
2100 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2102 inbuf->data + ivlen +
2103 paddedlen, packet_seq,
2104 stream->receive_psn))) {
2105 silc_mutex_unlock(stream->lock);
2106 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2107 silc_mutex_lock(stream->lock);
2108 memset(tmp, 0, sizeof(tmp));
2113 packet = silc_packet_alloc(stream->sc->engine);
2114 if (silc_unlikely(!packet)) {
2115 silc_mutex_unlock(stream->lock);
2116 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2117 silc_mutex_lock(stream->lock);
2118 memset(tmp, 0, sizeof(tmp));
2121 packet->stream = stream;
2123 /* Allocate more space to packet buffer, if needed */
2124 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2125 if (!silc_buffer_realloc(&packet->buffer,
2126 silc_buffer_truelen(&packet->buffer) +
2128 silc_buffer_truelen(&packet->buffer)))) {
2129 silc_mutex_unlock(stream->lock);
2130 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2131 silc_mutex_lock(stream->lock);
2132 silc_packet_free(packet);
2133 memset(tmp, 0, sizeof(tmp));
2138 /* Parse packet header */
2139 packet->flags = (SilcPacketFlags)header[2];
2140 packet->type = (SilcPacketType)header[3];
2142 if (stream->sc->engine->local_is_router) {
2143 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2144 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2146 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2147 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2148 stream->is_router == TRUE))
2151 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2152 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2154 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2158 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2159 stream->receive_psn, paddedlen + ivlen + mac_len),
2160 inbuf->data, paddedlen + ivlen + mac_len);
2162 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2163 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2164 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2165 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2166 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2167 psnlen + (block_len - psnlen)),
2168 paddedlen - ivlen - psnlen - (block_len - psnlen));
2169 if (silc_likely(cipher)) {
2170 silc_cipher_set_iv(cipher, iv);
2171 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2172 &packet->buffer, normal);
2173 if (silc_unlikely(ret < 0)) {
2174 silc_mutex_unlock(stream->lock);
2175 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2176 silc_mutex_lock(stream->lock);
2177 silc_packet_free(packet);
2178 memset(tmp, 0, sizeof(tmp));
2182 stream->receive_psn++;
2184 silc_buffer_push(&packet->buffer, block_len);
2186 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2187 silc_buffer_pull(inbuf, paddedlen + mac_len);
2189 /* Parse the packet */
2190 if (silc_unlikely(!silc_packet_parse(packet))) {
2191 silc_mutex_unlock(stream->lock);
2192 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2193 silc_mutex_lock(stream->lock);
2194 silc_packet_free(packet);
2195 memset(tmp, 0, sizeof(tmp));
2199 /* Dispatch the packet to application */
2200 if (!silc_packet_dispatch(packet))
2205 /* Add inbuf back to free list, if we owned it. */
2206 if (stream->inbuf) {
2207 silc_dlist_add(stream->sc->inbufs, inbuf);
2208 stream->inbuf = NULL;
2211 silc_buffer_reset(inbuf);
2214 /****************************** Packet Waiting ******************************/
2216 /* Packet wait receive callback */
2218 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2219 SilcPacketStream stream,
2221 void *callback_context,
2222 void *stream_context);
2224 /* Packet waiting callbacks */
2225 static SilcPacketCallbacks silc_packet_wait_cbs =
2227 silc_packet_wait_packet_receive, NULL, NULL
2230 /* Packet waiting context */
2232 SilcMutex wait_lock;
2234 SilcList packet_queue;
2235 unsigned int stopped : 1;
2238 /* Packet wait receive callback */
2241 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2242 SilcPacketStream stream,
2244 void *callback_context,
2245 void *stream_context)
2247 SilcPacketWait pw = callback_context;
2249 /* Signal the waiting thread for a new packet */
2250 silc_mutex_lock(pw->wait_lock);
2252 if (silc_unlikely(pw->stopped)) {
2253 silc_mutex_unlock(pw->wait_lock);
2257 silc_list_add(pw->packet_queue, packet);
2258 silc_cond_broadcast(pw->wait_cond);
2260 silc_mutex_unlock(pw->wait_lock);
2265 /* Initialize packet waiting */
2267 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2273 pw = silc_calloc(1, sizeof(*pw));
2277 /* Allocate mutex and conditional variable */
2278 if (!silc_mutex_alloc(&pw->wait_lock)) {
2282 if (!silc_cond_alloc(&pw->wait_cond)) {
2283 silc_mutex_free(pw->wait_lock);
2288 /* Link to the packet stream for the requested packet types */
2289 va_start(ap, stream);
2290 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2294 silc_cond_free(pw->wait_cond);
2295 silc_mutex_free(pw->wait_lock);
2300 /* Initialize packet queue */
2301 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2306 /* Uninitialize packet waiting */
2308 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2310 SilcPacketWait pw = waiter;
2313 /* Signal any threads to stop waiting */
2314 silc_mutex_lock(pw->wait_lock);
2316 silc_cond_broadcast(pw->wait_cond);
2317 silc_mutex_unlock(pw->wait_lock);
2319 /* Re-acquire lock and free resources */
2320 silc_mutex_lock(pw->wait_lock);
2321 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2323 /* Free any remaining packets */
2324 silc_list_start(pw->packet_queue);
2325 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2326 silc_packet_free(packet);
2328 silc_mutex_unlock(pw->wait_lock);
2329 silc_cond_free(pw->wait_cond);
2330 silc_mutex_free(pw->wait_lock);
2334 /* Blocks thread until a packet has been received. */
2336 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2338 SilcPacketWait pw = waiter;
2339 SilcBool ret = FALSE;
2341 silc_mutex_lock(pw->wait_lock);
2343 /* Wait here until packet has arrived */
2344 while (silc_list_count(pw->packet_queue) == 0) {
2345 if (silc_unlikely(pw->stopped)) {
2346 silc_mutex_unlock(pw->wait_lock);
2349 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2353 silc_list_start(pw->packet_queue);
2354 *return_packet = silc_list_get(pw->packet_queue);
2355 silc_list_del(pw->packet_queue, *return_packet);
2357 silc_mutex_unlock(pw->wait_lock);
2359 return ret == TRUE ? 1 : 0;
2362 /************************** Packet Stream Wrapper ***************************/
2364 /* Packet stream wrapper receive callback */
2366 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2367 SilcPacketStream stream,
2369 void *callback_context,
2370 void *stream_context);
2372 const SilcStreamOps silc_packet_stream_ops;
2374 /* Packet stream wrapper context */
2376 const SilcStreamOps *ops;
2377 SilcPacketStream stream;
2379 void *waiter; /* Waiter context in blocking mode */
2380 SilcPacketWrapCoder coder;
2381 void *coder_context;
2383 SilcStreamNotifier callback;
2386 SilcPacketType type;
2387 SilcPacketFlags flags;
2388 unsigned int closed : 1;
2389 unsigned int blocking : 1;
2390 unsigned int read_more : 1;
2391 } *SilcPacketWrapperStream;
2393 /* Packet wrapper callbacks */
2394 static SilcPacketCallbacks silc_packet_wrap_cbs =
2396 silc_packet_wrap_packet_receive, NULL, NULL
2399 /* Packet stream wrapper receive callback, non-blocking mode */
2402 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2403 SilcPacketStream stream,
2405 void *callback_context,
2406 void *stream_context)
2408 SilcPacketWrapperStream pws = callback_context;
2410 if (pws->closed || !pws->callback)
2413 silc_mutex_lock(pws->lock);
2414 silc_list_add(pws->in_queue, packet);
2415 silc_mutex_unlock(pws->lock);
2417 /* Call notifier callback */
2418 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2423 /* Task callback to notify more data is available for reading */
2425 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2427 SilcPacketWrapperStream pws = context;
2429 if (pws->closed || !pws->callback)
2432 /* Call notifier callback */
2433 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2436 /* Read SILC packet */
2438 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2441 SilcPacketWrapperStream pws = stream;
2443 SilcBool read_more = FALSE;
2449 if (pws->blocking) {
2450 /* Block until packet is received */
2451 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2456 /* Non-blocking mode */
2457 silc_mutex_lock(pws->lock);
2458 if (!silc_list_count(pws->in_queue)) {
2459 silc_mutex_unlock(pws->lock);
2463 silc_list_start(pws->in_queue);
2464 packet = silc_list_get(pws->in_queue);
2465 silc_list_del(pws->in_queue, packet);
2466 silc_mutex_unlock(pws->lock);
2469 /* Call decoder if set */
2470 if (pws->coder && !pws->read_more)
2471 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2472 pws->coder_context);
2474 len = silc_buffer_len(&packet->buffer);
2475 if (len > buf_len) {
2481 memcpy(buf, packet->buffer.data, len);
2483 if (read_more && !pws->blocking) {
2484 /* More data will be available (in blocking mode not supported). */
2485 silc_buffer_pull(&packet->buffer, len);
2486 silc_list_insert(pws->in_queue, NULL, packet);
2487 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2488 silc_packet_wrap_read_more, pws, 0, 0);
2489 pws->read_more = TRUE;
2493 pws->read_more = FALSE;
2494 silc_packet_free(packet);
2498 /* Write SILC packet */
2500 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2501 SilcUInt32 data_len)
2503 SilcPacketWrapperStream pws = stream;
2504 SilcBool ret = FALSE;
2506 /* Call decoder if set */
2508 silc_buffer_reset(pws->encbuf);
2509 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2510 pws->coder_context);
2513 /* Send the SILC packet */
2515 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2516 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2517 silc_buffer_len(pws->encbuf)),
2518 SILC_STR_DATA(data, data_len),
2522 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2531 SilcBool silc_packet_wrap_close(SilcStream stream)
2533 SilcPacketWrapperStream pws = stream;
2538 if (pws->blocking) {
2539 /* Close packet waiter */
2540 silc_packet_wait_uninit(pws->waiter, pws->stream);
2544 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2551 /* Destroy wrapper stream */
2553 void silc_packet_wrap_destroy(SilcStream stream)
2556 SilcPacketWrapperStream pws = stream;
2559 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2561 silc_stream_close(stream);
2562 silc_list_start(pws->in_queue);
2563 while ((packet = silc_list_get(pws->in_queue)))
2564 silc_packet_free(packet);
2566 silc_mutex_free(pws->lock);
2568 silc_buffer_free(pws->encbuf);
2569 silc_packet_stream_unref(pws->stream);
2574 /* Link stream to receive packets */
2576 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2577 SilcSchedule schedule,
2578 SilcStreamNotifier callback,
2581 SilcPacketWrapperStream pws = stream;
2583 if (pws->closed || pws->blocking)
2586 /* Link to receive packets */
2588 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2589 100000, pws->type, -1);
2591 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2593 pws->callback = callback;
2594 pws->context = context;
2599 /* Return schedule */
2601 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2606 /* Wraps packet stream into SilcStream. */
2608 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2609 SilcPacketType type,
2610 SilcPacketFlags flags,
2611 SilcBool blocking_mode,
2612 SilcPacketWrapCoder coder,
2615 SilcPacketWrapperStream pws;
2617 pws = silc_calloc(1, sizeof(*pws));
2621 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2623 pws->ops = &silc_packet_stream_ops;
2624 pws->stream = stream;
2627 pws->blocking = blocking_mode;
2629 pws->coder_context = context;
2631 /* Allocate small amount for encoder buffer. */
2633 pws->encbuf = silc_buffer_alloc(8);
2635 if (pws->blocking) {
2636 /* Blocking mode. Use packet waiter to do the thing. */
2637 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2643 /* Non-blocking mode */
2644 silc_mutex_alloc(&pws->lock);
2645 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2648 silc_packet_stream_ref(stream);
2650 return (SilcStream)pws;
2653 const SilcStreamOps silc_packet_stream_ops =
2655 silc_packet_wrap_read,
2656 silc_packet_wrap_write,
2657 silc_packet_wrap_close,
2658 silc_packet_wrap_destroy,
2659 silc_packet_wrap_notifier,
2660 silc_packet_wrap_get_schedule,