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)
828 SilcPacketEngine engine;
833 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
834 stream->destroyed = TRUE;
836 /* Close the underlaying stream */
837 if (!stream->udp && stream->stream)
838 silc_stream_close(stream->stream);
842 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
845 /* Delete from engine */
846 engine = stream->sc->engine;
847 silc_mutex_lock(engine->lock);
848 silc_list_del(engine->streams, stream);
850 /* Remove per scheduler context, if it is not used anymore */
852 stream->sc->stream_count--;
853 if (!stream->sc->stream_count)
854 silc_hash_table_del(engine->contexts, stream->sc->schedule);
856 silc_mutex_unlock(engine->lock);
858 /* Destroy the underlaying stream */
860 silc_stream_destroy(stream->stream);
862 /* Delete from UDP remote hash table */
864 engine = stream->sc->engine;
865 silc_snprintf(tuple, sizeof(tuple), "%d%s",
866 stream->remote_udp->remote_port,
867 stream->remote_udp->remote_ip);
868 silc_mutex_lock(engine->lock);
869 silc_hash_table_del(engine->udp_remote, tuple);
870 silc_mutex_unlock(engine->lock);
872 silc_free(stream->remote_udp->remote_ip);
873 silc_free(stream->remote_udp);
875 /* Unreference the underlaying packet stream */
876 silc_packet_stream_unref((SilcPacketStream)stream->stream);
879 /* Clear and free buffers */
880 silc_buffer_clear(&stream->outbuf);
881 silc_buffer_purge(&stream->outbuf);
883 if (stream->process) {
885 silc_dlist_start(stream->process);
886 while ((p = silc_dlist_get(stream->process))) {
889 silc_dlist_del(stream->process, p);
891 silc_dlist_uninit(stream->process);
894 /* Destroy ciphers and HMACs */
895 if (stream->send_key[0])
896 silc_cipher_free(stream->send_key[0]);
897 if (stream->receive_key[0])
898 silc_cipher_free(stream->receive_key[0]);
899 if (stream->send_hmac[0])
900 silc_hmac_free(stream->send_hmac[0]);
901 if (stream->receive_hmac[0])
902 silc_hmac_free(stream->receive_hmac[0]);
903 if (stream->send_key[1])
904 silc_cipher_free(stream->send_key[1]);
905 if (stream->receive_key[1])
906 silc_cipher_free(stream->receive_key[1]);
907 if (stream->send_hmac[1])
908 silc_hmac_free(stream->send_hmac[1]);
909 if (stream->receive_hmac[1])
910 silc_hmac_free(stream->receive_hmac[1]);
913 silc_free(stream->src_id);
914 silc_free(stream->dst_id);
916 silc_atomic_uninit8(&stream->refcnt);
917 silc_mutex_free(stream->lock);
921 /* Marks as router stream */
923 void silc_packet_stream_set_router(SilcPacketStream stream)
925 stream->is_router = TRUE;
928 /* Mark to include IV in ciphertext */
930 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
932 stream->iv_included = TRUE;
935 /* Links `callbacks' to `stream' for specified packet types */
937 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
938 SilcPacketCallbacks *callbacks,
939 void *callback_context,
940 int priority, va_list ap)
942 SilcPacketProcess p, e;
943 SilcInt32 packet_type;
946 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
950 if (!callbacks->packet_receive)
953 p = silc_calloc(1, sizeof(*p));
957 p->priority = priority;
958 p->callbacks = callbacks;
959 p->callback_context = callback_context;
961 silc_mutex_lock(stream->lock);
963 if (!stream->process) {
964 stream->process = silc_dlist_init();
965 if (!stream->process) {
966 silc_mutex_unlock(stream->lock);
971 /* According to priority set the procesor to correct position. First
972 entry has the highest priority */
973 silc_dlist_start(stream->process);
974 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
975 if (p->priority > e->priority) {
976 silc_dlist_insert(stream->process, p);
981 silc_dlist_add(stream->process, p);
983 /* Get packet types to process */
986 packet_type = va_arg(ap, SilcInt32);
988 if (packet_type == SILC_PACKET_ANY)
991 if (packet_type == -1)
994 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
996 silc_mutex_unlock(stream->lock);
1000 p->types[i - 1] = (SilcPacketType)packet_type;
1004 p->types[i - 1] = 0;
1006 silc_mutex_unlock(stream->lock);
1008 silc_packet_stream_ref(stream);
1013 /* Links `callbacks' to `stream' for specified packet types */
1015 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1016 SilcPacketCallbacks *callbacks,
1017 void *callback_context,
1023 va_start(ap, priority);
1024 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1031 /* Unlinks `callbacks' from `stream'. */
1033 void silc_packet_stream_unlink(SilcPacketStream stream,
1034 SilcPacketCallbacks *callbacks,
1035 void *callback_context)
1037 SilcPacketProcess p;
1039 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1040 callbacks, stream));
1042 silc_mutex_lock(stream->lock);
1044 silc_dlist_start(stream->process);
1045 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1046 if (p->callbacks == callbacks &&
1047 p->callback_context == callback_context) {
1048 silc_dlist_del(stream->process, p);
1049 silc_free(p->types);
1054 if (!silc_dlist_count(stream->process)) {
1055 silc_dlist_uninit(stream->process);
1056 stream->process = NULL;
1059 silc_mutex_unlock(stream->lock);
1061 silc_packet_stream_unref(stream);
1064 /* Returns TRUE if stream is UDP stream */
1066 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1068 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1071 /* Return packet sender IP and port for UDP packet stream */
1073 SilcBool silc_packet_get_sender(SilcPacket packet,
1074 const char **sender_ip,
1075 SilcUInt16 *sender_port)
1077 if (!packet->stream->remote_udp)
1080 *sender_ip = packet->stream->remote_udp->remote_ip;
1081 *sender_port = packet->stream->remote_udp->remote_port;
1086 /* Reference packet stream */
1088 void silc_packet_stream_ref(SilcPacketStream stream)
1090 silc_atomic_add_int8(&stream->refcnt, 1);
1091 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1092 silc_atomic_get_int8(&stream->refcnt) - 1,
1093 silc_atomic_get_int8(&stream->refcnt)));
1096 /* Unreference packet stream */
1098 void silc_packet_stream_unref(SilcPacketStream stream)
1100 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1101 silc_atomic_get_int8(&stream->refcnt),
1102 silc_atomic_get_int8(&stream->refcnt) - 1));
1103 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1105 silc_atomic_add_int8(&stream->refcnt, 1);
1106 silc_packet_stream_destroy(stream);
1111 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1113 return stream->sc->engine;
1116 /* Set application context for packet stream */
1118 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1120 silc_mutex_lock(stream->lock);
1121 stream->stream_context = stream_context;
1122 silc_mutex_unlock(stream->lock);
1125 /* Return application context from packet stream */
1127 void *silc_packet_get_context(SilcPacketStream stream)
1130 silc_mutex_lock(stream->lock);
1131 context = stream->stream_context;
1132 silc_mutex_unlock(stream->lock);
1136 /* Change underlaying stream */
1138 void silc_packet_stream_set_stream(SilcPacketStream ps,
1142 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1143 ps->stream = stream;
1144 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1148 /* Return underlaying stream */
1150 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1152 return stream->stream;
1157 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1158 SilcCipher receive_key, SilcHmac send_hmac,
1159 SilcHmac receive_hmac, SilcBool rekey)
1161 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1163 /* If doing rekey, send REKEY_DONE packet */
1165 /* This will take stream lock. */
1166 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1167 stream->src_id_type, stream->src_id,
1168 stream->src_id_len, stream->dst_id_type,
1169 stream->dst_id, stream->dst_id_len,
1170 NULL, 0, stream->send_key[0],
1171 stream->send_hmac[0]))
1174 /* Write the packet to the stream */
1175 if (!silc_packet_stream_write(stream, TRUE))
1178 silc_mutex_lock(stream->lock);
1181 /* In case IV Included is set, save the old keys */
1182 if (stream->iv_included) {
1183 if (stream->send_key[1] && send_key) {
1184 silc_cipher_free(stream->send_key[1]);
1185 stream->send_key[1] = stream->send_key[0];
1187 if (stream->receive_key[1] && receive_key) {
1188 silc_cipher_free(stream->receive_key[1]);
1189 stream->receive_key[1] = stream->receive_key[0];
1191 if (stream->send_hmac[1] && send_hmac) {
1192 silc_hmac_free(stream->send_hmac[1]);
1193 stream->send_hmac[1] = stream->send_hmac[0];
1195 if (stream->receive_hmac[1] && receive_hmac) {
1196 silc_hmac_free(stream->receive_hmac[1]);
1197 stream->receive_hmac[1] = stream->receive_hmac[0];
1200 if (stream->send_key[0] && send_key)
1201 silc_cipher_free(stream->send_key[0]);
1202 if (stream->receive_key[0] && receive_key)
1203 silc_cipher_free(stream->receive_key[0]);
1204 if (stream->send_hmac[0] && send_hmac)
1205 silc_hmac_free(stream->send_hmac[0]);
1206 if (stream->receive_hmac[0] && receive_hmac)
1207 silc_hmac_free(stream->receive_hmac[0]);
1212 stream->send_key[0] = send_key;
1214 stream->receive_key[0] = receive_key;
1216 stream->send_hmac[0] = send_hmac;
1218 stream->receive_hmac[0] = receive_hmac;
1220 silc_mutex_unlock(stream->lock);
1224 /* Return current ciphers from packet stream */
1226 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1227 SilcCipher *send_key,
1228 SilcCipher *receive_key,
1229 SilcHmac *send_hmac,
1230 SilcHmac *receive_hmac)
1232 if (!stream->send_key[0] && !stream->receive_key[0] &&
1233 !stream->send_hmac[0] && !stream->receive_hmac[0])
1236 silc_mutex_lock(stream->lock);
1239 *send_key = stream->send_key[0];
1241 *receive_key = stream->receive_key[0];
1243 *send_hmac = stream->send_hmac[0];
1245 *receive_hmac = stream->receive_hmac[0];
1247 silc_mutex_unlock(stream->lock);
1252 /* Set SILC IDs to packet stream */
1254 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1255 SilcIdType src_id_type, const void *src_id,
1256 SilcIdType dst_id_type, const void *dst_id)
1259 unsigned char tmp[32];
1261 if (!src_id && !dst_id)
1264 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1266 silc_mutex_lock(stream->lock);
1269 silc_free(stream->src_id);
1270 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1271 silc_mutex_unlock(stream->lock);
1274 stream->src_id = silc_memdup(tmp, len);
1275 if (!stream->src_id) {
1276 silc_mutex_unlock(stream->lock);
1279 stream->src_id_type = src_id_type;
1280 stream->src_id_len = len;
1284 silc_free(stream->dst_id);
1285 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1286 silc_mutex_unlock(stream->lock);
1289 stream->dst_id = silc_memdup(tmp, len);
1290 if (!stream->dst_id) {
1291 silc_mutex_unlock(stream->lock);
1294 stream->dst_id_type = dst_id_type;
1295 stream->dst_id_len = len;
1298 silc_mutex_unlock(stream->lock);
1303 /* Adds Security ID (SID) */
1305 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1307 if (!stream->iv_included)
1310 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1318 void silc_packet_free(SilcPacket packet)
1320 SilcPacketStream stream = packet->stream;
1322 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1324 /* Check for double free */
1325 SILC_ASSERT(packet->stream != NULL);
1327 packet->stream = NULL;
1328 packet->src_id = packet->dst_id = NULL;
1329 silc_buffer_reset(&packet->buffer);
1331 silc_mutex_lock(stream->sc->engine->lock);
1333 /* Put the packet back to freelist */
1334 silc_list_add(stream->sc->engine->packet_pool, packet);
1335 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1336 silc_list_start(stream->sc->engine->packet_pool);
1338 silc_mutex_unlock(stream->sc->engine->lock);
1341 /****************************** Packet Sending ******************************/
1343 /* Prepare outgoing data buffer for packet sending. Returns the
1344 pointer to that buffer into the `packet'. */
1346 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1351 unsigned char *oldptr;
1352 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1356 /* Allocate more space if needed */
1357 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1358 if (!silc_buffer_realloc(&stream->outbuf,
1359 silc_buffer_truelen(&stream->outbuf) + totlen))
1363 /* Pull data area for the new packet, and return pointer to the start of
1364 the data area and save the pointer in to the `packet'. MAC is pulled
1365 later after it's computed. */
1366 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1367 silc_buffer_set(packet, oldptr, totlen);
1368 silc_buffer_push_tail(packet, mac_len);
1373 /* Increments counter when encrypting in counter mode. */
1375 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1377 unsigned char *ret_iv)
1379 unsigned char *iv = silc_cipher_get_iv(cipher);
1380 SilcUInt32 pc1, pc2;
1382 /* Increment 64-bit packet counter */
1383 SILC_GET32_MSB(pc1, iv + 4);
1384 SILC_GET32_MSB(pc2, iv + 8);
1387 SILC_PUT32_MSB(pc1, iv + 4);
1388 SILC_PUT32_MSB(pc2, iv + 8);
1390 /* Reset block counter */
1391 memset(iv + 12, 0, 4);
1393 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1394 if (stream->iv_included) {
1396 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1397 ret_iv[1] = ret_iv[0] + iv[4];
1398 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1399 ret_iv[3] = ret_iv[0] + ret_iv[2];
1400 SILC_PUT32_MSB(pc2, ret_iv + 4);
1401 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1403 /* Set new nonce to counter block */
1404 memcpy(iv + 4, ret_iv, 4);
1407 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1410 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1411 the packet. The silc_packet_stream_write needs to be called to send it
1412 after this returns TRUE. */
1414 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1415 SilcPacketType type,
1416 SilcPacketFlags flags,
1417 SilcIdType src_id_type,
1418 unsigned char *src_id,
1419 SilcUInt32 src_id_len,
1420 SilcIdType dst_id_type,
1421 unsigned char *dst_id,
1422 SilcUInt32 dst_id_len,
1423 const unsigned char *data,
1424 SilcUInt32 data_len,
1428 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1429 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1430 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1432 SilcBufferStruct packet;
1434 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1435 "data len %d", silc_get_packet_name(type), stream->send_psn,
1436 flags, src_id_type, dst_id_type, data_len));
1438 /* Get the true length of the packet. This is saved as payload length
1439 into the packet header. This does not include the length of the
1441 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1442 src_id_len + dst_id_len));
1443 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1444 src_id_len + dst_id_len);
1446 /* If using CTR mode, increment the counter */
1447 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1449 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1451 /* If IV is included, the SID, IV and sequence number is added to packet */
1452 if (stream->iv_included && cipher) {
1453 psnlen = sizeof(psn);
1455 iv[0] = stream->sid;
1458 /* If IV is included, the SID, IV and sequence number is added to packet */
1459 if (stream->iv_included && cipher) {
1460 psnlen = sizeof(psn);
1461 ivlen = block_len + 1;
1462 iv[0] = stream->sid;
1463 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1467 /* We automatically figure out the packet structure from the packet
1468 type and flags, and calculate correct length. Private messages with
1469 private keys and channel messages are special packets as their
1470 payload is encrypted already. */
1471 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1472 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1473 type == SILC_PACKET_CHANNEL_MESSAGE) {
1475 /* Padding is calculated from header + IDs */
1477 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1478 psnlen), block_len, padlen);
1480 /* Length to encrypt, header + IDs + padding. */
1481 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1485 /* Padding is calculated from true length of the packet */
1486 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1487 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1489 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1491 enclen += padlen + psnlen;
1494 /* Remove implementation specific flags */
1495 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1497 /* Get random padding */
1498 for (i = 0; i < padlen; i++) tmppad[i] =
1499 silc_rng_get_byte_fast(stream->sc->engine->rng);
1501 silc_mutex_lock(stream->lock);
1503 /* Get packet pointer from the outgoing buffer */
1504 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1505 + psnlen, hmac, &packet))) {
1506 silc_mutex_unlock(stream->lock);
1510 SILC_PUT32_MSB(stream->send_psn, psn);
1512 /* Create the packet. This creates the SILC header, adds padding, and
1513 the actual packet data. */
1514 i = silc_buffer_format(&packet,
1515 SILC_STR_DATA(iv, ivlen),
1516 SILC_STR_DATA(psn, psnlen),
1517 SILC_STR_UI_SHORT(truelen),
1518 SILC_STR_UI_CHAR(flags),
1519 SILC_STR_UI_CHAR(type),
1520 SILC_STR_UI_CHAR(padlen),
1521 SILC_STR_UI_CHAR(0),
1522 SILC_STR_UI_CHAR(src_id_len),
1523 SILC_STR_UI_CHAR(dst_id_len),
1524 SILC_STR_UI_CHAR(src_id_type),
1525 SILC_STR_DATA(src_id, src_id_len),
1526 SILC_STR_UI_CHAR(dst_id_type),
1527 SILC_STR_DATA(dst_id, dst_id_len),
1528 SILC_STR_DATA(tmppad, padlen),
1529 SILC_STR_DATA(data, data_len),
1531 if (silc_unlikely(i < 0)) {
1532 silc_mutex_unlock(stream->lock);
1536 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1537 silc_buffer_data(&packet), silc_buffer_len(&packet));
1539 /* Encrypt the packet */
1540 if (silc_likely(cipher)) {
1541 SILC_LOG_DEBUG(("Encrypting packet"));
1542 silc_cipher_set_iv(cipher, NULL);
1543 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1544 packet.data + ivlen, enclen,
1546 SILC_LOG_ERROR(("Packet encryption failed"));
1547 silc_mutex_unlock(stream->lock);
1553 if (silc_likely(hmac)) {
1556 /* MAC is computed from the entire encrypted packet data, and put
1557 to the end of the packet. */
1558 silc_hmac_init(hmac);
1559 silc_hmac_update(hmac, psn, sizeof(psn));
1560 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1561 silc_hmac_final(hmac, packet.tail, &mac_len);
1562 silc_buffer_pull_tail(&packet, mac_len);
1569 /* Sends a packet */
1571 SilcBool silc_packet_send(SilcPacketStream stream,
1572 SilcPacketType type, SilcPacketFlags flags,
1573 const unsigned char *data, SilcUInt32 data_len)
1577 ret = silc_packet_send_raw(stream, type, flags,
1578 stream->src_id_type,
1581 stream->dst_id_type,
1585 stream->send_key[0],
1586 stream->send_hmac[0]);
1588 /* Write the packet to the stream */
1589 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1592 /* Sends a packet, extended routine */
1594 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1595 SilcPacketType type, SilcPacketFlags flags,
1596 SilcIdType src_id_type, void *src_id,
1597 SilcIdType dst_id_type, void *dst_id,
1598 const unsigned char *data, SilcUInt32 data_len,
1599 SilcCipher cipher, SilcHmac hmac)
1601 unsigned char src_id_data[32], dst_id_data[32];
1602 SilcUInt32 src_id_len, dst_id_len;
1606 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1607 sizeof(src_id_data), &src_id_len))
1610 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1611 sizeof(dst_id_data), &dst_id_len))
1614 ret = silc_packet_send_raw(stream, type, flags,
1615 src_id ? src_id_type : stream->src_id_type,
1616 src_id ? src_id_data : stream->src_id,
1617 src_id ? src_id_len : stream->src_id_len,
1618 dst_id ? dst_id_type : stream->dst_id_type,
1619 dst_id ? dst_id_data : stream->dst_id,
1620 dst_id ? dst_id_len : stream->dst_id_len,
1622 cipher ? cipher : stream->send_key[0],
1623 hmac ? hmac : stream->send_hmac[0]);
1625 /* Write the packet to the stream */
1626 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1629 /* Sends packet after formatting the arguments to buffer */
1631 SilcBool silc_packet_send_va(SilcPacketStream stream,
1632 SilcPacketType type, SilcPacketFlags flags, ...)
1634 SilcBufferStruct buf;
1638 va_start(va, flags);
1640 memset(&buf, 0, sizeof(buf));
1641 if (silc_buffer_format_vp(&buf, va) < 0) {
1646 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1647 silc_buffer_len(&buf));
1649 silc_buffer_purge(&buf);
1655 /* Sends packet after formatting the arguments to buffer, extended routine */
1657 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1658 SilcPacketType type, SilcPacketFlags flags,
1659 SilcIdType src_id_type, void *src_id,
1660 SilcIdType dst_id_type, void *dst_id,
1661 SilcCipher cipher, SilcHmac hmac, ...)
1663 SilcBufferStruct buf;
1669 memset(&buf, 0, sizeof(buf));
1670 if (silc_buffer_format_vp(&buf, va) < 0) {
1675 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1676 dst_id_type, dst_id, silc_buffer_data(&buf),
1677 silc_buffer_len(&buf), cipher, hmac);
1679 silc_buffer_purge(&buf);
1685 /***************************** Packet Receiving *****************************/
1687 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1689 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1690 const unsigned char *data,
1691 SilcUInt32 data_len,
1692 const unsigned char *packet_mac,
1693 const unsigned char *packet_seq,
1694 SilcUInt32 sequence)
1697 if (silc_likely(hmac)) {
1698 unsigned char mac[32], psn[4];
1701 SILC_LOG_DEBUG(("Verifying MAC"));
1703 /* Compute HMAC of packet */
1704 silc_hmac_init(hmac);
1707 SILC_PUT32_MSB(sequence, psn);
1708 silc_hmac_update(hmac, psn, 4);
1710 silc_hmac_update(hmac, packet_seq, 4);
1712 silc_hmac_update(hmac, data, data_len);
1713 silc_hmac_final(hmac, mac, &mac_len);
1715 /* Compare the MAC's */
1716 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1717 SILC_LOG_DEBUG(("MAC failed"));
1721 SILC_LOG_DEBUG(("MAC is Ok"));
1727 /* Increments/sets counter when decrypting in counter mode. */
1729 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1731 unsigned char *packet_iv)
1733 SilcUInt32 pc1, pc2;
1735 /* If IV Included flag, set the IV from packet to block counter. */
1736 if (stream->iv_included) {
1737 memcpy(iv + 4, packet_iv, 8);
1739 /* Increment 64-bit packet counter. */
1740 SILC_GET32_MSB(pc1, iv + 4);
1741 SILC_GET32_MSB(pc2, iv + 8);
1744 SILC_PUT32_MSB(pc1, iv + 4);
1745 SILC_PUT32_MSB(pc2, iv + 8);
1748 /* Reset block counter */
1749 memset(iv + 12, 0, 4);
1751 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1754 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1755 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1757 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1758 SilcUInt32 sequence, SilcBuffer buffer,
1761 if (normal == TRUE) {
1762 if (silc_likely(cipher)) {
1763 /* Decrypt rest of the packet */
1764 SILC_LOG_DEBUG(("Decrypting the packet"));
1765 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1767 silc_buffer_len(buffer), NULL)))
1773 /* Decrypt rest of the header plus padding */
1774 if (silc_likely(cipher)) {
1776 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1778 SILC_LOG_DEBUG(("Decrypting the header"));
1780 /* Padding length + src id len + dst id len + header length - 16
1781 bytes already decrypted, gives the rest of the encrypted packet */
1782 silc_buffer_push(buffer, block_len);
1783 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1784 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1786 silc_buffer_pull(buffer, block_len);
1788 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1789 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1793 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1794 buffer->data, len, NULL)))
1802 /* Parses the packet. This is called when a whole packet is ready to be
1803 parsed. The buffer sent must be already decrypted before calling this
1806 static inline SilcBool silc_packet_parse(SilcPacket packet)
1808 SilcBuffer buffer = &packet->buffer;
1809 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1810 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1813 SILC_LOG_DEBUG(("Parsing incoming packet"));
1815 /* Parse the buffer. This parses the SILC header of the packet. */
1816 ret = silc_buffer_unformat(buffer,
1819 SILC_STR_UI_CHAR(&src_id_len),
1820 SILC_STR_UI_CHAR(&dst_id_len),
1821 SILC_STR_UI_CHAR(&src_id_type),
1823 if (silc_unlikely(ret == -1)) {
1824 if (!packet->stream->udp &&
1825 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1826 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1830 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1831 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1832 if (!packet->stream->udp &&
1833 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1834 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1835 packet->src_id_len, packet->dst_id_len));
1839 ret = silc_buffer_unformat(buffer,
1841 SILC_STR_DATA(&packet->src_id, src_id_len),
1842 SILC_STR_UI_CHAR(&dst_id_type),
1843 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1844 SILC_STR_OFFSET(padlen),
1846 if (silc_unlikely(ret == -1)) {
1847 if (!packet->stream->udp &&
1848 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1849 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1853 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1854 dst_id_type > SILC_ID_CHANNEL)) {
1855 if (!packet->stream->udp &&
1856 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1857 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1858 src_id_type, dst_id_type));
1862 packet->src_id_len = src_id_len;
1863 packet->dst_id_len = dst_id_len;
1864 packet->src_id_type = src_id_type;
1865 packet->dst_id_type = dst_id_type;
1867 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1868 silc_buffer_len(buffer)), buffer->head,
1869 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1871 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1872 silc_get_packet_name(packet->type)));
1877 /* Dispatch packet to application. Called with stream->lock locked.
1878 Returns FALSE if the stream was destroyed while dispatching a packet. */
1880 static SilcBool silc_packet_dispatch(SilcPacket packet)
1882 SilcPacketStream stream = packet->stream;
1883 SilcPacketProcess p;
1884 SilcBool default_sent = FALSE;
1887 /* Dispatch packet to all packet processors that want it */
1889 if (silc_likely(!stream->process)) {
1890 /* Send to default processor as no others exist */
1891 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1892 silc_mutex_unlock(stream->lock);
1893 if (silc_unlikely(!stream->sc->engine->callbacks->
1894 packet_receive(stream->sc->engine, stream, packet,
1895 stream->sc->engine->callback_context,
1896 stream->stream_context)))
1897 silc_packet_free(packet);
1898 silc_mutex_lock(stream->lock);
1899 return stream->destroyed == FALSE;
1902 silc_dlist_start(stream->process);
1903 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1905 /* If priority is 0 or less, we send to default processor first
1906 because default processor has 0 priority */
1907 if (!default_sent && p->priority <= 0) {
1908 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1909 default_sent = TRUE;
1910 silc_mutex_unlock(stream->lock);
1911 if (stream->sc->engine->callbacks->
1912 packet_receive(stream->sc->engine, stream, packet,
1913 stream->sc->engine->callback_context,
1914 stream->stream_context)) {
1915 silc_mutex_lock(stream->lock);
1916 return stream->destroyed == FALSE;
1918 silc_mutex_lock(stream->lock);
1921 /* Send to processor */
1923 /* Send all packet types */
1924 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1925 silc_mutex_unlock(stream->lock);
1926 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1927 p->callback_context,
1928 stream->stream_context)) {
1929 silc_mutex_lock(stream->lock);
1930 return stream->destroyed == FALSE;
1932 silc_mutex_lock(stream->lock);
1934 /* Send specific types */
1935 for (pt = p->types; *pt; pt++) {
1936 if (*pt != packet->type)
1938 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1939 silc_mutex_unlock(stream->lock);
1940 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1941 p->callback_context,
1942 stream->stream_context)) {
1943 silc_mutex_lock(stream->lock);
1944 return stream->destroyed == FALSE;
1946 silc_mutex_lock(stream->lock);
1952 if (!default_sent) {
1953 /* Send to default processor as it has not been sent yet */
1954 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1955 silc_mutex_unlock(stream->lock);
1956 if (stream->sc->engine->callbacks->
1957 packet_receive(stream->sc->engine, stream, packet,
1958 stream->sc->engine->callback_context,
1959 stream->stream_context)) {
1960 silc_mutex_lock(stream->lock);
1961 return stream->destroyed == FALSE;
1963 silc_mutex_lock(stream->lock);
1966 /* If we got here, no one wanted the packet, so drop it */
1967 silc_packet_free(packet);
1968 return stream->destroyed == FALSE;
1971 /* Process incoming data and parse packets. Called with stream->lock
1974 static void silc_packet_read_process(SilcPacketStream stream)
1981 SilcUInt16 packetlen;
1982 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1983 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1984 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1988 /* Get inbuf. If there is already some data for this stream in the buffer
1989 we already have it. Otherwise get the current one from list, it will
1990 include the data. */
1991 inbuf = stream->inbuf;
1993 silc_dlist_start(stream->sc->inbufs);
1994 inbuf = silc_dlist_get(stream->sc->inbufs);
1997 /* Parse the packets from the data */
1998 while (silc_buffer_len(inbuf) > 0) {
2000 cipher = stream->receive_key[0];
2001 hmac = stream->receive_hmac[0];
2004 if (silc_unlikely(silc_buffer_len(inbuf) <
2005 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2006 SILC_PACKET_MIN_HEADER_LEN))) {
2007 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2008 silc_dlist_del(stream->sc->inbufs, inbuf);
2009 stream->inbuf = inbuf;
2013 if (silc_likely(hmac))
2014 mac_len = silc_hmac_len(hmac);
2018 /* Decrypt first block of the packet to get the length field out */
2019 if (silc_likely(cipher)) {
2020 block_len = silc_cipher_get_block_len(cipher);
2022 if (stream->iv_included) {
2023 /* SID, IV and sequence number is included in the ciphertext */
2024 sid = (SilcUInt8)inbuf->data[0];
2026 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2027 /* Set the CTR mode IV from packet to counter block */
2028 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2029 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2032 /* Get IV from packet */
2033 memcpy(iv, inbuf->data + 1, block_len);
2034 ivlen = block_len + 1;
2038 /* Check SID, and get correct decryption key */
2039 if (sid != stream->sid) {
2040 /* If SID is recent get the previous key and use it */
2041 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2042 stream->receive_key[1] && !stream->receive_hmac[1]) {
2043 cipher = stream->receive_key[1];
2044 hmac = stream->receive_hmac[1];
2046 /* The SID is unknown, drop rest of the data in buffer */
2047 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2049 silc_mutex_unlock(stream->lock);
2050 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2051 silc_mutex_lock(stream->lock);
2056 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2058 /* If using CTR mode, increment the counter */
2059 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2060 silc_packet_receive_ctr_increment(stream, iv, NULL);
2063 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2064 silc_cipher_set_iv(cipher, NULL);
2065 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2068 if (stream->iv_included) {
2069 /* Take sequence number from packet */
2070 packet_seq = header;
2074 /* Unencrypted packet */
2075 block_len = SILC_PACKET_MIN_HEADER_LEN;
2076 header = inbuf->data;
2079 /* Get packet length and full packet length with padding */
2080 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2083 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2084 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2085 SILC_LOG_ERROR(("Received too short packet"));
2086 silc_mutex_unlock(stream->lock);
2087 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2088 silc_mutex_lock(stream->lock);
2089 memset(tmp, 0, sizeof(tmp));
2093 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2094 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2096 paddedlen + mac_len - silc_buffer_len(inbuf)));
2097 memset(tmp, 0, sizeof(tmp));
2098 silc_dlist_del(stream->sc->inbufs, inbuf);
2099 stream->inbuf = inbuf;
2103 /* Check MAC of the packet */
2104 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2106 inbuf->data + ivlen +
2107 paddedlen, packet_seq,
2108 stream->receive_psn))) {
2109 silc_mutex_unlock(stream->lock);
2110 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2111 silc_mutex_lock(stream->lock);
2112 memset(tmp, 0, sizeof(tmp));
2117 packet = silc_packet_alloc(stream->sc->engine);
2118 if (silc_unlikely(!packet)) {
2119 silc_mutex_unlock(stream->lock);
2120 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2121 silc_mutex_lock(stream->lock);
2122 memset(tmp, 0, sizeof(tmp));
2125 packet->stream = stream;
2127 /* Allocate more space to packet buffer, if needed */
2128 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2129 if (!silc_buffer_realloc(&packet->buffer,
2130 silc_buffer_truelen(&packet->buffer) +
2132 silc_buffer_truelen(&packet->buffer)))) {
2133 silc_mutex_unlock(stream->lock);
2134 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2135 silc_mutex_lock(stream->lock);
2136 silc_packet_free(packet);
2137 memset(tmp, 0, sizeof(tmp));
2142 /* Parse packet header */
2143 packet->flags = (SilcPacketFlags)header[2];
2144 packet->type = (SilcPacketType)header[3];
2146 if (stream->sc->engine->local_is_router) {
2147 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2148 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2150 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2151 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2152 stream->is_router == TRUE))
2155 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2156 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2158 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2162 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2163 stream->receive_psn, paddedlen + ivlen + mac_len),
2164 inbuf->data, paddedlen + ivlen + mac_len);
2166 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2167 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2168 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2169 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2170 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2171 psnlen + (block_len - psnlen)),
2172 paddedlen - ivlen - psnlen - (block_len - psnlen));
2173 if (silc_likely(cipher)) {
2174 silc_cipher_set_iv(cipher, iv);
2175 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2176 &packet->buffer, normal);
2177 if (silc_unlikely(ret < 0)) {
2178 silc_mutex_unlock(stream->lock);
2179 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2180 silc_mutex_lock(stream->lock);
2181 silc_packet_free(packet);
2182 memset(tmp, 0, sizeof(tmp));
2186 stream->receive_psn++;
2188 silc_buffer_push(&packet->buffer, block_len);
2190 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2191 silc_buffer_pull(inbuf, paddedlen + mac_len);
2193 /* Parse the packet */
2194 if (silc_unlikely(!silc_packet_parse(packet))) {
2195 silc_mutex_unlock(stream->lock);
2196 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2197 silc_mutex_lock(stream->lock);
2198 silc_packet_free(packet);
2199 memset(tmp, 0, sizeof(tmp));
2203 /* Dispatch the packet to application */
2204 if (!silc_packet_dispatch(packet))
2209 /* Add inbuf back to free list, if we owned it. */
2210 if (stream->inbuf) {
2211 silc_dlist_add(stream->sc->inbufs, inbuf);
2212 stream->inbuf = NULL;
2215 silc_buffer_reset(inbuf);
2218 /****************************** Packet Waiting ******************************/
2220 /* Packet wait receive callback */
2222 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2223 SilcPacketStream stream,
2225 void *callback_context,
2226 void *stream_context);
2228 /* Packet waiting callbacks */
2229 static SilcPacketCallbacks silc_packet_wait_cbs =
2231 silc_packet_wait_packet_receive, NULL, NULL
2234 /* Packet waiting context */
2236 SilcMutex wait_lock;
2238 SilcList packet_queue;
2239 unsigned int stopped : 1;
2242 /* Packet wait receive callback */
2245 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2246 SilcPacketStream stream,
2248 void *callback_context,
2249 void *stream_context)
2251 SilcPacketWait pw = callback_context;
2253 /* Signal the waiting thread for a new packet */
2254 silc_mutex_lock(pw->wait_lock);
2256 if (silc_unlikely(pw->stopped)) {
2257 silc_mutex_unlock(pw->wait_lock);
2261 silc_list_add(pw->packet_queue, packet);
2262 silc_cond_broadcast(pw->wait_cond);
2264 silc_mutex_unlock(pw->wait_lock);
2269 /* Initialize packet waiting */
2271 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2277 pw = silc_calloc(1, sizeof(*pw));
2281 /* Allocate mutex and conditional variable */
2282 if (!silc_mutex_alloc(&pw->wait_lock)) {
2286 if (!silc_cond_alloc(&pw->wait_cond)) {
2287 silc_mutex_free(pw->wait_lock);
2292 /* Link to the packet stream for the requested packet types */
2293 va_start(ap, stream);
2294 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2298 silc_cond_free(pw->wait_cond);
2299 silc_mutex_free(pw->wait_lock);
2304 /* Initialize packet queue */
2305 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2310 /* Uninitialize packet waiting */
2312 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2314 SilcPacketWait pw = waiter;
2317 /* Signal any threads to stop waiting */
2318 silc_mutex_lock(pw->wait_lock);
2320 silc_cond_broadcast(pw->wait_cond);
2321 silc_mutex_unlock(pw->wait_lock);
2322 silc_thread_yield();
2324 /* Re-acquire lock and free resources */
2325 silc_mutex_lock(pw->wait_lock);
2326 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2328 /* Free any remaining packets */
2329 silc_list_start(pw->packet_queue);
2330 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2331 silc_packet_free(packet);
2333 silc_mutex_unlock(pw->wait_lock);
2334 silc_cond_free(pw->wait_cond);
2335 silc_mutex_free(pw->wait_lock);
2339 /* Blocks thread until a packet has been received. */
2341 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2343 SilcPacketWait pw = waiter;
2344 SilcBool ret = FALSE;
2346 silc_mutex_lock(pw->wait_lock);
2348 /* Wait here until packet has arrived */
2349 while (silc_list_count(pw->packet_queue) == 0) {
2350 if (silc_unlikely(pw->stopped)) {
2351 silc_mutex_unlock(pw->wait_lock);
2354 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2358 silc_list_start(pw->packet_queue);
2359 *return_packet = silc_list_get(pw->packet_queue);
2360 silc_list_del(pw->packet_queue, *return_packet);
2362 silc_mutex_unlock(pw->wait_lock);
2364 return ret == TRUE ? 1 : 0;
2367 /************************** Packet Stream Wrapper ***************************/
2369 /* Packet stream wrapper receive callback */
2371 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2372 SilcPacketStream stream,
2374 void *callback_context,
2375 void *stream_context);
2377 const SilcStreamOps silc_packet_stream_ops;
2379 /* Packet stream wrapper context */
2381 const SilcStreamOps *ops;
2382 SilcPacketStream stream;
2384 void *waiter; /* Waiter context in blocking mode */
2385 SilcPacketWrapCoder coder;
2386 void *coder_context;
2388 SilcStreamNotifier callback;
2391 SilcPacketType type;
2392 SilcPacketFlags flags;
2393 unsigned int closed : 1;
2394 unsigned int blocking : 1;
2395 unsigned int read_more : 1;
2396 } *SilcPacketWrapperStream;
2398 /* Packet wrapper callbacks */
2399 static SilcPacketCallbacks silc_packet_wrap_cbs =
2401 silc_packet_wrap_packet_receive, NULL, NULL
2404 /* Packet stream wrapper receive callback, non-blocking mode */
2407 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2408 SilcPacketStream stream,
2410 void *callback_context,
2411 void *stream_context)
2413 SilcPacketWrapperStream pws = callback_context;
2415 if (pws->closed || !pws->callback)
2418 silc_mutex_lock(pws->lock);
2419 silc_list_add(pws->in_queue, packet);
2420 silc_mutex_unlock(pws->lock);
2422 /* Call notifier callback */
2423 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2428 /* Task callback to notify more data is available for reading */
2430 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2432 SilcPacketWrapperStream pws = context;
2434 if (pws->closed || !pws->callback)
2437 /* Call notifier callback */
2438 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2441 /* Read SILC packet */
2443 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2446 SilcPacketWrapperStream pws = stream;
2448 SilcBool read_more = FALSE;
2454 if (pws->blocking) {
2455 /* Block until packet is received */
2456 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2461 /* Non-blocking mode */
2462 silc_mutex_lock(pws->lock);
2463 if (!silc_list_count(pws->in_queue)) {
2464 silc_mutex_unlock(pws->lock);
2468 silc_list_start(pws->in_queue);
2469 packet = silc_list_get(pws->in_queue);
2470 silc_list_del(pws->in_queue, packet);
2471 silc_mutex_unlock(pws->lock);
2474 /* Call decoder if set */
2475 if (pws->coder && !pws->read_more)
2476 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2477 pws->coder_context);
2479 len = silc_buffer_len(&packet->buffer);
2480 if (len > buf_len) {
2486 memcpy(buf, packet->buffer.data, len);
2488 if (read_more && !pws->blocking) {
2489 /* More data will be available (in blocking mode not supported). */
2490 silc_buffer_pull(&packet->buffer, len);
2491 silc_list_insert(pws->in_queue, NULL, packet);
2492 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2493 silc_packet_wrap_read_more, pws, 0, 0);
2494 pws->read_more = TRUE;
2498 pws->read_more = FALSE;
2499 silc_packet_free(packet);
2503 /* Write SILC packet */
2505 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2506 SilcUInt32 data_len)
2508 SilcPacketWrapperStream pws = stream;
2509 SilcBool ret = FALSE;
2511 /* Call encoder if set */
2513 silc_buffer_reset(pws->encbuf);
2514 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2515 pws->coder_context);
2518 /* Send the SILC packet */
2520 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2521 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2522 silc_buffer_len(pws->encbuf)),
2523 SILC_STR_DATA(data, data_len),
2527 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2536 SilcBool silc_packet_wrap_close(SilcStream stream)
2538 SilcPacketWrapperStream pws = stream;
2543 if (pws->blocking) {
2544 /* Close packet waiter */
2545 silc_packet_wait_uninit(pws->waiter, pws->stream);
2549 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2556 /* Destroy wrapper stream */
2558 void silc_packet_wrap_destroy(SilcStream stream)
2561 SilcPacketWrapperStream pws = stream;
2564 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2566 silc_stream_close(stream);
2567 silc_list_start(pws->in_queue);
2568 while ((packet = silc_list_get(pws->in_queue)))
2569 silc_packet_free(packet);
2571 silc_mutex_free(pws->lock);
2573 silc_buffer_free(pws->encbuf);
2574 silc_packet_stream_unref(pws->stream);
2579 /* Link stream to receive packets */
2581 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2582 SilcSchedule schedule,
2583 SilcStreamNotifier callback,
2586 SilcPacketWrapperStream pws = stream;
2588 if (pws->closed || pws->blocking)
2591 /* Link to receive packets */
2593 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2594 100000, pws->type, -1);
2596 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2598 pws->callback = callback;
2599 pws->context = context;
2604 /* Return schedule */
2606 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2611 /* Wraps packet stream into SilcStream. */
2613 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2614 SilcPacketType type,
2615 SilcPacketFlags flags,
2616 SilcBool blocking_mode,
2617 SilcPacketWrapCoder coder,
2620 SilcPacketWrapperStream pws;
2622 pws = silc_calloc(1, sizeof(*pws));
2626 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2628 pws->ops = &silc_packet_stream_ops;
2629 pws->stream = stream;
2632 pws->blocking = blocking_mode;
2634 pws->coder_context = context;
2636 /* Allocate small amount for encoder buffer. */
2638 pws->encbuf = silc_buffer_alloc(8);
2640 if (pws->blocking) {
2641 /* Blocking mode. Use packet waiter to do the thing. */
2642 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2648 /* Non-blocking mode */
2649 silc_mutex_alloc(&pws->lock);
2650 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2653 silc_packet_stream_ref(stream);
2655 return (SilcStream)pws;
2658 const SilcStreamOps silc_packet_stream_ops =
2660 silc_packet_wrap_read,
2661 silc_packet_wrap_write,
2662 silc_packet_wrap_close,
2663 silc_packet_wrap_destroy,
2664 silc_packet_wrap_notifier,
2665 silc_packet_wrap_get_schedule,