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 /* Return list of packet streams in the engine */
628 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
633 list = silc_dlist_init();
637 silc_mutex_lock(engine->lock);
638 silc_list_start(engine->streams);
639 while ((ps = silc_list_get(engine->streams)))
640 silc_dlist_add(list, ps);
641 silc_mutex_unlock(engine->lock);
646 /* Create new packet stream */
648 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
649 SilcSchedule schedule,
656 SILC_LOG_DEBUG(("Creating new packet stream"));
658 if (!engine || !stream)
661 ps = silc_calloc(1, sizeof(*ps));
666 silc_atomic_init8(&ps->refcnt, 1);
667 silc_mutex_alloc(&ps->lock);
669 /* Allocate out buffer */
670 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
672 silc_packet_stream_destroy(ps);
675 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
676 silc_buffer_reset(&ps->outbuf);
678 /* Initialize packet procesors list */
679 ps->process = silc_dlist_init();
681 silc_packet_stream_destroy(ps);
685 silc_mutex_lock(engine->lock);
687 /* Add per scheduler context */
688 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
690 ps->sc = silc_calloc(1, sizeof(*ps->sc));
692 silc_packet_stream_destroy(ps);
693 silc_mutex_unlock(engine->lock);
696 ps->sc->engine = engine;
697 ps->sc->schedule = schedule;
699 /* Allocate data input buffer */
700 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 31);
704 silc_packet_stream_destroy(ps);
705 silc_mutex_unlock(engine->lock);
708 silc_buffer_reset(inbuf);
710 ps->sc->inbufs = silc_dlist_init();
711 if (!ps->sc->inbufs) {
712 silc_buffer_free(inbuf);
715 silc_packet_stream_destroy(ps);
716 silc_mutex_unlock(engine->lock);
719 silc_dlist_add(ps->sc->inbufs, inbuf);
721 /* Add to per scheduler context hash table */
722 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
723 silc_buffer_free(inbuf);
724 silc_dlist_del(ps->sc->inbufs, inbuf);
727 silc_packet_stream_destroy(ps);
728 silc_mutex_unlock(engine->lock);
732 ps->sc->stream_count++;
734 /* Add the packet stream to engine */
735 silc_list_add(engine->streams, ps);
737 /* If this is UDP stream, allocate UDP remote stream hash table */
738 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
739 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
740 silc_hash_string_compare, NULL,
741 silc_packet_engine_hash_destr,
744 silc_mutex_unlock(engine->lock);
746 /* Set IO notifier callback. This schedules this stream for I/O. */
747 if (!silc_stream_set_notifier(ps->stream, schedule,
748 silc_packet_stream_io, ps)) {
749 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
750 silc_packet_stream_destroy(ps);
757 /* Add new remote packet stream for UDP packet streams */
759 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
760 const char *remote_ip,
761 SilcUInt16 remote_port,
764 SilcPacketEngine engine = stream->sc->engine;
769 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
770 remote_ip, remote_port, stream));
772 if (!stream || !remote_ip || !remote_port)
775 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
776 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
780 ps = silc_calloc(1, sizeof(*ps));
785 silc_atomic_init8(&ps->refcnt, 1);
786 silc_mutex_alloc(&ps->lock);
788 /* Set the UDP packet stream as underlaying stream */
789 silc_packet_stream_ref(stream);
790 ps->stream = (SilcStream)stream;
793 /* Allocate out buffer */
794 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
796 silc_packet_stream_destroy(ps);
799 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
800 silc_buffer_reset(&ps->outbuf);
802 /* Initialize packet procesors list */
803 ps->process = silc_dlist_init();
805 silc_packet_stream_destroy(ps);
809 /* Add to engine with this IP and port pair */
810 tuple = silc_format("%d%s", remote_port, remote_ip);
811 silc_mutex_lock(engine->lock);
812 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
813 silc_mutex_unlock(engine->lock);
814 silc_packet_stream_destroy(ps);
817 silc_mutex_unlock(engine->lock);
819 /* Save remote IP and port pair */
820 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
821 if (!ps->remote_udp) {
822 silc_packet_stream_destroy(ps);
825 ps->remote_udp->remote_port = remote_port;
826 ps->remote_udp->remote_ip = strdup(remote_ip);
827 if (!ps->remote_udp->remote_ip) {
828 silc_packet_stream_destroy(ps);
833 /* Inject packet to the new stream */
835 silc_packet_stream_ref(ps);
836 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
837 silc_packet_stream_inject_packet, packet,
844 /* Destroy packet stream */
846 void silc_packet_stream_destroy(SilcPacketStream stream)
848 SilcPacketEngine engine;
853 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
854 stream->destroyed = TRUE;
856 /* Close the underlaying stream */
857 if (!stream->udp && stream->stream)
858 silc_stream_close(stream->stream);
862 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
865 /* Delete from engine */
866 engine = stream->sc->engine;
867 silc_mutex_lock(engine->lock);
868 silc_list_del(engine->streams, stream);
870 /* Remove per scheduler context, if it is not used anymore */
872 stream->sc->stream_count--;
873 if (!stream->sc->stream_count)
874 silc_hash_table_del(engine->contexts, stream->sc->schedule);
876 silc_mutex_unlock(engine->lock);
878 /* Destroy the underlaying stream */
880 silc_stream_destroy(stream->stream);
882 /* Delete from UDP remote hash table */
884 engine = stream->sc->engine;
885 silc_snprintf(tuple, sizeof(tuple), "%d%s",
886 stream->remote_udp->remote_port,
887 stream->remote_udp->remote_ip);
888 silc_mutex_lock(engine->lock);
889 silc_hash_table_del(engine->udp_remote, tuple);
890 silc_mutex_unlock(engine->lock);
892 silc_free(stream->remote_udp->remote_ip);
893 silc_free(stream->remote_udp);
895 /* Unreference the underlaying packet stream */
896 silc_packet_stream_unref((SilcPacketStream)stream->stream);
899 /* Clear and free buffers */
900 silc_buffer_clear(&stream->outbuf);
901 silc_buffer_purge(&stream->outbuf);
903 if (stream->process) {
905 silc_dlist_start(stream->process);
906 while ((p = silc_dlist_get(stream->process))) {
909 silc_dlist_del(stream->process, p);
911 silc_dlist_uninit(stream->process);
914 /* Destroy ciphers and HMACs */
915 if (stream->send_key[0])
916 silc_cipher_free(stream->send_key[0]);
917 if (stream->receive_key[0])
918 silc_cipher_free(stream->receive_key[0]);
919 if (stream->send_hmac[0])
920 silc_hmac_free(stream->send_hmac[0]);
921 if (stream->receive_hmac[0])
922 silc_hmac_free(stream->receive_hmac[0]);
923 if (stream->send_key[1])
924 silc_cipher_free(stream->send_key[1]);
925 if (stream->receive_key[1])
926 silc_cipher_free(stream->receive_key[1]);
927 if (stream->send_hmac[1])
928 silc_hmac_free(stream->send_hmac[1]);
929 if (stream->receive_hmac[1])
930 silc_hmac_free(stream->receive_hmac[1]);
933 silc_free(stream->src_id);
934 silc_free(stream->dst_id);
936 silc_atomic_uninit8(&stream->refcnt);
937 silc_mutex_free(stream->lock);
941 /* Return TRUE if the stream is valid */
943 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
945 return stream->destroyed == FALSE;
948 /* Marks as router stream */
950 void silc_packet_stream_set_router(SilcPacketStream stream)
952 stream->is_router = TRUE;
955 /* Mark to include IV in ciphertext */
957 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
959 stream->iv_included = TRUE;
962 /* Links `callbacks' to `stream' for specified packet types */
964 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
965 SilcPacketCallbacks *callbacks,
966 void *callback_context,
967 int priority, va_list ap)
969 SilcPacketProcess p, e;
970 SilcInt32 packet_type;
973 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
977 if (!callbacks->packet_receive)
980 p = silc_calloc(1, sizeof(*p));
984 p->priority = priority;
985 p->callbacks = callbacks;
986 p->callback_context = callback_context;
988 silc_mutex_lock(stream->lock);
990 if (!stream->process) {
991 stream->process = silc_dlist_init();
992 if (!stream->process) {
993 silc_mutex_unlock(stream->lock);
998 /* According to priority set the procesor to correct position. First
999 entry has the highest priority */
1000 silc_dlist_start(stream->process);
1001 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1002 if (p->priority > e->priority) {
1003 silc_dlist_insert(stream->process, p);
1008 silc_dlist_add(stream->process, p);
1010 /* Get packet types to process */
1013 packet_type = va_arg(ap, SilcInt32);
1015 if (packet_type == SILC_PACKET_ANY)
1018 if (packet_type == -1)
1021 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1023 silc_mutex_unlock(stream->lock);
1027 p->types[i - 1] = (SilcPacketType)packet_type;
1031 p->types[i - 1] = 0;
1033 silc_mutex_unlock(stream->lock);
1035 silc_packet_stream_ref(stream);
1040 /* Links `callbacks' to `stream' for specified packet types */
1042 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1043 SilcPacketCallbacks *callbacks,
1044 void *callback_context,
1050 va_start(ap, priority);
1051 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1058 /* Unlinks `callbacks' from `stream'. */
1060 void silc_packet_stream_unlink(SilcPacketStream stream,
1061 SilcPacketCallbacks *callbacks,
1062 void *callback_context)
1064 SilcPacketProcess p;
1066 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1067 callbacks, stream));
1069 silc_mutex_lock(stream->lock);
1071 silc_dlist_start(stream->process);
1072 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1073 if (p->callbacks == callbacks &&
1074 p->callback_context == callback_context) {
1075 silc_dlist_del(stream->process, p);
1076 silc_free(p->types);
1081 if (!silc_dlist_count(stream->process)) {
1082 silc_dlist_uninit(stream->process);
1083 stream->process = NULL;
1086 silc_mutex_unlock(stream->lock);
1088 silc_packet_stream_unref(stream);
1091 /* Returns TRUE if stream is UDP stream */
1093 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1095 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1098 /* Return packet sender IP and port for UDP packet stream */
1100 SilcBool silc_packet_get_sender(SilcPacket packet,
1101 const char **sender_ip,
1102 SilcUInt16 *sender_port)
1104 if (!packet->stream->remote_udp)
1107 *sender_ip = packet->stream->remote_udp->remote_ip;
1108 *sender_port = packet->stream->remote_udp->remote_port;
1113 /* Reference packet stream */
1115 void silc_packet_stream_ref(SilcPacketStream stream)
1117 silc_atomic_add_int8(&stream->refcnt, 1);
1118 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1119 silc_atomic_get_int8(&stream->refcnt) - 1,
1120 silc_atomic_get_int8(&stream->refcnt)));
1123 /* Unreference packet stream */
1125 void silc_packet_stream_unref(SilcPacketStream stream)
1127 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1128 silc_atomic_get_int8(&stream->refcnt),
1129 silc_atomic_get_int8(&stream->refcnt) - 1));
1130 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1132 silc_atomic_add_int8(&stream->refcnt, 1);
1133 silc_packet_stream_destroy(stream);
1138 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1140 return stream->sc->engine;
1143 /* Set application context for packet stream */
1145 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1147 silc_mutex_lock(stream->lock);
1148 stream->stream_context = stream_context;
1149 silc_mutex_unlock(stream->lock);
1152 /* Return application context from packet stream */
1154 void *silc_packet_get_context(SilcPacketStream stream)
1157 silc_mutex_lock(stream->lock);
1158 context = stream->stream_context;
1159 silc_mutex_unlock(stream->lock);
1163 /* Change underlaying stream */
1165 void silc_packet_stream_set_stream(SilcPacketStream ps,
1169 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1170 ps->stream = stream;
1171 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1175 /* Return underlaying stream */
1177 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1179 return stream->stream;
1184 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1185 SilcCipher receive_key, SilcHmac send_hmac,
1186 SilcHmac receive_hmac, SilcBool rekey)
1188 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1190 /* If doing rekey, send REKEY_DONE packet */
1192 /* This will take stream lock. */
1193 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1194 stream->src_id_type, stream->src_id,
1195 stream->src_id_len, stream->dst_id_type,
1196 stream->dst_id, stream->dst_id_len,
1197 NULL, 0, stream->send_key[0],
1198 stream->send_hmac[0]))
1201 /* Write the packet to the stream */
1202 if (!silc_packet_stream_write(stream, TRUE))
1205 silc_mutex_lock(stream->lock);
1208 /* In case IV Included is set, save the old keys */
1209 if (stream->iv_included) {
1210 if (stream->send_key[1] && send_key) {
1211 silc_cipher_free(stream->send_key[1]);
1212 stream->send_key[1] = stream->send_key[0];
1214 if (stream->receive_key[1] && receive_key) {
1215 silc_cipher_free(stream->receive_key[1]);
1216 stream->receive_key[1] = stream->receive_key[0];
1218 if (stream->send_hmac[1] && send_hmac) {
1219 silc_hmac_free(stream->send_hmac[1]);
1220 stream->send_hmac[1] = stream->send_hmac[0];
1222 if (stream->receive_hmac[1] && receive_hmac) {
1223 silc_hmac_free(stream->receive_hmac[1]);
1224 stream->receive_hmac[1] = stream->receive_hmac[0];
1227 if (stream->send_key[0] && send_key)
1228 silc_cipher_free(stream->send_key[0]);
1229 if (stream->receive_key[0] && receive_key)
1230 silc_cipher_free(stream->receive_key[0]);
1231 if (stream->send_hmac[0] && send_hmac)
1232 silc_hmac_free(stream->send_hmac[0]);
1233 if (stream->receive_hmac[0] && receive_hmac)
1234 silc_hmac_free(stream->receive_hmac[0]);
1239 stream->send_key[0] = send_key;
1241 stream->receive_key[0] = receive_key;
1243 stream->send_hmac[0] = send_hmac;
1245 stream->receive_hmac[0] = receive_hmac;
1247 silc_mutex_unlock(stream->lock);
1251 /* Return current ciphers from packet stream */
1253 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1254 SilcCipher *send_key,
1255 SilcCipher *receive_key,
1256 SilcHmac *send_hmac,
1257 SilcHmac *receive_hmac)
1259 if (!stream->send_key[0] && !stream->receive_key[0] &&
1260 !stream->send_hmac[0] && !stream->receive_hmac[0])
1263 silc_mutex_lock(stream->lock);
1266 *send_key = stream->send_key[0];
1268 *receive_key = stream->receive_key[0];
1270 *send_hmac = stream->send_hmac[0];
1272 *receive_hmac = stream->receive_hmac[0];
1274 silc_mutex_unlock(stream->lock);
1279 /* Set SILC IDs to packet stream */
1281 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1282 SilcIdType src_id_type, const void *src_id,
1283 SilcIdType dst_id_type, const void *dst_id)
1286 unsigned char tmp[32];
1288 if (!src_id && !dst_id)
1291 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1293 silc_mutex_lock(stream->lock);
1296 silc_free(stream->src_id);
1297 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1298 silc_mutex_unlock(stream->lock);
1301 stream->src_id = silc_memdup(tmp, len);
1302 if (!stream->src_id) {
1303 silc_mutex_unlock(stream->lock);
1306 stream->src_id_type = src_id_type;
1307 stream->src_id_len = len;
1311 silc_free(stream->dst_id);
1312 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1313 silc_mutex_unlock(stream->lock);
1316 stream->dst_id = silc_memdup(tmp, len);
1317 if (!stream->dst_id) {
1318 silc_mutex_unlock(stream->lock);
1321 stream->dst_id_type = dst_id_type;
1322 stream->dst_id_len = len;
1325 silc_mutex_unlock(stream->lock);
1330 /* Return IDs from the packet stream */
1332 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1333 SilcBool *src_id_set, SilcID *src_id,
1334 SilcBool *dst_id_set, SilcID *dst_id)
1336 if (src_id && stream->src_id) {
1337 (*src_id).type = stream->src_id_type;
1338 switch (stream->src_id_type) {
1339 case SILC_ID_CLIENT:
1340 (*src_id).u.client_id = *(SilcClientID *)stream->src_id;
1342 case SILC_ID_SERVER:
1343 (*src_id).u.server_id = *(SilcServerID *)stream->src_id;
1345 case SILC_ID_CHANNEL:
1346 (*src_id).u.channel_id = *(SilcChannelID *)stream->src_id;
1350 if (stream->src_id && src_id_set)
1353 if (dst_id && stream->dst_id) {
1354 (*dst_id).type = stream->dst_id_type;
1355 switch (stream->dst_id_type) {
1356 case SILC_ID_CLIENT:
1357 (*dst_id).u.client_id = *(SilcClientID *)stream->dst_id;
1359 case SILC_ID_SERVER:
1360 (*dst_id).u.server_id = *(SilcServerID *)stream->dst_id;
1362 case SILC_ID_CHANNEL:
1363 (*dst_id).u.channel_id = *(SilcChannelID *)stream->dst_id;
1367 if (stream->dst_id && dst_id_set)
1373 /* Adds Security ID (SID) */
1375 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1377 if (!stream->iv_included)
1380 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1388 void silc_packet_free(SilcPacket packet)
1390 SilcPacketStream stream = packet->stream;
1392 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1394 /* Check for double free */
1395 SILC_ASSERT(packet->stream != NULL);
1397 packet->stream = NULL;
1398 packet->src_id = packet->dst_id = NULL;
1399 silc_buffer_reset(&packet->buffer);
1401 silc_mutex_lock(stream->sc->engine->lock);
1403 /* Put the packet back to freelist */
1404 silc_list_add(stream->sc->engine->packet_pool, packet);
1405 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1406 silc_list_start(stream->sc->engine->packet_pool);
1408 silc_mutex_unlock(stream->sc->engine->lock);
1411 /****************************** Packet Sending ******************************/
1413 /* Prepare outgoing data buffer for packet sending. Returns the
1414 pointer to that buffer into the `packet'. */
1416 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1421 unsigned char *oldptr;
1422 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1426 /* Allocate more space if needed */
1427 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1428 if (!silc_buffer_realloc(&stream->outbuf,
1429 silc_buffer_truelen(&stream->outbuf) + totlen))
1433 /* Pull data area for the new packet, and return pointer to the start of
1434 the data area and save the pointer in to the `packet'. MAC is pulled
1435 later after it's computed. */
1436 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1437 silc_buffer_set(packet, oldptr, totlen);
1438 silc_buffer_push_tail(packet, mac_len);
1443 /* Increments counter when encrypting in counter mode. */
1445 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1447 unsigned char *ret_iv)
1449 unsigned char *iv = silc_cipher_get_iv(cipher);
1450 SilcUInt32 pc1, pc2;
1452 /* Increment 64-bit packet counter */
1453 SILC_GET32_MSB(pc1, iv + 4);
1454 SILC_GET32_MSB(pc2, iv + 8);
1457 SILC_PUT32_MSB(pc1, iv + 4);
1458 SILC_PUT32_MSB(pc2, iv + 8);
1460 /* Reset block counter */
1461 memset(iv + 12, 0, 4);
1463 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1464 if (stream->iv_included) {
1466 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1467 ret_iv[1] = ret_iv[0] + iv[4];
1468 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1469 ret_iv[3] = ret_iv[0] + ret_iv[2];
1470 SILC_PUT32_MSB(pc2, ret_iv + 4);
1471 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1473 /* Set new nonce to counter block */
1474 memcpy(iv + 4, ret_iv, 4);
1477 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1480 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1481 the packet. The silc_packet_stream_write needs to be called to send it
1482 after this returns TRUE. */
1484 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1485 SilcPacketType type,
1486 SilcPacketFlags flags,
1487 SilcIdType src_id_type,
1488 unsigned char *src_id,
1489 SilcUInt32 src_id_len,
1490 SilcIdType dst_id_type,
1491 unsigned char *dst_id,
1492 SilcUInt32 dst_id_len,
1493 const unsigned char *data,
1494 SilcUInt32 data_len,
1498 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1499 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1500 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1502 SilcBufferStruct packet;
1504 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1505 "data len %d", silc_get_packet_name(type), stream->send_psn,
1506 flags, src_id_type, dst_id_type, data_len));
1508 /* Get the true length of the packet. This is saved as payload length
1509 into the packet header. This does not include the length of the
1511 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1512 src_id_len + dst_id_len));
1513 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1514 src_id_len + dst_id_len);
1516 /* If using CTR mode, increment the counter */
1517 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1519 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1521 /* If IV is included, the SID, IV and sequence number is added to packet */
1522 if (stream->iv_included && cipher) {
1523 psnlen = sizeof(psn);
1525 iv[0] = stream->sid;
1528 /* If IV is included, the SID, IV and sequence number is added to packet */
1529 if (stream->iv_included && cipher) {
1530 psnlen = sizeof(psn);
1531 ivlen = block_len + 1;
1532 iv[0] = stream->sid;
1533 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1537 /* We automatically figure out the packet structure from the packet
1538 type and flags, and calculate correct length. Private messages with
1539 private keys and channel messages are special packets as their
1540 payload is encrypted already. */
1541 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1542 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1543 /* Padding is calculated from header + IDs */
1545 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1546 psnlen), block_len, padlen);
1548 /* Length to encrypt, header + IDs + padding. */
1549 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1552 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1553 if (stream->sc->engine->local_is_router && stream->is_router) {
1554 /* Channel messages between routers are encrypted as normal packets.
1555 Padding is calculated from true length of the packet. */
1557 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1559 enclen += padlen + psnlen;
1561 /* Padding is calculated from header + IDs */
1563 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1564 psnlen), block_len, padlen);
1566 /* Length to encrypt, header + IDs + padding. */
1567 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1571 /* Padding is calculated from true length of the packet */
1572 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1573 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1575 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1577 enclen += padlen + psnlen;
1580 /* Remove implementation specific flags */
1581 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1583 /* Get random padding */
1584 for (i = 0; i < padlen; i++) tmppad[i] =
1585 silc_rng_get_byte_fast(stream->sc->engine->rng);
1587 silc_mutex_lock(stream->lock);
1589 /* Get packet pointer from the outgoing buffer */
1590 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1591 + psnlen, hmac, &packet))) {
1592 silc_mutex_unlock(stream->lock);
1596 SILC_PUT32_MSB(stream->send_psn, psn);
1598 /* Create the packet. This creates the SILC header, adds padding, and
1599 the actual packet data. */
1600 i = silc_buffer_format(&packet,
1601 SILC_STR_DATA(iv, ivlen),
1602 SILC_STR_DATA(psn, psnlen),
1603 SILC_STR_UI_SHORT(truelen),
1604 SILC_STR_UI_CHAR(flags),
1605 SILC_STR_UI_CHAR(type),
1606 SILC_STR_UI_CHAR(padlen),
1607 SILC_STR_UI_CHAR(0),
1608 SILC_STR_UI_CHAR(src_id_len),
1609 SILC_STR_UI_CHAR(dst_id_len),
1610 SILC_STR_UI_CHAR(src_id_type),
1611 SILC_STR_DATA(src_id, src_id_len),
1612 SILC_STR_UI_CHAR(dst_id_type),
1613 SILC_STR_DATA(dst_id, dst_id_len),
1614 SILC_STR_DATA(tmppad, padlen),
1615 SILC_STR_DATA(data, data_len),
1617 if (silc_unlikely(i < 0)) {
1618 silc_mutex_unlock(stream->lock);
1622 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1623 silc_buffer_data(&packet), silc_buffer_len(&packet));
1625 /* Encrypt the packet */
1626 if (silc_likely(cipher)) {
1627 SILC_LOG_DEBUG(("Encrypting packet"));
1628 silc_cipher_set_iv(cipher, NULL);
1629 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1630 packet.data + ivlen, enclen,
1632 SILC_LOG_ERROR(("Packet encryption failed"));
1633 silc_mutex_unlock(stream->lock);
1639 if (silc_likely(hmac)) {
1642 /* MAC is computed from the entire encrypted packet data, and put
1643 to the end of the packet. */
1644 silc_hmac_init(hmac);
1645 silc_hmac_update(hmac, psn, sizeof(psn));
1646 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1647 silc_hmac_final(hmac, packet.tail, &mac_len);
1648 silc_buffer_pull_tail(&packet, mac_len);
1655 /* Sends a packet */
1657 SilcBool silc_packet_send(SilcPacketStream stream,
1658 SilcPacketType type, SilcPacketFlags flags,
1659 const unsigned char *data, SilcUInt32 data_len)
1663 ret = silc_packet_send_raw(stream, type, flags,
1664 stream->src_id_type,
1667 stream->dst_id_type,
1671 stream->send_key[0],
1672 stream->send_hmac[0]);
1674 /* Write the packet to the stream */
1675 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1678 /* Sends a packet, extended routine */
1680 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1681 SilcPacketType type, SilcPacketFlags flags,
1682 SilcIdType src_id_type, void *src_id,
1683 SilcIdType dst_id_type, void *dst_id,
1684 const unsigned char *data, SilcUInt32 data_len,
1685 SilcCipher cipher, SilcHmac hmac)
1687 unsigned char src_id_data[32], dst_id_data[32];
1688 SilcUInt32 src_id_len, dst_id_len;
1692 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1693 sizeof(src_id_data), &src_id_len))
1696 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1697 sizeof(dst_id_data), &dst_id_len))
1700 ret = silc_packet_send_raw(stream, type, flags,
1701 src_id ? src_id_type : stream->src_id_type,
1702 src_id ? src_id_data : stream->src_id,
1703 src_id ? src_id_len : stream->src_id_len,
1704 dst_id ? dst_id_type : stream->dst_id_type,
1705 dst_id ? dst_id_data : stream->dst_id,
1706 dst_id ? dst_id_len : stream->dst_id_len,
1708 cipher ? cipher : stream->send_key[0],
1709 hmac ? hmac : stream->send_hmac[0]);
1711 /* Write the packet to the stream */
1712 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1715 /* Sends packet after formatting the arguments to buffer */
1717 SilcBool silc_packet_send_va(SilcPacketStream stream,
1718 SilcPacketType type, SilcPacketFlags flags, ...)
1720 SilcBufferStruct buf;
1724 va_start(va, flags);
1726 memset(&buf, 0, sizeof(buf));
1727 if (silc_buffer_format_vp(&buf, va) < 0) {
1732 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1733 silc_buffer_len(&buf));
1735 silc_buffer_purge(&buf);
1741 /* Sends packet after formatting the arguments to buffer, extended routine */
1743 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1744 SilcPacketType type, SilcPacketFlags flags,
1745 SilcIdType src_id_type, void *src_id,
1746 SilcIdType dst_id_type, void *dst_id,
1747 SilcCipher cipher, SilcHmac hmac, ...)
1749 SilcBufferStruct buf;
1755 memset(&buf, 0, sizeof(buf));
1756 if (silc_buffer_format_vp(&buf, va) < 0) {
1761 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1762 dst_id_type, dst_id, silc_buffer_data(&buf),
1763 silc_buffer_len(&buf), cipher, hmac);
1765 silc_buffer_purge(&buf);
1771 /***************************** Packet Receiving *****************************/
1773 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1775 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1776 const unsigned char *data,
1777 SilcUInt32 data_len,
1778 const unsigned char *packet_mac,
1779 const unsigned char *packet_seq,
1780 SilcUInt32 sequence)
1783 if (silc_likely(hmac)) {
1784 unsigned char mac[32], psn[4];
1787 SILC_LOG_DEBUG(("Verifying MAC"));
1789 /* Compute HMAC of packet */
1790 silc_hmac_init(hmac);
1793 SILC_PUT32_MSB(sequence, psn);
1794 silc_hmac_update(hmac, psn, 4);
1796 silc_hmac_update(hmac, packet_seq, 4);
1798 silc_hmac_update(hmac, data, data_len);
1799 silc_hmac_final(hmac, mac, &mac_len);
1801 /* Compare the MAC's */
1802 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1803 SILC_LOG_DEBUG(("MAC failed"));
1807 SILC_LOG_DEBUG(("MAC is Ok"));
1813 /* Increments/sets counter when decrypting in counter mode. */
1815 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1817 unsigned char *packet_iv)
1819 SilcUInt32 pc1, pc2;
1821 /* If IV Included flag, set the IV from packet to block counter. */
1822 if (stream->iv_included) {
1823 memcpy(iv + 4, packet_iv, 8);
1825 /* Increment 64-bit packet counter. */
1826 SILC_GET32_MSB(pc1, iv + 4);
1827 SILC_GET32_MSB(pc2, iv + 8);
1830 SILC_PUT32_MSB(pc1, iv + 4);
1831 SILC_PUT32_MSB(pc2, iv + 8);
1834 /* Reset block counter */
1835 memset(iv + 12, 0, 4);
1837 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1840 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1841 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1843 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1844 SilcUInt32 sequence, SilcBuffer buffer,
1847 if (normal == TRUE) {
1848 if (silc_likely(cipher)) {
1849 /* Decrypt rest of the packet */
1850 SILC_LOG_DEBUG(("Decrypting the packet"));
1851 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1853 silc_buffer_len(buffer), NULL)))
1859 /* Decrypt rest of the header plus padding */
1860 if (silc_likely(cipher)) {
1862 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1864 SILC_LOG_DEBUG(("Decrypting the header"));
1866 /* Padding length + src id len + dst id len + header length - 16
1867 bytes already decrypted, gives the rest of the encrypted packet */
1868 silc_buffer_push(buffer, block_len);
1869 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1870 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1872 silc_buffer_pull(buffer, block_len);
1874 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1875 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1879 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1880 buffer->data, len, NULL)))
1888 /* Parses the packet. This is called when a whole packet is ready to be
1889 parsed. The buffer sent must be already decrypted before calling this
1892 static inline SilcBool silc_packet_parse(SilcPacket packet)
1894 SilcBuffer buffer = &packet->buffer;
1895 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1896 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1899 SILC_LOG_DEBUG(("Parsing incoming packet"));
1901 /* Parse the buffer. This parses the SILC header of the packet. */
1902 ret = silc_buffer_unformat(buffer,
1905 SILC_STR_UI_CHAR(&src_id_len),
1906 SILC_STR_UI_CHAR(&dst_id_len),
1907 SILC_STR_UI_CHAR(&src_id_type),
1909 if (silc_unlikely(ret == -1)) {
1910 if (!packet->stream->udp &&
1911 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1912 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1916 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1917 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1918 if (!packet->stream->udp &&
1919 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1920 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1921 packet->src_id_len, packet->dst_id_len));
1925 ret = silc_buffer_unformat(buffer,
1927 SILC_STR_DATA(&packet->src_id, src_id_len),
1928 SILC_STR_UI_CHAR(&dst_id_type),
1929 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1930 SILC_STR_OFFSET(padlen),
1932 if (silc_unlikely(ret == -1)) {
1933 if (!packet->stream->udp &&
1934 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1935 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1939 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1940 dst_id_type > SILC_ID_CHANNEL)) {
1941 if (!packet->stream->udp &&
1942 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1943 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1944 src_id_type, dst_id_type));
1948 packet->src_id_len = src_id_len;
1949 packet->dst_id_len = dst_id_len;
1950 packet->src_id_type = src_id_type;
1951 packet->dst_id_type = dst_id_type;
1953 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1954 silc_buffer_len(buffer)), buffer->head,
1955 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1957 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1958 silc_get_packet_name(packet->type)));
1963 /* Dispatch packet to application. Called with stream->lock locked.
1964 Returns FALSE if the stream was destroyed while dispatching a packet. */
1966 static SilcBool silc_packet_dispatch(SilcPacket packet)
1968 SilcPacketStream stream = packet->stream;
1969 SilcPacketProcess p;
1970 SilcBool default_sent = FALSE;
1973 /* Dispatch packet to all packet processors that want it */
1975 if (silc_likely(!stream->process)) {
1976 /* Send to default processor as no others exist */
1977 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1978 silc_mutex_unlock(stream->lock);
1979 if (silc_unlikely(!stream->sc->engine->callbacks->
1980 packet_receive(stream->sc->engine, stream, packet,
1981 stream->sc->engine->callback_context,
1982 stream->stream_context)))
1983 silc_packet_free(packet);
1984 silc_mutex_lock(stream->lock);
1985 return stream->destroyed == FALSE;
1988 silc_dlist_start(stream->process);
1989 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1991 /* If priority is 0 or less, we send to default processor first
1992 because default processor has 0 priority */
1993 if (!default_sent && p->priority <= 0) {
1994 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1995 default_sent = TRUE;
1996 silc_mutex_unlock(stream->lock);
1997 if (stream->sc->engine->callbacks->
1998 packet_receive(stream->sc->engine, stream, packet,
1999 stream->sc->engine->callback_context,
2000 stream->stream_context)) {
2001 silc_mutex_lock(stream->lock);
2002 return stream->destroyed == FALSE;
2004 silc_mutex_lock(stream->lock);
2007 /* Send to processor */
2009 /* Send all packet types */
2010 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2011 silc_mutex_unlock(stream->lock);
2012 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2013 p->callback_context,
2014 stream->stream_context)) {
2015 silc_mutex_lock(stream->lock);
2016 return stream->destroyed == FALSE;
2018 silc_mutex_lock(stream->lock);
2020 /* Send specific types */
2021 for (pt = p->types; *pt; pt++) {
2022 if (*pt != packet->type)
2024 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2025 silc_mutex_unlock(stream->lock);
2026 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2027 p->callback_context,
2028 stream->stream_context)) {
2029 silc_mutex_lock(stream->lock);
2030 return stream->destroyed == FALSE;
2032 silc_mutex_lock(stream->lock);
2038 if (!default_sent) {
2039 /* Send to default processor as it has not been sent yet */
2040 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2041 silc_mutex_unlock(stream->lock);
2042 if (stream->sc->engine->callbacks->
2043 packet_receive(stream->sc->engine, stream, packet,
2044 stream->sc->engine->callback_context,
2045 stream->stream_context)) {
2046 silc_mutex_lock(stream->lock);
2047 return stream->destroyed == FALSE;
2049 silc_mutex_lock(stream->lock);
2052 /* If we got here, no one wanted the packet, so drop it */
2053 silc_packet_free(packet);
2054 return stream->destroyed == FALSE;
2057 /* Process incoming data and parse packets. Called with stream->lock
2060 static void silc_packet_read_process(SilcPacketStream stream)
2067 SilcUInt16 packetlen;
2068 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2069 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2070 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2074 /* Get inbuf. If there is already some data for this stream in the buffer
2075 we already have it. Otherwise get the current one from list, it will
2076 include the data. */
2077 inbuf = stream->inbuf;
2079 silc_dlist_start(stream->sc->inbufs);
2080 inbuf = silc_dlist_get(stream->sc->inbufs);
2083 /* Parse the packets from the data */
2084 while (silc_buffer_len(inbuf) > 0) {
2086 cipher = stream->receive_key[0];
2087 hmac = stream->receive_hmac[0];
2090 if (silc_unlikely(silc_buffer_len(inbuf) <
2091 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2092 SILC_PACKET_MIN_HEADER_LEN))) {
2093 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2094 silc_dlist_del(stream->sc->inbufs, inbuf);
2095 stream->inbuf = inbuf;
2099 if (silc_likely(hmac))
2100 mac_len = silc_hmac_len(hmac);
2104 /* Decrypt first block of the packet to get the length field out */
2105 if (silc_likely(cipher)) {
2106 block_len = silc_cipher_get_block_len(cipher);
2108 if (stream->iv_included) {
2109 /* SID, IV and sequence number is included in the ciphertext */
2110 sid = (SilcUInt8)inbuf->data[0];
2112 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2113 /* Set the CTR mode IV from packet to counter block */
2114 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2115 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2118 /* Get IV from packet */
2119 memcpy(iv, inbuf->data + 1, block_len);
2120 ivlen = block_len + 1;
2124 /* Check SID, and get correct decryption key */
2125 if (sid != stream->sid) {
2126 /* If SID is recent get the previous key and use it */
2127 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2128 stream->receive_key[1] && !stream->receive_hmac[1]) {
2129 cipher = stream->receive_key[1];
2130 hmac = stream->receive_hmac[1];
2132 /* The SID is unknown, drop rest of the data in buffer */
2133 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2135 silc_mutex_unlock(stream->lock);
2136 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2137 silc_mutex_lock(stream->lock);
2142 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2144 /* If using CTR mode, increment the counter */
2145 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2146 silc_packet_receive_ctr_increment(stream, iv, NULL);
2149 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2150 silc_cipher_set_iv(cipher, NULL);
2151 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2154 if (stream->iv_included) {
2155 /* Take sequence number from packet */
2156 packet_seq = header;
2160 /* Unencrypted packet */
2161 block_len = SILC_PACKET_MIN_HEADER_LEN;
2162 header = inbuf->data;
2165 /* Get packet length and full packet length with padding */
2166 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2169 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2170 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2171 SILC_LOG_ERROR(("Received too short packet"));
2172 silc_mutex_unlock(stream->lock);
2173 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2174 silc_mutex_lock(stream->lock);
2175 memset(tmp, 0, sizeof(tmp));
2179 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2180 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2182 paddedlen + mac_len - silc_buffer_len(inbuf)));
2183 memset(tmp, 0, sizeof(tmp));
2184 silc_dlist_del(stream->sc->inbufs, inbuf);
2185 stream->inbuf = inbuf;
2189 /* Check MAC of the packet */
2190 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2192 inbuf->data + ivlen +
2193 paddedlen, packet_seq,
2194 stream->receive_psn))) {
2195 silc_mutex_unlock(stream->lock);
2196 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2197 silc_mutex_lock(stream->lock);
2198 memset(tmp, 0, sizeof(tmp));
2203 packet = silc_packet_alloc(stream->sc->engine);
2204 if (silc_unlikely(!packet)) {
2205 silc_mutex_unlock(stream->lock);
2206 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2207 silc_mutex_lock(stream->lock);
2208 memset(tmp, 0, sizeof(tmp));
2211 packet->stream = stream;
2213 /* Allocate more space to packet buffer, if needed */
2214 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2215 if (!silc_buffer_realloc(&packet->buffer,
2216 silc_buffer_truelen(&packet->buffer) +
2218 silc_buffer_truelen(&packet->buffer)))) {
2219 silc_mutex_unlock(stream->lock);
2220 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2221 silc_mutex_lock(stream->lock);
2222 silc_packet_free(packet);
2223 memset(tmp, 0, sizeof(tmp));
2228 /* Parse packet header */
2229 packet->flags = (SilcPacketFlags)header[2];
2230 packet->type = (SilcPacketType)header[3];
2232 if (stream->sc->engine->local_is_router) {
2233 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2234 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2236 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2237 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2238 stream->is_router == TRUE))
2241 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2242 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2244 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2248 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2249 stream->receive_psn, paddedlen + ivlen + mac_len),
2250 inbuf->data, paddedlen + ivlen + mac_len);
2252 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2253 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2254 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2255 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2256 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2257 psnlen + (block_len - psnlen)),
2258 paddedlen - ivlen - psnlen - (block_len - psnlen));
2259 if (silc_likely(cipher)) {
2260 silc_cipher_set_iv(cipher, iv);
2261 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2262 &packet->buffer, normal);
2263 if (silc_unlikely(ret < 0)) {
2264 silc_mutex_unlock(stream->lock);
2265 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2266 silc_mutex_lock(stream->lock);
2267 silc_packet_free(packet);
2268 memset(tmp, 0, sizeof(tmp));
2272 stream->receive_psn++;
2274 silc_buffer_push(&packet->buffer, block_len);
2276 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2277 silc_buffer_pull(inbuf, paddedlen + mac_len);
2279 /* Parse the packet */
2280 if (silc_unlikely(!silc_packet_parse(packet))) {
2281 silc_mutex_unlock(stream->lock);
2282 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2283 silc_mutex_lock(stream->lock);
2284 silc_packet_free(packet);
2285 memset(tmp, 0, sizeof(tmp));
2289 /* Dispatch the packet to application */
2290 if (!silc_packet_dispatch(packet))
2295 /* Add inbuf back to free list, if we owned it. */
2296 if (stream->inbuf) {
2297 silc_dlist_add(stream->sc->inbufs, inbuf);
2298 stream->inbuf = NULL;
2301 silc_buffer_reset(inbuf);
2304 /****************************** Packet Waiting ******************************/
2306 /* Packet wait receive callback */
2308 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2309 SilcPacketStream stream,
2311 void *callback_context,
2312 void *stream_context);
2314 /* Packet waiting callbacks */
2315 static SilcPacketCallbacks silc_packet_wait_cbs =
2317 silc_packet_wait_packet_receive, NULL, NULL
2320 /* Packet waiting context */
2322 SilcMutex wait_lock;
2324 SilcList packet_queue;
2325 unsigned int stopped : 1;
2328 /* Packet wait receive callback */
2331 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2332 SilcPacketStream stream,
2334 void *callback_context,
2335 void *stream_context)
2337 SilcPacketWait pw = callback_context;
2339 /* Signal the waiting thread for a new packet */
2340 silc_mutex_lock(pw->wait_lock);
2342 if (silc_unlikely(pw->stopped)) {
2343 silc_mutex_unlock(pw->wait_lock);
2347 silc_list_add(pw->packet_queue, packet);
2348 silc_cond_broadcast(pw->wait_cond);
2350 silc_mutex_unlock(pw->wait_lock);
2355 /* Initialize packet waiting */
2357 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2363 pw = silc_calloc(1, sizeof(*pw));
2367 /* Allocate mutex and conditional variable */
2368 if (!silc_mutex_alloc(&pw->wait_lock)) {
2372 if (!silc_cond_alloc(&pw->wait_cond)) {
2373 silc_mutex_free(pw->wait_lock);
2378 /* Link to the packet stream for the requested packet types */
2379 va_start(ap, stream);
2380 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2384 silc_cond_free(pw->wait_cond);
2385 silc_mutex_free(pw->wait_lock);
2390 /* Initialize packet queue */
2391 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2396 /* Uninitialize packet waiting */
2398 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2400 SilcPacketWait pw = waiter;
2403 /* Signal any threads to stop waiting */
2404 silc_mutex_lock(pw->wait_lock);
2406 silc_cond_broadcast(pw->wait_cond);
2407 silc_mutex_unlock(pw->wait_lock);
2408 silc_thread_yield();
2410 /* Re-acquire lock and free resources */
2411 silc_mutex_lock(pw->wait_lock);
2412 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2414 /* Free any remaining packets */
2415 silc_list_start(pw->packet_queue);
2416 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2417 silc_packet_free(packet);
2419 silc_mutex_unlock(pw->wait_lock);
2420 silc_cond_free(pw->wait_cond);
2421 silc_mutex_free(pw->wait_lock);
2425 /* Blocks thread until a packet has been received. */
2427 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2429 SilcPacketWait pw = waiter;
2430 SilcBool ret = FALSE;
2432 silc_mutex_lock(pw->wait_lock);
2434 /* Wait here until packet has arrived */
2435 while (silc_list_count(pw->packet_queue) == 0) {
2436 if (silc_unlikely(pw->stopped)) {
2437 silc_mutex_unlock(pw->wait_lock);
2440 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2444 silc_list_start(pw->packet_queue);
2445 *return_packet = silc_list_get(pw->packet_queue);
2446 silc_list_del(pw->packet_queue, *return_packet);
2448 silc_mutex_unlock(pw->wait_lock);
2450 return ret == TRUE ? 1 : 0;
2453 /************************** Packet Stream Wrapper ***************************/
2455 /* Packet stream wrapper receive callback */
2457 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2458 SilcPacketStream stream,
2460 void *callback_context,
2461 void *stream_context);
2463 const SilcStreamOps silc_packet_stream_ops;
2465 /* Packet stream wrapper context */
2467 const SilcStreamOps *ops;
2468 SilcPacketStream stream;
2470 void *waiter; /* Waiter context in blocking mode */
2471 SilcPacketWrapCoder coder;
2472 void *coder_context;
2474 SilcStreamNotifier callback;
2477 SilcPacketType type;
2478 SilcPacketFlags flags;
2479 unsigned int closed : 1;
2480 unsigned int blocking : 1;
2481 unsigned int read_more : 1;
2482 } *SilcPacketWrapperStream;
2484 /* Packet wrapper callbacks */
2485 static SilcPacketCallbacks silc_packet_wrap_cbs =
2487 silc_packet_wrap_packet_receive, NULL, NULL
2490 /* Packet stream wrapper receive callback, non-blocking mode */
2493 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2494 SilcPacketStream stream,
2496 void *callback_context,
2497 void *stream_context)
2499 SilcPacketWrapperStream pws = callback_context;
2501 if (pws->closed || !pws->callback)
2504 silc_mutex_lock(pws->lock);
2505 silc_list_add(pws->in_queue, packet);
2506 silc_mutex_unlock(pws->lock);
2508 /* Call notifier callback */
2509 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2514 /* Task callback to notify more data is available for reading */
2516 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2518 SilcPacketWrapperStream pws = context;
2520 if (pws->closed || !pws->callback)
2523 /* Call notifier callback */
2524 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2527 /* Read SILC packet */
2529 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2532 SilcPacketWrapperStream pws = stream;
2534 SilcBool read_more = FALSE;
2540 if (pws->blocking) {
2541 /* Block until packet is received */
2542 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2547 /* Non-blocking mode */
2548 silc_mutex_lock(pws->lock);
2549 if (!silc_list_count(pws->in_queue)) {
2550 silc_mutex_unlock(pws->lock);
2554 silc_list_start(pws->in_queue);
2555 packet = silc_list_get(pws->in_queue);
2556 silc_list_del(pws->in_queue, packet);
2557 silc_mutex_unlock(pws->lock);
2560 /* Call decoder if set */
2561 if (pws->coder && !pws->read_more)
2562 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2563 pws->coder_context);
2565 len = silc_buffer_len(&packet->buffer);
2566 if (len > buf_len) {
2572 memcpy(buf, packet->buffer.data, len);
2574 if (read_more && !pws->blocking) {
2575 /* More data will be available (in blocking mode not supported). */
2576 silc_buffer_pull(&packet->buffer, len);
2577 silc_list_insert(pws->in_queue, NULL, packet);
2578 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2579 silc_packet_wrap_read_more, pws, 0, 0);
2580 pws->read_more = TRUE;
2584 pws->read_more = FALSE;
2585 silc_packet_free(packet);
2589 /* Write SILC packet */
2591 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2592 SilcUInt32 data_len)
2594 SilcPacketWrapperStream pws = stream;
2595 SilcBool ret = FALSE;
2597 /* Call encoder if set */
2599 silc_buffer_reset(pws->encbuf);
2600 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2601 pws->coder_context);
2604 /* Send the SILC packet */
2606 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2607 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2608 silc_buffer_len(pws->encbuf)),
2609 SILC_STR_DATA(data, data_len),
2613 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2622 SilcBool silc_packet_wrap_close(SilcStream stream)
2624 SilcPacketWrapperStream pws = stream;
2629 if (pws->blocking) {
2630 /* Close packet waiter */
2631 silc_packet_wait_uninit(pws->waiter, pws->stream);
2635 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2642 /* Destroy wrapper stream */
2644 void silc_packet_wrap_destroy(SilcStream stream)
2647 SilcPacketWrapperStream pws = stream;
2650 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2652 silc_stream_close(stream);
2653 silc_list_start(pws->in_queue);
2654 while ((packet = silc_list_get(pws->in_queue)))
2655 silc_packet_free(packet);
2657 silc_mutex_free(pws->lock);
2659 silc_buffer_free(pws->encbuf);
2660 silc_packet_stream_unref(pws->stream);
2665 /* Link stream to receive packets */
2667 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2668 SilcSchedule schedule,
2669 SilcStreamNotifier callback,
2672 SilcPacketWrapperStream pws = stream;
2674 if (pws->closed || pws->blocking)
2677 /* Link to receive packets */
2679 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2680 100000, pws->type, -1);
2682 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2684 pws->callback = callback;
2685 pws->context = context;
2690 /* Return schedule */
2692 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2697 /* Wraps packet stream into SilcStream. */
2699 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2700 SilcPacketType type,
2701 SilcPacketFlags flags,
2702 SilcBool blocking_mode,
2703 SilcPacketWrapCoder coder,
2706 SilcPacketWrapperStream pws;
2708 pws = silc_calloc(1, sizeof(*pws));
2712 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2714 pws->ops = &silc_packet_stream_ops;
2715 pws->stream = stream;
2718 pws->blocking = blocking_mode;
2720 pws->coder_context = context;
2722 /* Allocate small amount for encoder buffer. */
2724 pws->encbuf = silc_buffer_alloc(8);
2726 if (pws->blocking) {
2727 /* Blocking mode. Use packet waiter to do the thing. */
2728 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2734 /* Non-blocking mode */
2735 silc_mutex_alloc(&pws->lock);
2736 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2739 silc_packet_stream_ref(stream);
2741 return (SilcStream)pws;
2744 const SilcStreamOps silc_packet_stream_ops =
2746 silc_packet_wrap_read,
2747 silc_packet_wrap_write,
2748 silc_packet_wrap_close,
2749 silc_packet_wrap_destroy,
2750 silc_packet_wrap_notifier,
2751 silc_packet_wrap_get_schedule,