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(NULL, 0, silc_hash_ptr,
566 silc_packet_engine_context_destr,
568 if (!engine->contexts) {
574 engine->local_is_router = router;
575 engine->callbacks = callbacks;
576 engine->callback_context = callback_context;
577 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
578 silc_mutex_alloc(&engine->lock);
580 /* Allocate packet free list */
581 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
582 for (i = 0; i < 5; i++) {
583 packet = silc_calloc(1, sizeof(*packet));
585 silc_packet_engine_stop(engine);
589 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
591 silc_packet_engine_stop(engine);
594 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
595 silc_buffer_reset(&packet->buffer);
597 silc_list_add(engine->packet_pool, packet);
599 silc_list_start(engine->packet_pool);
604 /* Stop packet engine */
606 void silc_packet_engine_stop(SilcPacketEngine engine)
610 SILC_LOG_DEBUG(("Stopping packet engine"));
615 /* Free packet free list */
616 silc_list_start(engine->packet_pool);
617 while ((packet = silc_list_get(engine->packet_pool))) {
618 silc_buffer_purge(&packet->buffer);
622 silc_hash_table_free(engine->contexts);
623 silc_mutex_free(engine->lock);
627 static const char *packet_error[] = {
628 "Cannot read from stream",
629 "Cannot write to stream",
631 "Packet decryption failed",
633 "Packet is malformed",
634 "System out of memory",
637 /* Return packet error string */
639 const char *silc_packet_error_string(SilcPacketError error)
641 if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
642 return "<invalid error code>";
643 return packet_error[error];
646 /* Return list of packet streams in the engine */
648 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
653 list = silc_dlist_init();
657 silc_mutex_lock(engine->lock);
658 silc_list_start(engine->streams);
659 while ((ps = silc_list_get(engine->streams))) {
660 silc_packet_stream_ref(ps);
661 silc_dlist_add(list, ps);
663 silc_mutex_unlock(engine->lock);
668 /* Free list returned by silc_packet_engine_get_streams */
670 void silc_packet_engine_free_streams_list(SilcDList streams)
674 silc_dlist_start(streams);
675 while ((ps = silc_dlist_get(streams)))
676 silc_packet_stream_unref(ps);
678 silc_dlist_uninit(streams);
681 /* Create new packet stream */
683 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
684 SilcSchedule schedule,
691 SILC_LOG_DEBUG(("Creating new packet stream"));
693 if (!engine || !stream)
696 ps = silc_calloc(1, sizeof(*ps));
701 silc_atomic_init8(&ps->refcnt, 1);
702 silc_mutex_alloc(&ps->lock);
704 /* Allocate out buffer */
705 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
707 silc_packet_stream_destroy(ps);
710 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
711 silc_buffer_reset(&ps->outbuf);
713 /* Initialize packet procesors list */
714 ps->process = silc_dlist_init();
716 silc_packet_stream_destroy(ps);
720 silc_mutex_lock(engine->lock);
722 /* Add per scheduler context */
723 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
725 ps->sc = silc_calloc(1, sizeof(*ps->sc));
727 silc_packet_stream_destroy(ps);
728 silc_mutex_unlock(engine->lock);
731 ps->sc->engine = engine;
732 ps->sc->schedule = schedule;
734 /* Allocate data input buffer */
735 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
739 silc_packet_stream_destroy(ps);
740 silc_mutex_unlock(engine->lock);
743 silc_buffer_reset(inbuf);
745 ps->sc->inbufs = silc_dlist_init();
746 if (!ps->sc->inbufs) {
747 silc_buffer_free(inbuf);
750 silc_packet_stream_destroy(ps);
751 silc_mutex_unlock(engine->lock);
754 silc_dlist_add(ps->sc->inbufs, inbuf);
756 /* Add to per scheduler context hash table */
757 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
758 silc_buffer_free(inbuf);
759 silc_dlist_del(ps->sc->inbufs, inbuf);
762 silc_packet_stream_destroy(ps);
763 silc_mutex_unlock(engine->lock);
767 ps->sc->stream_count++;
769 /* Add the packet stream to engine */
770 silc_list_add(engine->streams, ps);
772 /* If this is UDP stream, allocate UDP remote stream hash table */
773 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
774 engine->udp_remote = silc_hash_table_alloc(NULL, 0, silc_hash_string, NULL,
775 silc_hash_string_compare, NULL,
776 silc_packet_engine_hash_destr,
779 silc_mutex_unlock(engine->lock);
781 /* Set IO notifier callback. This schedules this stream for I/O. */
782 if (!silc_stream_set_notifier(ps->stream, schedule,
783 silc_packet_stream_io, ps)) {
784 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
785 silc_packet_stream_destroy(ps);
792 /* Add new remote packet stream for UDP packet streams */
794 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
795 const char *remote_ip,
796 SilcUInt16 remote_port,
799 SilcPacketEngine engine = stream->sc->engine;
804 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
805 remote_ip, remote_port, stream));
807 if (!stream || !remote_ip || !remote_port)
810 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
811 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
815 ps = silc_calloc(1, sizeof(*ps));
820 silc_atomic_init8(&ps->refcnt, 1);
821 silc_mutex_alloc(&ps->lock);
823 /* Set the UDP packet stream as underlaying stream */
824 silc_packet_stream_ref(stream);
825 ps->stream = (SilcStream)stream;
828 /* Allocate out buffer */
829 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
831 silc_packet_stream_destroy(ps);
834 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
835 silc_buffer_reset(&ps->outbuf);
837 /* Initialize packet procesors list */
838 ps->process = silc_dlist_init();
840 silc_packet_stream_destroy(ps);
844 /* Add to engine with this IP and port pair */
845 tuple = silc_format("%d%s", remote_port, remote_ip);
846 silc_mutex_lock(engine->lock);
847 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
848 silc_mutex_unlock(engine->lock);
849 silc_packet_stream_destroy(ps);
852 silc_mutex_unlock(engine->lock);
854 /* Save remote IP and port pair */
855 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
856 if (!ps->remote_udp) {
857 silc_packet_stream_destroy(ps);
860 ps->remote_udp->remote_port = remote_port;
861 ps->remote_udp->remote_ip = strdup(remote_ip);
862 if (!ps->remote_udp->remote_ip) {
863 silc_packet_stream_destroy(ps);
868 /* Inject packet to the new stream */
870 silc_packet_stream_ref(ps);
871 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
872 silc_packet_stream_inject_packet, packet,
879 /* Destroy packet stream */
881 void silc_packet_stream_destroy(SilcPacketStream stream)
883 SilcPacketEngine engine;
888 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
889 stream->destroyed = TRUE;
891 /* Close the underlaying stream */
892 if (!stream->udp && stream->stream)
893 silc_stream_close(stream->stream);
897 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
900 /* Delete from engine */
901 engine = stream->sc->engine;
902 silc_mutex_lock(engine->lock);
903 silc_list_del(engine->streams, stream);
905 /* Remove per scheduler context, if it is not used anymore */
907 stream->sc->stream_count--;
908 if (!stream->sc->stream_count)
909 silc_hash_table_del(engine->contexts, stream->sc->schedule);
911 silc_mutex_unlock(engine->lock);
913 /* Destroy the underlaying stream */
915 silc_stream_destroy(stream->stream);
917 /* Delete from UDP remote hash table */
919 engine = stream->sc->engine;
920 silc_snprintf(tuple, sizeof(tuple), "%d%s",
921 stream->remote_udp->remote_port,
922 stream->remote_udp->remote_ip);
923 silc_mutex_lock(engine->lock);
924 silc_hash_table_del(engine->udp_remote, tuple);
925 silc_mutex_unlock(engine->lock);
927 silc_free(stream->remote_udp->remote_ip);
928 silc_free(stream->remote_udp);
930 /* Unreference the underlaying packet stream */
931 silc_packet_stream_unref((SilcPacketStream)stream->stream);
934 /* Clear and free buffers */
935 silc_buffer_clear(&stream->outbuf);
936 silc_buffer_purge(&stream->outbuf);
938 if (stream->process) {
940 silc_dlist_start(stream->process);
941 while ((p = silc_dlist_get(stream->process))) {
944 silc_dlist_del(stream->process, p);
946 silc_dlist_uninit(stream->process);
949 /* Destroy ciphers and HMACs */
950 if (stream->send_key[0])
951 silc_cipher_free(stream->send_key[0]);
952 if (stream->receive_key[0])
953 silc_cipher_free(stream->receive_key[0]);
954 if (stream->send_hmac[0])
955 silc_hmac_free(stream->send_hmac[0]);
956 if (stream->receive_hmac[0])
957 silc_hmac_free(stream->receive_hmac[0]);
958 if (stream->send_key[1])
959 silc_cipher_free(stream->send_key[1]);
960 if (stream->receive_key[1])
961 silc_cipher_free(stream->receive_key[1]);
962 if (stream->send_hmac[1])
963 silc_hmac_free(stream->send_hmac[1]);
964 if (stream->receive_hmac[1])
965 silc_hmac_free(stream->receive_hmac[1]);
968 silc_free(stream->src_id);
969 silc_free(stream->dst_id);
971 silc_atomic_uninit8(&stream->refcnt);
972 silc_mutex_free(stream->lock);
976 /* Return TRUE if the stream is valid */
978 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
980 return stream->destroyed == FALSE;
983 /* Marks as router stream */
985 void silc_packet_stream_set_router(SilcPacketStream stream)
987 stream->is_router = TRUE;
990 /* Mark to include IV in ciphertext */
992 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
994 stream->iv_included = TRUE;
997 /* Links `callbacks' to `stream' for specified packet types */
999 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1000 SilcPacketCallbacks *callbacks,
1001 void *callback_context,
1002 int priority, va_list ap)
1004 SilcPacketProcess p, e;
1005 SilcInt32 packet_type;
1008 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1012 if (!callbacks->packet_receive)
1015 p = silc_calloc(1, sizeof(*p));
1019 p->priority = priority;
1020 p->callbacks = callbacks;
1021 p->callback_context = callback_context;
1023 silc_mutex_lock(stream->lock);
1025 if (!stream->process) {
1026 stream->process = silc_dlist_init();
1027 if (!stream->process) {
1028 silc_mutex_unlock(stream->lock);
1033 /* According to priority set the procesor to correct position. First
1034 entry has the highest priority */
1035 silc_dlist_start(stream->process);
1036 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1037 if (p->priority > e->priority) {
1038 silc_dlist_insert(stream->process, p);
1043 silc_dlist_add(stream->process, p);
1045 /* Get packet types to process */
1048 packet_type = va_arg(ap, SilcInt32);
1050 if (packet_type == SILC_PACKET_ANY)
1053 if (packet_type == -1)
1056 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1058 silc_mutex_unlock(stream->lock);
1062 p->types[i - 1] = (SilcPacketType)packet_type;
1066 p->types[i - 1] = 0;
1068 silc_mutex_unlock(stream->lock);
1070 silc_packet_stream_ref(stream);
1075 /* Links `callbacks' to `stream' for specified packet types */
1077 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1078 SilcPacketCallbacks *callbacks,
1079 void *callback_context,
1085 va_start(ap, priority);
1086 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1093 /* Unlinks `callbacks' from `stream'. */
1095 void silc_packet_stream_unlink(SilcPacketStream stream,
1096 SilcPacketCallbacks *callbacks,
1097 void *callback_context)
1099 SilcPacketProcess p;
1101 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1102 callbacks, stream));
1104 silc_mutex_lock(stream->lock);
1106 silc_dlist_start(stream->process);
1107 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1108 if (p->callbacks == callbacks &&
1109 p->callback_context == callback_context) {
1110 silc_dlist_del(stream->process, p);
1111 silc_free(p->types);
1116 if (!silc_dlist_count(stream->process)) {
1117 silc_dlist_uninit(stream->process);
1118 stream->process = NULL;
1121 silc_mutex_unlock(stream->lock);
1123 silc_packet_stream_unref(stream);
1126 /* Returns TRUE if stream is UDP stream */
1128 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1130 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1133 /* Return packet sender IP and port for UDP packet stream */
1135 SilcBool silc_packet_get_sender(SilcPacket packet,
1136 const char **sender_ip,
1137 SilcUInt16 *sender_port)
1139 if (!packet->stream->remote_udp)
1142 *sender_ip = packet->stream->remote_udp->remote_ip;
1143 *sender_port = packet->stream->remote_udp->remote_port;
1148 /* Reference packet stream */
1150 void silc_packet_stream_ref(SilcPacketStream stream)
1152 silc_atomic_add_int8(&stream->refcnt, 1);
1153 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1154 silc_atomic_get_int8(&stream->refcnt) - 1,
1155 silc_atomic_get_int8(&stream->refcnt)));
1158 /* Unreference packet stream */
1160 void silc_packet_stream_unref(SilcPacketStream stream)
1162 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1163 silc_atomic_get_int8(&stream->refcnt),
1164 silc_atomic_get_int8(&stream->refcnt) - 1));
1165 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1167 silc_atomic_add_int8(&stream->refcnt, 1);
1168 silc_packet_stream_destroy(stream);
1173 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1175 return stream->sc->engine;
1178 /* Set application context for packet stream */
1180 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1182 silc_mutex_lock(stream->lock);
1183 stream->stream_context = stream_context;
1184 silc_mutex_unlock(stream->lock);
1187 /* Return application context from packet stream */
1189 void *silc_packet_get_context(SilcPacketStream stream)
1192 silc_mutex_lock(stream->lock);
1193 context = stream->stream_context;
1194 silc_mutex_unlock(stream->lock);
1198 /* Change underlaying stream */
1200 void silc_packet_stream_set_stream(SilcPacketStream ps,
1204 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1205 ps->stream = stream;
1206 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1210 /* Return underlaying stream */
1212 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1214 return stream->stream;
1219 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1220 SilcCipher receive_key, SilcHmac send_hmac,
1221 SilcHmac receive_hmac, SilcBool rekey)
1223 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1225 /* If doing rekey, send REKEY_DONE packet */
1227 /* This will take stream lock. */
1228 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1229 stream->src_id_type, stream->src_id,
1230 stream->src_id_len, stream->dst_id_type,
1231 stream->dst_id, stream->dst_id_len,
1232 NULL, 0, stream->send_key[0],
1233 stream->send_hmac[0]))
1236 /* Write the packet to the stream */
1237 if (!silc_packet_stream_write(stream, TRUE))
1240 silc_mutex_lock(stream->lock);
1243 /* In case IV Included is set, save the old keys */
1244 if (stream->iv_included) {
1245 if (stream->send_key[1] && send_key) {
1246 silc_cipher_free(stream->send_key[1]);
1247 stream->send_key[1] = stream->send_key[0];
1249 if (stream->receive_key[1] && receive_key) {
1250 silc_cipher_free(stream->receive_key[1]);
1251 stream->receive_key[1] = stream->receive_key[0];
1253 if (stream->send_hmac[1] && send_hmac) {
1254 silc_hmac_free(stream->send_hmac[1]);
1255 stream->send_hmac[1] = stream->send_hmac[0];
1257 if (stream->receive_hmac[1] && receive_hmac) {
1258 silc_hmac_free(stream->receive_hmac[1]);
1259 stream->receive_hmac[1] = stream->receive_hmac[0];
1262 if (stream->send_key[0] && send_key)
1263 silc_cipher_free(stream->send_key[0]);
1264 if (stream->receive_key[0] && receive_key)
1265 silc_cipher_free(stream->receive_key[0]);
1266 if (stream->send_hmac[0] && send_hmac)
1267 silc_hmac_free(stream->send_hmac[0]);
1268 if (stream->receive_hmac[0] && receive_hmac)
1269 silc_hmac_free(stream->receive_hmac[0]);
1274 stream->send_key[0] = send_key;
1276 stream->receive_key[0] = receive_key;
1278 stream->send_hmac[0] = send_hmac;
1280 stream->receive_hmac[0] = receive_hmac;
1282 silc_mutex_unlock(stream->lock);
1286 /* Return current ciphers from packet stream */
1288 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1289 SilcCipher *send_key,
1290 SilcCipher *receive_key,
1291 SilcHmac *send_hmac,
1292 SilcHmac *receive_hmac)
1294 if (!stream->send_key[0] && !stream->receive_key[0] &&
1295 !stream->send_hmac[0] && !stream->receive_hmac[0])
1298 silc_mutex_lock(stream->lock);
1301 *send_key = stream->send_key[0];
1303 *receive_key = stream->receive_key[0];
1305 *send_hmac = stream->send_hmac[0];
1307 *receive_hmac = stream->receive_hmac[0];
1309 silc_mutex_unlock(stream->lock);
1314 /* Set SILC IDs to packet stream */
1316 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1317 SilcIdType src_id_type, const void *src_id,
1318 SilcIdType dst_id_type, const void *dst_id)
1321 unsigned char tmp[32];
1323 if (!src_id && !dst_id)
1326 silc_mutex_lock(stream->lock);
1329 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1331 silc_free(stream->src_id);
1332 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1333 silc_mutex_unlock(stream->lock);
1336 stream->src_id = silc_memdup(tmp, len);
1337 if (!stream->src_id) {
1338 silc_mutex_unlock(stream->lock);
1341 stream->src_id_type = src_id_type;
1342 stream->src_id_len = len;
1346 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1348 silc_free(stream->dst_id);
1349 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1350 silc_mutex_unlock(stream->lock);
1353 stream->dst_id = silc_memdup(tmp, len);
1354 if (!stream->dst_id) {
1355 silc_mutex_unlock(stream->lock);
1358 stream->dst_id_type = dst_id_type;
1359 stream->dst_id_len = len;
1362 silc_mutex_unlock(stream->lock);
1367 /* Return IDs from the packet stream */
1369 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1370 SilcBool *src_id_set, SilcID *src_id,
1371 SilcBool *dst_id_set, SilcID *dst_id)
1373 if (src_id && stream->src_id)
1374 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1375 stream->src_id_type, src_id))
1378 if (stream->src_id && src_id_set)
1381 if (dst_id && stream->dst_id)
1382 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1383 stream->dst_id_type, dst_id))
1386 if (stream->dst_id && dst_id_set)
1392 /* Adds Security ID (SID) */
1394 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1396 if (!stream->iv_included)
1399 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1407 void silc_packet_free(SilcPacket packet)
1409 SilcPacketStream stream = packet->stream;
1411 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1413 /* Check for double free */
1414 SILC_ASSERT(packet->stream != NULL);
1416 packet->stream = NULL;
1417 packet->src_id = packet->dst_id = NULL;
1418 silc_buffer_reset(&packet->buffer);
1420 silc_mutex_lock(stream->sc->engine->lock);
1422 /* Put the packet back to freelist */
1423 silc_list_add(stream->sc->engine->packet_pool, packet);
1424 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1425 silc_list_start(stream->sc->engine->packet_pool);
1427 silc_mutex_unlock(stream->sc->engine->lock);
1430 /****************************** Packet Sending ******************************/
1432 /* Prepare outgoing data buffer for packet sending. Returns the
1433 pointer to that buffer into the `packet'. */
1435 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1440 unsigned char *oldptr;
1441 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1445 /* Allocate more space if needed */
1446 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1447 if (!silc_buffer_realloc(&stream->outbuf,
1448 silc_buffer_truelen(&stream->outbuf) + totlen))
1452 /* Pull data area for the new packet, and return pointer to the start of
1453 the data area and save the pointer in to the `packet'. MAC is pulled
1454 later after it's computed. */
1455 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1456 silc_buffer_set(packet, oldptr, totlen);
1457 silc_buffer_push_tail(packet, mac_len);
1462 /* Increments counter when encrypting in counter mode. */
1464 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1466 unsigned char *ret_iv)
1468 unsigned char *iv = silc_cipher_get_iv(cipher);
1469 SilcUInt32 pc1, pc2;
1471 /* Increment 64-bit packet counter */
1472 SILC_GET32_MSB(pc1, iv + 4);
1473 SILC_GET32_MSB(pc2, iv + 8);
1476 SILC_PUT32_MSB(pc1, iv + 4);
1477 SILC_PUT32_MSB(pc2, iv + 8);
1479 /* Reset block counter */
1480 memset(iv + 12, 0, 4);
1482 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1483 if (stream->iv_included) {
1485 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1486 ret_iv[1] = ret_iv[0] + iv[4];
1487 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1488 ret_iv[3] = ret_iv[0] + ret_iv[2];
1489 SILC_PUT32_MSB(pc2, ret_iv + 4);
1490 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1492 /* Set new nonce to counter block */
1493 memcpy(iv + 4, ret_iv, 4);
1496 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1499 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1500 the packet. The silc_packet_stream_write needs to be called to send it
1501 after this returns TRUE. */
1503 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1504 SilcPacketType type,
1505 SilcPacketFlags flags,
1506 SilcIdType src_id_type,
1507 unsigned char *src_id,
1508 SilcUInt32 src_id_len,
1509 SilcIdType dst_id_type,
1510 unsigned char *dst_id,
1511 SilcUInt32 dst_id_len,
1512 const unsigned char *data,
1513 SilcUInt32 data_len,
1517 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1518 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1519 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1521 SilcBufferStruct packet;
1523 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1524 "data len %d", silc_get_packet_name(type), stream->send_psn,
1525 flags, src_id_type, dst_id_type, data_len));
1527 /* Get the true length of the packet. This is saved as payload length
1528 into the packet header. This does not include the length of the
1530 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1531 src_id_len + dst_id_len));
1532 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1533 src_id_len + dst_id_len);
1535 /* If using CTR mode, increment the counter */
1536 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1538 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1540 /* If IV is included, the SID, IV and sequence number is added to packet */
1541 if (stream->iv_included && cipher) {
1542 psnlen = sizeof(psn);
1544 iv[0] = stream->sid;
1547 /* If IV is included, the SID, IV and sequence number is added to packet */
1548 if (stream->iv_included && cipher) {
1549 psnlen = sizeof(psn);
1550 ivlen = block_len + 1;
1551 iv[0] = stream->sid;
1552 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1556 /* We automatically figure out the packet structure from the packet
1557 type and flags, and calculate correct length. Private messages with
1558 private keys and channel messages are special packets as their
1559 payload is encrypted already. */
1560 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1561 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
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 +
1571 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1572 if (stream->sc->engine->local_is_router && stream->is_router) {
1573 /* Channel messages between routers are encrypted as normal packets.
1574 Padding is calculated from true length of the packet. */
1576 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1578 enclen += padlen + psnlen;
1580 /* Padding is calculated from header + IDs */
1582 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1583 psnlen), block_len, padlen);
1585 /* Length to encrypt, header + IDs + padding. */
1586 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1590 /* Padding is calculated from true length of the packet */
1591 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1592 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1594 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1596 enclen += padlen + psnlen;
1599 /* Remove implementation specific flags */
1600 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1602 /* Get random padding */
1603 for (i = 0; i < padlen; i++) tmppad[i] =
1604 silc_rng_get_byte_fast(stream->sc->engine->rng);
1606 silc_mutex_lock(stream->lock);
1608 /* Get packet pointer from the outgoing buffer */
1609 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1610 + psnlen, hmac, &packet))) {
1611 silc_mutex_unlock(stream->lock);
1615 SILC_PUT32_MSB(stream->send_psn, psn);
1617 /* Create the packet. This creates the SILC header, adds padding, and
1618 the actual packet data. */
1619 i = silc_buffer_format(&packet,
1620 SILC_STR_DATA(iv, ivlen),
1621 SILC_STR_DATA(psn, psnlen),
1622 SILC_STR_UI_SHORT(truelen),
1623 SILC_STR_UI_CHAR(flags),
1624 SILC_STR_UI_CHAR(type),
1625 SILC_STR_UI_CHAR(padlen),
1626 SILC_STR_UI_CHAR(0),
1627 SILC_STR_UI_CHAR(src_id_len),
1628 SILC_STR_UI_CHAR(dst_id_len),
1629 SILC_STR_UI_CHAR(src_id_type),
1630 SILC_STR_DATA(src_id, src_id_len),
1631 SILC_STR_UI_CHAR(dst_id_type),
1632 SILC_STR_DATA(dst_id, dst_id_len),
1633 SILC_STR_DATA(tmppad, padlen),
1634 SILC_STR_DATA(data, data_len),
1636 if (silc_unlikely(i < 0)) {
1637 silc_mutex_unlock(stream->lock);
1641 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1642 silc_buffer_data(&packet), silc_buffer_len(&packet));
1644 /* Encrypt the packet */
1645 if (silc_likely(cipher)) {
1646 SILC_LOG_DEBUG(("Encrypting packet"));
1647 silc_cipher_set_iv(cipher, NULL);
1648 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1649 packet.data + ivlen, enclen,
1651 SILC_LOG_ERROR(("Packet encryption failed"));
1652 silc_mutex_unlock(stream->lock);
1658 if (silc_likely(hmac)) {
1661 /* MAC is computed from the entire encrypted packet data, and put
1662 to the end of the packet. */
1663 silc_hmac_init(hmac);
1664 silc_hmac_update(hmac, psn, sizeof(psn));
1665 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1666 silc_hmac_final(hmac, packet.tail, &mac_len);
1667 silc_buffer_pull_tail(&packet, mac_len);
1674 /* Sends a packet */
1676 SilcBool silc_packet_send(SilcPacketStream stream,
1677 SilcPacketType type, SilcPacketFlags flags,
1678 const unsigned char *data, SilcUInt32 data_len)
1682 ret = silc_packet_send_raw(stream, type, flags,
1683 stream->src_id_type,
1686 stream->dst_id_type,
1690 stream->send_key[0],
1691 stream->send_hmac[0]);
1693 /* Write the packet to the stream */
1694 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1697 /* Sends a packet, extended routine */
1699 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1700 SilcPacketType type, SilcPacketFlags flags,
1701 SilcIdType src_id_type, void *src_id,
1702 SilcIdType dst_id_type, void *dst_id,
1703 const unsigned char *data, SilcUInt32 data_len,
1704 SilcCipher cipher, SilcHmac hmac)
1706 unsigned char src_id_data[32], dst_id_data[32];
1707 SilcUInt32 src_id_len, dst_id_len;
1711 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1712 sizeof(src_id_data), &src_id_len))
1715 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1716 sizeof(dst_id_data), &dst_id_len))
1719 ret = silc_packet_send_raw(stream, type, flags,
1720 src_id ? src_id_type : stream->src_id_type,
1721 src_id ? src_id_data : stream->src_id,
1722 src_id ? src_id_len : stream->src_id_len,
1723 dst_id ? dst_id_type : stream->dst_id_type,
1724 dst_id ? dst_id_data : stream->dst_id,
1725 dst_id ? dst_id_len : stream->dst_id_len,
1727 cipher ? cipher : stream->send_key[0],
1728 hmac ? hmac : stream->send_hmac[0]);
1730 /* Write the packet to the stream */
1731 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1734 /* Sends packet after formatting the arguments to buffer */
1736 SilcBool silc_packet_send_va(SilcPacketStream stream,
1737 SilcPacketType type, SilcPacketFlags flags, ...)
1739 SilcBufferStruct buf;
1743 va_start(va, flags);
1745 memset(&buf, 0, sizeof(buf));
1746 if (silc_buffer_format_vp(&buf, va) < 0) {
1751 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1752 silc_buffer_len(&buf));
1754 silc_buffer_purge(&buf);
1760 /* Sends packet after formatting the arguments to buffer, extended routine */
1762 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1763 SilcPacketType type, SilcPacketFlags flags,
1764 SilcIdType src_id_type, void *src_id,
1765 SilcIdType dst_id_type, void *dst_id,
1766 SilcCipher cipher, SilcHmac hmac, ...)
1768 SilcBufferStruct buf;
1774 memset(&buf, 0, sizeof(buf));
1775 if (silc_buffer_format_vp(&buf, va) < 0) {
1780 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1781 dst_id_type, dst_id, silc_buffer_data(&buf),
1782 silc_buffer_len(&buf), cipher, hmac);
1784 silc_buffer_purge(&buf);
1790 /***************************** Packet Receiving *****************************/
1792 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1794 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1795 const unsigned char *data,
1796 SilcUInt32 data_len,
1797 const unsigned char *packet_mac,
1798 const unsigned char *packet_seq,
1799 SilcUInt32 sequence)
1802 if (silc_likely(hmac)) {
1803 unsigned char mac[32], psn[4];
1806 SILC_LOG_DEBUG(("Verifying MAC"));
1808 /* Compute HMAC of packet */
1809 silc_hmac_init(hmac);
1812 SILC_PUT32_MSB(sequence, psn);
1813 silc_hmac_update(hmac, psn, 4);
1815 silc_hmac_update(hmac, packet_seq, 4);
1817 silc_hmac_update(hmac, data, data_len);
1818 silc_hmac_final(hmac, mac, &mac_len);
1820 /* Compare the MAC's */
1821 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1822 SILC_LOG_DEBUG(("MAC failed"));
1826 SILC_LOG_DEBUG(("MAC is Ok"));
1832 /* Increments/sets counter when decrypting in counter mode. */
1834 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1836 unsigned char *packet_iv)
1838 SilcUInt32 pc1, pc2;
1840 /* If IV Included flag, set the IV from packet to block counter. */
1841 if (stream->iv_included) {
1842 memcpy(iv + 4, packet_iv, 8);
1844 /* Increment 64-bit packet counter. */
1845 SILC_GET32_MSB(pc1, iv + 4);
1846 SILC_GET32_MSB(pc2, iv + 8);
1849 SILC_PUT32_MSB(pc1, iv + 4);
1850 SILC_PUT32_MSB(pc2, iv + 8);
1853 /* Reset block counter */
1854 memset(iv + 12, 0, 4);
1856 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1859 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1860 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1862 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1863 SilcUInt32 sequence, SilcBuffer buffer,
1866 if (normal == TRUE) {
1867 if (silc_likely(cipher)) {
1868 /* Decrypt rest of the packet */
1869 SILC_LOG_DEBUG(("Decrypting the packet"));
1870 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1872 silc_buffer_len(buffer), NULL)))
1878 /* Decrypt rest of the header plus padding */
1879 if (silc_likely(cipher)) {
1881 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1883 SILC_LOG_DEBUG(("Decrypting the header"));
1885 /* Padding length + src id len + dst id len + header length - 16
1886 bytes already decrypted, gives the rest of the encrypted packet */
1887 silc_buffer_push(buffer, block_len);
1888 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1889 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1891 silc_buffer_pull(buffer, block_len);
1893 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1894 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1898 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1899 buffer->data, len, NULL)))
1907 /* Parses the packet. This is called when a whole packet is ready to be
1908 parsed. The buffer sent must be already decrypted before calling this
1911 static inline SilcBool silc_packet_parse(SilcPacket packet)
1913 SilcBuffer buffer = &packet->buffer;
1914 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1915 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1918 SILC_LOG_DEBUG(("Parsing incoming packet"));
1920 /* Parse the buffer. This parses the SILC header of the packet. */
1921 ret = silc_buffer_unformat(buffer,
1924 SILC_STR_UI_CHAR(&src_id_len),
1925 SILC_STR_UI_CHAR(&dst_id_len),
1926 SILC_STR_UI_CHAR(&src_id_type),
1928 if (silc_unlikely(ret == -1)) {
1929 if (!packet->stream->udp &&
1930 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1931 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1935 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1936 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1937 if (!packet->stream->udp &&
1938 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1939 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1940 packet->src_id_len, packet->dst_id_len));
1944 ret = silc_buffer_unformat(buffer,
1946 SILC_STR_DATA(&packet->src_id, src_id_len),
1947 SILC_STR_UI_CHAR(&dst_id_type),
1948 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1949 SILC_STR_OFFSET(padlen),
1951 if (silc_unlikely(ret == -1)) {
1952 if (!packet->stream->udp &&
1953 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1954 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1958 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1959 dst_id_type > SILC_ID_CHANNEL)) {
1960 if (!packet->stream->udp &&
1961 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1962 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1963 src_id_type, dst_id_type));
1967 packet->src_id_len = src_id_len;
1968 packet->dst_id_len = dst_id_len;
1969 packet->src_id_type = src_id_type;
1970 packet->dst_id_type = dst_id_type;
1972 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1973 silc_buffer_len(buffer)), buffer->head,
1974 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1976 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1977 silc_get_packet_name(packet->type), packet->flags));
1982 /* Dispatch packet to application. Called with stream->lock locked.
1983 Returns FALSE if the stream was destroyed while dispatching a packet. */
1985 static SilcBool silc_packet_dispatch(SilcPacket packet)
1987 SilcPacketStream stream = packet->stream;
1988 SilcPacketProcess p;
1989 SilcBool default_sent = FALSE;
1992 /* Dispatch packet to all packet processors that want it */
1994 if (silc_likely(!stream->process)) {
1995 /* Send to default processor as no others exist */
1996 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1997 silc_mutex_unlock(stream->lock);
1998 if (silc_unlikely(!stream->sc->engine->callbacks->
1999 packet_receive(stream->sc->engine, stream, packet,
2000 stream->sc->engine->callback_context,
2001 stream->stream_context)))
2002 silc_packet_free(packet);
2003 silc_mutex_lock(stream->lock);
2004 return stream->destroyed == FALSE;
2007 silc_dlist_start(stream->process);
2008 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2010 /* If priority is 0 or less, we send to default processor first
2011 because default processor has 0 priority */
2012 if (!default_sent && p->priority <= 0) {
2013 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2014 default_sent = TRUE;
2015 silc_mutex_unlock(stream->lock);
2016 if (stream->sc->engine->callbacks->
2017 packet_receive(stream->sc->engine, stream, packet,
2018 stream->sc->engine->callback_context,
2019 stream->stream_context)) {
2020 silc_mutex_lock(stream->lock);
2021 return stream->destroyed == FALSE;
2023 silc_mutex_lock(stream->lock);
2026 /* Send to processor */
2028 /* Send all packet types */
2029 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2030 silc_mutex_unlock(stream->lock);
2031 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2032 p->callback_context,
2033 stream->stream_context)) {
2034 silc_mutex_lock(stream->lock);
2035 return stream->destroyed == FALSE;
2037 silc_mutex_lock(stream->lock);
2039 /* Send specific types */
2040 for (pt = p->types; *pt; pt++) {
2041 if (*pt != packet->type)
2043 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2044 silc_mutex_unlock(stream->lock);
2045 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2046 p->callback_context,
2047 stream->stream_context)) {
2048 silc_mutex_lock(stream->lock);
2049 return stream->destroyed == FALSE;
2051 silc_mutex_lock(stream->lock);
2057 if (!default_sent) {
2058 /* Send to default processor as it has not been sent yet */
2059 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2060 silc_mutex_unlock(stream->lock);
2061 if (stream->sc->engine->callbacks->
2062 packet_receive(stream->sc->engine, stream, packet,
2063 stream->sc->engine->callback_context,
2064 stream->stream_context)) {
2065 silc_mutex_lock(stream->lock);
2066 return stream->destroyed == FALSE;
2068 silc_mutex_lock(stream->lock);
2071 /* If we got here, no one wanted the packet, so drop it */
2072 silc_packet_free(packet);
2073 return stream->destroyed == FALSE;
2076 /* Process incoming data and parse packets. Called with stream->lock
2079 static void silc_packet_read_process(SilcPacketStream stream)
2086 SilcUInt16 packetlen;
2087 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2088 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2089 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2093 /* Get inbuf. If there is already some data for this stream in the buffer
2094 we already have it. Otherwise get the current one from list, it will
2095 include the data. */
2096 inbuf = stream->inbuf;
2098 silc_dlist_start(stream->sc->inbufs);
2099 inbuf = silc_dlist_get(stream->sc->inbufs);
2102 /* Parse the packets from the data */
2103 while (silc_buffer_len(inbuf) > 0) {
2105 cipher = stream->receive_key[0];
2106 hmac = stream->receive_hmac[0];
2109 if (silc_unlikely(silc_buffer_len(inbuf) <
2110 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2111 SILC_PACKET_MIN_HEADER_LEN))) {
2112 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2113 silc_dlist_del(stream->sc->inbufs, inbuf);
2114 stream->inbuf = inbuf;
2118 if (silc_likely(hmac))
2119 mac_len = silc_hmac_len(hmac);
2123 /* Decrypt first block of the packet to get the length field out */
2124 if (silc_likely(cipher)) {
2125 block_len = silc_cipher_get_block_len(cipher);
2127 if (stream->iv_included) {
2128 /* SID, IV and sequence number is included in the ciphertext */
2129 sid = (SilcUInt8)inbuf->data[0];
2131 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2132 /* Set the CTR mode IV from packet to counter block */
2133 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2134 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2137 /* Get IV from packet */
2138 memcpy(iv, inbuf->data + 1, block_len);
2139 ivlen = block_len + 1;
2143 /* Check SID, and get correct decryption key */
2144 if (sid != stream->sid) {
2145 /* If SID is recent get the previous key and use it */
2146 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2147 stream->receive_key[1] && !stream->receive_hmac[1]) {
2148 cipher = stream->receive_key[1];
2149 hmac = stream->receive_hmac[1];
2151 /* The SID is unknown, drop rest of the data in buffer */
2152 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2154 silc_mutex_unlock(stream->lock);
2155 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2156 silc_mutex_lock(stream->lock);
2161 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2163 /* If using CTR mode, increment the counter */
2164 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2165 silc_packet_receive_ctr_increment(stream, iv, NULL);
2168 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2169 silc_cipher_set_iv(cipher, NULL);
2170 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2173 if (stream->iv_included) {
2174 /* Take sequence number from packet */
2175 packet_seq = header;
2179 /* Unencrypted packet */
2180 block_len = SILC_PACKET_MIN_HEADER_LEN;
2181 header = inbuf->data;
2184 /* Get packet length and full packet length with padding */
2185 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2188 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2189 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2190 SILC_LOG_ERROR(("Received too short packet"));
2191 silc_mutex_unlock(stream->lock);
2192 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2193 silc_mutex_lock(stream->lock);
2194 memset(tmp, 0, sizeof(tmp));
2198 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2199 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2201 paddedlen + mac_len - silc_buffer_len(inbuf)));
2202 memset(tmp, 0, sizeof(tmp));
2203 silc_dlist_del(stream->sc->inbufs, inbuf);
2204 stream->inbuf = inbuf;
2208 /* Check MAC of the packet */
2209 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2211 inbuf->data + ivlen +
2212 paddedlen, packet_seq,
2213 stream->receive_psn))) {
2214 silc_mutex_unlock(stream->lock);
2215 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2216 silc_mutex_lock(stream->lock);
2217 memset(tmp, 0, sizeof(tmp));
2222 packet = silc_packet_alloc(stream->sc->engine);
2223 if (silc_unlikely(!packet)) {
2224 silc_mutex_unlock(stream->lock);
2225 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2226 silc_mutex_lock(stream->lock);
2227 memset(tmp, 0, sizeof(tmp));
2230 packet->stream = stream;
2232 /* Allocate more space to packet buffer, if needed */
2233 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2234 if (!silc_buffer_realloc(&packet->buffer,
2235 silc_buffer_truelen(&packet->buffer) +
2237 silc_buffer_truelen(&packet->buffer)))) {
2238 silc_mutex_unlock(stream->lock);
2239 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2240 silc_mutex_lock(stream->lock);
2241 silc_packet_free(packet);
2242 memset(tmp, 0, sizeof(tmp));
2247 /* Parse packet header */
2248 packet->flags = (SilcPacketFlags)header[2];
2249 packet->type = (SilcPacketType)header[3];
2251 if (stream->sc->engine->local_is_router) {
2252 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2253 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2255 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2256 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2257 stream->is_router == TRUE))
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)
2267 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2268 stream->receive_psn, paddedlen + ivlen + mac_len),
2269 inbuf->data, paddedlen + ivlen + mac_len);
2271 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2272 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2273 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2274 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2275 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2276 psnlen + (block_len - psnlen)),
2277 paddedlen - ivlen - psnlen - (block_len - psnlen));
2278 if (silc_likely(cipher)) {
2279 silc_cipher_set_iv(cipher, iv);
2280 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2281 &packet->buffer, normal);
2282 if (silc_unlikely(ret < 0)) {
2283 silc_mutex_unlock(stream->lock);
2284 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2285 silc_mutex_lock(stream->lock);
2286 silc_packet_free(packet);
2287 memset(tmp, 0, sizeof(tmp));
2291 stream->receive_psn++;
2293 silc_buffer_push(&packet->buffer, block_len);
2295 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2296 silc_buffer_pull(inbuf, paddedlen + mac_len);
2298 /* Parse the packet */
2299 if (silc_unlikely(!silc_packet_parse(packet))) {
2300 silc_mutex_unlock(stream->lock);
2301 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2302 silc_mutex_lock(stream->lock);
2303 silc_packet_free(packet);
2304 memset(tmp, 0, sizeof(tmp));
2308 /* Dispatch the packet to application */
2309 if (!silc_packet_dispatch(packet))
2314 /* Add inbuf back to free list, if we owned it. */
2315 if (stream->inbuf) {
2316 silc_dlist_add(stream->sc->inbufs, inbuf);
2317 stream->inbuf = NULL;
2320 silc_buffer_reset(inbuf);
2323 /****************************** Packet Waiting ******************************/
2325 /* Packet wait receive callback */
2327 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2328 SilcPacketStream stream,
2330 void *callback_context,
2331 void *stream_context);
2333 /* Packet waiting callbacks */
2334 static SilcPacketCallbacks silc_packet_wait_cbs =
2336 silc_packet_wait_packet_receive, NULL, NULL
2339 /* Packet waiting context */
2341 SilcMutex wait_lock;
2343 SilcList packet_queue;
2344 unsigned char id[28];
2345 unsigned int id_type : 2;
2346 unsigned int id_len : 5;
2347 unsigned int stopped : 1;
2350 /* Packet wait receive callback */
2353 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2354 SilcPacketStream stream,
2356 void *callback_context,
2357 void *stream_context)
2359 SilcPacketWait pw = callback_context;
2361 /* If source ID is specified check for it */
2363 if (pw->id_type != packet->src_id_type ||
2364 memcmp(pw->id, packet->src_id, pw->id_len))
2368 /* Signal the waiting thread for a new packet */
2369 silc_mutex_lock(pw->wait_lock);
2371 if (silc_unlikely(pw->stopped)) {
2372 silc_mutex_unlock(pw->wait_lock);
2376 silc_list_add(pw->packet_queue, packet);
2377 silc_cond_broadcast(pw->wait_cond);
2379 silc_mutex_unlock(pw->wait_lock);
2384 /* Initialize packet waiting */
2386 void *silc_packet_wait_init(SilcPacketStream stream,
2387 const SilcID *source_id, ...)
2393 pw = silc_calloc(1, sizeof(*pw));
2397 /* Allocate mutex and conditional variable */
2398 if (!silc_mutex_alloc(&pw->wait_lock)) {
2402 if (!silc_cond_alloc(&pw->wait_cond)) {
2403 silc_mutex_free(pw->wait_lock);
2408 /* Link to the packet stream for the requested packet types */
2409 va_start(ap, source_id);
2410 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2414 silc_cond_free(pw->wait_cond);
2415 silc_mutex_free(pw->wait_lock);
2420 /* Initialize packet queue */
2421 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2425 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2426 sizeof(pw->id), &id_len);
2427 pw->id_type = source_id->type;
2428 pw->id_len = id_len;
2434 /* Uninitialize packet waiting */
2436 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2438 SilcPacketWait pw = waiter;
2441 /* Signal any threads to stop waiting */
2442 silc_mutex_lock(pw->wait_lock);
2444 silc_cond_broadcast(pw->wait_cond);
2445 silc_mutex_unlock(pw->wait_lock);
2446 silc_thread_yield();
2448 /* Re-acquire lock and free resources */
2449 silc_mutex_lock(pw->wait_lock);
2450 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2452 /* Free any remaining packets */
2453 silc_list_start(pw->packet_queue);
2454 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2455 silc_packet_free(packet);
2457 silc_mutex_unlock(pw->wait_lock);
2458 silc_cond_free(pw->wait_cond);
2459 silc_mutex_free(pw->wait_lock);
2463 /* Blocks thread until a packet has been received. */
2465 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2467 SilcPacketWait pw = waiter;
2468 SilcBool ret = FALSE;
2470 silc_mutex_lock(pw->wait_lock);
2472 /* Wait here until packet has arrived */
2473 while (silc_list_count(pw->packet_queue) == 0) {
2474 if (silc_unlikely(pw->stopped)) {
2475 silc_mutex_unlock(pw->wait_lock);
2478 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2482 silc_list_start(pw->packet_queue);
2483 *return_packet = silc_list_get(pw->packet_queue);
2484 silc_list_del(pw->packet_queue, *return_packet);
2486 silc_mutex_unlock(pw->wait_lock);
2488 return ret == TRUE ? 1 : 0;
2491 /************************** Packet Stream Wrapper ***************************/
2493 /* Packet stream wrapper receive callback */
2495 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2496 SilcPacketStream stream,
2498 void *callback_context,
2499 void *stream_context);
2501 const SilcStreamOps silc_packet_stream_ops;
2503 /* Packet stream wrapper context */
2505 const SilcStreamOps *ops;
2506 SilcPacketStream stream;
2508 void *waiter; /* Waiter context in blocking mode */
2509 SilcPacketWrapCoder coder;
2510 void *coder_context;
2512 SilcStreamNotifier callback;
2515 SilcPacketType type;
2516 SilcPacketFlags flags;
2517 unsigned int closed : 1;
2518 unsigned int blocking : 1;
2519 unsigned int read_more : 1;
2520 } *SilcPacketWrapperStream;
2522 /* Packet wrapper callbacks */
2523 static SilcPacketCallbacks silc_packet_wrap_cbs =
2525 silc_packet_wrap_packet_receive, NULL, NULL
2528 /* Packet stream wrapper receive callback, non-blocking mode */
2531 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2532 SilcPacketStream stream,
2534 void *callback_context,
2535 void *stream_context)
2537 SilcPacketWrapperStream pws = callback_context;
2539 if (pws->closed || !pws->callback)
2542 silc_mutex_lock(pws->lock);
2543 silc_list_add(pws->in_queue, packet);
2544 silc_mutex_unlock(pws->lock);
2546 /* Call notifier callback */
2547 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2552 /* Task callback to notify more data is available for reading */
2554 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2556 SilcPacketWrapperStream pws = context;
2558 if (pws->closed || !pws->callback)
2561 /* Call notifier callback */
2562 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2565 /* Read SILC packet */
2567 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2570 SilcPacketWrapperStream pws = stream;
2572 SilcBool read_more = FALSE;
2578 if (pws->blocking) {
2579 /* Block until packet is received */
2580 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2585 /* Non-blocking mode */
2586 silc_mutex_lock(pws->lock);
2587 if (!silc_list_count(pws->in_queue)) {
2588 silc_mutex_unlock(pws->lock);
2592 silc_list_start(pws->in_queue);
2593 packet = silc_list_get(pws->in_queue);
2594 silc_list_del(pws->in_queue, packet);
2595 silc_mutex_unlock(pws->lock);
2598 /* Call decoder if set */
2599 if (pws->coder && !pws->read_more)
2600 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2601 pws->coder_context);
2603 len = silc_buffer_len(&packet->buffer);
2604 if (len > buf_len) {
2610 memcpy(buf, packet->buffer.data, len);
2612 if (read_more && !pws->blocking) {
2613 /* More data will be available (in blocking mode not supported). */
2614 silc_buffer_pull(&packet->buffer, len);
2615 silc_list_insert(pws->in_queue, NULL, packet);
2616 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2617 silc_packet_wrap_read_more, pws, 0, 0);
2618 pws->read_more = TRUE;
2622 pws->read_more = FALSE;
2623 silc_packet_free(packet);
2627 /* Write SILC packet */
2629 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2630 SilcUInt32 data_len)
2632 SilcPacketWrapperStream pws = stream;
2633 SilcBool ret = FALSE;
2635 /* Call encoder if set */
2637 silc_buffer_reset(pws->encbuf);
2638 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2639 pws->coder_context);
2642 /* Send the SILC packet */
2644 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2645 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2646 silc_buffer_len(pws->encbuf)),
2647 SILC_STR_DATA(data, data_len),
2651 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2660 SilcBool silc_packet_wrap_close(SilcStream stream)
2662 SilcPacketWrapperStream pws = stream;
2667 if (pws->blocking) {
2668 /* Close packet waiter */
2669 silc_packet_wait_uninit(pws->waiter, pws->stream);
2673 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2680 /* Destroy wrapper stream */
2682 void silc_packet_wrap_destroy(SilcStream stream)
2685 SilcPacketWrapperStream pws = stream;
2688 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2690 silc_stream_close(stream);
2691 silc_list_start(pws->in_queue);
2692 while ((packet = silc_list_get(pws->in_queue)))
2693 silc_packet_free(packet);
2695 silc_mutex_free(pws->lock);
2697 silc_buffer_free(pws->encbuf);
2698 silc_packet_stream_unref(pws->stream);
2703 /* Link stream to receive packets */
2705 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2706 SilcSchedule schedule,
2707 SilcStreamNotifier callback,
2710 SilcPacketWrapperStream pws = stream;
2712 if (pws->closed || pws->blocking)
2715 /* Link to receive packets */
2717 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2718 100000, pws->type, -1);
2720 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2722 pws->callback = callback;
2723 pws->context = context;
2728 /* Return schedule */
2730 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2735 /* Wraps packet stream into SilcStream. */
2737 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2738 SilcPacketType type,
2739 SilcPacketFlags flags,
2740 SilcBool blocking_mode,
2741 SilcPacketWrapCoder coder,
2744 SilcPacketWrapperStream pws;
2746 pws = silc_calloc(1, sizeof(*pws));
2750 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2752 pws->ops = &silc_packet_stream_ops;
2753 pws->stream = stream;
2756 pws->blocking = blocking_mode;
2758 pws->coder_context = context;
2760 /* Allocate small amount for encoder buffer. */
2762 pws->encbuf = silc_buffer_alloc(8);
2764 if (pws->blocking) {
2765 /* Blocking mode. Use packet waiter to do the thing. */
2766 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2772 /* Non-blocking mode */
2773 silc_mutex_alloc(&pws->lock);
2774 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2777 silc_packet_stream_ref(stream);
2779 return (SilcStream)pws;
2782 const SilcStreamOps silc_packet_stream_ops =
2784 silc_packet_wrap_read,
2785 silc_packet_wrap_write,
2786 silc_packet_wrap_close,
2787 silc_packet_wrap_destroy,
2788 silc_packet_wrap_notifier,
2789 silc_packet_wrap_get_schedule,