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);
788 SILC_LOG_DEBUG(("Created packet stream %p", ps));
793 /* Add new remote packet stream for UDP packet streams */
795 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
796 const char *remote_ip,
797 SilcUInt16 remote_port,
800 SilcPacketEngine engine = stream->sc->engine;
805 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
806 remote_ip, remote_port, stream));
808 if (!stream || !remote_ip || !remote_port)
811 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
812 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
816 ps = silc_calloc(1, sizeof(*ps));
821 silc_atomic_init8(&ps->refcnt, 1);
822 silc_mutex_alloc(&ps->lock);
824 /* Set the UDP packet stream as underlaying stream */
825 silc_packet_stream_ref(stream);
826 ps->stream = (SilcStream)stream;
829 /* Allocate out buffer */
830 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
832 silc_packet_stream_destroy(ps);
835 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
836 silc_buffer_reset(&ps->outbuf);
838 /* Initialize packet procesors list */
839 ps->process = silc_dlist_init();
841 silc_packet_stream_destroy(ps);
845 /* Add to engine with this IP and port pair */
846 tuple = silc_format("%d%s", remote_port, remote_ip);
847 silc_mutex_lock(engine->lock);
848 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
849 silc_mutex_unlock(engine->lock);
850 silc_packet_stream_destroy(ps);
853 silc_mutex_unlock(engine->lock);
855 /* Save remote IP and port pair */
856 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
857 if (!ps->remote_udp) {
858 silc_packet_stream_destroy(ps);
861 ps->remote_udp->remote_port = remote_port;
862 ps->remote_udp->remote_ip = strdup(remote_ip);
863 if (!ps->remote_udp->remote_ip) {
864 silc_packet_stream_destroy(ps);
869 /* Inject packet to the new stream */
871 silc_packet_stream_ref(ps);
872 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
873 silc_packet_stream_inject_packet, packet,
880 /* Destroy packet stream */
882 void silc_packet_stream_destroy(SilcPacketStream stream)
884 SilcPacketEngine engine;
889 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
890 stream->destroyed = TRUE;
892 SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
894 /* Close the underlaying stream */
895 if (!stream->udp && stream->stream)
896 silc_stream_close(stream->stream);
900 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
903 /* Delete from engine */
904 engine = stream->sc->engine;
905 silc_mutex_lock(engine->lock);
906 silc_list_del(engine->streams, stream);
908 /* Remove per scheduler context, if it is not used anymore */
910 stream->sc->stream_count--;
911 if (!stream->sc->stream_count)
912 silc_hash_table_del(engine->contexts, stream->sc->schedule);
914 silc_mutex_unlock(engine->lock);
916 /* Destroy the underlaying stream */
918 silc_stream_destroy(stream->stream);
920 /* Delete from UDP remote hash table */
922 engine = stream->sc->engine;
923 silc_snprintf(tuple, sizeof(tuple), "%d%s",
924 stream->remote_udp->remote_port,
925 stream->remote_udp->remote_ip);
926 silc_mutex_lock(engine->lock);
927 silc_hash_table_del(engine->udp_remote, tuple);
928 silc_mutex_unlock(engine->lock);
930 silc_free(stream->remote_udp->remote_ip);
931 silc_free(stream->remote_udp);
933 /* Unreference the underlaying packet stream */
934 silc_packet_stream_unref((SilcPacketStream)stream->stream);
937 /* Clear and free buffers */
938 silc_buffer_clear(&stream->outbuf);
939 silc_buffer_purge(&stream->outbuf);
941 if (stream->process) {
943 silc_dlist_start(stream->process);
944 while ((p = silc_dlist_get(stream->process))) {
947 silc_dlist_del(stream->process, p);
949 silc_dlist_uninit(stream->process);
952 /* Destroy ciphers and HMACs */
953 if (stream->send_key[0])
954 silc_cipher_free(stream->send_key[0]);
955 if (stream->receive_key[0])
956 silc_cipher_free(stream->receive_key[0]);
957 if (stream->send_hmac[0])
958 silc_hmac_free(stream->send_hmac[0]);
959 if (stream->receive_hmac[0])
960 silc_hmac_free(stream->receive_hmac[0]);
961 if (stream->send_key[1])
962 silc_cipher_free(stream->send_key[1]);
963 if (stream->receive_key[1])
964 silc_cipher_free(stream->receive_key[1]);
965 if (stream->send_hmac[1])
966 silc_hmac_free(stream->send_hmac[1]);
967 if (stream->receive_hmac[1])
968 silc_hmac_free(stream->receive_hmac[1]);
971 silc_free(stream->src_id);
972 silc_free(stream->dst_id);
974 silc_atomic_uninit8(&stream->refcnt);
975 silc_mutex_free(stream->lock);
979 /* Return TRUE if the stream is valid */
981 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
983 return stream->destroyed == FALSE;
986 /* Marks as router stream */
988 void silc_packet_stream_set_router(SilcPacketStream stream)
990 stream->is_router = TRUE;
993 /* Mark to include IV in ciphertext */
995 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
997 stream->iv_included = TRUE;
1000 /* Links `callbacks' to `stream' for specified packet types */
1002 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1003 SilcPacketCallbacks *callbacks,
1004 void *callback_context,
1005 int priority, va_list ap)
1007 SilcPacketProcess p, e;
1008 SilcInt32 packet_type;
1011 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1015 if (!callbacks->packet_receive)
1018 p = silc_calloc(1, sizeof(*p));
1022 p->priority = priority;
1023 p->callbacks = callbacks;
1024 p->callback_context = callback_context;
1026 silc_mutex_lock(stream->lock);
1028 if (!stream->process) {
1029 stream->process = silc_dlist_init();
1030 if (!stream->process) {
1031 silc_mutex_unlock(stream->lock);
1036 /* According to priority set the procesor to correct position. First
1037 entry has the highest priority */
1038 silc_dlist_start(stream->process);
1039 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1040 if (p->priority > e->priority) {
1041 silc_dlist_insert(stream->process, p);
1046 silc_dlist_add(stream->process, p);
1048 /* Get packet types to process */
1051 packet_type = va_arg(ap, SilcInt32);
1053 if (packet_type == SILC_PACKET_ANY)
1056 if (packet_type == -1)
1059 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1061 silc_mutex_unlock(stream->lock);
1065 p->types[i - 1] = (SilcPacketType)packet_type;
1069 p->types[i - 1] = 0;
1071 silc_mutex_unlock(stream->lock);
1073 silc_packet_stream_ref(stream);
1078 /* Links `callbacks' to `stream' for specified packet types */
1080 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1081 SilcPacketCallbacks *callbacks,
1082 void *callback_context,
1088 va_start(ap, priority);
1089 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1096 /* Unlinks `callbacks' from `stream'. */
1098 void silc_packet_stream_unlink(SilcPacketStream stream,
1099 SilcPacketCallbacks *callbacks,
1100 void *callback_context)
1102 SilcPacketProcess p;
1104 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1105 callbacks, stream));
1107 silc_mutex_lock(stream->lock);
1109 silc_dlist_start(stream->process);
1110 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1111 if (p->callbacks == callbacks &&
1112 p->callback_context == callback_context) {
1113 silc_dlist_del(stream->process, p);
1114 silc_free(p->types);
1119 if (!silc_dlist_count(stream->process)) {
1120 silc_dlist_uninit(stream->process);
1121 stream->process = NULL;
1124 silc_mutex_unlock(stream->lock);
1126 silc_packet_stream_unref(stream);
1129 /* Returns TRUE if stream is UDP stream */
1131 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1133 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1136 /* Return packet sender IP and port for UDP packet stream */
1138 SilcBool silc_packet_get_sender(SilcPacket packet,
1139 const char **sender_ip,
1140 SilcUInt16 *sender_port)
1142 if (!packet->stream->remote_udp)
1145 *sender_ip = packet->stream->remote_udp->remote_ip;
1146 *sender_port = packet->stream->remote_udp->remote_port;
1151 /* Reference packet stream */
1153 void silc_packet_stream_ref(SilcPacketStream stream)
1155 silc_atomic_add_int8(&stream->refcnt, 1);
1156 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1157 silc_atomic_get_int8(&stream->refcnt) - 1,
1158 silc_atomic_get_int8(&stream->refcnt)));
1161 /* Unreference packet stream */
1163 void silc_packet_stream_unref(SilcPacketStream stream)
1165 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1166 silc_atomic_get_int8(&stream->refcnt),
1167 silc_atomic_get_int8(&stream->refcnt) - 1));
1168 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1170 silc_atomic_add_int8(&stream->refcnt, 1);
1171 silc_packet_stream_destroy(stream);
1176 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1178 return stream->sc->engine;
1181 /* Set application context for packet stream */
1183 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1185 silc_mutex_lock(stream->lock);
1186 stream->stream_context = stream_context;
1187 silc_mutex_unlock(stream->lock);
1190 /* Return application context from packet stream */
1192 void *silc_packet_get_context(SilcPacketStream stream)
1195 silc_mutex_lock(stream->lock);
1196 context = stream->stream_context;
1197 silc_mutex_unlock(stream->lock);
1201 /* Change underlaying stream */
1203 void silc_packet_stream_set_stream(SilcPacketStream ps,
1207 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1208 ps->stream = stream;
1209 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1213 /* Return underlaying stream */
1215 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1217 return stream->stream;
1222 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1223 SilcCipher receive_key, SilcHmac send_hmac,
1224 SilcHmac receive_hmac, SilcBool rekey)
1226 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1228 /* If doing rekey, send REKEY_DONE packet */
1230 /* This will take stream lock. */
1231 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1232 stream->src_id_type, stream->src_id,
1233 stream->src_id_len, stream->dst_id_type,
1234 stream->dst_id, stream->dst_id_len,
1235 NULL, 0, stream->send_key[0],
1236 stream->send_hmac[0]))
1239 /* Write the packet to the stream */
1240 if (!silc_packet_stream_write(stream, TRUE))
1243 silc_mutex_lock(stream->lock);
1246 /* In case IV Included is set, save the old keys */
1247 if (stream->iv_included) {
1248 if (stream->send_key[1] && send_key) {
1249 silc_cipher_free(stream->send_key[1]);
1250 stream->send_key[1] = stream->send_key[0];
1252 if (stream->receive_key[1] && receive_key) {
1253 silc_cipher_free(stream->receive_key[1]);
1254 stream->receive_key[1] = stream->receive_key[0];
1256 if (stream->send_hmac[1] && send_hmac) {
1257 silc_hmac_free(stream->send_hmac[1]);
1258 stream->send_hmac[1] = stream->send_hmac[0];
1260 if (stream->receive_hmac[1] && receive_hmac) {
1261 silc_hmac_free(stream->receive_hmac[1]);
1262 stream->receive_hmac[1] = stream->receive_hmac[0];
1265 if (stream->send_key[0] && send_key)
1266 silc_cipher_free(stream->send_key[0]);
1267 if (stream->receive_key[0] && receive_key)
1268 silc_cipher_free(stream->receive_key[0]);
1269 if (stream->send_hmac[0] && send_hmac)
1270 silc_hmac_free(stream->send_hmac[0]);
1271 if (stream->receive_hmac[0] && receive_hmac)
1272 silc_hmac_free(stream->receive_hmac[0]);
1277 stream->send_key[0] = send_key;
1279 stream->receive_key[0] = receive_key;
1281 stream->send_hmac[0] = send_hmac;
1283 stream->receive_hmac[0] = receive_hmac;
1285 silc_mutex_unlock(stream->lock);
1289 /* Return current ciphers from packet stream */
1291 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1292 SilcCipher *send_key,
1293 SilcCipher *receive_key,
1294 SilcHmac *send_hmac,
1295 SilcHmac *receive_hmac)
1297 if (!stream->send_key[0] && !stream->receive_key[0] &&
1298 !stream->send_hmac[0] && !stream->receive_hmac[0])
1301 silc_mutex_lock(stream->lock);
1304 *send_key = stream->send_key[0];
1306 *receive_key = stream->receive_key[0];
1308 *send_hmac = stream->send_hmac[0];
1310 *receive_hmac = stream->receive_hmac[0];
1312 silc_mutex_unlock(stream->lock);
1317 /* Set SILC IDs to packet stream */
1319 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1320 SilcIdType src_id_type, const void *src_id,
1321 SilcIdType dst_id_type, const void *dst_id)
1324 unsigned char tmp[32];
1326 if (!src_id && !dst_id)
1329 silc_mutex_lock(stream->lock);
1332 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1334 silc_free(stream->src_id);
1335 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1336 silc_mutex_unlock(stream->lock);
1339 stream->src_id = silc_memdup(tmp, len);
1340 if (!stream->src_id) {
1341 silc_mutex_unlock(stream->lock);
1344 stream->src_id_type = src_id_type;
1345 stream->src_id_len = len;
1349 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1351 silc_free(stream->dst_id);
1352 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1353 silc_mutex_unlock(stream->lock);
1356 stream->dst_id = silc_memdup(tmp, len);
1357 if (!stream->dst_id) {
1358 silc_mutex_unlock(stream->lock);
1361 stream->dst_id_type = dst_id_type;
1362 stream->dst_id_len = len;
1365 silc_mutex_unlock(stream->lock);
1370 /* Return IDs from the packet stream */
1372 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1373 SilcBool *src_id_set, SilcID *src_id,
1374 SilcBool *dst_id_set, SilcID *dst_id)
1376 if (src_id && stream->src_id)
1377 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1378 stream->src_id_type, src_id))
1381 if (stream->src_id && src_id_set)
1384 if (dst_id && stream->dst_id)
1385 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1386 stream->dst_id_type, dst_id))
1389 if (stream->dst_id && dst_id_set)
1395 /* Adds Security ID (SID) */
1397 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1399 if (!stream->iv_included)
1402 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1410 void silc_packet_free(SilcPacket packet)
1412 SilcPacketStream stream = packet->stream;
1414 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1416 /* Check for double free */
1417 SILC_ASSERT(packet->stream != NULL);
1419 packet->stream = NULL;
1420 packet->src_id = packet->dst_id = NULL;
1421 silc_buffer_reset(&packet->buffer);
1423 silc_mutex_lock(stream->sc->engine->lock);
1425 /* Put the packet back to freelist */
1426 silc_list_add(stream->sc->engine->packet_pool, packet);
1427 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1428 silc_list_start(stream->sc->engine->packet_pool);
1430 silc_mutex_unlock(stream->sc->engine->lock);
1433 /****************************** Packet Sending ******************************/
1435 /* Prepare outgoing data buffer for packet sending. Returns the
1436 pointer to that buffer into the `packet'. */
1438 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1443 unsigned char *oldptr;
1444 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1448 /* Allocate more space if needed */
1449 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1450 if (!silc_buffer_realloc(&stream->outbuf,
1451 silc_buffer_truelen(&stream->outbuf) + totlen))
1455 /* Pull data area for the new packet, and return pointer to the start of
1456 the data area and save the pointer in to the `packet'. MAC is pulled
1457 later after it's computed. */
1458 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1459 silc_buffer_set(packet, oldptr, totlen);
1460 silc_buffer_push_tail(packet, mac_len);
1465 /* Increments counter when encrypting in counter mode. */
1467 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1469 unsigned char *ret_iv)
1471 unsigned char *iv = silc_cipher_get_iv(cipher);
1472 SilcUInt32 pc1, pc2;
1474 /* Reset block counter */
1475 memset(iv + 12, 0, 4);
1477 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1478 if (stream->iv_included) {
1480 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1481 ret_iv[1] = ret_iv[0] + iv[4];
1482 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1483 ret_iv[3] = ret_iv[0] + ret_iv[2];
1485 /* Increment 32-bit packet counter */
1486 SILC_GET32_MSB(pc1, iv + 8);
1488 SILC_PUT32_MSB(pc1, ret_iv + 4);
1490 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1492 /* Set new nonce to counter block */
1493 memcpy(iv + 4, ret_iv, 8);
1495 /* Increment 64-bit packet counter */
1496 SILC_GET32_MSB(pc1, iv + 4);
1497 SILC_GET32_MSB(pc2, iv + 8);
1500 SILC_PUT32_MSB(pc1, iv + 4);
1501 SILC_PUT32_MSB(pc2, iv + 8);
1504 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1507 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1508 the packet. The silc_packet_stream_write needs to be called to send it
1509 after this returns TRUE. */
1511 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1512 SilcPacketType type,
1513 SilcPacketFlags flags,
1514 SilcIdType src_id_type,
1515 unsigned char *src_id,
1516 SilcUInt32 src_id_len,
1517 SilcIdType dst_id_type,
1518 unsigned char *dst_id,
1519 SilcUInt32 dst_id_len,
1520 const unsigned char *data,
1521 SilcUInt32 data_len,
1525 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1526 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1527 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1529 SilcBufferStruct packet;
1531 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1532 "data len %d", silc_get_packet_name(type), stream->send_psn,
1533 flags, src_id_type, dst_id_type, data_len));
1535 /* Get the true length of the packet. This is saved as payload length
1536 into the packet header. This does not include the length of the
1538 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1539 src_id_len + dst_id_len));
1540 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1541 src_id_len + dst_id_len);
1543 /* If using CTR mode, increment the counter */
1544 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1546 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1548 /* If IV is included, the SID, IV and sequence number is added to packet */
1549 if (stream->iv_included && cipher) {
1550 psnlen = sizeof(psn);
1552 iv[0] = stream->sid;
1555 /* If IV is included, the SID, IV and sequence number is added to packet */
1556 if (stream->iv_included && cipher) {
1557 psnlen = sizeof(psn);
1558 ivlen = block_len + 1;
1559 iv[0] = stream->sid;
1560 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1564 /* We automatically figure out the packet structure from the packet
1565 type and flags, and calculate correct length. Private messages with
1566 private keys and channel messages are special packets as their
1567 payload is encrypted already. */
1568 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1569 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1570 /* Padding is calculated from header + IDs */
1572 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1573 psnlen), block_len, padlen);
1575 /* Length to encrypt, header + IDs + padding. */
1576 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1579 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1580 if (stream->sc->engine->local_is_router && stream->is_router) {
1581 /* Channel messages between routers are encrypted as normal packets.
1582 Padding is calculated from true length of the packet. */
1584 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1586 enclen += padlen + psnlen;
1588 /* Padding is calculated from header + IDs */
1590 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1591 psnlen), block_len, padlen);
1593 /* Length to encrypt, header + IDs + padding. */
1594 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1598 /* Padding is calculated from true length of the packet */
1599 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1600 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1602 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1604 enclen += padlen + psnlen;
1607 /* Remove implementation specific flags */
1608 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1610 /* Get random padding */
1611 for (i = 0; i < padlen; i++) tmppad[i] =
1612 silc_rng_get_byte_fast(stream->sc->engine->rng);
1614 silc_mutex_lock(stream->lock);
1616 /* Get packet pointer from the outgoing buffer */
1617 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1618 + psnlen, hmac, &packet))) {
1619 silc_mutex_unlock(stream->lock);
1623 SILC_PUT32_MSB(stream->send_psn, psn);
1625 /* Create the packet. This creates the SILC header, adds padding, and
1626 the actual packet data. */
1627 i = silc_buffer_format(&packet,
1628 SILC_STR_DATA(iv, ivlen),
1629 SILC_STR_DATA(psn, psnlen),
1630 SILC_STR_UI_SHORT(truelen),
1631 SILC_STR_UI_CHAR(flags),
1632 SILC_STR_UI_CHAR(type),
1633 SILC_STR_UI_CHAR(padlen),
1634 SILC_STR_UI_CHAR(0),
1635 SILC_STR_UI_CHAR(src_id_len),
1636 SILC_STR_UI_CHAR(dst_id_len),
1637 SILC_STR_UI_CHAR(src_id_type),
1638 SILC_STR_DATA(src_id, src_id_len),
1639 SILC_STR_UI_CHAR(dst_id_type),
1640 SILC_STR_DATA(dst_id, dst_id_len),
1641 SILC_STR_DATA(tmppad, padlen),
1642 SILC_STR_DATA(data, data_len),
1644 if (silc_unlikely(i < 0)) {
1645 silc_mutex_unlock(stream->lock);
1649 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1650 silc_buffer_data(&packet), silc_buffer_len(&packet));
1652 /* Encrypt the packet */
1653 if (silc_likely(cipher)) {
1654 SILC_LOG_DEBUG(("Encrypting packet"));
1655 silc_cipher_set_iv(cipher, NULL);
1656 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1657 packet.data + ivlen, enclen,
1659 SILC_LOG_ERROR(("Packet encryption failed"));
1660 silc_mutex_unlock(stream->lock);
1666 if (silc_likely(hmac)) {
1669 /* MAC is computed from the entire encrypted packet data, and put
1670 to the end of the packet. */
1671 silc_hmac_init(hmac);
1672 silc_hmac_update(hmac, psn, sizeof(psn));
1673 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1674 silc_hmac_final(hmac, packet.tail, &mac_len);
1675 silc_buffer_pull_tail(&packet, mac_len);
1682 /* Sends a packet */
1684 SilcBool silc_packet_send(SilcPacketStream stream,
1685 SilcPacketType type, SilcPacketFlags flags,
1686 const unsigned char *data, SilcUInt32 data_len)
1690 ret = silc_packet_send_raw(stream, type, flags,
1691 stream->src_id_type,
1694 stream->dst_id_type,
1698 stream->send_key[0],
1699 stream->send_hmac[0]);
1701 /* Write the packet to the stream */
1702 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1705 /* Sends a packet, extended routine */
1707 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1708 SilcPacketType type, SilcPacketFlags flags,
1709 SilcIdType src_id_type, void *src_id,
1710 SilcIdType dst_id_type, void *dst_id,
1711 const unsigned char *data, SilcUInt32 data_len,
1712 SilcCipher cipher, SilcHmac hmac)
1714 unsigned char src_id_data[32], dst_id_data[32];
1715 SilcUInt32 src_id_len, dst_id_len;
1719 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1720 sizeof(src_id_data), &src_id_len))
1723 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1724 sizeof(dst_id_data), &dst_id_len))
1727 ret = silc_packet_send_raw(stream, type, flags,
1728 src_id ? src_id_type : stream->src_id_type,
1729 src_id ? src_id_data : stream->src_id,
1730 src_id ? src_id_len : stream->src_id_len,
1731 dst_id ? dst_id_type : stream->dst_id_type,
1732 dst_id ? dst_id_data : stream->dst_id,
1733 dst_id ? dst_id_len : stream->dst_id_len,
1735 cipher ? cipher : stream->send_key[0],
1736 hmac ? hmac : stream->send_hmac[0]);
1738 /* Write the packet to the stream */
1739 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1742 /* Sends packet after formatting the arguments to buffer */
1744 SilcBool silc_packet_send_va(SilcPacketStream stream,
1745 SilcPacketType type, SilcPacketFlags flags, ...)
1747 SilcBufferStruct buf;
1751 va_start(va, flags);
1753 memset(&buf, 0, sizeof(buf));
1754 if (silc_buffer_format_vp(&buf, va) < 0) {
1759 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1760 silc_buffer_len(&buf));
1762 silc_buffer_purge(&buf);
1768 /* Sends packet after formatting the arguments to buffer, extended routine */
1770 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1771 SilcPacketType type, SilcPacketFlags flags,
1772 SilcIdType src_id_type, void *src_id,
1773 SilcIdType dst_id_type, void *dst_id,
1774 SilcCipher cipher, SilcHmac hmac, ...)
1776 SilcBufferStruct buf;
1782 memset(&buf, 0, sizeof(buf));
1783 if (silc_buffer_format_vp(&buf, va) < 0) {
1788 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1789 dst_id_type, dst_id, silc_buffer_data(&buf),
1790 silc_buffer_len(&buf), cipher, hmac);
1792 silc_buffer_purge(&buf);
1798 /***************************** Packet Receiving *****************************/
1800 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1802 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1803 const unsigned char *data,
1804 SilcUInt32 data_len,
1805 const unsigned char *packet_mac,
1806 const unsigned char *packet_seq,
1807 SilcUInt32 sequence)
1810 if (silc_likely(hmac)) {
1811 unsigned char mac[32], psn[4];
1814 SILC_LOG_DEBUG(("Verifying MAC"));
1816 /* Compute HMAC of packet */
1817 silc_hmac_init(hmac);
1820 SILC_PUT32_MSB(sequence, psn);
1821 silc_hmac_update(hmac, psn, 4);
1823 silc_hmac_update(hmac, packet_seq, 4);
1825 silc_hmac_update(hmac, data, data_len);
1826 silc_hmac_final(hmac, mac, &mac_len);
1828 /* Compare the MAC's */
1829 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1830 SILC_LOG_DEBUG(("MAC failed"));
1834 SILC_LOG_DEBUG(("MAC is Ok"));
1840 /* Increments/sets counter when decrypting in counter mode. */
1842 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1844 unsigned char *packet_iv)
1846 SilcUInt32 pc1, pc2;
1848 /* If IV Included flag, set the IV from packet to block counter. */
1849 if (stream->iv_included) {
1850 memcpy(iv + 4, packet_iv, 8);
1852 /* Increment 64-bit packet counter. */
1853 SILC_GET32_MSB(pc1, iv + 4);
1854 SILC_GET32_MSB(pc2, iv + 8);
1857 SILC_PUT32_MSB(pc1, iv + 4);
1858 SILC_PUT32_MSB(pc2, iv + 8);
1861 /* Reset block counter */
1862 memset(iv + 12, 0, 4);
1864 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1867 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1868 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1870 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1871 SilcUInt32 sequence, SilcBuffer buffer,
1874 if (normal == TRUE) {
1875 if (silc_likely(cipher)) {
1876 /* Decrypt rest of the packet */
1877 SILC_LOG_DEBUG(("Decrypting the packet"));
1878 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1880 silc_buffer_len(buffer), NULL)))
1886 /* Decrypt rest of the header plus padding */
1887 if (silc_likely(cipher)) {
1889 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1891 SILC_LOG_DEBUG(("Decrypting the header"));
1893 /* Padding length + src id len + dst id len + header length - 16
1894 bytes already decrypted, gives the rest of the encrypted packet */
1895 silc_buffer_push(buffer, block_len);
1896 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1897 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1899 silc_buffer_pull(buffer, block_len);
1901 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1902 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1906 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1907 buffer->data, len, NULL)))
1915 /* Parses the packet. This is called when a whole packet is ready to be
1916 parsed. The buffer sent must be already decrypted before calling this
1919 static inline SilcBool silc_packet_parse(SilcPacket packet)
1921 SilcBuffer buffer = &packet->buffer;
1922 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1923 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1926 SILC_LOG_DEBUG(("Parsing incoming packet"));
1928 /* Parse the buffer. This parses the SILC header of the packet. */
1929 ret = silc_buffer_unformat(buffer,
1932 SILC_STR_UI_CHAR(&src_id_len),
1933 SILC_STR_UI_CHAR(&dst_id_len),
1934 SILC_STR_UI_CHAR(&src_id_type),
1936 if (silc_unlikely(ret == -1)) {
1937 if (!packet->stream->udp &&
1938 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1939 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1943 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1944 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1945 if (!packet->stream->udp &&
1946 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1947 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1948 packet->src_id_len, packet->dst_id_len));
1952 ret = silc_buffer_unformat(buffer,
1954 SILC_STR_DATA(&packet->src_id, src_id_len),
1955 SILC_STR_UI_CHAR(&dst_id_type),
1956 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1957 SILC_STR_OFFSET(padlen),
1959 if (silc_unlikely(ret == -1)) {
1960 if (!packet->stream->udp &&
1961 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1962 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1966 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1967 dst_id_type > SILC_ID_CHANNEL)) {
1968 if (!packet->stream->udp &&
1969 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1970 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1971 src_id_type, dst_id_type));
1975 packet->src_id_len = src_id_len;
1976 packet->dst_id_len = dst_id_len;
1977 packet->src_id_type = src_id_type;
1978 packet->dst_id_type = dst_id_type;
1980 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1981 silc_buffer_len(buffer)), buffer->head,
1982 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1984 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1985 silc_get_packet_name(packet->type), packet->flags));
1990 /* Dispatch packet to application. Called with stream->lock locked.
1991 Returns FALSE if the stream was destroyed while dispatching a packet. */
1993 static SilcBool silc_packet_dispatch(SilcPacket packet)
1995 SilcPacketStream stream = packet->stream;
1996 SilcPacketProcess p;
1997 SilcBool default_sent = FALSE;
2000 /* Dispatch packet to all packet processors that want it */
2002 if (silc_likely(!stream->process)) {
2003 /* Send to default processor as no others exist */
2004 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2005 silc_mutex_unlock(stream->lock);
2006 if (silc_unlikely(!stream->sc->engine->callbacks->
2007 packet_receive(stream->sc->engine, stream, packet,
2008 stream->sc->engine->callback_context,
2009 stream->stream_context)))
2010 silc_packet_free(packet);
2011 silc_mutex_lock(stream->lock);
2012 return stream->destroyed == FALSE;
2015 silc_dlist_start(stream->process);
2016 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2018 /* If priority is 0 or less, we send to default processor first
2019 because default processor has 0 priority */
2020 if (!default_sent && p->priority <= 0) {
2021 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2022 default_sent = TRUE;
2023 silc_mutex_unlock(stream->lock);
2024 if (stream->sc->engine->callbacks->
2025 packet_receive(stream->sc->engine, stream, packet,
2026 stream->sc->engine->callback_context,
2027 stream->stream_context)) {
2028 silc_mutex_lock(stream->lock);
2029 return stream->destroyed == FALSE;
2031 silc_mutex_lock(stream->lock);
2034 /* Send to processor */
2036 /* Send all packet types */
2037 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2038 silc_mutex_unlock(stream->lock);
2039 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2040 p->callback_context,
2041 stream->stream_context)) {
2042 silc_mutex_lock(stream->lock);
2043 return stream->destroyed == FALSE;
2045 silc_mutex_lock(stream->lock);
2047 /* Send specific types */
2048 for (pt = p->types; *pt; pt++) {
2049 if (*pt != packet->type)
2051 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2052 silc_mutex_unlock(stream->lock);
2053 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2054 p->callback_context,
2055 stream->stream_context)) {
2056 silc_mutex_lock(stream->lock);
2057 return stream->destroyed == FALSE;
2059 silc_mutex_lock(stream->lock);
2065 if (!default_sent) {
2066 /* Send to default processor as it has not been sent yet */
2067 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2068 silc_mutex_unlock(stream->lock);
2069 if (stream->sc->engine->callbacks->
2070 packet_receive(stream->sc->engine, stream, packet,
2071 stream->sc->engine->callback_context,
2072 stream->stream_context)) {
2073 silc_mutex_lock(stream->lock);
2074 return stream->destroyed == FALSE;
2076 silc_mutex_lock(stream->lock);
2079 /* If we got here, no one wanted the packet, so drop it */
2080 silc_packet_free(packet);
2081 return stream->destroyed == FALSE;
2084 /* Process incoming data and parse packets. Called with stream->lock
2087 static void silc_packet_read_process(SilcPacketStream stream)
2094 SilcUInt16 packetlen;
2095 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2096 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2097 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2101 /* Get inbuf. If there is already some data for this stream in the buffer
2102 we already have it. Otherwise get the current one from list, it will
2103 include the data. */
2104 inbuf = stream->inbuf;
2106 silc_dlist_start(stream->sc->inbufs);
2107 inbuf = silc_dlist_get(stream->sc->inbufs);
2110 /* Parse the packets from the data */
2111 while (silc_buffer_len(inbuf) > 0) {
2113 cipher = stream->receive_key[0];
2114 hmac = stream->receive_hmac[0];
2117 if (silc_unlikely(silc_buffer_len(inbuf) <
2118 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2119 SILC_PACKET_MIN_HEADER_LEN))) {
2120 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2121 silc_dlist_del(stream->sc->inbufs, inbuf);
2122 stream->inbuf = inbuf;
2126 if (silc_likely(hmac))
2127 mac_len = silc_hmac_len(hmac);
2131 /* Decrypt first block of the packet to get the length field out */
2132 if (silc_likely(cipher)) {
2133 block_len = silc_cipher_get_block_len(cipher);
2135 if (stream->iv_included) {
2136 /* SID, IV and sequence number is included in the ciphertext */
2137 sid = (SilcUInt8)inbuf->data[0];
2139 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2140 /* Set the CTR mode IV from packet to counter block */
2141 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2142 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2145 /* Get IV from packet */
2146 memcpy(iv, inbuf->data + 1, block_len);
2147 ivlen = block_len + 1;
2151 /* Check SID, and get correct decryption key */
2152 if (sid != stream->sid) {
2153 /* If SID is recent get the previous key and use it */
2154 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2155 stream->receive_key[1] && !stream->receive_hmac[1]) {
2156 cipher = stream->receive_key[1];
2157 hmac = stream->receive_hmac[1];
2159 /* The SID is unknown, drop rest of the data in buffer */
2160 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2162 silc_mutex_unlock(stream->lock);
2163 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2164 silc_mutex_lock(stream->lock);
2169 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2171 /* If using CTR mode, increment the counter */
2172 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2173 silc_packet_receive_ctr_increment(stream, iv, NULL);
2176 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2177 silc_cipher_set_iv(cipher, NULL);
2178 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2181 if (stream->iv_included) {
2182 /* Take sequence number from packet */
2183 packet_seq = header;
2187 /* Unencrypted packet */
2188 block_len = SILC_PACKET_MIN_HEADER_LEN;
2189 header = inbuf->data;
2192 /* Get packet length and full packet length with padding */
2193 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2196 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2197 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2198 SILC_LOG_ERROR(("Received too short packet"));
2199 silc_mutex_unlock(stream->lock);
2200 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2201 silc_mutex_lock(stream->lock);
2202 memset(tmp, 0, sizeof(tmp));
2206 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2207 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2209 paddedlen + mac_len - silc_buffer_len(inbuf)));
2210 memset(tmp, 0, sizeof(tmp));
2211 silc_dlist_del(stream->sc->inbufs, inbuf);
2212 stream->inbuf = inbuf;
2216 /* Check MAC of the packet */
2217 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2219 inbuf->data + ivlen +
2220 paddedlen, packet_seq,
2221 stream->receive_psn))) {
2222 silc_mutex_unlock(stream->lock);
2223 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2224 silc_mutex_lock(stream->lock);
2225 memset(tmp, 0, sizeof(tmp));
2230 packet = silc_packet_alloc(stream->sc->engine);
2231 if (silc_unlikely(!packet)) {
2232 silc_mutex_unlock(stream->lock);
2233 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2234 silc_mutex_lock(stream->lock);
2235 memset(tmp, 0, sizeof(tmp));
2238 packet->stream = stream;
2240 /* Allocate more space to packet buffer, if needed */
2241 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2242 if (!silc_buffer_realloc(&packet->buffer,
2243 silc_buffer_truelen(&packet->buffer) +
2245 silc_buffer_truelen(&packet->buffer)))) {
2246 silc_mutex_unlock(stream->lock);
2247 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2248 silc_mutex_lock(stream->lock);
2249 silc_packet_free(packet);
2250 memset(tmp, 0, sizeof(tmp));
2255 /* Parse packet header */
2256 packet->flags = (SilcPacketFlags)header[2];
2257 packet->type = (SilcPacketType)header[3];
2259 if (stream->sc->engine->local_is_router) {
2260 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2261 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2263 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2264 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2265 stream->is_router == TRUE))
2268 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2269 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2271 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2275 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2276 stream->receive_psn, paddedlen + ivlen + mac_len),
2277 inbuf->data, paddedlen + ivlen + mac_len);
2279 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2280 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2281 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2282 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2283 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2284 psnlen + (block_len - psnlen)),
2285 paddedlen - ivlen - psnlen - (block_len - psnlen));
2286 if (silc_likely(cipher)) {
2287 silc_cipher_set_iv(cipher, iv);
2288 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2289 &packet->buffer, normal);
2290 if (silc_unlikely(ret < 0)) {
2291 silc_mutex_unlock(stream->lock);
2292 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2293 silc_mutex_lock(stream->lock);
2294 silc_packet_free(packet);
2295 memset(tmp, 0, sizeof(tmp));
2299 stream->receive_psn++;
2301 silc_buffer_push(&packet->buffer, block_len);
2303 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2304 silc_buffer_pull(inbuf, paddedlen + mac_len);
2306 /* Parse the packet */
2307 if (silc_unlikely(!silc_packet_parse(packet))) {
2308 silc_mutex_unlock(stream->lock);
2309 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2310 silc_mutex_lock(stream->lock);
2311 silc_packet_free(packet);
2312 memset(tmp, 0, sizeof(tmp));
2316 /* Dispatch the packet to application */
2317 if (!silc_packet_dispatch(packet))
2322 /* Add inbuf back to free list, if we owned it. */
2323 if (stream->inbuf) {
2324 silc_dlist_add(stream->sc->inbufs, inbuf);
2325 stream->inbuf = NULL;
2328 silc_buffer_reset(inbuf);
2331 /****************************** Packet Waiting ******************************/
2333 /* Packet wait receive callback */
2335 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2336 SilcPacketStream stream,
2338 void *callback_context,
2339 void *stream_context);
2341 /* Packet waiting callbacks */
2342 static SilcPacketCallbacks silc_packet_wait_cbs =
2344 silc_packet_wait_packet_receive, NULL, NULL
2347 /* Packet waiting context */
2349 SilcMutex wait_lock;
2351 SilcList packet_queue;
2352 unsigned char id[28];
2353 unsigned int id_type : 2;
2354 unsigned int id_len : 5;
2355 unsigned int stopped : 1;
2358 /* Packet wait receive callback */
2361 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2362 SilcPacketStream stream,
2364 void *callback_context,
2365 void *stream_context)
2367 SilcPacketWait pw = callback_context;
2369 /* If source ID is specified check for it */
2371 if (pw->id_type != packet->src_id_type ||
2372 memcmp(pw->id, packet->src_id, pw->id_len))
2376 /* Signal the waiting thread for a new packet */
2377 silc_mutex_lock(pw->wait_lock);
2379 if (silc_unlikely(pw->stopped)) {
2380 silc_mutex_unlock(pw->wait_lock);
2384 silc_list_add(pw->packet_queue, packet);
2385 silc_cond_broadcast(pw->wait_cond);
2387 silc_mutex_unlock(pw->wait_lock);
2392 /* Initialize packet waiting */
2394 void *silc_packet_wait_init(SilcPacketStream stream,
2395 const SilcID *source_id, ...)
2401 pw = silc_calloc(1, sizeof(*pw));
2405 /* Allocate mutex and conditional variable */
2406 if (!silc_mutex_alloc(&pw->wait_lock)) {
2410 if (!silc_cond_alloc(&pw->wait_cond)) {
2411 silc_mutex_free(pw->wait_lock);
2416 /* Link to the packet stream for the requested packet types */
2417 va_start(ap, source_id);
2418 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2422 silc_cond_free(pw->wait_cond);
2423 silc_mutex_free(pw->wait_lock);
2428 /* Initialize packet queue */
2429 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2433 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2434 sizeof(pw->id), &id_len);
2435 pw->id_type = source_id->type;
2436 pw->id_len = id_len;
2442 /* Uninitialize packet waiting */
2444 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2446 SilcPacketWait pw = waiter;
2449 /* Signal any threads to stop waiting */
2450 silc_mutex_lock(pw->wait_lock);
2452 silc_cond_broadcast(pw->wait_cond);
2453 silc_mutex_unlock(pw->wait_lock);
2454 silc_thread_yield();
2456 /* Re-acquire lock and free resources */
2457 silc_mutex_lock(pw->wait_lock);
2458 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2460 /* Free any remaining packets */
2461 silc_list_start(pw->packet_queue);
2462 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2463 silc_packet_free(packet);
2465 silc_mutex_unlock(pw->wait_lock);
2466 silc_cond_free(pw->wait_cond);
2467 silc_mutex_free(pw->wait_lock);
2471 /* Blocks thread until a packet has been received. */
2473 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2475 SilcPacketWait pw = waiter;
2476 SilcBool ret = FALSE;
2478 silc_mutex_lock(pw->wait_lock);
2480 /* Wait here until packet has arrived */
2481 while (silc_list_count(pw->packet_queue) == 0) {
2482 if (silc_unlikely(pw->stopped)) {
2483 silc_mutex_unlock(pw->wait_lock);
2486 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2490 silc_list_start(pw->packet_queue);
2491 *return_packet = silc_list_get(pw->packet_queue);
2492 silc_list_del(pw->packet_queue, *return_packet);
2494 silc_mutex_unlock(pw->wait_lock);
2496 return ret == TRUE ? 1 : 0;
2499 /************************** Packet Stream Wrapper ***************************/
2501 /* Packet stream wrapper receive callback */
2503 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2504 SilcPacketStream stream,
2506 void *callback_context,
2507 void *stream_context);
2509 const SilcStreamOps silc_packet_stream_ops;
2511 /* Packet stream wrapper context */
2513 const SilcStreamOps *ops;
2514 SilcPacketStream stream;
2516 void *waiter; /* Waiter context in blocking mode */
2517 SilcPacketWrapCoder coder;
2518 void *coder_context;
2520 SilcStreamNotifier callback;
2523 SilcPacketType type;
2524 SilcPacketFlags flags;
2525 unsigned int closed : 1;
2526 unsigned int blocking : 1;
2527 unsigned int read_more : 1;
2528 } *SilcPacketWrapperStream;
2530 /* Packet wrapper callbacks */
2531 static SilcPacketCallbacks silc_packet_wrap_cbs =
2533 silc_packet_wrap_packet_receive, NULL, NULL
2536 /* Packet stream wrapper receive callback, non-blocking mode */
2539 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2540 SilcPacketStream stream,
2542 void *callback_context,
2543 void *stream_context)
2545 SilcPacketWrapperStream pws = callback_context;
2547 if (pws->closed || !pws->callback)
2550 silc_mutex_lock(pws->lock);
2551 silc_list_add(pws->in_queue, packet);
2552 silc_mutex_unlock(pws->lock);
2554 /* Call notifier callback */
2555 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2560 /* Task callback to notify more data is available for reading */
2562 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2564 SilcPacketWrapperStream pws = context;
2566 if (pws->closed || !pws->callback)
2569 /* Call notifier callback */
2570 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2573 /* Read SILC packet */
2575 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2578 SilcPacketWrapperStream pws = stream;
2580 SilcBool read_more = FALSE;
2586 if (pws->blocking) {
2587 /* Block until packet is received */
2588 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2593 /* Non-blocking mode */
2594 silc_mutex_lock(pws->lock);
2595 if (!silc_list_count(pws->in_queue)) {
2596 silc_mutex_unlock(pws->lock);
2600 silc_list_start(pws->in_queue);
2601 packet = silc_list_get(pws->in_queue);
2602 silc_list_del(pws->in_queue, packet);
2603 silc_mutex_unlock(pws->lock);
2606 /* Call decoder if set */
2607 if (pws->coder && !pws->read_more)
2608 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2609 pws->coder_context);
2611 len = silc_buffer_len(&packet->buffer);
2612 if (len > buf_len) {
2618 memcpy(buf, packet->buffer.data, len);
2620 if (read_more && !pws->blocking) {
2621 /* More data will be available (in blocking mode not supported). */
2622 silc_buffer_pull(&packet->buffer, len);
2623 silc_list_insert(pws->in_queue, NULL, packet);
2624 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2625 silc_packet_wrap_read_more, pws, 0, 0);
2626 pws->read_more = TRUE;
2630 pws->read_more = FALSE;
2631 silc_packet_free(packet);
2635 /* Write SILC packet */
2637 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2638 SilcUInt32 data_len)
2640 SilcPacketWrapperStream pws = stream;
2641 SilcBool ret = FALSE;
2643 /* Call encoder if set */
2645 silc_buffer_reset(pws->encbuf);
2646 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2647 pws->coder_context);
2650 /* Send the SILC packet */
2652 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2653 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2654 silc_buffer_len(pws->encbuf)),
2655 SILC_STR_DATA(data, data_len),
2659 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2668 SilcBool silc_packet_wrap_close(SilcStream stream)
2670 SilcPacketWrapperStream pws = stream;
2675 if (pws->blocking) {
2676 /* Close packet waiter */
2677 silc_packet_wait_uninit(pws->waiter, pws->stream);
2681 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2688 /* Destroy wrapper stream */
2690 void silc_packet_wrap_destroy(SilcStream stream)
2693 SilcPacketWrapperStream pws = stream;
2696 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2698 silc_stream_close(stream);
2699 silc_list_start(pws->in_queue);
2700 while ((packet = silc_list_get(pws->in_queue)))
2701 silc_packet_free(packet);
2703 silc_mutex_free(pws->lock);
2705 silc_buffer_free(pws->encbuf);
2706 silc_packet_stream_unref(pws->stream);
2711 /* Link stream to receive packets */
2713 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2714 SilcSchedule schedule,
2715 SilcStreamNotifier callback,
2718 SilcPacketWrapperStream pws = stream;
2720 if (pws->closed || pws->blocking)
2723 /* Link to receive packets */
2725 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2726 100000, pws->type, -1);
2728 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2730 pws->callback = callback;
2731 pws->context = context;
2736 /* Return schedule */
2738 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2743 /* Wraps packet stream into SilcStream. */
2745 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2746 SilcPacketType type,
2747 SilcPacketFlags flags,
2748 SilcBool blocking_mode,
2749 SilcPacketWrapCoder coder,
2752 SilcPacketWrapperStream pws;
2754 pws = silc_calloc(1, sizeof(*pws));
2758 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2760 pws->ops = &silc_packet_stream_ops;
2761 pws->stream = stream;
2764 pws->blocking = blocking_mode;
2766 pws->coder_context = context;
2768 /* Allocate small amount for encoder buffer. */
2770 pws->encbuf = silc_buffer_alloc(8);
2772 if (pws->blocking) {
2773 /* Blocking mode. Use packet waiter to do the thing. */
2774 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2780 /* Non-blocking mode */
2781 silc_mutex_alloc(&pws->lock);
2782 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2785 silc_packet_stream_ref(stream);
2787 return (SilcStream)pws;
2790 const SilcStreamOps silc_packet_stream_ops =
2792 silc_packet_wrap_read,
2793 silc_packet_wrap_write,
2794 silc_packet_wrap_close,
2795 silc_packet_wrap_destroy,
2796 silc_packet_wrap_notifier,
2797 silc_packet_wrap_get_schedule,