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)
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_dlist_add(list, ps);
660 silc_mutex_unlock(engine->lock);
665 /* Create new packet stream */
667 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
668 SilcSchedule schedule,
675 SILC_LOG_DEBUG(("Creating new packet stream"));
677 if (!engine || !stream)
680 ps = silc_calloc(1, sizeof(*ps));
685 silc_atomic_init8(&ps->refcnt, 1);
686 silc_mutex_alloc(&ps->lock);
688 /* Allocate out buffer */
689 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
691 silc_packet_stream_destroy(ps);
694 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
695 silc_buffer_reset(&ps->outbuf);
697 /* Initialize packet procesors list */
698 ps->process = silc_dlist_init();
700 silc_packet_stream_destroy(ps);
704 silc_mutex_lock(engine->lock);
706 /* Add per scheduler context */
707 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
709 ps->sc = silc_calloc(1, sizeof(*ps->sc));
711 silc_packet_stream_destroy(ps);
712 silc_mutex_unlock(engine->lock);
715 ps->sc->engine = engine;
716 ps->sc->schedule = schedule;
718 /* Allocate data input buffer */
719 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
723 silc_packet_stream_destroy(ps);
724 silc_mutex_unlock(engine->lock);
727 silc_buffer_reset(inbuf);
729 ps->sc->inbufs = silc_dlist_init();
730 if (!ps->sc->inbufs) {
731 silc_buffer_free(inbuf);
734 silc_packet_stream_destroy(ps);
735 silc_mutex_unlock(engine->lock);
738 silc_dlist_add(ps->sc->inbufs, inbuf);
740 /* Add to per scheduler context hash table */
741 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
742 silc_buffer_free(inbuf);
743 silc_dlist_del(ps->sc->inbufs, inbuf);
746 silc_packet_stream_destroy(ps);
747 silc_mutex_unlock(engine->lock);
751 ps->sc->stream_count++;
753 /* Add the packet stream to engine */
754 silc_list_add(engine->streams, ps);
756 /* If this is UDP stream, allocate UDP remote stream hash table */
757 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
758 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
759 silc_hash_string_compare, NULL,
760 silc_packet_engine_hash_destr,
763 silc_mutex_unlock(engine->lock);
765 /* Set IO notifier callback. This schedules this stream for I/O. */
766 if (!silc_stream_set_notifier(ps->stream, schedule,
767 silc_packet_stream_io, ps)) {
768 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
769 silc_packet_stream_destroy(ps);
776 /* Add new remote packet stream for UDP packet streams */
778 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
779 const char *remote_ip,
780 SilcUInt16 remote_port,
783 SilcPacketEngine engine = stream->sc->engine;
788 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
789 remote_ip, remote_port, stream));
791 if (!stream || !remote_ip || !remote_port)
794 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
795 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
799 ps = silc_calloc(1, sizeof(*ps));
804 silc_atomic_init8(&ps->refcnt, 1);
805 silc_mutex_alloc(&ps->lock);
807 /* Set the UDP packet stream as underlaying stream */
808 silc_packet_stream_ref(stream);
809 ps->stream = (SilcStream)stream;
812 /* Allocate out buffer */
813 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
815 silc_packet_stream_destroy(ps);
818 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
819 silc_buffer_reset(&ps->outbuf);
821 /* Initialize packet procesors list */
822 ps->process = silc_dlist_init();
824 silc_packet_stream_destroy(ps);
828 /* Add to engine with this IP and port pair */
829 tuple = silc_format("%d%s", remote_port, remote_ip);
830 silc_mutex_lock(engine->lock);
831 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
832 silc_mutex_unlock(engine->lock);
833 silc_packet_stream_destroy(ps);
836 silc_mutex_unlock(engine->lock);
838 /* Save remote IP and port pair */
839 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
840 if (!ps->remote_udp) {
841 silc_packet_stream_destroy(ps);
844 ps->remote_udp->remote_port = remote_port;
845 ps->remote_udp->remote_ip = strdup(remote_ip);
846 if (!ps->remote_udp->remote_ip) {
847 silc_packet_stream_destroy(ps);
852 /* Inject packet to the new stream */
854 silc_packet_stream_ref(ps);
855 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
856 silc_packet_stream_inject_packet, packet,
863 /* Destroy packet stream */
865 void silc_packet_stream_destroy(SilcPacketStream stream)
867 SilcPacketEngine engine;
872 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
873 stream->destroyed = TRUE;
875 /* Close the underlaying stream */
876 if (!stream->udp && stream->stream)
877 silc_stream_close(stream->stream);
881 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
884 /* Delete from engine */
885 engine = stream->sc->engine;
886 silc_mutex_lock(engine->lock);
887 silc_list_del(engine->streams, stream);
889 /* Remove per scheduler context, if it is not used anymore */
891 stream->sc->stream_count--;
892 if (!stream->sc->stream_count)
893 silc_hash_table_del(engine->contexts, stream->sc->schedule);
895 silc_mutex_unlock(engine->lock);
897 /* Destroy the underlaying stream */
899 silc_stream_destroy(stream->stream);
901 /* Delete from UDP remote hash table */
903 engine = stream->sc->engine;
904 silc_snprintf(tuple, sizeof(tuple), "%d%s",
905 stream->remote_udp->remote_port,
906 stream->remote_udp->remote_ip);
907 silc_mutex_lock(engine->lock);
908 silc_hash_table_del(engine->udp_remote, tuple);
909 silc_mutex_unlock(engine->lock);
911 silc_free(stream->remote_udp->remote_ip);
912 silc_free(stream->remote_udp);
914 /* Unreference the underlaying packet stream */
915 silc_packet_stream_unref((SilcPacketStream)stream->stream);
918 /* Clear and free buffers */
919 silc_buffer_clear(&stream->outbuf);
920 silc_buffer_purge(&stream->outbuf);
922 if (stream->process) {
924 silc_dlist_start(stream->process);
925 while ((p = silc_dlist_get(stream->process))) {
928 silc_dlist_del(stream->process, p);
930 silc_dlist_uninit(stream->process);
933 /* Destroy ciphers and HMACs */
934 if (stream->send_key[0])
935 silc_cipher_free(stream->send_key[0]);
936 if (stream->receive_key[0])
937 silc_cipher_free(stream->receive_key[0]);
938 if (stream->send_hmac[0])
939 silc_hmac_free(stream->send_hmac[0]);
940 if (stream->receive_hmac[0])
941 silc_hmac_free(stream->receive_hmac[0]);
942 if (stream->send_key[1])
943 silc_cipher_free(stream->send_key[1]);
944 if (stream->receive_key[1])
945 silc_cipher_free(stream->receive_key[1]);
946 if (stream->send_hmac[1])
947 silc_hmac_free(stream->send_hmac[1]);
948 if (stream->receive_hmac[1])
949 silc_hmac_free(stream->receive_hmac[1]);
952 silc_free(stream->src_id);
953 silc_free(stream->dst_id);
955 silc_atomic_uninit8(&stream->refcnt);
956 silc_mutex_free(stream->lock);
960 /* Return TRUE if the stream is valid */
962 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
964 return stream->destroyed == FALSE;
967 /* Marks as router stream */
969 void silc_packet_stream_set_router(SilcPacketStream stream)
971 stream->is_router = TRUE;
974 /* Mark to include IV in ciphertext */
976 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
978 stream->iv_included = TRUE;
981 /* Links `callbacks' to `stream' for specified packet types */
983 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
984 SilcPacketCallbacks *callbacks,
985 void *callback_context,
986 int priority, va_list ap)
988 SilcPacketProcess p, e;
989 SilcInt32 packet_type;
992 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
996 if (!callbacks->packet_receive)
999 p = silc_calloc(1, sizeof(*p));
1003 p->priority = priority;
1004 p->callbacks = callbacks;
1005 p->callback_context = callback_context;
1007 silc_mutex_lock(stream->lock);
1009 if (!stream->process) {
1010 stream->process = silc_dlist_init();
1011 if (!stream->process) {
1012 silc_mutex_unlock(stream->lock);
1017 /* According to priority set the procesor to correct position. First
1018 entry has the highest priority */
1019 silc_dlist_start(stream->process);
1020 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1021 if (p->priority > e->priority) {
1022 silc_dlist_insert(stream->process, p);
1027 silc_dlist_add(stream->process, p);
1029 /* Get packet types to process */
1032 packet_type = va_arg(ap, SilcInt32);
1034 if (packet_type == SILC_PACKET_ANY)
1037 if (packet_type == -1)
1040 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1042 silc_mutex_unlock(stream->lock);
1046 p->types[i - 1] = (SilcPacketType)packet_type;
1050 p->types[i - 1] = 0;
1052 silc_mutex_unlock(stream->lock);
1054 silc_packet_stream_ref(stream);
1059 /* Links `callbacks' to `stream' for specified packet types */
1061 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1062 SilcPacketCallbacks *callbacks,
1063 void *callback_context,
1069 va_start(ap, priority);
1070 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1077 /* Unlinks `callbacks' from `stream'. */
1079 void silc_packet_stream_unlink(SilcPacketStream stream,
1080 SilcPacketCallbacks *callbacks,
1081 void *callback_context)
1083 SilcPacketProcess p;
1085 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1086 callbacks, stream));
1088 silc_mutex_lock(stream->lock);
1090 silc_dlist_start(stream->process);
1091 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1092 if (p->callbacks == callbacks &&
1093 p->callback_context == callback_context) {
1094 silc_dlist_del(stream->process, p);
1095 silc_free(p->types);
1100 if (!silc_dlist_count(stream->process)) {
1101 silc_dlist_uninit(stream->process);
1102 stream->process = NULL;
1105 silc_mutex_unlock(stream->lock);
1107 silc_packet_stream_unref(stream);
1110 /* Returns TRUE if stream is UDP stream */
1112 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1114 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1117 /* Return packet sender IP and port for UDP packet stream */
1119 SilcBool silc_packet_get_sender(SilcPacket packet,
1120 const char **sender_ip,
1121 SilcUInt16 *sender_port)
1123 if (!packet->stream->remote_udp)
1126 *sender_ip = packet->stream->remote_udp->remote_ip;
1127 *sender_port = packet->stream->remote_udp->remote_port;
1132 /* Reference packet stream */
1134 void silc_packet_stream_ref(SilcPacketStream stream)
1136 silc_atomic_add_int8(&stream->refcnt, 1);
1137 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1138 silc_atomic_get_int8(&stream->refcnt) - 1,
1139 silc_atomic_get_int8(&stream->refcnt)));
1142 /* Unreference packet stream */
1144 void silc_packet_stream_unref(SilcPacketStream stream)
1146 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1147 silc_atomic_get_int8(&stream->refcnt),
1148 silc_atomic_get_int8(&stream->refcnt) - 1));
1149 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1151 silc_atomic_add_int8(&stream->refcnt, 1);
1152 silc_packet_stream_destroy(stream);
1157 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1159 return stream->sc->engine;
1162 /* Set application context for packet stream */
1164 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1166 silc_mutex_lock(stream->lock);
1167 stream->stream_context = stream_context;
1168 silc_mutex_unlock(stream->lock);
1171 /* Return application context from packet stream */
1173 void *silc_packet_get_context(SilcPacketStream stream)
1176 silc_mutex_lock(stream->lock);
1177 context = stream->stream_context;
1178 silc_mutex_unlock(stream->lock);
1182 /* Change underlaying stream */
1184 void silc_packet_stream_set_stream(SilcPacketStream ps,
1188 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1189 ps->stream = stream;
1190 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1194 /* Return underlaying stream */
1196 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1198 return stream->stream;
1203 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1204 SilcCipher receive_key, SilcHmac send_hmac,
1205 SilcHmac receive_hmac, SilcBool rekey)
1207 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1209 /* If doing rekey, send REKEY_DONE packet */
1211 /* This will take stream lock. */
1212 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1213 stream->src_id_type, stream->src_id,
1214 stream->src_id_len, stream->dst_id_type,
1215 stream->dst_id, stream->dst_id_len,
1216 NULL, 0, stream->send_key[0],
1217 stream->send_hmac[0]))
1220 /* Write the packet to the stream */
1221 if (!silc_packet_stream_write(stream, TRUE))
1224 silc_mutex_lock(stream->lock);
1227 /* In case IV Included is set, save the old keys */
1228 if (stream->iv_included) {
1229 if (stream->send_key[1] && send_key) {
1230 silc_cipher_free(stream->send_key[1]);
1231 stream->send_key[1] = stream->send_key[0];
1233 if (stream->receive_key[1] && receive_key) {
1234 silc_cipher_free(stream->receive_key[1]);
1235 stream->receive_key[1] = stream->receive_key[0];
1237 if (stream->send_hmac[1] && send_hmac) {
1238 silc_hmac_free(stream->send_hmac[1]);
1239 stream->send_hmac[1] = stream->send_hmac[0];
1241 if (stream->receive_hmac[1] && receive_hmac) {
1242 silc_hmac_free(stream->receive_hmac[1]);
1243 stream->receive_hmac[1] = stream->receive_hmac[0];
1246 if (stream->send_key[0] && send_key)
1247 silc_cipher_free(stream->send_key[0]);
1248 if (stream->receive_key[0] && receive_key)
1249 silc_cipher_free(stream->receive_key[0]);
1250 if (stream->send_hmac[0] && send_hmac)
1251 silc_hmac_free(stream->send_hmac[0]);
1252 if (stream->receive_hmac[0] && receive_hmac)
1253 silc_hmac_free(stream->receive_hmac[0]);
1258 stream->send_key[0] = send_key;
1260 stream->receive_key[0] = receive_key;
1262 stream->send_hmac[0] = send_hmac;
1264 stream->receive_hmac[0] = receive_hmac;
1266 silc_mutex_unlock(stream->lock);
1270 /* Return current ciphers from packet stream */
1272 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1273 SilcCipher *send_key,
1274 SilcCipher *receive_key,
1275 SilcHmac *send_hmac,
1276 SilcHmac *receive_hmac)
1278 if (!stream->send_key[0] && !stream->receive_key[0] &&
1279 !stream->send_hmac[0] && !stream->receive_hmac[0])
1282 silc_mutex_lock(stream->lock);
1285 *send_key = stream->send_key[0];
1287 *receive_key = stream->receive_key[0];
1289 *send_hmac = stream->send_hmac[0];
1291 *receive_hmac = stream->receive_hmac[0];
1293 silc_mutex_unlock(stream->lock);
1298 /* Set SILC IDs to packet stream */
1300 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1301 SilcIdType src_id_type, const void *src_id,
1302 SilcIdType dst_id_type, const void *dst_id)
1305 unsigned char tmp[32];
1307 if (!src_id && !dst_id)
1310 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1312 silc_mutex_lock(stream->lock);
1315 silc_free(stream->src_id);
1316 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1317 silc_mutex_unlock(stream->lock);
1320 stream->src_id = silc_memdup(tmp, len);
1321 if (!stream->src_id) {
1322 silc_mutex_unlock(stream->lock);
1325 stream->src_id_type = src_id_type;
1326 stream->src_id_len = len;
1330 silc_free(stream->dst_id);
1331 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1332 silc_mutex_unlock(stream->lock);
1335 stream->dst_id = silc_memdup(tmp, len);
1336 if (!stream->dst_id) {
1337 silc_mutex_unlock(stream->lock);
1340 stream->dst_id_type = dst_id_type;
1341 stream->dst_id_len = len;
1344 silc_mutex_unlock(stream->lock);
1349 /* Return IDs from the packet stream */
1351 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1352 SilcBool *src_id_set, SilcID *src_id,
1353 SilcBool *dst_id_set, SilcID *dst_id)
1355 if (src_id && stream->src_id)
1356 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1357 stream->src_id_type, src_id))
1360 if (stream->src_id && src_id_set)
1363 if (dst_id && stream->dst_id)
1364 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1365 stream->dst_id_type, dst_id))
1368 if (stream->dst_id && dst_id_set)
1374 /* Adds Security ID (SID) */
1376 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1378 if (!stream->iv_included)
1381 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1389 void silc_packet_free(SilcPacket packet)
1391 SilcPacketStream stream = packet->stream;
1393 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1395 /* Check for double free */
1396 SILC_ASSERT(packet->stream != NULL);
1398 packet->stream = NULL;
1399 packet->src_id = packet->dst_id = NULL;
1400 silc_buffer_reset(&packet->buffer);
1402 silc_mutex_lock(stream->sc->engine->lock);
1404 /* Put the packet back to freelist */
1405 silc_list_add(stream->sc->engine->packet_pool, packet);
1406 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1407 silc_list_start(stream->sc->engine->packet_pool);
1409 silc_mutex_unlock(stream->sc->engine->lock);
1412 /****************************** Packet Sending ******************************/
1414 /* Prepare outgoing data buffer for packet sending. Returns the
1415 pointer to that buffer into the `packet'. */
1417 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1422 unsigned char *oldptr;
1423 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1427 /* Allocate more space if needed */
1428 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1429 if (!silc_buffer_realloc(&stream->outbuf,
1430 silc_buffer_truelen(&stream->outbuf) + totlen))
1434 /* Pull data area for the new packet, and return pointer to the start of
1435 the data area and save the pointer in to the `packet'. MAC is pulled
1436 later after it's computed. */
1437 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1438 silc_buffer_set(packet, oldptr, totlen);
1439 silc_buffer_push_tail(packet, mac_len);
1444 /* Increments counter when encrypting in counter mode. */
1446 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1448 unsigned char *ret_iv)
1450 unsigned char *iv = silc_cipher_get_iv(cipher);
1451 SilcUInt32 pc1, pc2;
1453 /* Increment 64-bit packet counter */
1454 SILC_GET32_MSB(pc1, iv + 4);
1455 SILC_GET32_MSB(pc2, iv + 8);
1458 SILC_PUT32_MSB(pc1, iv + 4);
1459 SILC_PUT32_MSB(pc2, iv + 8);
1461 /* Reset block counter */
1462 memset(iv + 12, 0, 4);
1464 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1465 if (stream->iv_included) {
1467 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1468 ret_iv[1] = ret_iv[0] + iv[4];
1469 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1470 ret_iv[3] = ret_iv[0] + ret_iv[2];
1471 SILC_PUT32_MSB(pc2, ret_iv + 4);
1472 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1474 /* Set new nonce to counter block */
1475 memcpy(iv + 4, ret_iv, 4);
1478 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1481 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1482 the packet. The silc_packet_stream_write needs to be called to send it
1483 after this returns TRUE. */
1485 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1486 SilcPacketType type,
1487 SilcPacketFlags flags,
1488 SilcIdType src_id_type,
1489 unsigned char *src_id,
1490 SilcUInt32 src_id_len,
1491 SilcIdType dst_id_type,
1492 unsigned char *dst_id,
1493 SilcUInt32 dst_id_len,
1494 const unsigned char *data,
1495 SilcUInt32 data_len,
1499 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1500 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1501 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1503 SilcBufferStruct packet;
1505 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1506 "data len %d", silc_get_packet_name(type), stream->send_psn,
1507 flags, src_id_type, dst_id_type, data_len));
1509 /* Get the true length of the packet. This is saved as payload length
1510 into the packet header. This does not include the length of the
1512 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1513 src_id_len + dst_id_len));
1514 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1515 src_id_len + dst_id_len);
1517 /* If using CTR mode, increment the counter */
1518 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1520 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1522 /* If IV is included, the SID, IV and sequence number is added to packet */
1523 if (stream->iv_included && cipher) {
1524 psnlen = sizeof(psn);
1526 iv[0] = stream->sid;
1529 /* If IV is included, the SID, IV and sequence number is added to packet */
1530 if (stream->iv_included && cipher) {
1531 psnlen = sizeof(psn);
1532 ivlen = block_len + 1;
1533 iv[0] = stream->sid;
1534 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1538 /* We automatically figure out the packet structure from the packet
1539 type and flags, and calculate correct length. Private messages with
1540 private keys and channel messages are special packets as their
1541 payload is encrypted already. */
1542 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1543 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1544 /* Padding is calculated from header + IDs */
1546 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1547 psnlen), block_len, padlen);
1549 /* Length to encrypt, header + IDs + padding. */
1550 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1553 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1554 if (stream->sc->engine->local_is_router && stream->is_router) {
1555 /* Channel messages between routers are encrypted as normal packets.
1556 Padding is calculated from true length of the packet. */
1558 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1560 enclen += padlen + psnlen;
1562 /* Padding is calculated from header + IDs */
1564 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1565 psnlen), block_len, padlen);
1567 /* Length to encrypt, header + IDs + padding. */
1568 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1572 /* Padding is calculated from true length of the packet */
1573 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1574 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1576 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1578 enclen += padlen + psnlen;
1581 /* Remove implementation specific flags */
1582 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1584 /* Get random padding */
1585 for (i = 0; i < padlen; i++) tmppad[i] =
1586 silc_rng_get_byte_fast(stream->sc->engine->rng);
1588 silc_mutex_lock(stream->lock);
1590 /* Get packet pointer from the outgoing buffer */
1591 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1592 + psnlen, hmac, &packet))) {
1593 silc_mutex_unlock(stream->lock);
1597 SILC_PUT32_MSB(stream->send_psn, psn);
1599 /* Create the packet. This creates the SILC header, adds padding, and
1600 the actual packet data. */
1601 i = silc_buffer_format(&packet,
1602 SILC_STR_DATA(iv, ivlen),
1603 SILC_STR_DATA(psn, psnlen),
1604 SILC_STR_UI_SHORT(truelen),
1605 SILC_STR_UI_CHAR(flags),
1606 SILC_STR_UI_CHAR(type),
1607 SILC_STR_UI_CHAR(padlen),
1608 SILC_STR_UI_CHAR(0),
1609 SILC_STR_UI_CHAR(src_id_len),
1610 SILC_STR_UI_CHAR(dst_id_len),
1611 SILC_STR_UI_CHAR(src_id_type),
1612 SILC_STR_DATA(src_id, src_id_len),
1613 SILC_STR_UI_CHAR(dst_id_type),
1614 SILC_STR_DATA(dst_id, dst_id_len),
1615 SILC_STR_DATA(tmppad, padlen),
1616 SILC_STR_DATA(data, data_len),
1618 if (silc_unlikely(i < 0)) {
1619 silc_mutex_unlock(stream->lock);
1623 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1624 silc_buffer_data(&packet), silc_buffer_len(&packet));
1626 /* Encrypt the packet */
1627 if (silc_likely(cipher)) {
1628 SILC_LOG_DEBUG(("Encrypting packet"));
1629 silc_cipher_set_iv(cipher, NULL);
1630 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1631 packet.data + ivlen, enclen,
1633 SILC_LOG_ERROR(("Packet encryption failed"));
1634 silc_mutex_unlock(stream->lock);
1640 if (silc_likely(hmac)) {
1643 /* MAC is computed from the entire encrypted packet data, and put
1644 to the end of the packet. */
1645 silc_hmac_init(hmac);
1646 silc_hmac_update(hmac, psn, sizeof(psn));
1647 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1648 silc_hmac_final(hmac, packet.tail, &mac_len);
1649 silc_buffer_pull_tail(&packet, mac_len);
1656 /* Sends a packet */
1658 SilcBool silc_packet_send(SilcPacketStream stream,
1659 SilcPacketType type, SilcPacketFlags flags,
1660 const unsigned char *data, SilcUInt32 data_len)
1664 ret = silc_packet_send_raw(stream, type, flags,
1665 stream->src_id_type,
1668 stream->dst_id_type,
1672 stream->send_key[0],
1673 stream->send_hmac[0]);
1675 /* Write the packet to the stream */
1676 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1679 /* Sends a packet, extended routine */
1681 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1682 SilcPacketType type, SilcPacketFlags flags,
1683 SilcIdType src_id_type, void *src_id,
1684 SilcIdType dst_id_type, void *dst_id,
1685 const unsigned char *data, SilcUInt32 data_len,
1686 SilcCipher cipher, SilcHmac hmac)
1688 unsigned char src_id_data[32], dst_id_data[32];
1689 SilcUInt32 src_id_len, dst_id_len;
1693 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1694 sizeof(src_id_data), &src_id_len))
1697 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1698 sizeof(dst_id_data), &dst_id_len))
1701 ret = silc_packet_send_raw(stream, type, flags,
1702 src_id ? src_id_type : stream->src_id_type,
1703 src_id ? src_id_data : stream->src_id,
1704 src_id ? src_id_len : stream->src_id_len,
1705 dst_id ? dst_id_type : stream->dst_id_type,
1706 dst_id ? dst_id_data : stream->dst_id,
1707 dst_id ? dst_id_len : stream->dst_id_len,
1709 cipher ? cipher : stream->send_key[0],
1710 hmac ? hmac : stream->send_hmac[0]);
1712 /* Write the packet to the stream */
1713 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1716 /* Sends packet after formatting the arguments to buffer */
1718 SilcBool silc_packet_send_va(SilcPacketStream stream,
1719 SilcPacketType type, SilcPacketFlags flags, ...)
1721 SilcBufferStruct buf;
1725 va_start(va, flags);
1727 memset(&buf, 0, sizeof(buf));
1728 if (silc_buffer_format_vp(&buf, va) < 0) {
1733 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1734 silc_buffer_len(&buf));
1736 silc_buffer_purge(&buf);
1742 /* Sends packet after formatting the arguments to buffer, extended routine */
1744 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1745 SilcPacketType type, SilcPacketFlags flags,
1746 SilcIdType src_id_type, void *src_id,
1747 SilcIdType dst_id_type, void *dst_id,
1748 SilcCipher cipher, SilcHmac hmac, ...)
1750 SilcBufferStruct buf;
1756 memset(&buf, 0, sizeof(buf));
1757 if (silc_buffer_format_vp(&buf, va) < 0) {
1762 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1763 dst_id_type, dst_id, silc_buffer_data(&buf),
1764 silc_buffer_len(&buf), cipher, hmac);
1766 silc_buffer_purge(&buf);
1772 /***************************** Packet Receiving *****************************/
1774 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1776 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1777 const unsigned char *data,
1778 SilcUInt32 data_len,
1779 const unsigned char *packet_mac,
1780 const unsigned char *packet_seq,
1781 SilcUInt32 sequence)
1784 if (silc_likely(hmac)) {
1785 unsigned char mac[32], psn[4];
1788 SILC_LOG_DEBUG(("Verifying MAC"));
1790 /* Compute HMAC of packet */
1791 silc_hmac_init(hmac);
1794 SILC_PUT32_MSB(sequence, psn);
1795 silc_hmac_update(hmac, psn, 4);
1797 silc_hmac_update(hmac, packet_seq, 4);
1799 silc_hmac_update(hmac, data, data_len);
1800 silc_hmac_final(hmac, mac, &mac_len);
1802 /* Compare the MAC's */
1803 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1804 SILC_LOG_DEBUG(("MAC failed"));
1808 SILC_LOG_DEBUG(("MAC is Ok"));
1814 /* Increments/sets counter when decrypting in counter mode. */
1816 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1818 unsigned char *packet_iv)
1820 SilcUInt32 pc1, pc2;
1822 /* If IV Included flag, set the IV from packet to block counter. */
1823 if (stream->iv_included) {
1824 memcpy(iv + 4, packet_iv, 8);
1826 /* Increment 64-bit packet counter. */
1827 SILC_GET32_MSB(pc1, iv + 4);
1828 SILC_GET32_MSB(pc2, iv + 8);
1831 SILC_PUT32_MSB(pc1, iv + 4);
1832 SILC_PUT32_MSB(pc2, iv + 8);
1835 /* Reset block counter */
1836 memset(iv + 12, 0, 4);
1838 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1841 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1842 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1844 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1845 SilcUInt32 sequence, SilcBuffer buffer,
1848 if (normal == TRUE) {
1849 if (silc_likely(cipher)) {
1850 /* Decrypt rest of the packet */
1851 SILC_LOG_DEBUG(("Decrypting the packet"));
1852 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1854 silc_buffer_len(buffer), NULL)))
1860 /* Decrypt rest of the header plus padding */
1861 if (silc_likely(cipher)) {
1863 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1865 SILC_LOG_DEBUG(("Decrypting the header"));
1867 /* Padding length + src id len + dst id len + header length - 16
1868 bytes already decrypted, gives the rest of the encrypted packet */
1869 silc_buffer_push(buffer, block_len);
1870 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1871 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1873 silc_buffer_pull(buffer, block_len);
1875 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1876 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1880 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1881 buffer->data, len, NULL)))
1889 /* Parses the packet. This is called when a whole packet is ready to be
1890 parsed. The buffer sent must be already decrypted before calling this
1893 static inline SilcBool silc_packet_parse(SilcPacket packet)
1895 SilcBuffer buffer = &packet->buffer;
1896 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1897 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1900 SILC_LOG_DEBUG(("Parsing incoming packet"));
1902 /* Parse the buffer. This parses the SILC header of the packet. */
1903 ret = silc_buffer_unformat(buffer,
1906 SILC_STR_UI_CHAR(&src_id_len),
1907 SILC_STR_UI_CHAR(&dst_id_len),
1908 SILC_STR_UI_CHAR(&src_id_type),
1910 if (silc_unlikely(ret == -1)) {
1911 if (!packet->stream->udp &&
1912 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1913 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1917 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1918 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1919 if (!packet->stream->udp &&
1920 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1921 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1922 packet->src_id_len, packet->dst_id_len));
1926 ret = silc_buffer_unformat(buffer,
1928 SILC_STR_DATA(&packet->src_id, src_id_len),
1929 SILC_STR_UI_CHAR(&dst_id_type),
1930 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1931 SILC_STR_OFFSET(padlen),
1933 if (silc_unlikely(ret == -1)) {
1934 if (!packet->stream->udp &&
1935 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1936 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1940 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1941 dst_id_type > SILC_ID_CHANNEL)) {
1942 if (!packet->stream->udp &&
1943 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1944 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1945 src_id_type, dst_id_type));
1949 packet->src_id_len = src_id_len;
1950 packet->dst_id_len = dst_id_len;
1951 packet->src_id_type = src_id_type;
1952 packet->dst_id_type = dst_id_type;
1954 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1955 silc_buffer_len(buffer)), buffer->head,
1956 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1958 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1959 silc_get_packet_name(packet->type)));
1964 /* Dispatch packet to application. Called with stream->lock locked.
1965 Returns FALSE if the stream was destroyed while dispatching a packet. */
1967 static SilcBool silc_packet_dispatch(SilcPacket packet)
1969 SilcPacketStream stream = packet->stream;
1970 SilcPacketProcess p;
1971 SilcBool default_sent = FALSE;
1974 /* Dispatch packet to all packet processors that want it */
1976 if (silc_likely(!stream->process)) {
1977 /* Send to default processor as no others exist */
1978 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1979 silc_mutex_unlock(stream->lock);
1980 if (silc_unlikely(!stream->sc->engine->callbacks->
1981 packet_receive(stream->sc->engine, stream, packet,
1982 stream->sc->engine->callback_context,
1983 stream->stream_context)))
1984 silc_packet_free(packet);
1985 silc_mutex_lock(stream->lock);
1986 return stream->destroyed == FALSE;
1989 silc_dlist_start(stream->process);
1990 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1992 /* If priority is 0 or less, we send to default processor first
1993 because default processor has 0 priority */
1994 if (!default_sent && p->priority <= 0) {
1995 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1996 default_sent = TRUE;
1997 silc_mutex_unlock(stream->lock);
1998 if (stream->sc->engine->callbacks->
1999 packet_receive(stream->sc->engine, stream, packet,
2000 stream->sc->engine->callback_context,
2001 stream->stream_context)) {
2002 silc_mutex_lock(stream->lock);
2003 return stream->destroyed == FALSE;
2005 silc_mutex_lock(stream->lock);
2008 /* Send to processor */
2010 /* Send all packet types */
2011 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2012 silc_mutex_unlock(stream->lock);
2013 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2014 p->callback_context,
2015 stream->stream_context)) {
2016 silc_mutex_lock(stream->lock);
2017 return stream->destroyed == FALSE;
2019 silc_mutex_lock(stream->lock);
2021 /* Send specific types */
2022 for (pt = p->types; *pt; pt++) {
2023 if (*pt != packet->type)
2025 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2026 silc_mutex_unlock(stream->lock);
2027 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2028 p->callback_context,
2029 stream->stream_context)) {
2030 silc_mutex_lock(stream->lock);
2031 return stream->destroyed == FALSE;
2033 silc_mutex_lock(stream->lock);
2039 if (!default_sent) {
2040 /* Send to default processor as it has not been sent yet */
2041 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2042 silc_mutex_unlock(stream->lock);
2043 if (stream->sc->engine->callbacks->
2044 packet_receive(stream->sc->engine, stream, packet,
2045 stream->sc->engine->callback_context,
2046 stream->stream_context)) {
2047 silc_mutex_lock(stream->lock);
2048 return stream->destroyed == FALSE;
2050 silc_mutex_lock(stream->lock);
2053 /* If we got here, no one wanted the packet, so drop it */
2054 silc_packet_free(packet);
2055 return stream->destroyed == FALSE;
2058 /* Process incoming data and parse packets. Called with stream->lock
2061 static void silc_packet_read_process(SilcPacketStream stream)
2068 SilcUInt16 packetlen;
2069 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2070 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2071 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2075 /* Get inbuf. If there is already some data for this stream in the buffer
2076 we already have it. Otherwise get the current one from list, it will
2077 include the data. */
2078 inbuf = stream->inbuf;
2080 silc_dlist_start(stream->sc->inbufs);
2081 inbuf = silc_dlist_get(stream->sc->inbufs);
2084 /* Parse the packets from the data */
2085 while (silc_buffer_len(inbuf) > 0) {
2087 cipher = stream->receive_key[0];
2088 hmac = stream->receive_hmac[0];
2091 if (silc_unlikely(silc_buffer_len(inbuf) <
2092 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2093 SILC_PACKET_MIN_HEADER_LEN))) {
2094 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2095 silc_dlist_del(stream->sc->inbufs, inbuf);
2096 stream->inbuf = inbuf;
2100 if (silc_likely(hmac))
2101 mac_len = silc_hmac_len(hmac);
2105 /* Decrypt first block of the packet to get the length field out */
2106 if (silc_likely(cipher)) {
2107 block_len = silc_cipher_get_block_len(cipher);
2109 if (stream->iv_included) {
2110 /* SID, IV and sequence number is included in the ciphertext */
2111 sid = (SilcUInt8)inbuf->data[0];
2113 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2114 /* Set the CTR mode IV from packet to counter block */
2115 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2116 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2119 /* Get IV from packet */
2120 memcpy(iv, inbuf->data + 1, block_len);
2121 ivlen = block_len + 1;
2125 /* Check SID, and get correct decryption key */
2126 if (sid != stream->sid) {
2127 /* If SID is recent get the previous key and use it */
2128 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2129 stream->receive_key[1] && !stream->receive_hmac[1]) {
2130 cipher = stream->receive_key[1];
2131 hmac = stream->receive_hmac[1];
2133 /* The SID is unknown, drop rest of the data in buffer */
2134 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2136 silc_mutex_unlock(stream->lock);
2137 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2138 silc_mutex_lock(stream->lock);
2143 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2145 /* If using CTR mode, increment the counter */
2146 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2147 silc_packet_receive_ctr_increment(stream, iv, NULL);
2150 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2151 silc_cipher_set_iv(cipher, NULL);
2152 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2155 if (stream->iv_included) {
2156 /* Take sequence number from packet */
2157 packet_seq = header;
2161 /* Unencrypted packet */
2162 block_len = SILC_PACKET_MIN_HEADER_LEN;
2163 header = inbuf->data;
2166 /* Get packet length and full packet length with padding */
2167 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2170 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2171 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2172 SILC_LOG_ERROR(("Received too short packet"));
2173 silc_mutex_unlock(stream->lock);
2174 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2175 silc_mutex_lock(stream->lock);
2176 memset(tmp, 0, sizeof(tmp));
2180 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2181 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2183 paddedlen + mac_len - silc_buffer_len(inbuf)));
2184 memset(tmp, 0, sizeof(tmp));
2185 silc_dlist_del(stream->sc->inbufs, inbuf);
2186 stream->inbuf = inbuf;
2190 /* Check MAC of the packet */
2191 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2193 inbuf->data + ivlen +
2194 paddedlen, packet_seq,
2195 stream->receive_psn))) {
2196 silc_mutex_unlock(stream->lock);
2197 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2198 silc_mutex_lock(stream->lock);
2199 memset(tmp, 0, sizeof(tmp));
2204 packet = silc_packet_alloc(stream->sc->engine);
2205 if (silc_unlikely(!packet)) {
2206 silc_mutex_unlock(stream->lock);
2207 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2208 silc_mutex_lock(stream->lock);
2209 memset(tmp, 0, sizeof(tmp));
2212 packet->stream = stream;
2214 /* Allocate more space to packet buffer, if needed */
2215 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2216 if (!silc_buffer_realloc(&packet->buffer,
2217 silc_buffer_truelen(&packet->buffer) +
2219 silc_buffer_truelen(&packet->buffer)))) {
2220 silc_mutex_unlock(stream->lock);
2221 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2222 silc_mutex_lock(stream->lock);
2223 silc_packet_free(packet);
2224 memset(tmp, 0, sizeof(tmp));
2229 /* Parse packet header */
2230 packet->flags = (SilcPacketFlags)header[2];
2231 packet->type = (SilcPacketType)header[3];
2233 if (stream->sc->engine->local_is_router) {
2234 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2235 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2237 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2238 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2239 stream->is_router == TRUE))
2242 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2243 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2245 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2249 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2250 stream->receive_psn, paddedlen + ivlen + mac_len),
2251 inbuf->data, paddedlen + ivlen + mac_len);
2253 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2254 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2255 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2256 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2257 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2258 psnlen + (block_len - psnlen)),
2259 paddedlen - ivlen - psnlen - (block_len - psnlen));
2260 if (silc_likely(cipher)) {
2261 silc_cipher_set_iv(cipher, iv);
2262 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2263 &packet->buffer, normal);
2264 if (silc_unlikely(ret < 0)) {
2265 silc_mutex_unlock(stream->lock);
2266 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2267 silc_mutex_lock(stream->lock);
2268 silc_packet_free(packet);
2269 memset(tmp, 0, sizeof(tmp));
2273 stream->receive_psn++;
2275 silc_buffer_push(&packet->buffer, block_len);
2277 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2278 silc_buffer_pull(inbuf, paddedlen + mac_len);
2280 /* Parse the packet */
2281 if (silc_unlikely(!silc_packet_parse(packet))) {
2282 silc_mutex_unlock(stream->lock);
2283 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2284 silc_mutex_lock(stream->lock);
2285 silc_packet_free(packet);
2286 memset(tmp, 0, sizeof(tmp));
2290 /* Dispatch the packet to application */
2291 if (!silc_packet_dispatch(packet))
2296 /* Add inbuf back to free list, if we owned it. */
2297 if (stream->inbuf) {
2298 silc_dlist_add(stream->sc->inbufs, inbuf);
2299 stream->inbuf = NULL;
2302 silc_buffer_reset(inbuf);
2305 /****************************** Packet Waiting ******************************/
2307 /* Packet wait receive callback */
2309 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2310 SilcPacketStream stream,
2312 void *callback_context,
2313 void *stream_context);
2315 /* Packet waiting callbacks */
2316 static SilcPacketCallbacks silc_packet_wait_cbs =
2318 silc_packet_wait_packet_receive, NULL, NULL
2321 /* Packet waiting context */
2323 SilcMutex wait_lock;
2325 SilcList packet_queue;
2326 unsigned char id[28];
2327 unsigned int id_type : 2;
2328 unsigned int id_len : 5;
2329 unsigned int stopped : 1;
2332 /* Packet wait receive callback */
2335 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2336 SilcPacketStream stream,
2338 void *callback_context,
2339 void *stream_context)
2341 SilcPacketWait pw = callback_context;
2343 /* If source ID is specified check for it */
2345 if (pw->id_type != packet->src_id_type ||
2346 memcmp(pw->id, packet->src_id, pw->id_len))
2350 /* Signal the waiting thread for a new packet */
2351 silc_mutex_lock(pw->wait_lock);
2353 if (silc_unlikely(pw->stopped)) {
2354 silc_mutex_unlock(pw->wait_lock);
2358 silc_list_add(pw->packet_queue, packet);
2359 silc_cond_broadcast(pw->wait_cond);
2361 silc_mutex_unlock(pw->wait_lock);
2366 /* Initialize packet waiting */
2368 void *silc_packet_wait_init(SilcPacketStream stream,
2369 const SilcID *source_id, ...)
2375 pw = silc_calloc(1, sizeof(*pw));
2379 /* Allocate mutex and conditional variable */
2380 if (!silc_mutex_alloc(&pw->wait_lock)) {
2384 if (!silc_cond_alloc(&pw->wait_cond)) {
2385 silc_mutex_free(pw->wait_lock);
2390 /* Link to the packet stream for the requested packet types */
2391 va_start(ap, source_id);
2392 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2396 silc_cond_free(pw->wait_cond);
2397 silc_mutex_free(pw->wait_lock);
2402 /* Initialize packet queue */
2403 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2407 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2408 sizeof(pw->id), &id_len);
2409 pw->id_type = source_id->type;
2410 pw->id_len = id_len;
2416 /* Uninitialize packet waiting */
2418 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2420 SilcPacketWait pw = waiter;
2423 /* Signal any threads to stop waiting */
2424 silc_mutex_lock(pw->wait_lock);
2426 silc_cond_broadcast(pw->wait_cond);
2427 silc_mutex_unlock(pw->wait_lock);
2428 silc_thread_yield();
2430 /* Re-acquire lock and free resources */
2431 silc_mutex_lock(pw->wait_lock);
2432 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2434 /* Free any remaining packets */
2435 silc_list_start(pw->packet_queue);
2436 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2437 silc_packet_free(packet);
2439 silc_mutex_unlock(pw->wait_lock);
2440 silc_cond_free(pw->wait_cond);
2441 silc_mutex_free(pw->wait_lock);
2445 /* Blocks thread until a packet has been received. */
2447 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2449 SilcPacketWait pw = waiter;
2450 SilcBool ret = FALSE;
2452 silc_mutex_lock(pw->wait_lock);
2454 /* Wait here until packet has arrived */
2455 while (silc_list_count(pw->packet_queue) == 0) {
2456 if (silc_unlikely(pw->stopped)) {
2457 silc_mutex_unlock(pw->wait_lock);
2460 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2464 silc_list_start(pw->packet_queue);
2465 *return_packet = silc_list_get(pw->packet_queue);
2466 silc_list_del(pw->packet_queue, *return_packet);
2468 silc_mutex_unlock(pw->wait_lock);
2470 return ret == TRUE ? 1 : 0;
2473 /************************** Packet Stream Wrapper ***************************/
2475 /* Packet stream wrapper receive callback */
2477 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2478 SilcPacketStream stream,
2480 void *callback_context,
2481 void *stream_context);
2483 const SilcStreamOps silc_packet_stream_ops;
2485 /* Packet stream wrapper context */
2487 const SilcStreamOps *ops;
2488 SilcPacketStream stream;
2490 void *waiter; /* Waiter context in blocking mode */
2491 SilcPacketWrapCoder coder;
2492 void *coder_context;
2494 SilcStreamNotifier callback;
2497 SilcPacketType type;
2498 SilcPacketFlags flags;
2499 unsigned int closed : 1;
2500 unsigned int blocking : 1;
2501 unsigned int read_more : 1;
2502 } *SilcPacketWrapperStream;
2504 /* Packet wrapper callbacks */
2505 static SilcPacketCallbacks silc_packet_wrap_cbs =
2507 silc_packet_wrap_packet_receive, NULL, NULL
2510 /* Packet stream wrapper receive callback, non-blocking mode */
2513 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2514 SilcPacketStream stream,
2516 void *callback_context,
2517 void *stream_context)
2519 SilcPacketWrapperStream pws = callback_context;
2521 if (pws->closed || !pws->callback)
2524 silc_mutex_lock(pws->lock);
2525 silc_list_add(pws->in_queue, packet);
2526 silc_mutex_unlock(pws->lock);
2528 /* Call notifier callback */
2529 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2534 /* Task callback to notify more data is available for reading */
2536 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2538 SilcPacketWrapperStream pws = context;
2540 if (pws->closed || !pws->callback)
2543 /* Call notifier callback */
2544 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2547 /* Read SILC packet */
2549 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2552 SilcPacketWrapperStream pws = stream;
2554 SilcBool read_more = FALSE;
2560 if (pws->blocking) {
2561 /* Block until packet is received */
2562 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2567 /* Non-blocking mode */
2568 silc_mutex_lock(pws->lock);
2569 if (!silc_list_count(pws->in_queue)) {
2570 silc_mutex_unlock(pws->lock);
2574 silc_list_start(pws->in_queue);
2575 packet = silc_list_get(pws->in_queue);
2576 silc_list_del(pws->in_queue, packet);
2577 silc_mutex_unlock(pws->lock);
2580 /* Call decoder if set */
2581 if (pws->coder && !pws->read_more)
2582 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2583 pws->coder_context);
2585 len = silc_buffer_len(&packet->buffer);
2586 if (len > buf_len) {
2592 memcpy(buf, packet->buffer.data, len);
2594 if (read_more && !pws->blocking) {
2595 /* More data will be available (in blocking mode not supported). */
2596 silc_buffer_pull(&packet->buffer, len);
2597 silc_list_insert(pws->in_queue, NULL, packet);
2598 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2599 silc_packet_wrap_read_more, pws, 0, 0);
2600 pws->read_more = TRUE;
2604 pws->read_more = FALSE;
2605 silc_packet_free(packet);
2609 /* Write SILC packet */
2611 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2612 SilcUInt32 data_len)
2614 SilcPacketWrapperStream pws = stream;
2615 SilcBool ret = FALSE;
2617 /* Call encoder if set */
2619 silc_buffer_reset(pws->encbuf);
2620 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2621 pws->coder_context);
2624 /* Send the SILC packet */
2626 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2627 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2628 silc_buffer_len(pws->encbuf)),
2629 SILC_STR_DATA(data, data_len),
2633 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2642 SilcBool silc_packet_wrap_close(SilcStream stream)
2644 SilcPacketWrapperStream pws = stream;
2649 if (pws->blocking) {
2650 /* Close packet waiter */
2651 silc_packet_wait_uninit(pws->waiter, pws->stream);
2655 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2662 /* Destroy wrapper stream */
2664 void silc_packet_wrap_destroy(SilcStream stream)
2667 SilcPacketWrapperStream pws = stream;
2670 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2672 silc_stream_close(stream);
2673 silc_list_start(pws->in_queue);
2674 while ((packet = silc_list_get(pws->in_queue)))
2675 silc_packet_free(packet);
2677 silc_mutex_free(pws->lock);
2679 silc_buffer_free(pws->encbuf);
2680 silc_packet_stream_unref(pws->stream);
2685 /* Link stream to receive packets */
2687 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2688 SilcSchedule schedule,
2689 SilcStreamNotifier callback,
2692 SilcPacketWrapperStream pws = stream;
2694 if (pws->closed || pws->blocking)
2697 /* Link to receive packets */
2699 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2700 100000, pws->type, -1);
2702 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2704 pws->callback = callback;
2705 pws->context = context;
2710 /* Return schedule */
2712 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2717 /* Wraps packet stream into SilcStream. */
2719 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2720 SilcPacketType type,
2721 SilcPacketFlags flags,
2722 SilcBool blocking_mode,
2723 SilcPacketWrapCoder coder,
2726 SilcPacketWrapperStream pws;
2728 pws = silc_calloc(1, sizeof(*pws));
2732 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2734 pws->ops = &silc_packet_stream_ops;
2735 pws->stream = stream;
2738 pws->blocking = blocking_mode;
2740 pws->coder_context = context;
2742 /* Allocate small amount for encoder buffer. */
2744 pws->encbuf = silc_buffer_alloc(8);
2746 if (pws->blocking) {
2747 /* Blocking mode. Use packet waiter to do the thing. */
2748 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2754 /* Non-blocking mode */
2755 silc_mutex_alloc(&pws->lock);
2756 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2759 silc_packet_stream_ref(stream);
2761 return (SilcStream)pws;
2764 const SilcStreamOps silc_packet_stream_ops =
2766 silc_packet_wrap_read,
2767 silc_packet_wrap_write,
2768 silc_packet_wrap_close,
2769 silc_packet_wrap_destroy,
2770 silc_packet_wrap_notifier,
2771 silc_packet_wrap_get_schedule,