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 * 65);
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 static const char *packet_error[] = {
627 "Cannot read from stream",
628 "Cannot write to stream",
630 "Packet decryption failed",
632 "Packet is malformed",
633 "System out of memory",
636 /* Return packet error string */
638 const char *silc_packet_error_string(SilcPacketError error)
640 if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
641 return "<invalid error code>";
642 return packet_error[error];
645 /* Return list of packet streams in the engine */
647 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
652 list = silc_dlist_init();
656 silc_mutex_lock(engine->lock);
657 silc_list_start(engine->streams);
658 while ((ps = silc_list_get(engine->streams))) {
659 silc_packet_stream_ref(ps);
660 silc_dlist_add(list, ps);
662 silc_mutex_unlock(engine->lock);
667 /* Free list returned by silc_packet_engine_get_streams */
669 void silc_packet_engine_free_streams_list(SilcDList streams)
673 silc_dlist_start(streams);
674 while ((ps = silc_dlist_get(streams)))
675 silc_packet_stream_unref(ps);
677 silc_dlist_uninit(streams);
680 /* Create new packet stream */
682 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
683 SilcSchedule schedule,
690 SILC_LOG_DEBUG(("Creating new packet stream"));
692 if (!engine || !stream)
695 ps = silc_calloc(1, sizeof(*ps));
700 silc_atomic_init8(&ps->refcnt, 1);
701 silc_mutex_alloc(&ps->lock);
703 /* Allocate out buffer */
704 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
706 silc_packet_stream_destroy(ps);
709 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
710 silc_buffer_reset(&ps->outbuf);
712 /* Initialize packet procesors list */
713 ps->process = silc_dlist_init();
715 silc_packet_stream_destroy(ps);
719 silc_mutex_lock(engine->lock);
721 /* Add per scheduler context */
722 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
724 ps->sc = silc_calloc(1, sizeof(*ps->sc));
726 silc_packet_stream_destroy(ps);
727 silc_mutex_unlock(engine->lock);
730 ps->sc->engine = engine;
731 ps->sc->schedule = schedule;
733 /* Allocate data input buffer */
734 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
738 silc_packet_stream_destroy(ps);
739 silc_mutex_unlock(engine->lock);
742 silc_buffer_reset(inbuf);
744 ps->sc->inbufs = silc_dlist_init();
745 if (!ps->sc->inbufs) {
746 silc_buffer_free(inbuf);
749 silc_packet_stream_destroy(ps);
750 silc_mutex_unlock(engine->lock);
753 silc_dlist_add(ps->sc->inbufs, inbuf);
755 /* Add to per scheduler context hash table */
756 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
757 silc_buffer_free(inbuf);
758 silc_dlist_del(ps->sc->inbufs, inbuf);
761 silc_packet_stream_destroy(ps);
762 silc_mutex_unlock(engine->lock);
766 ps->sc->stream_count++;
768 /* Add the packet stream to engine */
769 silc_list_add(engine->streams, ps);
771 /* If this is UDP stream, allocate UDP remote stream hash table */
772 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
773 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
774 silc_hash_string_compare, NULL,
775 silc_packet_engine_hash_destr,
778 silc_mutex_unlock(engine->lock);
780 /* Set IO notifier callback. This schedules this stream for I/O. */
781 if (!silc_stream_set_notifier(ps->stream, schedule,
782 silc_packet_stream_io, ps)) {
783 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
784 silc_packet_stream_destroy(ps);
791 /* Add new remote packet stream for UDP packet streams */
793 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
794 const char *remote_ip,
795 SilcUInt16 remote_port,
798 SilcPacketEngine engine = stream->sc->engine;
803 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
804 remote_ip, remote_port, stream));
806 if (!stream || !remote_ip || !remote_port)
809 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
810 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
814 ps = silc_calloc(1, sizeof(*ps));
819 silc_atomic_init8(&ps->refcnt, 1);
820 silc_mutex_alloc(&ps->lock);
822 /* Set the UDP packet stream as underlaying stream */
823 silc_packet_stream_ref(stream);
824 ps->stream = (SilcStream)stream;
827 /* Allocate out buffer */
828 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
830 silc_packet_stream_destroy(ps);
833 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
834 silc_buffer_reset(&ps->outbuf);
836 /* Initialize packet procesors list */
837 ps->process = silc_dlist_init();
839 silc_packet_stream_destroy(ps);
843 /* Add to engine with this IP and port pair */
844 tuple = silc_format("%d%s", remote_port, remote_ip);
845 silc_mutex_lock(engine->lock);
846 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
847 silc_mutex_unlock(engine->lock);
848 silc_packet_stream_destroy(ps);
851 silc_mutex_unlock(engine->lock);
853 /* Save remote IP and port pair */
854 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
855 if (!ps->remote_udp) {
856 silc_packet_stream_destroy(ps);
859 ps->remote_udp->remote_port = remote_port;
860 ps->remote_udp->remote_ip = strdup(remote_ip);
861 if (!ps->remote_udp->remote_ip) {
862 silc_packet_stream_destroy(ps);
867 /* Inject packet to the new stream */
869 silc_packet_stream_ref(ps);
870 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
871 silc_packet_stream_inject_packet, packet,
878 /* Destroy packet stream */
880 void silc_packet_stream_destroy(SilcPacketStream stream)
882 SilcPacketEngine engine;
887 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
888 stream->destroyed = TRUE;
890 /* Close the underlaying stream */
891 if (!stream->udp && stream->stream)
892 silc_stream_close(stream->stream);
896 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
899 /* Delete from engine */
900 engine = stream->sc->engine;
901 silc_mutex_lock(engine->lock);
902 silc_list_del(engine->streams, stream);
904 /* Remove per scheduler context, if it is not used anymore */
906 stream->sc->stream_count--;
907 if (!stream->sc->stream_count)
908 silc_hash_table_del(engine->contexts, stream->sc->schedule);
910 silc_mutex_unlock(engine->lock);
912 /* Destroy the underlaying stream */
914 silc_stream_destroy(stream->stream);
916 /* Delete from UDP remote hash table */
918 engine = stream->sc->engine;
919 silc_snprintf(tuple, sizeof(tuple), "%d%s",
920 stream->remote_udp->remote_port,
921 stream->remote_udp->remote_ip);
922 silc_mutex_lock(engine->lock);
923 silc_hash_table_del(engine->udp_remote, tuple);
924 silc_mutex_unlock(engine->lock);
926 silc_free(stream->remote_udp->remote_ip);
927 silc_free(stream->remote_udp);
929 /* Unreference the underlaying packet stream */
930 silc_packet_stream_unref((SilcPacketStream)stream->stream);
933 /* Clear and free buffers */
934 silc_buffer_clear(&stream->outbuf);
935 silc_buffer_purge(&stream->outbuf);
937 if (stream->process) {
939 silc_dlist_start(stream->process);
940 while ((p = silc_dlist_get(stream->process))) {
943 silc_dlist_del(stream->process, p);
945 silc_dlist_uninit(stream->process);
948 /* Destroy ciphers and HMACs */
949 if (stream->send_key[0])
950 silc_cipher_free(stream->send_key[0]);
951 if (stream->receive_key[0])
952 silc_cipher_free(stream->receive_key[0]);
953 if (stream->send_hmac[0])
954 silc_hmac_free(stream->send_hmac[0]);
955 if (stream->receive_hmac[0])
956 silc_hmac_free(stream->receive_hmac[0]);
957 if (stream->send_key[1])
958 silc_cipher_free(stream->send_key[1]);
959 if (stream->receive_key[1])
960 silc_cipher_free(stream->receive_key[1]);
961 if (stream->send_hmac[1])
962 silc_hmac_free(stream->send_hmac[1]);
963 if (stream->receive_hmac[1])
964 silc_hmac_free(stream->receive_hmac[1]);
967 silc_free(stream->src_id);
968 silc_free(stream->dst_id);
970 silc_atomic_uninit8(&stream->refcnt);
971 silc_mutex_free(stream->lock);
975 /* Return TRUE if the stream is valid */
977 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
979 return stream->destroyed == FALSE;
982 /* Marks as router stream */
984 void silc_packet_stream_set_router(SilcPacketStream stream)
986 stream->is_router = TRUE;
989 /* Mark to include IV in ciphertext */
991 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
993 stream->iv_included = TRUE;
996 /* Links `callbacks' to `stream' for specified packet types */
998 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
999 SilcPacketCallbacks *callbacks,
1000 void *callback_context,
1001 int priority, va_list ap)
1003 SilcPacketProcess p, e;
1004 SilcInt32 packet_type;
1007 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1011 if (!callbacks->packet_receive)
1014 p = silc_calloc(1, sizeof(*p));
1018 p->priority = priority;
1019 p->callbacks = callbacks;
1020 p->callback_context = callback_context;
1022 silc_mutex_lock(stream->lock);
1024 if (!stream->process) {
1025 stream->process = silc_dlist_init();
1026 if (!stream->process) {
1027 silc_mutex_unlock(stream->lock);
1032 /* According to priority set the procesor to correct position. First
1033 entry has the highest priority */
1034 silc_dlist_start(stream->process);
1035 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1036 if (p->priority > e->priority) {
1037 silc_dlist_insert(stream->process, p);
1042 silc_dlist_add(stream->process, p);
1044 /* Get packet types to process */
1047 packet_type = va_arg(ap, SilcInt32);
1049 if (packet_type == SILC_PACKET_ANY)
1052 if (packet_type == -1)
1055 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1057 silc_mutex_unlock(stream->lock);
1061 p->types[i - 1] = (SilcPacketType)packet_type;
1065 p->types[i - 1] = 0;
1067 silc_mutex_unlock(stream->lock);
1069 silc_packet_stream_ref(stream);
1074 /* Links `callbacks' to `stream' for specified packet types */
1076 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1077 SilcPacketCallbacks *callbacks,
1078 void *callback_context,
1084 va_start(ap, priority);
1085 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1092 /* Unlinks `callbacks' from `stream'. */
1094 void silc_packet_stream_unlink(SilcPacketStream stream,
1095 SilcPacketCallbacks *callbacks,
1096 void *callback_context)
1098 SilcPacketProcess p;
1100 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1101 callbacks, stream));
1103 silc_mutex_lock(stream->lock);
1105 silc_dlist_start(stream->process);
1106 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1107 if (p->callbacks == callbacks &&
1108 p->callback_context == callback_context) {
1109 silc_dlist_del(stream->process, p);
1110 silc_free(p->types);
1115 if (!silc_dlist_count(stream->process)) {
1116 silc_dlist_uninit(stream->process);
1117 stream->process = NULL;
1120 silc_mutex_unlock(stream->lock);
1122 silc_packet_stream_unref(stream);
1125 /* Returns TRUE if stream is UDP stream */
1127 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1129 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1132 /* Return packet sender IP and port for UDP packet stream */
1134 SilcBool silc_packet_get_sender(SilcPacket packet,
1135 const char **sender_ip,
1136 SilcUInt16 *sender_port)
1138 if (!packet->stream->remote_udp)
1141 *sender_ip = packet->stream->remote_udp->remote_ip;
1142 *sender_port = packet->stream->remote_udp->remote_port;
1147 /* Reference packet stream */
1149 void silc_packet_stream_ref(SilcPacketStream stream)
1151 silc_atomic_add_int8(&stream->refcnt, 1);
1152 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1153 silc_atomic_get_int8(&stream->refcnt) - 1,
1154 silc_atomic_get_int8(&stream->refcnt)));
1157 /* Unreference packet stream */
1159 void silc_packet_stream_unref(SilcPacketStream stream)
1161 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1162 silc_atomic_get_int8(&stream->refcnt),
1163 silc_atomic_get_int8(&stream->refcnt) - 1));
1164 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1166 silc_atomic_add_int8(&stream->refcnt, 1);
1167 silc_packet_stream_destroy(stream);
1172 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1174 return stream->sc->engine;
1177 /* Set application context for packet stream */
1179 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1181 silc_mutex_lock(stream->lock);
1182 stream->stream_context = stream_context;
1183 silc_mutex_unlock(stream->lock);
1186 /* Return application context from packet stream */
1188 void *silc_packet_get_context(SilcPacketStream stream)
1191 silc_mutex_lock(stream->lock);
1192 context = stream->stream_context;
1193 silc_mutex_unlock(stream->lock);
1197 /* Change underlaying stream */
1199 void silc_packet_stream_set_stream(SilcPacketStream ps,
1203 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1204 ps->stream = stream;
1205 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1209 /* Return underlaying stream */
1211 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1213 return stream->stream;
1218 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1219 SilcCipher receive_key, SilcHmac send_hmac,
1220 SilcHmac receive_hmac, SilcBool rekey)
1222 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1224 /* If doing rekey, send REKEY_DONE packet */
1226 /* This will take stream lock. */
1227 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1228 stream->src_id_type, stream->src_id,
1229 stream->src_id_len, stream->dst_id_type,
1230 stream->dst_id, stream->dst_id_len,
1231 NULL, 0, stream->send_key[0],
1232 stream->send_hmac[0]))
1235 /* Write the packet to the stream */
1236 if (!silc_packet_stream_write(stream, TRUE))
1239 silc_mutex_lock(stream->lock);
1242 /* In case IV Included is set, save the old keys */
1243 if (stream->iv_included) {
1244 if (stream->send_key[1] && send_key) {
1245 silc_cipher_free(stream->send_key[1]);
1246 stream->send_key[1] = stream->send_key[0];
1248 if (stream->receive_key[1] && receive_key) {
1249 silc_cipher_free(stream->receive_key[1]);
1250 stream->receive_key[1] = stream->receive_key[0];
1252 if (stream->send_hmac[1] && send_hmac) {
1253 silc_hmac_free(stream->send_hmac[1]);
1254 stream->send_hmac[1] = stream->send_hmac[0];
1256 if (stream->receive_hmac[1] && receive_hmac) {
1257 silc_hmac_free(stream->receive_hmac[1]);
1258 stream->receive_hmac[1] = stream->receive_hmac[0];
1261 if (stream->send_key[0] && send_key)
1262 silc_cipher_free(stream->send_key[0]);
1263 if (stream->receive_key[0] && receive_key)
1264 silc_cipher_free(stream->receive_key[0]);
1265 if (stream->send_hmac[0] && send_hmac)
1266 silc_hmac_free(stream->send_hmac[0]);
1267 if (stream->receive_hmac[0] && receive_hmac)
1268 silc_hmac_free(stream->receive_hmac[0]);
1273 stream->send_key[0] = send_key;
1275 stream->receive_key[0] = receive_key;
1277 stream->send_hmac[0] = send_hmac;
1279 stream->receive_hmac[0] = receive_hmac;
1281 silc_mutex_unlock(stream->lock);
1285 /* Return current ciphers from packet stream */
1287 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1288 SilcCipher *send_key,
1289 SilcCipher *receive_key,
1290 SilcHmac *send_hmac,
1291 SilcHmac *receive_hmac)
1293 if (!stream->send_key[0] && !stream->receive_key[0] &&
1294 !stream->send_hmac[0] && !stream->receive_hmac[0])
1297 silc_mutex_lock(stream->lock);
1300 *send_key = stream->send_key[0];
1302 *receive_key = stream->receive_key[0];
1304 *send_hmac = stream->send_hmac[0];
1306 *receive_hmac = stream->receive_hmac[0];
1308 silc_mutex_unlock(stream->lock);
1313 /* Set SILC IDs to packet stream */
1315 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1316 SilcIdType src_id_type, const void *src_id,
1317 SilcIdType dst_id_type, const void *dst_id)
1320 unsigned char tmp[32];
1322 if (!src_id && !dst_id)
1325 silc_mutex_lock(stream->lock);
1328 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1330 silc_free(stream->src_id);
1331 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1332 silc_mutex_unlock(stream->lock);
1335 stream->src_id = silc_memdup(tmp, len);
1336 if (!stream->src_id) {
1337 silc_mutex_unlock(stream->lock);
1340 stream->src_id_type = src_id_type;
1341 stream->src_id_len = len;
1345 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1347 silc_free(stream->dst_id);
1348 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1349 silc_mutex_unlock(stream->lock);
1352 stream->dst_id = silc_memdup(tmp, len);
1353 if (!stream->dst_id) {
1354 silc_mutex_unlock(stream->lock);
1357 stream->dst_id_type = dst_id_type;
1358 stream->dst_id_len = len;
1361 silc_mutex_unlock(stream->lock);
1366 /* Return IDs from the packet stream */
1368 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1369 SilcBool *src_id_set, SilcID *src_id,
1370 SilcBool *dst_id_set, SilcID *dst_id)
1372 if (src_id && stream->src_id)
1373 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1374 stream->src_id_type, src_id))
1377 if (stream->src_id && src_id_set)
1380 if (dst_id && stream->dst_id)
1381 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1382 stream->dst_id_type, dst_id))
1385 if (stream->dst_id && dst_id_set)
1391 /* Adds Security ID (SID) */
1393 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1395 if (!stream->iv_included)
1398 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1406 void silc_packet_free(SilcPacket packet)
1408 SilcPacketStream stream = packet->stream;
1410 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1412 /* Check for double free */
1413 SILC_ASSERT(packet->stream != NULL);
1415 packet->stream = NULL;
1416 packet->src_id = packet->dst_id = NULL;
1417 silc_buffer_reset(&packet->buffer);
1419 silc_mutex_lock(stream->sc->engine->lock);
1421 /* Put the packet back to freelist */
1422 silc_list_add(stream->sc->engine->packet_pool, packet);
1423 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1424 silc_list_start(stream->sc->engine->packet_pool);
1426 silc_mutex_unlock(stream->sc->engine->lock);
1429 /****************************** Packet Sending ******************************/
1431 /* Prepare outgoing data buffer for packet sending. Returns the
1432 pointer to that buffer into the `packet'. */
1434 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1439 unsigned char *oldptr;
1440 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1444 /* Allocate more space if needed */
1445 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1446 if (!silc_buffer_realloc(&stream->outbuf,
1447 silc_buffer_truelen(&stream->outbuf) + totlen))
1451 /* Pull data area for the new packet, and return pointer to the start of
1452 the data area and save the pointer in to the `packet'. MAC is pulled
1453 later after it's computed. */
1454 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1455 silc_buffer_set(packet, oldptr, totlen);
1456 silc_buffer_push_tail(packet, mac_len);
1461 /* Increments counter when encrypting in counter mode. */
1463 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1465 unsigned char *ret_iv)
1467 unsigned char *iv = silc_cipher_get_iv(cipher);
1468 SilcUInt32 pc1, pc2;
1470 /* Increment 64-bit packet counter */
1471 SILC_GET32_MSB(pc1, iv + 4);
1472 SILC_GET32_MSB(pc2, iv + 8);
1475 SILC_PUT32_MSB(pc1, iv + 4);
1476 SILC_PUT32_MSB(pc2, iv + 8);
1478 /* Reset block counter */
1479 memset(iv + 12, 0, 4);
1481 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1482 if (stream->iv_included) {
1484 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1485 ret_iv[1] = ret_iv[0] + iv[4];
1486 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1487 ret_iv[3] = ret_iv[0] + ret_iv[2];
1488 SILC_PUT32_MSB(pc2, ret_iv + 4);
1489 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1491 /* Set new nonce to counter block */
1492 memcpy(iv + 4, ret_iv, 4);
1495 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1498 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1499 the packet. The silc_packet_stream_write needs to be called to send it
1500 after this returns TRUE. */
1502 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1503 SilcPacketType type,
1504 SilcPacketFlags flags,
1505 SilcIdType src_id_type,
1506 unsigned char *src_id,
1507 SilcUInt32 src_id_len,
1508 SilcIdType dst_id_type,
1509 unsigned char *dst_id,
1510 SilcUInt32 dst_id_len,
1511 const unsigned char *data,
1512 SilcUInt32 data_len,
1516 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1517 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1518 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1520 SilcBufferStruct packet;
1522 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1523 "data len %d", silc_get_packet_name(type), stream->send_psn,
1524 flags, src_id_type, dst_id_type, data_len));
1526 /* Get the true length of the packet. This is saved as payload length
1527 into the packet header. This does not include the length of the
1529 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1530 src_id_len + dst_id_len));
1531 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1532 src_id_len + dst_id_len);
1534 /* If using CTR mode, increment the counter */
1535 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1537 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1539 /* If IV is included, the SID, IV and sequence number is added to packet */
1540 if (stream->iv_included && cipher) {
1541 psnlen = sizeof(psn);
1543 iv[0] = stream->sid;
1546 /* If IV is included, the SID, IV and sequence number is added to packet */
1547 if (stream->iv_included && cipher) {
1548 psnlen = sizeof(psn);
1549 ivlen = block_len + 1;
1550 iv[0] = stream->sid;
1551 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1555 /* We automatically figure out the packet structure from the packet
1556 type and flags, and calculate correct length. Private messages with
1557 private keys and channel messages are special packets as their
1558 payload is encrypted already. */
1559 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1560 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
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 +
1570 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1571 if (stream->sc->engine->local_is_router && stream->is_router) {
1572 /* Channel messages between routers are encrypted as normal packets.
1573 Padding is calculated from true length of the packet. */
1575 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1577 enclen += padlen + psnlen;
1579 /* Padding is calculated from header + IDs */
1581 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1582 psnlen), block_len, padlen);
1584 /* Length to encrypt, header + IDs + padding. */
1585 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1589 /* Padding is calculated from true length of the packet */
1590 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1591 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1593 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1595 enclen += padlen + psnlen;
1598 /* Remove implementation specific flags */
1599 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1601 /* Get random padding */
1602 for (i = 0; i < padlen; i++) tmppad[i] =
1603 silc_rng_get_byte_fast(stream->sc->engine->rng);
1605 silc_mutex_lock(stream->lock);
1607 /* Get packet pointer from the outgoing buffer */
1608 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1609 + psnlen, hmac, &packet))) {
1610 silc_mutex_unlock(stream->lock);
1614 SILC_PUT32_MSB(stream->send_psn, psn);
1616 /* Create the packet. This creates the SILC header, adds padding, and
1617 the actual packet data. */
1618 i = silc_buffer_format(&packet,
1619 SILC_STR_DATA(iv, ivlen),
1620 SILC_STR_DATA(psn, psnlen),
1621 SILC_STR_UI_SHORT(truelen),
1622 SILC_STR_UI_CHAR(flags),
1623 SILC_STR_UI_CHAR(type),
1624 SILC_STR_UI_CHAR(padlen),
1625 SILC_STR_UI_CHAR(0),
1626 SILC_STR_UI_CHAR(src_id_len),
1627 SILC_STR_UI_CHAR(dst_id_len),
1628 SILC_STR_UI_CHAR(src_id_type),
1629 SILC_STR_DATA(src_id, src_id_len),
1630 SILC_STR_UI_CHAR(dst_id_type),
1631 SILC_STR_DATA(dst_id, dst_id_len),
1632 SILC_STR_DATA(tmppad, padlen),
1633 SILC_STR_DATA(data, data_len),
1635 if (silc_unlikely(i < 0)) {
1636 silc_mutex_unlock(stream->lock);
1640 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1641 silc_buffer_data(&packet), silc_buffer_len(&packet));
1643 /* Encrypt the packet */
1644 if (silc_likely(cipher)) {
1645 SILC_LOG_DEBUG(("Encrypting packet"));
1646 silc_cipher_set_iv(cipher, NULL);
1647 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1648 packet.data + ivlen, enclen,
1650 SILC_LOG_ERROR(("Packet encryption failed"));
1651 silc_mutex_unlock(stream->lock);
1657 if (silc_likely(hmac)) {
1660 /* MAC is computed from the entire encrypted packet data, and put
1661 to the end of the packet. */
1662 silc_hmac_init(hmac);
1663 silc_hmac_update(hmac, psn, sizeof(psn));
1664 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1665 silc_hmac_final(hmac, packet.tail, &mac_len);
1666 silc_buffer_pull_tail(&packet, mac_len);
1673 /* Sends a packet */
1675 SilcBool silc_packet_send(SilcPacketStream stream,
1676 SilcPacketType type, SilcPacketFlags flags,
1677 const unsigned char *data, SilcUInt32 data_len)
1681 ret = silc_packet_send_raw(stream, type, flags,
1682 stream->src_id_type,
1685 stream->dst_id_type,
1689 stream->send_key[0],
1690 stream->send_hmac[0]);
1692 /* Write the packet to the stream */
1693 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1696 /* Sends a packet, extended routine */
1698 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1699 SilcPacketType type, SilcPacketFlags flags,
1700 SilcIdType src_id_type, void *src_id,
1701 SilcIdType dst_id_type, void *dst_id,
1702 const unsigned char *data, SilcUInt32 data_len,
1703 SilcCipher cipher, SilcHmac hmac)
1705 unsigned char src_id_data[32], dst_id_data[32];
1706 SilcUInt32 src_id_len, dst_id_len;
1710 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1711 sizeof(src_id_data), &src_id_len))
1714 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1715 sizeof(dst_id_data), &dst_id_len))
1718 ret = silc_packet_send_raw(stream, type, flags,
1719 src_id ? src_id_type : stream->src_id_type,
1720 src_id ? src_id_data : stream->src_id,
1721 src_id ? src_id_len : stream->src_id_len,
1722 dst_id ? dst_id_type : stream->dst_id_type,
1723 dst_id ? dst_id_data : stream->dst_id,
1724 dst_id ? dst_id_len : stream->dst_id_len,
1726 cipher ? cipher : stream->send_key[0],
1727 hmac ? hmac : stream->send_hmac[0]);
1729 /* Write the packet to the stream */
1730 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1733 /* Sends packet after formatting the arguments to buffer */
1735 SilcBool silc_packet_send_va(SilcPacketStream stream,
1736 SilcPacketType type, SilcPacketFlags flags, ...)
1738 SilcBufferStruct buf;
1742 va_start(va, flags);
1744 memset(&buf, 0, sizeof(buf));
1745 if (silc_buffer_format_vp(&buf, va) < 0) {
1750 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1751 silc_buffer_len(&buf));
1753 silc_buffer_purge(&buf);
1759 /* Sends packet after formatting the arguments to buffer, extended routine */
1761 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1762 SilcPacketType type, SilcPacketFlags flags,
1763 SilcIdType src_id_type, void *src_id,
1764 SilcIdType dst_id_type, void *dst_id,
1765 SilcCipher cipher, SilcHmac hmac, ...)
1767 SilcBufferStruct buf;
1773 memset(&buf, 0, sizeof(buf));
1774 if (silc_buffer_format_vp(&buf, va) < 0) {
1779 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1780 dst_id_type, dst_id, silc_buffer_data(&buf),
1781 silc_buffer_len(&buf), cipher, hmac);
1783 silc_buffer_purge(&buf);
1789 /***************************** Packet Receiving *****************************/
1791 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1793 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1794 const unsigned char *data,
1795 SilcUInt32 data_len,
1796 const unsigned char *packet_mac,
1797 const unsigned char *packet_seq,
1798 SilcUInt32 sequence)
1801 if (silc_likely(hmac)) {
1802 unsigned char mac[32], psn[4];
1805 SILC_LOG_DEBUG(("Verifying MAC"));
1807 /* Compute HMAC of packet */
1808 silc_hmac_init(hmac);
1811 SILC_PUT32_MSB(sequence, psn);
1812 silc_hmac_update(hmac, psn, 4);
1814 silc_hmac_update(hmac, packet_seq, 4);
1816 silc_hmac_update(hmac, data, data_len);
1817 silc_hmac_final(hmac, mac, &mac_len);
1819 /* Compare the MAC's */
1820 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1821 SILC_LOG_DEBUG(("MAC failed"));
1825 SILC_LOG_DEBUG(("MAC is Ok"));
1831 /* Increments/sets counter when decrypting in counter mode. */
1833 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1835 unsigned char *packet_iv)
1837 SilcUInt32 pc1, pc2;
1839 /* If IV Included flag, set the IV from packet to block counter. */
1840 if (stream->iv_included) {
1841 memcpy(iv + 4, packet_iv, 8);
1843 /* Increment 64-bit packet counter. */
1844 SILC_GET32_MSB(pc1, iv + 4);
1845 SILC_GET32_MSB(pc2, iv + 8);
1848 SILC_PUT32_MSB(pc1, iv + 4);
1849 SILC_PUT32_MSB(pc2, iv + 8);
1852 /* Reset block counter */
1853 memset(iv + 12, 0, 4);
1855 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1858 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1859 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1861 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1862 SilcUInt32 sequence, SilcBuffer buffer,
1865 if (normal == TRUE) {
1866 if (silc_likely(cipher)) {
1867 /* Decrypt rest of the packet */
1868 SILC_LOG_DEBUG(("Decrypting the packet"));
1869 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1871 silc_buffer_len(buffer), NULL)))
1877 /* Decrypt rest of the header plus padding */
1878 if (silc_likely(cipher)) {
1880 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1882 SILC_LOG_DEBUG(("Decrypting the header"));
1884 /* Padding length + src id len + dst id len + header length - 16
1885 bytes already decrypted, gives the rest of the encrypted packet */
1886 silc_buffer_push(buffer, block_len);
1887 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1888 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1890 silc_buffer_pull(buffer, block_len);
1892 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1893 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1897 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1898 buffer->data, len, NULL)))
1906 /* Parses the packet. This is called when a whole packet is ready to be
1907 parsed. The buffer sent must be already decrypted before calling this
1910 static inline SilcBool silc_packet_parse(SilcPacket packet)
1912 SilcBuffer buffer = &packet->buffer;
1913 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1914 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1917 SILC_LOG_DEBUG(("Parsing incoming packet"));
1919 /* Parse the buffer. This parses the SILC header of the packet. */
1920 ret = silc_buffer_unformat(buffer,
1923 SILC_STR_UI_CHAR(&src_id_len),
1924 SILC_STR_UI_CHAR(&dst_id_len),
1925 SILC_STR_UI_CHAR(&src_id_type),
1927 if (silc_unlikely(ret == -1)) {
1928 if (!packet->stream->udp &&
1929 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1930 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1934 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1935 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1936 if (!packet->stream->udp &&
1937 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1938 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1939 packet->src_id_len, packet->dst_id_len));
1943 ret = silc_buffer_unformat(buffer,
1945 SILC_STR_DATA(&packet->src_id, src_id_len),
1946 SILC_STR_UI_CHAR(&dst_id_type),
1947 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1948 SILC_STR_OFFSET(padlen),
1950 if (silc_unlikely(ret == -1)) {
1951 if (!packet->stream->udp &&
1952 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1953 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1957 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1958 dst_id_type > SILC_ID_CHANNEL)) {
1959 if (!packet->stream->udp &&
1960 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1961 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1962 src_id_type, dst_id_type));
1966 packet->src_id_len = src_id_len;
1967 packet->dst_id_len = dst_id_len;
1968 packet->src_id_type = src_id_type;
1969 packet->dst_id_type = dst_id_type;
1971 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1972 silc_buffer_len(buffer)), buffer->head,
1973 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1975 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1976 silc_get_packet_name(packet->type)));
1981 /* Dispatch packet to application. Called with stream->lock locked.
1982 Returns FALSE if the stream was destroyed while dispatching a packet. */
1984 static SilcBool silc_packet_dispatch(SilcPacket packet)
1986 SilcPacketStream stream = packet->stream;
1987 SilcPacketProcess p;
1988 SilcBool default_sent = FALSE;
1991 /* Dispatch packet to all packet processors that want it */
1993 if (silc_likely(!stream->process)) {
1994 /* Send to default processor as no others exist */
1995 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1996 silc_mutex_unlock(stream->lock);
1997 if (silc_unlikely(!stream->sc->engine->callbacks->
1998 packet_receive(stream->sc->engine, stream, packet,
1999 stream->sc->engine->callback_context,
2000 stream->stream_context)))
2001 silc_packet_free(packet);
2002 silc_mutex_lock(stream->lock);
2003 return stream->destroyed == FALSE;
2006 silc_dlist_start(stream->process);
2007 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2009 /* If priority is 0 or less, we send to default processor first
2010 because default processor has 0 priority */
2011 if (!default_sent && p->priority <= 0) {
2012 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2013 default_sent = TRUE;
2014 silc_mutex_unlock(stream->lock);
2015 if (stream->sc->engine->callbacks->
2016 packet_receive(stream->sc->engine, stream, packet,
2017 stream->sc->engine->callback_context,
2018 stream->stream_context)) {
2019 silc_mutex_lock(stream->lock);
2020 return stream->destroyed == FALSE;
2022 silc_mutex_lock(stream->lock);
2025 /* Send to processor */
2027 /* Send all packet types */
2028 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2029 silc_mutex_unlock(stream->lock);
2030 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2031 p->callback_context,
2032 stream->stream_context)) {
2033 silc_mutex_lock(stream->lock);
2034 return stream->destroyed == FALSE;
2036 silc_mutex_lock(stream->lock);
2038 /* Send specific types */
2039 for (pt = p->types; *pt; pt++) {
2040 if (*pt != packet->type)
2042 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2043 silc_mutex_unlock(stream->lock);
2044 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2045 p->callback_context,
2046 stream->stream_context)) {
2047 silc_mutex_lock(stream->lock);
2048 return stream->destroyed == FALSE;
2050 silc_mutex_lock(stream->lock);
2056 if (!default_sent) {
2057 /* Send to default processor as it has not been sent yet */
2058 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2059 silc_mutex_unlock(stream->lock);
2060 if (stream->sc->engine->callbacks->
2061 packet_receive(stream->sc->engine, stream, packet,
2062 stream->sc->engine->callback_context,
2063 stream->stream_context)) {
2064 silc_mutex_lock(stream->lock);
2065 return stream->destroyed == FALSE;
2067 silc_mutex_lock(stream->lock);
2070 /* If we got here, no one wanted the packet, so drop it */
2071 silc_packet_free(packet);
2072 return stream->destroyed == FALSE;
2075 /* Process incoming data and parse packets. Called with stream->lock
2078 static void silc_packet_read_process(SilcPacketStream stream)
2085 SilcUInt16 packetlen;
2086 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2087 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2088 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2092 /* Get inbuf. If there is already some data for this stream in the buffer
2093 we already have it. Otherwise get the current one from list, it will
2094 include the data. */
2095 inbuf = stream->inbuf;
2097 silc_dlist_start(stream->sc->inbufs);
2098 inbuf = silc_dlist_get(stream->sc->inbufs);
2101 /* Parse the packets from the data */
2102 while (silc_buffer_len(inbuf) > 0) {
2104 cipher = stream->receive_key[0];
2105 hmac = stream->receive_hmac[0];
2108 if (silc_unlikely(silc_buffer_len(inbuf) <
2109 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2110 SILC_PACKET_MIN_HEADER_LEN))) {
2111 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2112 silc_dlist_del(stream->sc->inbufs, inbuf);
2113 stream->inbuf = inbuf;
2117 if (silc_likely(hmac))
2118 mac_len = silc_hmac_len(hmac);
2122 /* Decrypt first block of the packet to get the length field out */
2123 if (silc_likely(cipher)) {
2124 block_len = silc_cipher_get_block_len(cipher);
2126 if (stream->iv_included) {
2127 /* SID, IV and sequence number is included in the ciphertext */
2128 sid = (SilcUInt8)inbuf->data[0];
2130 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2131 /* Set the CTR mode IV from packet to counter block */
2132 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2133 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2136 /* Get IV from packet */
2137 memcpy(iv, inbuf->data + 1, block_len);
2138 ivlen = block_len + 1;
2142 /* Check SID, and get correct decryption key */
2143 if (sid != stream->sid) {
2144 /* If SID is recent get the previous key and use it */
2145 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2146 stream->receive_key[1] && !stream->receive_hmac[1]) {
2147 cipher = stream->receive_key[1];
2148 hmac = stream->receive_hmac[1];
2150 /* The SID is unknown, drop rest of the data in buffer */
2151 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2153 silc_mutex_unlock(stream->lock);
2154 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2155 silc_mutex_lock(stream->lock);
2160 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2162 /* If using CTR mode, increment the counter */
2163 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2164 silc_packet_receive_ctr_increment(stream, iv, NULL);
2167 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2168 silc_cipher_set_iv(cipher, NULL);
2169 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2172 if (stream->iv_included) {
2173 /* Take sequence number from packet */
2174 packet_seq = header;
2178 /* Unencrypted packet */
2179 block_len = SILC_PACKET_MIN_HEADER_LEN;
2180 header = inbuf->data;
2183 /* Get packet length and full packet length with padding */
2184 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2187 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2188 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2189 SILC_LOG_ERROR(("Received too short packet"));
2190 silc_mutex_unlock(stream->lock);
2191 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2192 silc_mutex_lock(stream->lock);
2193 memset(tmp, 0, sizeof(tmp));
2197 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2198 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2200 paddedlen + mac_len - silc_buffer_len(inbuf)));
2201 memset(tmp, 0, sizeof(tmp));
2202 silc_dlist_del(stream->sc->inbufs, inbuf);
2203 stream->inbuf = inbuf;
2207 /* Check MAC of the packet */
2208 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2210 inbuf->data + ivlen +
2211 paddedlen, packet_seq,
2212 stream->receive_psn))) {
2213 silc_mutex_unlock(stream->lock);
2214 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2215 silc_mutex_lock(stream->lock);
2216 memset(tmp, 0, sizeof(tmp));
2221 packet = silc_packet_alloc(stream->sc->engine);
2222 if (silc_unlikely(!packet)) {
2223 silc_mutex_unlock(stream->lock);
2224 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2225 silc_mutex_lock(stream->lock);
2226 memset(tmp, 0, sizeof(tmp));
2229 packet->stream = stream;
2231 /* Allocate more space to packet buffer, if needed */
2232 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2233 if (!silc_buffer_realloc(&packet->buffer,
2234 silc_buffer_truelen(&packet->buffer) +
2236 silc_buffer_truelen(&packet->buffer)))) {
2237 silc_mutex_unlock(stream->lock);
2238 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2239 silc_mutex_lock(stream->lock);
2240 silc_packet_free(packet);
2241 memset(tmp, 0, sizeof(tmp));
2246 /* Parse packet header */
2247 packet->flags = (SilcPacketFlags)header[2];
2248 packet->type = (SilcPacketType)header[3];
2250 if (stream->sc->engine->local_is_router) {
2251 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2252 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2254 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2255 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2256 stream->is_router == TRUE))
2259 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2260 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2262 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2266 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2267 stream->receive_psn, paddedlen + ivlen + mac_len),
2268 inbuf->data, paddedlen + ivlen + mac_len);
2270 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2271 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2272 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2273 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2274 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2275 psnlen + (block_len - psnlen)),
2276 paddedlen - ivlen - psnlen - (block_len - psnlen));
2277 if (silc_likely(cipher)) {
2278 silc_cipher_set_iv(cipher, iv);
2279 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2280 &packet->buffer, normal);
2281 if (silc_unlikely(ret < 0)) {
2282 silc_mutex_unlock(stream->lock);
2283 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2284 silc_mutex_lock(stream->lock);
2285 silc_packet_free(packet);
2286 memset(tmp, 0, sizeof(tmp));
2290 stream->receive_psn++;
2292 silc_buffer_push(&packet->buffer, block_len);
2294 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2295 silc_buffer_pull(inbuf, paddedlen + mac_len);
2297 /* Parse the packet */
2298 if (silc_unlikely(!silc_packet_parse(packet))) {
2299 silc_mutex_unlock(stream->lock);
2300 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2301 silc_mutex_lock(stream->lock);
2302 silc_packet_free(packet);
2303 memset(tmp, 0, sizeof(tmp));
2307 /* Dispatch the packet to application */
2308 if (!silc_packet_dispatch(packet))
2313 /* Add inbuf back to free list, if we owned it. */
2314 if (stream->inbuf) {
2315 silc_dlist_add(stream->sc->inbufs, inbuf);
2316 stream->inbuf = NULL;
2319 silc_buffer_reset(inbuf);
2322 /****************************** Packet Waiting ******************************/
2324 /* Packet wait receive callback */
2326 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2327 SilcPacketStream stream,
2329 void *callback_context,
2330 void *stream_context);
2332 /* Packet waiting callbacks */
2333 static SilcPacketCallbacks silc_packet_wait_cbs =
2335 silc_packet_wait_packet_receive, NULL, NULL
2338 /* Packet waiting context */
2340 SilcMutex wait_lock;
2342 SilcList packet_queue;
2343 unsigned char id[28];
2344 unsigned int id_type : 2;
2345 unsigned int id_len : 5;
2346 unsigned int stopped : 1;
2349 /* Packet wait receive callback */
2352 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2353 SilcPacketStream stream,
2355 void *callback_context,
2356 void *stream_context)
2358 SilcPacketWait pw = callback_context;
2360 /* If source ID is specified check for it */
2362 if (pw->id_type != packet->src_id_type ||
2363 memcmp(pw->id, packet->src_id, pw->id_len))
2367 /* Signal the waiting thread for a new packet */
2368 silc_mutex_lock(pw->wait_lock);
2370 if (silc_unlikely(pw->stopped)) {
2371 silc_mutex_unlock(pw->wait_lock);
2375 silc_list_add(pw->packet_queue, packet);
2376 silc_cond_broadcast(pw->wait_cond);
2378 silc_mutex_unlock(pw->wait_lock);
2383 /* Initialize packet waiting */
2385 void *silc_packet_wait_init(SilcPacketStream stream,
2386 const SilcID *source_id, ...)
2392 pw = silc_calloc(1, sizeof(*pw));
2396 /* Allocate mutex and conditional variable */
2397 if (!silc_mutex_alloc(&pw->wait_lock)) {
2401 if (!silc_cond_alloc(&pw->wait_cond)) {
2402 silc_mutex_free(pw->wait_lock);
2407 /* Link to the packet stream for the requested packet types */
2408 va_start(ap, source_id);
2409 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2413 silc_cond_free(pw->wait_cond);
2414 silc_mutex_free(pw->wait_lock);
2419 /* Initialize packet queue */
2420 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2424 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2425 sizeof(pw->id), &id_len);
2426 pw->id_type = source_id->type;
2427 pw->id_len = id_len;
2433 /* Uninitialize packet waiting */
2435 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2437 SilcPacketWait pw = waiter;
2440 /* Signal any threads to stop waiting */
2441 silc_mutex_lock(pw->wait_lock);
2443 silc_cond_broadcast(pw->wait_cond);
2444 silc_mutex_unlock(pw->wait_lock);
2445 silc_thread_yield();
2447 /* Re-acquire lock and free resources */
2448 silc_mutex_lock(pw->wait_lock);
2449 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2451 /* Free any remaining packets */
2452 silc_list_start(pw->packet_queue);
2453 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2454 silc_packet_free(packet);
2456 silc_mutex_unlock(pw->wait_lock);
2457 silc_cond_free(pw->wait_cond);
2458 silc_mutex_free(pw->wait_lock);
2462 /* Blocks thread until a packet has been received. */
2464 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2466 SilcPacketWait pw = waiter;
2467 SilcBool ret = FALSE;
2469 silc_mutex_lock(pw->wait_lock);
2471 /* Wait here until packet has arrived */
2472 while (silc_list_count(pw->packet_queue) == 0) {
2473 if (silc_unlikely(pw->stopped)) {
2474 silc_mutex_unlock(pw->wait_lock);
2477 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2481 silc_list_start(pw->packet_queue);
2482 *return_packet = silc_list_get(pw->packet_queue);
2483 silc_list_del(pw->packet_queue, *return_packet);
2485 silc_mutex_unlock(pw->wait_lock);
2487 return ret == TRUE ? 1 : 0;
2490 /************************** Packet Stream Wrapper ***************************/
2492 /* Packet stream wrapper receive callback */
2494 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2495 SilcPacketStream stream,
2497 void *callback_context,
2498 void *stream_context);
2500 const SilcStreamOps silc_packet_stream_ops;
2502 /* Packet stream wrapper context */
2504 const SilcStreamOps *ops;
2505 SilcPacketStream stream;
2507 void *waiter; /* Waiter context in blocking mode */
2508 SilcPacketWrapCoder coder;
2509 void *coder_context;
2511 SilcStreamNotifier callback;
2514 SilcPacketType type;
2515 SilcPacketFlags flags;
2516 unsigned int closed : 1;
2517 unsigned int blocking : 1;
2518 unsigned int read_more : 1;
2519 } *SilcPacketWrapperStream;
2521 /* Packet wrapper callbacks */
2522 static SilcPacketCallbacks silc_packet_wrap_cbs =
2524 silc_packet_wrap_packet_receive, NULL, NULL
2527 /* Packet stream wrapper receive callback, non-blocking mode */
2530 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2531 SilcPacketStream stream,
2533 void *callback_context,
2534 void *stream_context)
2536 SilcPacketWrapperStream pws = callback_context;
2538 if (pws->closed || !pws->callback)
2541 silc_mutex_lock(pws->lock);
2542 silc_list_add(pws->in_queue, packet);
2543 silc_mutex_unlock(pws->lock);
2545 /* Call notifier callback */
2546 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2551 /* Task callback to notify more data is available for reading */
2553 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2555 SilcPacketWrapperStream pws = context;
2557 if (pws->closed || !pws->callback)
2560 /* Call notifier callback */
2561 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2564 /* Read SILC packet */
2566 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2569 SilcPacketWrapperStream pws = stream;
2571 SilcBool read_more = FALSE;
2577 if (pws->blocking) {
2578 /* Block until packet is received */
2579 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2584 /* Non-blocking mode */
2585 silc_mutex_lock(pws->lock);
2586 if (!silc_list_count(pws->in_queue)) {
2587 silc_mutex_unlock(pws->lock);
2591 silc_list_start(pws->in_queue);
2592 packet = silc_list_get(pws->in_queue);
2593 silc_list_del(pws->in_queue, packet);
2594 silc_mutex_unlock(pws->lock);
2597 /* Call decoder if set */
2598 if (pws->coder && !pws->read_more)
2599 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2600 pws->coder_context);
2602 len = silc_buffer_len(&packet->buffer);
2603 if (len > buf_len) {
2609 memcpy(buf, packet->buffer.data, len);
2611 if (read_more && !pws->blocking) {
2612 /* More data will be available (in blocking mode not supported). */
2613 silc_buffer_pull(&packet->buffer, len);
2614 silc_list_insert(pws->in_queue, NULL, packet);
2615 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2616 silc_packet_wrap_read_more, pws, 0, 0);
2617 pws->read_more = TRUE;
2621 pws->read_more = FALSE;
2622 silc_packet_free(packet);
2626 /* Write SILC packet */
2628 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2629 SilcUInt32 data_len)
2631 SilcPacketWrapperStream pws = stream;
2632 SilcBool ret = FALSE;
2634 /* Call encoder if set */
2636 silc_buffer_reset(pws->encbuf);
2637 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2638 pws->coder_context);
2641 /* Send the SILC packet */
2643 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2644 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2645 silc_buffer_len(pws->encbuf)),
2646 SILC_STR_DATA(data, data_len),
2650 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2659 SilcBool silc_packet_wrap_close(SilcStream stream)
2661 SilcPacketWrapperStream pws = stream;
2666 if (pws->blocking) {
2667 /* Close packet waiter */
2668 silc_packet_wait_uninit(pws->waiter, pws->stream);
2672 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2679 /* Destroy wrapper stream */
2681 void silc_packet_wrap_destroy(SilcStream stream)
2684 SilcPacketWrapperStream pws = stream;
2687 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2689 silc_stream_close(stream);
2690 silc_list_start(pws->in_queue);
2691 while ((packet = silc_list_get(pws->in_queue)))
2692 silc_packet_free(packet);
2694 silc_mutex_free(pws->lock);
2696 silc_buffer_free(pws->encbuf);
2697 silc_packet_stream_unref(pws->stream);
2702 /* Link stream to receive packets */
2704 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2705 SilcSchedule schedule,
2706 SilcStreamNotifier callback,
2709 SilcPacketWrapperStream pws = stream;
2711 if (pws->closed || pws->blocking)
2714 /* Link to receive packets */
2716 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2717 100000, pws->type, -1);
2719 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2721 pws->callback = callback;
2722 pws->context = context;
2727 /* Return schedule */
2729 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2734 /* Wraps packet stream into SilcStream. */
2736 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2737 SilcPacketType type,
2738 SilcPacketFlags flags,
2739 SilcBool blocking_mode,
2740 SilcPacketWrapCoder coder,
2743 SilcPacketWrapperStream pws;
2745 pws = silc_calloc(1, sizeof(*pws));
2749 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2751 pws->ops = &silc_packet_stream_ops;
2752 pws->stream = stream;
2755 pws->blocking = blocking_mode;
2757 pws->coder_context = context;
2759 /* Allocate small amount for encoder buffer. */
2761 pws->encbuf = silc_buffer_alloc(8);
2763 if (pws->blocking) {
2764 /* Blocking mode. Use packet waiter to do the thing. */
2765 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2771 /* Non-blocking mode */
2772 silc_mutex_alloc(&pws->lock);
2773 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2776 silc_packet_stream_ref(stream);
2778 return (SilcStream)pws;
2781 const SilcStreamOps silc_packet_stream_ops =
2783 silc_packet_wrap_read,
2784 silc_packet_wrap_write,
2785 silc_packet_wrap_close,
2786 silc_packet_wrap_destroy,
2787 silc_packet_wrap_notifier,
2788 silc_packet_wrap_get_schedule,