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);
789 SILC_LOG_DEBUG(("Created packet stream %p", ps));
794 /* Add new remote packet stream for UDP packet streams */
796 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
797 const char *remote_ip,
798 SilcUInt16 remote_port,
801 SilcPacketEngine engine = stream->sc->engine;
806 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
807 remote_ip, remote_port, stream));
809 if (!stream || !remote_ip || !remote_port)
812 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
813 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
817 ps = silc_calloc(1, sizeof(*ps));
822 silc_atomic_init8(&ps->refcnt, 1);
823 silc_mutex_alloc(&ps->lock);
825 /* Set the UDP packet stream as underlaying stream */
826 silc_packet_stream_ref(stream);
827 ps->stream = (SilcStream)stream;
830 /* Allocate out buffer */
831 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
833 silc_packet_stream_destroy(ps);
836 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
837 silc_buffer_reset(&ps->outbuf);
839 /* Initialize packet procesors list */
840 ps->process = silc_dlist_init();
842 silc_packet_stream_destroy(ps);
846 /* Add to engine with this IP and port pair */
847 tuple = silc_format("%d%s", remote_port, remote_ip);
848 silc_mutex_lock(engine->lock);
849 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
850 silc_mutex_unlock(engine->lock);
851 silc_packet_stream_destroy(ps);
854 silc_mutex_unlock(engine->lock);
856 /* Save remote IP and port pair */
857 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
858 if (!ps->remote_udp) {
859 silc_packet_stream_destroy(ps);
862 ps->remote_udp->remote_port = remote_port;
863 ps->remote_udp->remote_ip = strdup(remote_ip);
864 if (!ps->remote_udp->remote_ip) {
865 silc_packet_stream_destroy(ps);
870 /* Inject packet to the new stream */
872 silc_packet_stream_ref(ps);
873 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
874 silc_packet_stream_inject_packet, packet,
881 /* Destroy packet stream */
883 void silc_packet_stream_destroy(SilcPacketStream stream)
885 SilcPacketEngine engine;
890 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
891 stream->destroyed = TRUE;
893 SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
895 /* Close the underlaying stream */
896 if (!stream->udp && stream->stream)
897 silc_stream_close(stream->stream);
901 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
904 /* Delete from engine */
905 engine = stream->sc->engine;
906 silc_mutex_lock(engine->lock);
907 silc_list_del(engine->streams, stream);
909 /* Remove per scheduler context, if it is not used anymore */
911 stream->sc->stream_count--;
912 if (!stream->sc->stream_count)
913 silc_hash_table_del(engine->contexts, stream->sc->schedule);
915 silc_mutex_unlock(engine->lock);
917 /* Destroy the underlaying stream */
919 silc_stream_destroy(stream->stream);
921 /* Delete from UDP remote hash table */
923 engine = stream->sc->engine;
924 silc_snprintf(tuple, sizeof(tuple), "%d%s",
925 stream->remote_udp->remote_port,
926 stream->remote_udp->remote_ip);
927 silc_mutex_lock(engine->lock);
928 silc_hash_table_del(engine->udp_remote, tuple);
929 silc_mutex_unlock(engine->lock);
931 silc_free(stream->remote_udp->remote_ip);
932 silc_free(stream->remote_udp);
934 /* Unreference the underlaying packet stream */
935 silc_packet_stream_unref((SilcPacketStream)stream->stream);
938 /* Clear and free buffers */
939 silc_buffer_clear(&stream->outbuf);
940 silc_buffer_purge(&stream->outbuf);
942 if (stream->process) {
944 silc_dlist_start(stream->process);
945 while ((p = silc_dlist_get(stream->process))) {
948 silc_dlist_del(stream->process, p);
950 silc_dlist_uninit(stream->process);
953 /* Destroy ciphers and HMACs */
954 if (stream->send_key[0])
955 silc_cipher_free(stream->send_key[0]);
956 if (stream->receive_key[0])
957 silc_cipher_free(stream->receive_key[0]);
958 if (stream->send_hmac[0])
959 silc_hmac_free(stream->send_hmac[0]);
960 if (stream->receive_hmac[0])
961 silc_hmac_free(stream->receive_hmac[0]);
962 if (stream->send_key[1])
963 silc_cipher_free(stream->send_key[1]);
964 if (stream->receive_key[1])
965 silc_cipher_free(stream->receive_key[1]);
966 if (stream->send_hmac[1])
967 silc_hmac_free(stream->send_hmac[1]);
968 if (stream->receive_hmac[1])
969 silc_hmac_free(stream->receive_hmac[1]);
972 silc_free(stream->src_id);
973 silc_free(stream->dst_id);
975 silc_atomic_uninit8(&stream->refcnt);
976 silc_mutex_free(stream->lock);
980 /* Return TRUE if the stream is valid */
982 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
984 return stream->destroyed == FALSE;
987 /* Marks as router stream */
989 void silc_packet_stream_set_router(SilcPacketStream stream)
991 stream->is_router = TRUE;
994 /* Mark to include IV in ciphertext */
996 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
998 stream->iv_included = TRUE;
1001 /* Links `callbacks' to `stream' for specified packet types */
1003 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1004 SilcPacketCallbacks *callbacks,
1005 void *callback_context,
1006 int priority, va_list ap)
1008 SilcPacketProcess p, e;
1009 SilcInt32 packet_type;
1012 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1016 if (!callbacks->packet_receive)
1019 p = silc_calloc(1, sizeof(*p));
1023 p->priority = priority;
1024 p->callbacks = callbacks;
1025 p->callback_context = callback_context;
1027 silc_mutex_lock(stream->lock);
1029 if (!stream->process) {
1030 stream->process = silc_dlist_init();
1031 if (!stream->process) {
1032 silc_mutex_unlock(stream->lock);
1037 /* According to priority set the procesor to correct position. First
1038 entry has the highest priority */
1039 silc_dlist_start(stream->process);
1040 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1041 if (p->priority > e->priority) {
1042 silc_dlist_insert(stream->process, p);
1047 silc_dlist_add(stream->process, p);
1049 /* Get packet types to process */
1052 packet_type = va_arg(ap, SilcInt32);
1054 if (packet_type == SILC_PACKET_ANY)
1057 if (packet_type == -1)
1060 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1062 silc_mutex_unlock(stream->lock);
1066 p->types[i - 1] = (SilcPacketType)packet_type;
1070 p->types[i - 1] = 0;
1072 silc_mutex_unlock(stream->lock);
1074 silc_packet_stream_ref(stream);
1079 /* Links `callbacks' to `stream' for specified packet types */
1081 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1082 SilcPacketCallbacks *callbacks,
1083 void *callback_context,
1089 va_start(ap, priority);
1090 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1097 /* Unlinks `callbacks' from `stream'. */
1099 void silc_packet_stream_unlink(SilcPacketStream stream,
1100 SilcPacketCallbacks *callbacks,
1101 void *callback_context)
1103 SilcPacketProcess p;
1105 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1106 callbacks, stream));
1108 silc_mutex_lock(stream->lock);
1110 silc_dlist_start(stream->process);
1111 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1112 if (p->callbacks == callbacks &&
1113 p->callback_context == callback_context) {
1114 silc_dlist_del(stream->process, p);
1115 silc_free(p->types);
1120 if (!silc_dlist_count(stream->process)) {
1121 silc_dlist_uninit(stream->process);
1122 stream->process = NULL;
1125 silc_mutex_unlock(stream->lock);
1127 silc_packet_stream_unref(stream);
1130 /* Returns TRUE if stream is UDP stream */
1132 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1134 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1137 /* Return packet sender IP and port for UDP packet stream */
1139 SilcBool silc_packet_get_sender(SilcPacket packet,
1140 const char **sender_ip,
1141 SilcUInt16 *sender_port)
1143 if (!packet->stream->remote_udp)
1146 *sender_ip = packet->stream->remote_udp->remote_ip;
1147 *sender_port = packet->stream->remote_udp->remote_port;
1152 /* Reference packet stream */
1154 void silc_packet_stream_ref(SilcPacketStream stream)
1156 silc_atomic_add_int8(&stream->refcnt, 1);
1157 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1158 silc_atomic_get_int8(&stream->refcnt) - 1,
1159 silc_atomic_get_int8(&stream->refcnt)));
1162 /* Unreference packet stream */
1164 void silc_packet_stream_unref(SilcPacketStream stream)
1166 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1167 silc_atomic_get_int8(&stream->refcnt),
1168 silc_atomic_get_int8(&stream->refcnt) - 1));
1169 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1171 silc_atomic_add_int8(&stream->refcnt, 1);
1172 silc_packet_stream_destroy(stream);
1177 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1179 return stream->sc->engine;
1182 /* Set application context for packet stream */
1184 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1186 silc_mutex_lock(stream->lock);
1187 stream->stream_context = stream_context;
1188 silc_mutex_unlock(stream->lock);
1191 /* Return application context from packet stream */
1193 void *silc_packet_get_context(SilcPacketStream stream)
1196 silc_mutex_lock(stream->lock);
1197 context = stream->stream_context;
1198 silc_mutex_unlock(stream->lock);
1202 /* Change underlaying stream */
1204 void silc_packet_stream_set_stream(SilcPacketStream ps,
1208 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1209 ps->stream = stream;
1210 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1214 /* Return underlaying stream */
1216 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1218 return stream->stream;
1223 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1224 SilcCipher receive_key, SilcHmac send_hmac,
1225 SilcHmac receive_hmac, SilcBool rekey)
1227 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1229 /* If doing rekey, send REKEY_DONE packet */
1231 /* This will take stream lock. */
1232 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1233 stream->src_id_type, stream->src_id,
1234 stream->src_id_len, stream->dst_id_type,
1235 stream->dst_id, stream->dst_id_len,
1236 NULL, 0, stream->send_key[0],
1237 stream->send_hmac[0]))
1240 /* Write the packet to the stream */
1241 if (!silc_packet_stream_write(stream, TRUE))
1244 silc_mutex_lock(stream->lock);
1247 /* In case IV Included is set, save the old keys */
1248 if (stream->iv_included) {
1249 if (stream->send_key[1] && send_key) {
1250 silc_cipher_free(stream->send_key[1]);
1251 stream->send_key[1] = stream->send_key[0];
1253 if (stream->receive_key[1] && receive_key) {
1254 silc_cipher_free(stream->receive_key[1]);
1255 stream->receive_key[1] = stream->receive_key[0];
1257 if (stream->send_hmac[1] && send_hmac) {
1258 silc_hmac_free(stream->send_hmac[1]);
1259 stream->send_hmac[1] = stream->send_hmac[0];
1261 if (stream->receive_hmac[1] && receive_hmac) {
1262 silc_hmac_free(stream->receive_hmac[1]);
1263 stream->receive_hmac[1] = stream->receive_hmac[0];
1266 if (stream->send_key[0] && send_key)
1267 silc_cipher_free(stream->send_key[0]);
1268 if (stream->receive_key[0] && receive_key)
1269 silc_cipher_free(stream->receive_key[0]);
1270 if (stream->send_hmac[0] && send_hmac)
1271 silc_hmac_free(stream->send_hmac[0]);
1272 if (stream->receive_hmac[0] && receive_hmac)
1273 silc_hmac_free(stream->receive_hmac[0]);
1278 stream->send_key[0] = send_key;
1280 stream->receive_key[0] = receive_key;
1282 stream->send_hmac[0] = send_hmac;
1284 stream->receive_hmac[0] = receive_hmac;
1286 silc_mutex_unlock(stream->lock);
1290 /* Return current ciphers from packet stream */
1292 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1293 SilcCipher *send_key,
1294 SilcCipher *receive_key,
1295 SilcHmac *send_hmac,
1296 SilcHmac *receive_hmac)
1298 if (!stream->send_key[0] && !stream->receive_key[0] &&
1299 !stream->send_hmac[0] && !stream->receive_hmac[0])
1302 silc_mutex_lock(stream->lock);
1305 *send_key = stream->send_key[0];
1307 *receive_key = stream->receive_key[0];
1309 *send_hmac = stream->send_hmac[0];
1311 *receive_hmac = stream->receive_hmac[0];
1313 silc_mutex_unlock(stream->lock);
1318 /* Set SILC IDs to packet stream */
1320 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1321 SilcIdType src_id_type, const void *src_id,
1322 SilcIdType dst_id_type, const void *dst_id)
1325 unsigned char tmp[32];
1327 if (!src_id && !dst_id)
1330 silc_mutex_lock(stream->lock);
1333 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1335 silc_free(stream->src_id);
1336 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1337 silc_mutex_unlock(stream->lock);
1340 stream->src_id = silc_memdup(tmp, len);
1341 if (!stream->src_id) {
1342 silc_mutex_unlock(stream->lock);
1345 stream->src_id_type = src_id_type;
1346 stream->src_id_len = len;
1350 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1352 silc_free(stream->dst_id);
1353 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1354 silc_mutex_unlock(stream->lock);
1357 stream->dst_id = silc_memdup(tmp, len);
1358 if (!stream->dst_id) {
1359 silc_mutex_unlock(stream->lock);
1362 stream->dst_id_type = dst_id_type;
1363 stream->dst_id_len = len;
1366 silc_mutex_unlock(stream->lock);
1371 /* Return IDs from the packet stream */
1373 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1374 SilcBool *src_id_set, SilcID *src_id,
1375 SilcBool *dst_id_set, SilcID *dst_id)
1377 if (src_id && stream->src_id)
1378 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1379 stream->src_id_type, src_id))
1382 if (stream->src_id && src_id_set)
1385 if (dst_id && stream->dst_id)
1386 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1387 stream->dst_id_type, dst_id))
1390 if (stream->dst_id && dst_id_set)
1396 /* Adds Security ID (SID) */
1398 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1400 if (!stream->iv_included)
1403 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1411 void silc_packet_free(SilcPacket packet)
1413 SilcPacketStream stream = packet->stream;
1415 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1417 /* Check for double free */
1418 SILC_ASSERT(packet->stream != NULL);
1420 packet->stream = NULL;
1421 packet->src_id = packet->dst_id = NULL;
1422 silc_buffer_reset(&packet->buffer);
1424 silc_mutex_lock(stream->sc->engine->lock);
1426 /* Put the packet back to freelist */
1427 silc_list_add(stream->sc->engine->packet_pool, packet);
1428 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1429 silc_list_start(stream->sc->engine->packet_pool);
1431 silc_mutex_unlock(stream->sc->engine->lock);
1434 /****************************** Packet Sending ******************************/
1436 /* Prepare outgoing data buffer for packet sending. Returns the
1437 pointer to that buffer into the `packet'. */
1439 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1444 unsigned char *oldptr;
1445 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1449 /* Allocate more space if needed */
1450 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1451 if (!silc_buffer_realloc(&stream->outbuf,
1452 silc_buffer_truelen(&stream->outbuf) + totlen))
1456 /* Pull data area for the new packet, and return pointer to the start of
1457 the data area and save the pointer in to the `packet'. MAC is pulled
1458 later after it's computed. */
1459 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1460 silc_buffer_set(packet, oldptr, totlen);
1461 silc_buffer_push_tail(packet, mac_len);
1466 /* Increments counter when encrypting in counter mode. */
1468 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1470 unsigned char *ret_iv)
1472 unsigned char *iv = silc_cipher_get_iv(cipher);
1473 SilcUInt32 pc1, pc2;
1475 /* Reset block counter */
1476 memset(iv + 12, 0, 4);
1478 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1479 if (stream->iv_included) {
1481 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1482 ret_iv[1] = ret_iv[0] + iv[4];
1483 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1484 ret_iv[3] = ret_iv[0] + ret_iv[2];
1486 /* Increment 32-bit packet counter */
1487 SILC_GET32_MSB(pc1, iv + 8);
1489 SILC_PUT32_MSB(pc1, ret_iv + 4);
1491 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1493 /* Set new IV to counter block */
1494 memcpy(iv + 4, ret_iv, 8);
1496 /* Increment 64-bit packet counter */
1497 SILC_GET32_MSB(pc1, iv + 4);
1498 SILC_GET32_MSB(pc2, iv + 8);
1501 SILC_PUT32_MSB(pc1, iv + 4);
1502 SILC_PUT32_MSB(pc2, iv + 8);
1505 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1508 /* Internal routine to assemble outgoing packet. Assembles and encrypts
1509 the packet. The silc_packet_stream_write needs to be called to send it
1510 after this returns TRUE. */
1512 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1513 SilcPacketType type,
1514 SilcPacketFlags flags,
1515 SilcIdType src_id_type,
1516 unsigned char *src_id,
1517 SilcUInt32 src_id_len,
1518 SilcIdType dst_id_type,
1519 unsigned char *dst_id,
1520 SilcUInt32 dst_id_len,
1521 const unsigned char *data,
1522 SilcUInt32 data_len,
1526 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1527 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1528 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1530 SilcBufferStruct packet;
1532 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1533 "data len %d", silc_get_packet_name(type), stream->send_psn,
1534 flags, src_id_type, dst_id_type, data_len));
1536 /* Get the true length of the packet. This is saved as payload length
1537 into the packet header. This does not include the length of the
1539 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1540 src_id_len + dst_id_len));
1541 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1542 src_id_len + dst_id_len);
1544 /* If using CTR mode, increment the counter */
1545 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1547 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1549 /* If IV is included, the SID, IV and sequence number is added to packet */
1550 if (stream->iv_included && cipher) {
1551 psnlen = sizeof(psn);
1553 iv[0] = stream->sid;
1556 /* If IV is included, the SID, IV and sequence number is added to packet */
1557 if (stream->iv_included && cipher) {
1558 psnlen = sizeof(psn);
1559 ivlen = block_len + 1;
1560 iv[0] = stream->sid;
1561 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1565 /* We automatically figure out the packet structure from the packet
1566 type and flags, and calculate correct length. Private messages with
1567 private keys and channel messages are special packets as their
1568 payload is encrypted already. */
1569 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1570 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1571 /* Padding is calculated from header + IDs */
1573 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1574 psnlen), block_len, padlen);
1576 /* Length to encrypt, header + IDs + padding. */
1577 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1580 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1581 if (stream->sc->engine->local_is_router && stream->is_router) {
1582 /* Channel messages between routers are encrypted as normal packets.
1583 Padding is calculated from true length of the packet. */
1585 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1587 enclen += padlen + psnlen;
1589 /* Padding is calculated from header + IDs */
1591 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1592 psnlen), block_len, padlen);
1594 /* Length to encrypt, header + IDs + padding. */
1595 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1599 /* Padding is calculated from true length of the packet */
1600 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1601 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1603 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1605 enclen += padlen + psnlen;
1608 /* Remove implementation specific flags */
1609 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1611 /* Get random padding */
1612 for (i = 0; i < padlen; i++) tmppad[i] =
1613 silc_rng_get_byte_fast(stream->sc->engine->rng);
1615 silc_mutex_lock(stream->lock);
1617 if (silc_unlikely(stream->destroyed)) {
1618 SILC_LOG_DEBUG(("Stream %p is destroyed, cannot send packet", stream));
1619 silc_mutex_unlock(stream->lock);
1623 /* Get packet pointer from the outgoing buffer */
1624 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1625 + psnlen, hmac, &packet))) {
1626 silc_mutex_unlock(stream->lock);
1630 SILC_PUT32_MSB(stream->send_psn, psn);
1632 /* Create the packet. This creates the SILC header, adds padding, and
1633 the actual packet data. */
1634 i = silc_buffer_format(&packet,
1635 SILC_STR_DATA(iv, ivlen),
1636 SILC_STR_DATA(psn, psnlen),
1637 SILC_STR_UI_SHORT(truelen),
1638 SILC_STR_UI_CHAR(flags),
1639 SILC_STR_UI_CHAR(type),
1640 SILC_STR_UI_CHAR(padlen),
1641 SILC_STR_UI_CHAR(0),
1642 SILC_STR_UI_CHAR(src_id_len),
1643 SILC_STR_UI_CHAR(dst_id_len),
1644 SILC_STR_UI_CHAR(src_id_type),
1645 SILC_STR_DATA(src_id, src_id_len),
1646 SILC_STR_UI_CHAR(dst_id_type),
1647 SILC_STR_DATA(dst_id, dst_id_len),
1648 SILC_STR_DATA(tmppad, padlen),
1649 SILC_STR_DATA(data, data_len),
1651 if (silc_unlikely(i < 0)) {
1652 silc_mutex_unlock(stream->lock);
1656 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1657 silc_buffer_data(&packet), silc_buffer_len(&packet));
1659 /* Encrypt the packet */
1660 if (silc_likely(cipher)) {
1661 SILC_LOG_DEBUG(("Encrypting packet"));
1662 silc_cipher_set_iv(cipher, NULL);
1663 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1664 packet.data + ivlen, enclen,
1666 SILC_LOG_ERROR(("Packet encryption failed"));
1667 silc_mutex_unlock(stream->lock);
1673 if (silc_likely(hmac)) {
1676 /* MAC is computed from the entire encrypted packet data, and put
1677 to the end of the packet. */
1678 silc_hmac_init(hmac);
1679 silc_hmac_update(hmac, psn, sizeof(psn));
1680 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1681 silc_hmac_final(hmac, packet.tail, &mac_len);
1682 silc_buffer_pull_tail(&packet, mac_len);
1689 /* Sends a packet */
1691 SilcBool silc_packet_send(SilcPacketStream stream,
1692 SilcPacketType type, SilcPacketFlags flags,
1693 const unsigned char *data, SilcUInt32 data_len)
1697 ret = silc_packet_send_raw(stream, type, flags,
1698 stream->src_id_type,
1701 stream->dst_id_type,
1705 stream->send_key[0],
1706 stream->send_hmac[0]);
1708 /* Write the packet to the stream */
1709 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1712 /* Sends a packet, extended routine */
1714 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1715 SilcPacketType type, SilcPacketFlags flags,
1716 SilcIdType src_id_type, void *src_id,
1717 SilcIdType dst_id_type, void *dst_id,
1718 const unsigned char *data, SilcUInt32 data_len,
1719 SilcCipher cipher, SilcHmac hmac)
1721 unsigned char src_id_data[32], dst_id_data[32];
1722 SilcUInt32 src_id_len, dst_id_len;
1726 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1727 sizeof(src_id_data), &src_id_len))
1730 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1731 sizeof(dst_id_data), &dst_id_len))
1734 ret = silc_packet_send_raw(stream, type, flags,
1735 src_id ? src_id_type : stream->src_id_type,
1736 src_id ? src_id_data : stream->src_id,
1737 src_id ? src_id_len : stream->src_id_len,
1738 dst_id ? dst_id_type : stream->dst_id_type,
1739 dst_id ? dst_id_data : stream->dst_id,
1740 dst_id ? dst_id_len : stream->dst_id_len,
1742 cipher ? cipher : stream->send_key[0],
1743 hmac ? hmac : stream->send_hmac[0]);
1745 /* Write the packet to the stream */
1746 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1749 /* Sends packet after formatting the arguments to buffer */
1751 SilcBool silc_packet_send_va(SilcPacketStream stream,
1752 SilcPacketType type, SilcPacketFlags flags, ...)
1754 SilcBufferStruct buf;
1758 va_start(va, flags);
1760 memset(&buf, 0, sizeof(buf));
1761 if (silc_buffer_format_vp(&buf, va) < 0) {
1766 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1767 silc_buffer_len(&buf));
1769 silc_buffer_purge(&buf);
1775 /* Sends packet after formatting the arguments to buffer, extended routine */
1777 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1778 SilcPacketType type, SilcPacketFlags flags,
1779 SilcIdType src_id_type, void *src_id,
1780 SilcIdType dst_id_type, void *dst_id,
1781 SilcCipher cipher, SilcHmac hmac, ...)
1783 SilcBufferStruct buf;
1789 memset(&buf, 0, sizeof(buf));
1790 if (silc_buffer_format_vp(&buf, va) < 0) {
1795 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1796 dst_id_type, dst_id, silc_buffer_data(&buf),
1797 silc_buffer_len(&buf), cipher, hmac);
1799 silc_buffer_purge(&buf);
1805 /***************************** Packet Receiving *****************************/
1807 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1809 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1810 const unsigned char *data,
1811 SilcUInt32 data_len,
1812 const unsigned char *packet_mac,
1813 const unsigned char *packet_seq,
1814 SilcUInt32 sequence)
1817 if (silc_likely(hmac)) {
1818 unsigned char mac[32], psn[4];
1821 SILC_LOG_DEBUG(("Verifying MAC"));
1823 /* Compute HMAC of packet */
1824 silc_hmac_init(hmac);
1827 SILC_PUT32_MSB(sequence, psn);
1828 silc_hmac_update(hmac, psn, 4);
1830 silc_hmac_update(hmac, packet_seq, 4);
1832 silc_hmac_update(hmac, data, data_len);
1833 silc_hmac_final(hmac, mac, &mac_len);
1835 /* Compare the MAC's */
1836 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1837 SILC_LOG_DEBUG(("MAC failed"));
1841 SILC_LOG_DEBUG(("MAC is Ok"));
1847 /* Increments/sets counter when decrypting in counter mode. */
1849 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1851 unsigned char *packet_iv)
1853 SilcUInt32 pc1, pc2;
1855 /* If IV Included flag, set the IV from packet to block counter. */
1856 if (stream->iv_included) {
1857 memcpy(iv + 4, packet_iv, 8);
1859 /* Increment 64-bit packet counter. */
1860 SILC_GET32_MSB(pc1, iv + 4);
1861 SILC_GET32_MSB(pc2, iv + 8);
1864 SILC_PUT32_MSB(pc1, iv + 4);
1865 SILC_PUT32_MSB(pc2, iv + 8);
1868 /* Reset block counter */
1869 memset(iv + 12, 0, 4);
1871 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1874 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1875 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1877 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1878 SilcUInt32 sequence, SilcBuffer buffer,
1881 if (normal == TRUE) {
1882 if (silc_likely(cipher)) {
1883 /* Decrypt rest of the packet */
1884 SILC_LOG_DEBUG(("Decrypting the packet"));
1885 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1887 silc_buffer_len(buffer), NULL)))
1893 /* Decrypt rest of the header plus padding */
1894 if (silc_likely(cipher)) {
1896 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1898 SILC_LOG_DEBUG(("Decrypting the header"));
1900 /* Padding length + src id len + dst id len + header length - 16
1901 bytes already decrypted, gives the rest of the encrypted packet */
1902 silc_buffer_push(buffer, block_len);
1903 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1904 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1906 silc_buffer_pull(buffer, block_len);
1908 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1909 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1913 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1914 buffer->data, len, NULL)))
1922 /* Parses the packet. This is called when a whole packet is ready to be
1923 parsed. The buffer sent must be already decrypted before calling this
1926 static inline SilcBool silc_packet_parse(SilcPacket packet)
1928 SilcBuffer buffer = &packet->buffer;
1929 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1930 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1933 SILC_LOG_DEBUG(("Parsing incoming packet"));
1935 /* Parse the buffer. This parses the SILC header of the packet. */
1936 ret = silc_buffer_unformat(buffer,
1939 SILC_STR_UI_CHAR(&src_id_len),
1940 SILC_STR_UI_CHAR(&dst_id_len),
1941 SILC_STR_UI_CHAR(&src_id_type),
1943 if (silc_unlikely(ret == -1)) {
1944 if (!packet->stream->udp &&
1945 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1946 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1950 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1951 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1952 if (!packet->stream->udp &&
1953 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1954 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1955 packet->src_id_len, packet->dst_id_len));
1959 ret = silc_buffer_unformat(buffer,
1961 SILC_STR_DATA(&packet->src_id, src_id_len),
1962 SILC_STR_UI_CHAR(&dst_id_type),
1963 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1964 SILC_STR_OFFSET(padlen),
1966 if (silc_unlikely(ret == -1)) {
1967 if (!packet->stream->udp &&
1968 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1969 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1973 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1974 dst_id_type > SILC_ID_CHANNEL)) {
1975 if (!packet->stream->udp &&
1976 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1977 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1978 src_id_type, dst_id_type));
1982 packet->src_id_len = src_id_len;
1983 packet->dst_id_len = dst_id_len;
1984 packet->src_id_type = src_id_type;
1985 packet->dst_id_type = dst_id_type;
1987 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1988 silc_buffer_len(buffer)), buffer->head,
1989 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1991 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1992 silc_get_packet_name(packet->type), packet->flags));
1997 /* Dispatch packet to application. Called with stream->lock locked.
1998 Returns FALSE if the stream was destroyed while dispatching a packet. */
2000 static SilcBool silc_packet_dispatch(SilcPacket packet)
2002 SilcPacketStream stream = packet->stream;
2003 SilcPacketProcess p;
2004 SilcBool default_sent = FALSE;
2007 /* Dispatch packet to all packet processors that want it */
2009 if (silc_likely(!stream->process)) {
2010 /* Send to default processor as no others exist */
2011 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2012 silc_mutex_unlock(stream->lock);
2013 if (silc_unlikely(!stream->sc->engine->callbacks->
2014 packet_receive(stream->sc->engine, stream, packet,
2015 stream->sc->engine->callback_context,
2016 stream->stream_context)))
2017 silc_packet_free(packet);
2018 silc_mutex_lock(stream->lock);
2019 return stream->destroyed == FALSE;
2022 silc_dlist_start(stream->process);
2023 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2025 /* If priority is 0 or less, we send to default processor first
2026 because default processor has 0 priority */
2027 if (!default_sent && p->priority <= 0) {
2028 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2029 default_sent = TRUE;
2030 silc_mutex_unlock(stream->lock);
2031 if (stream->sc->engine->callbacks->
2032 packet_receive(stream->sc->engine, stream, packet,
2033 stream->sc->engine->callback_context,
2034 stream->stream_context)) {
2035 silc_mutex_lock(stream->lock);
2036 return stream->destroyed == FALSE;
2038 silc_mutex_lock(stream->lock);
2041 /* Send to processor */
2043 /* Send all packet types */
2044 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2045 silc_mutex_unlock(stream->lock);
2046 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2047 p->callback_context,
2048 stream->stream_context)) {
2049 silc_mutex_lock(stream->lock);
2050 return stream->destroyed == FALSE;
2052 silc_mutex_lock(stream->lock);
2054 /* Send specific types */
2055 for (pt = p->types; *pt; pt++) {
2056 if (*pt != packet->type)
2058 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2059 silc_mutex_unlock(stream->lock);
2060 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2061 p->callback_context,
2062 stream->stream_context)) {
2063 silc_mutex_lock(stream->lock);
2064 return stream->destroyed == FALSE;
2066 silc_mutex_lock(stream->lock);
2072 if (!default_sent) {
2073 /* Send to default processor as it has not been sent yet */
2074 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2075 silc_mutex_unlock(stream->lock);
2076 if (stream->sc->engine->callbacks->
2077 packet_receive(stream->sc->engine, stream, packet,
2078 stream->sc->engine->callback_context,
2079 stream->stream_context)) {
2080 silc_mutex_lock(stream->lock);
2081 return stream->destroyed == FALSE;
2083 silc_mutex_lock(stream->lock);
2086 /* If we got here, no one wanted the packet, so drop it */
2087 silc_packet_free(packet);
2088 return stream->destroyed == FALSE;
2091 /* Process incoming data and parse packets. Called with stream->lock
2094 static void silc_packet_read_process(SilcPacketStream stream)
2101 SilcUInt16 packetlen;
2102 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2103 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2104 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2108 /* Get inbuf. If there is already some data for this stream in the buffer
2109 we already have it. Otherwise get the current one from list, it will
2110 include the data. */
2111 inbuf = stream->inbuf;
2113 silc_dlist_start(stream->sc->inbufs);
2114 inbuf = silc_dlist_get(stream->sc->inbufs);
2117 /* Parse the packets from the data */
2118 while (silc_buffer_len(inbuf) > 0) {
2120 cipher = stream->receive_key[0];
2121 hmac = stream->receive_hmac[0];
2124 if (silc_unlikely(silc_buffer_len(inbuf) <
2125 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2126 SILC_PACKET_MIN_HEADER_LEN))) {
2127 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2128 silc_dlist_del(stream->sc->inbufs, inbuf);
2129 stream->inbuf = inbuf;
2133 if (silc_likely(hmac))
2134 mac_len = silc_hmac_len(hmac);
2138 /* Decrypt first block of the packet to get the length field out */
2139 if (silc_likely(cipher)) {
2140 block_len = silc_cipher_get_block_len(cipher);
2142 if (stream->iv_included) {
2143 /* SID, IV and sequence number is included in the ciphertext */
2144 sid = (SilcUInt8)inbuf->data[0];
2146 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2147 /* Set the CTR mode IV from packet to counter block */
2148 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2149 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2152 /* Get IV from packet */
2153 memcpy(iv, inbuf->data + 1, block_len);
2154 ivlen = block_len + 1;
2158 /* Check SID, and get correct decryption key */
2159 if (sid != stream->sid) {
2160 /* If SID is recent get the previous key and use it */
2161 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2162 stream->receive_key[1] && !stream->receive_hmac[1]) {
2163 cipher = stream->receive_key[1];
2164 hmac = stream->receive_hmac[1];
2166 /* The SID is unknown, drop rest of the data in buffer */
2167 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2169 silc_mutex_unlock(stream->lock);
2170 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2171 silc_mutex_lock(stream->lock);
2176 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2178 /* If using CTR mode, increment the counter */
2179 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2180 silc_packet_receive_ctr_increment(stream, iv, NULL);
2183 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2184 silc_cipher_set_iv(cipher, NULL);
2185 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2188 if (stream->iv_included) {
2189 /* Take sequence number from packet */
2190 packet_seq = header;
2194 /* Unencrypted packet */
2195 block_len = SILC_PACKET_MIN_HEADER_LEN;
2196 header = inbuf->data;
2199 /* Get packet length and full packet length with padding */
2200 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2203 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2204 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2205 SILC_LOG_ERROR(("Received too short packet"));
2206 silc_mutex_unlock(stream->lock);
2207 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2208 silc_mutex_lock(stream->lock);
2209 memset(tmp, 0, sizeof(tmp));
2213 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2214 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2216 paddedlen + mac_len - silc_buffer_len(inbuf)));
2217 memset(tmp, 0, sizeof(tmp));
2218 silc_dlist_del(stream->sc->inbufs, inbuf);
2219 stream->inbuf = inbuf;
2223 /* Check MAC of the packet */
2224 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2226 inbuf->data + ivlen +
2227 paddedlen, packet_seq,
2228 stream->receive_psn))) {
2229 silc_mutex_unlock(stream->lock);
2230 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2231 silc_mutex_lock(stream->lock);
2232 memset(tmp, 0, sizeof(tmp));
2237 packet = silc_packet_alloc(stream->sc->engine);
2238 if (silc_unlikely(!packet)) {
2239 silc_mutex_unlock(stream->lock);
2240 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2241 silc_mutex_lock(stream->lock);
2242 memset(tmp, 0, sizeof(tmp));
2245 packet->stream = stream;
2247 /* Allocate more space to packet buffer, if needed */
2248 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2249 if (!silc_buffer_realloc(&packet->buffer,
2250 silc_buffer_truelen(&packet->buffer) +
2252 silc_buffer_truelen(&packet->buffer)))) {
2253 silc_mutex_unlock(stream->lock);
2254 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2255 silc_mutex_lock(stream->lock);
2256 silc_packet_free(packet);
2257 memset(tmp, 0, sizeof(tmp));
2262 /* Parse packet header */
2263 packet->flags = (SilcPacketFlags)header[2];
2264 packet->type = (SilcPacketType)header[3];
2266 if (stream->sc->engine->local_is_router) {
2267 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2268 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2270 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2271 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2272 stream->is_router == TRUE))
2275 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2276 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2278 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2282 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2283 stream->receive_psn, paddedlen + ivlen + mac_len),
2284 inbuf->data, paddedlen + ivlen + mac_len);
2286 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2287 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2288 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2289 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2290 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2291 psnlen + (block_len - psnlen)),
2292 paddedlen - ivlen - psnlen - (block_len - psnlen));
2293 if (silc_likely(cipher)) {
2294 silc_cipher_set_iv(cipher, iv);
2295 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2296 &packet->buffer, normal);
2297 if (silc_unlikely(ret < 0)) {
2298 silc_mutex_unlock(stream->lock);
2299 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2300 silc_mutex_lock(stream->lock);
2301 silc_packet_free(packet);
2302 memset(tmp, 0, sizeof(tmp));
2306 stream->receive_psn++;
2308 silc_buffer_push(&packet->buffer, block_len);
2310 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2311 silc_buffer_pull(inbuf, paddedlen + mac_len);
2313 /* Parse the packet */
2314 if (silc_unlikely(!silc_packet_parse(packet))) {
2315 silc_mutex_unlock(stream->lock);
2316 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2317 silc_mutex_lock(stream->lock);
2318 silc_packet_free(packet);
2319 memset(tmp, 0, sizeof(tmp));
2323 /* Dispatch the packet to application */
2324 if (!silc_packet_dispatch(packet))
2329 /* Add inbuf back to free list, if we owned it. */
2330 if (stream->inbuf) {
2331 silc_dlist_add(stream->sc->inbufs, inbuf);
2332 stream->inbuf = NULL;
2335 silc_buffer_reset(inbuf);
2338 /****************************** Packet Waiting ******************************/
2340 /* Packet wait receive callback */
2342 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2343 SilcPacketStream stream,
2345 void *callback_context,
2346 void *stream_context);
2348 /* Packet waiting callbacks */
2349 static SilcPacketCallbacks silc_packet_wait_cbs =
2351 silc_packet_wait_packet_receive, NULL, NULL
2354 /* Packet waiting context */
2356 SilcMutex wait_lock;
2358 SilcList packet_queue;
2359 unsigned char id[28];
2360 unsigned int id_type : 2;
2361 unsigned int id_len : 5;
2362 unsigned int stopped : 1;
2365 /* Packet wait receive callback */
2368 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2369 SilcPacketStream stream,
2371 void *callback_context,
2372 void *stream_context)
2374 SilcPacketWait pw = callback_context;
2376 /* If source ID is specified check for it */
2378 if (pw->id_type != packet->src_id_type ||
2379 memcmp(pw->id, packet->src_id, pw->id_len))
2383 /* Signal the waiting thread for a new packet */
2384 silc_mutex_lock(pw->wait_lock);
2386 if (silc_unlikely(pw->stopped)) {
2387 silc_mutex_unlock(pw->wait_lock);
2391 silc_list_add(pw->packet_queue, packet);
2392 silc_cond_broadcast(pw->wait_cond);
2394 silc_mutex_unlock(pw->wait_lock);
2399 /* Initialize packet waiting */
2401 void *silc_packet_wait_init(SilcPacketStream stream,
2402 const SilcID *source_id, ...)
2408 pw = silc_calloc(1, sizeof(*pw));
2412 /* Allocate mutex and conditional variable */
2413 if (!silc_mutex_alloc(&pw->wait_lock)) {
2417 if (!silc_cond_alloc(&pw->wait_cond)) {
2418 silc_mutex_free(pw->wait_lock);
2423 /* Link to the packet stream for the requested packet types */
2424 va_start(ap, source_id);
2425 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2429 silc_cond_free(pw->wait_cond);
2430 silc_mutex_free(pw->wait_lock);
2435 /* Initialize packet queue */
2436 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2440 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2441 sizeof(pw->id), &id_len);
2442 pw->id_type = source_id->type;
2443 pw->id_len = id_len;
2449 /* Uninitialize packet waiting */
2451 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2453 SilcPacketWait pw = waiter;
2456 /* Signal any threads to stop waiting */
2457 silc_mutex_lock(pw->wait_lock);
2459 silc_cond_broadcast(pw->wait_cond);
2460 silc_mutex_unlock(pw->wait_lock);
2461 silc_thread_yield();
2463 /* Re-acquire lock and free resources */
2464 silc_mutex_lock(pw->wait_lock);
2465 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2467 /* Free any remaining packets */
2468 silc_list_start(pw->packet_queue);
2469 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2470 silc_packet_free(packet);
2472 silc_mutex_unlock(pw->wait_lock);
2473 silc_cond_free(pw->wait_cond);
2474 silc_mutex_free(pw->wait_lock);
2478 /* Blocks thread until a packet has been received. */
2480 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2482 SilcPacketWait pw = waiter;
2483 SilcBool ret = FALSE;
2485 silc_mutex_lock(pw->wait_lock);
2487 /* Wait here until packet has arrived */
2488 while (silc_list_count(pw->packet_queue) == 0) {
2489 if (silc_unlikely(pw->stopped)) {
2490 silc_mutex_unlock(pw->wait_lock);
2493 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2497 silc_list_start(pw->packet_queue);
2498 *return_packet = silc_list_get(pw->packet_queue);
2499 silc_list_del(pw->packet_queue, *return_packet);
2501 silc_mutex_unlock(pw->wait_lock);
2503 return ret == TRUE ? 1 : 0;
2506 /************************** Packet Stream Wrapper ***************************/
2508 /* Packet stream wrapper receive callback */
2510 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2511 SilcPacketStream stream,
2513 void *callback_context,
2514 void *stream_context);
2516 const SilcStreamOps silc_packet_stream_ops;
2518 /* Packet stream wrapper context */
2520 const SilcStreamOps *ops;
2521 SilcPacketStream stream;
2523 void *waiter; /* Waiter context in blocking mode */
2524 SilcPacketWrapCoder coder;
2525 void *coder_context;
2527 SilcStreamNotifier callback;
2530 SilcPacketType type;
2531 SilcPacketFlags flags;
2532 unsigned int closed : 1;
2533 unsigned int blocking : 1;
2534 unsigned int read_more : 1;
2535 } *SilcPacketWrapperStream;
2537 /* Packet wrapper callbacks */
2538 static SilcPacketCallbacks silc_packet_wrap_cbs =
2540 silc_packet_wrap_packet_receive, NULL, NULL
2543 /* Packet stream wrapper receive callback, non-blocking mode */
2546 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2547 SilcPacketStream stream,
2549 void *callback_context,
2550 void *stream_context)
2552 SilcPacketWrapperStream pws = callback_context;
2554 if (pws->closed || !pws->callback)
2557 silc_mutex_lock(pws->lock);
2558 silc_list_add(pws->in_queue, packet);
2559 silc_mutex_unlock(pws->lock);
2561 /* Call notifier callback */
2562 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2567 /* Task callback to notify more data is available for reading */
2569 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2571 SilcPacketWrapperStream pws = context;
2573 if (pws->closed || !pws->callback)
2576 /* Call notifier callback */
2577 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2580 /* Read SILC packet */
2582 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2585 SilcPacketWrapperStream pws = stream;
2587 SilcBool read_more = FALSE;
2593 if (pws->blocking) {
2594 /* Block until packet is received */
2595 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2600 /* Non-blocking mode */
2601 silc_mutex_lock(pws->lock);
2602 if (!silc_list_count(pws->in_queue)) {
2603 silc_mutex_unlock(pws->lock);
2607 silc_list_start(pws->in_queue);
2608 packet = silc_list_get(pws->in_queue);
2609 silc_list_del(pws->in_queue, packet);
2610 silc_mutex_unlock(pws->lock);
2613 /* Call decoder if set */
2614 if (pws->coder && !pws->read_more)
2615 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2616 pws->coder_context);
2618 len = silc_buffer_len(&packet->buffer);
2619 if (len > buf_len) {
2625 memcpy(buf, packet->buffer.data, len);
2627 if (read_more && !pws->blocking) {
2628 /* More data will be available (in blocking mode not supported). */
2629 silc_buffer_pull(&packet->buffer, len);
2630 silc_list_insert(pws->in_queue, NULL, packet);
2631 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2632 silc_packet_wrap_read_more, pws, 0, 0);
2633 pws->read_more = TRUE;
2637 pws->read_more = FALSE;
2638 silc_packet_free(packet);
2642 /* Write SILC packet */
2644 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2645 SilcUInt32 data_len)
2647 SilcPacketWrapperStream pws = stream;
2648 SilcBool ret = FALSE;
2650 /* Call encoder if set */
2652 silc_buffer_reset(pws->encbuf);
2653 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2654 pws->coder_context);
2657 /* Send the SILC packet */
2659 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2660 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2661 silc_buffer_len(pws->encbuf)),
2662 SILC_STR_DATA(data, data_len),
2666 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2675 SilcBool silc_packet_wrap_close(SilcStream stream)
2677 SilcPacketWrapperStream pws = stream;
2682 if (pws->blocking) {
2683 /* Close packet waiter */
2684 silc_packet_wait_uninit(pws->waiter, pws->stream);
2688 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2695 /* Destroy wrapper stream */
2697 void silc_packet_wrap_destroy(SilcStream stream)
2700 SilcPacketWrapperStream pws = stream;
2703 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2705 silc_stream_close(stream);
2706 silc_list_start(pws->in_queue);
2707 while ((packet = silc_list_get(pws->in_queue)))
2708 silc_packet_free(packet);
2710 silc_mutex_free(pws->lock);
2712 silc_buffer_free(pws->encbuf);
2713 silc_packet_stream_unref(pws->stream);
2718 /* Link stream to receive packets */
2720 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2721 SilcSchedule schedule,
2722 SilcStreamNotifier callback,
2725 SilcPacketWrapperStream pws = stream;
2727 if (pws->closed || pws->blocking)
2730 /* Link to receive packets */
2732 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2733 100000, pws->type, -1);
2735 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2737 pws->callback = callback;
2738 pws->context = context;
2743 /* Return schedule */
2745 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2750 /* Wraps packet stream into SilcStream. */
2752 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2753 SilcPacketType type,
2754 SilcPacketFlags flags,
2755 SilcBool blocking_mode,
2756 SilcPacketWrapCoder coder,
2759 SilcPacketWrapperStream pws;
2761 pws = silc_calloc(1, sizeof(*pws));
2765 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2767 pws->ops = &silc_packet_stream_ops;
2768 pws->stream = stream;
2771 pws->blocking = blocking_mode;
2773 pws->coder_context = context;
2775 /* Allocate small amount for encoder buffer. */
2777 pws->encbuf = silc_buffer_alloc(8);
2779 if (pws->blocking) {
2780 /* Blocking mode. Use packet waiter to do the thing. */
2781 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2787 /* Non-blocking mode */
2788 silc_mutex_alloc(&pws->lock);
2789 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2792 silc_packet_stream_ref(stream);
2794 return (SilcStream)pws;
2797 const SilcStreamOps silc_packet_stream_ops =
2799 silc_packet_wrap_read,
2800 silc_packet_wrap_write,
2801 silc_packet_wrap_close,
2802 silc_packet_wrap_destroy,
2803 silc_packet_wrap_notifier,
2804 silc_packet_wrap_get_schedule,