5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2008 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 const 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 const 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 SilcAtomic32 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. */
343 silc_buffer_reset(inbuf);
344 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
348 /* See if remote packet stream exist for this sender */
349 silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
350 silc_mutex_lock(ps->sc->engine->lock);
351 if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
353 silc_mutex_unlock(ps->sc->engine->lock);
354 SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
355 remote_port, remote));
356 silc_mutex_unlock(ps->lock);
357 silc_mutex_lock(remote->lock);
361 silc_mutex_unlock(ps->sc->engine->lock);
364 if (!ps->remote_udp) {
365 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
366 if (silc_unlikely(!ps->remote_udp)) {
367 silc_mutex_unlock(ps->lock);
368 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
373 /* Save sender IP and port */
374 silc_free(ps->remote_udp->remote_ip);
375 ps->remote_udp->remote_ip = strdup(remote_ip);
376 ps->remote_udp->remote_port = remote_port;
378 silc_buffer_pull_tail(inbuf, ret);
383 /* Read data from the stream */
384 ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
385 if (silc_unlikely(ret <= 0)) {
386 silc_mutex_unlock(ps->lock);
389 silc_buffer_reset(inbuf);
390 SILC_PACKET_CALLBACK_EOS(ps);
395 /* Cannot read now, do it later. */
400 silc_buffer_reset(inbuf);
401 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
405 silc_buffer_pull_tail(inbuf, ret);
409 /* Our stream IO notifier callback. */
411 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
414 SilcPacketStream remote = NULL, ps = context;
416 silc_mutex_lock(ps->lock);
418 if (silc_unlikely(ps->destroyed)) {
419 silc_mutex_unlock(ps->lock);
424 case SILC_STREAM_CAN_READ:
425 /* Reading is locked also with stream->lock because we may be reading
426 at the same time other thread is writing to same underlaying stream. */
427 SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
429 /* Read data from stream */
430 if (!silc_packet_stream_read(ps, &remote))
433 /* Now process the data */
434 silc_packet_stream_ref(ps);
436 silc_packet_read_process(ps);
437 silc_mutex_unlock(ps->lock);
439 silc_packet_read_process(remote);
440 silc_mutex_unlock(remote->lock);
442 silc_packet_stream_unref(ps);
445 case SILC_STREAM_CAN_WRITE:
446 SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
449 if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
450 silc_mutex_unlock(ps->lock);
454 /* Write pending data to stream */
455 silc_packet_stream_write(ps, FALSE);
459 silc_mutex_unlock(ps->lock);
464 /* Allocate packet */
466 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
470 SILC_LOG_DEBUG(("Packet pool count %d",
471 silc_list_count(engine->packet_pool)));
473 silc_mutex_lock(engine->lock);
475 /* Get packet from freelist or allocate new one. */
476 packet = silc_list_get(engine->packet_pool);
480 silc_mutex_unlock(engine->lock);
482 packet = silc_calloc(1, sizeof(*packet));
483 if (silc_unlikely(!packet))
486 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
488 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
489 if (silc_unlikely(!tmp)) {
493 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
494 silc_buffer_reset(&packet->buffer);
499 SILC_LOG_DEBUG(("Get packet %p", packet));
501 /* Delete from freelist */
502 silc_list_del(engine->packet_pool, packet);
504 silc_mutex_unlock(engine->lock);
509 /* UDP remote stream hash table destructor */
511 static void silc_packet_engine_hash_destr(void *key, void *context,
517 /* Per scheduler context hash table destructor */
519 static void silc_packet_engine_context_destr(void *key, void *context,
522 SilcPacketEngineContext sc = context;
525 silc_dlist_start(sc->inbufs);
526 while ((buffer = silc_dlist_get(sc->inbufs))) {
527 silc_buffer_clear(buffer);
528 silc_buffer_free(buffer);
529 silc_dlist_del(sc->inbufs, buffer);
532 silc_dlist_uninit(sc->inbufs);
537 /******************************** Packet API ********************************/
539 /* Allocate new packet engine */
542 silc_packet_engine_start(SilcRng rng, SilcBool router,
543 const SilcPacketCallbacks *callbacks,
544 void *callback_context)
546 SilcPacketEngine engine;
551 SILC_LOG_DEBUG(("Starting new packet engine"));
555 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
558 engine = silc_calloc(1, sizeof(*engine));
562 engine->contexts = silc_hash_table_alloc(NULL, 0, silc_hash_ptr,
564 silc_packet_engine_context_destr,
566 if (!engine->contexts) {
572 engine->local_is_router = router;
573 engine->callbacks = callbacks;
574 engine->callback_context = callback_context;
575 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
576 silc_mutex_alloc(&engine->lock);
578 /* Allocate packet free list */
579 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
580 for (i = 0; i < 5; i++) {
581 packet = silc_calloc(1, sizeof(*packet));
583 silc_packet_engine_stop(engine);
587 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
589 silc_packet_engine_stop(engine);
592 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
593 silc_buffer_reset(&packet->buffer);
595 silc_list_add(engine->packet_pool, packet);
597 silc_list_start(engine->packet_pool);
602 /* Stop packet engine */
604 void silc_packet_engine_stop(SilcPacketEngine engine)
608 SILC_LOG_DEBUG(("Stopping packet engine"));
613 /* Free packet free list */
614 silc_list_start(engine->packet_pool);
615 while ((packet = silc_list_get(engine->packet_pool))) {
616 silc_buffer_purge(&packet->buffer);
620 silc_hash_table_free(engine->contexts);
621 silc_mutex_free(engine->lock);
625 static const char * const packet_error[] = {
626 "Cannot read from stream",
627 "Cannot write to stream",
629 "Packet decryption failed",
631 "Packet is malformed",
632 "System out of memory",
635 /* Return packet error string */
637 const char *silc_packet_error_string(SilcPacketError error)
639 if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
640 return "<invalid error code>";
641 return packet_error[error];
644 /* Return list of packet streams in the engine */
646 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
651 list = silc_dlist_init();
655 silc_mutex_lock(engine->lock);
656 silc_list_start(engine->streams);
657 while ((ps = silc_list_get(engine->streams))) {
658 silc_packet_stream_ref(ps);
659 silc_dlist_add(list, ps);
661 silc_mutex_unlock(engine->lock);
666 /* Free list returned by silc_packet_engine_get_streams */
668 void silc_packet_engine_free_streams_list(SilcDList streams)
672 silc_dlist_start(streams);
673 while ((ps = silc_dlist_get(streams)))
674 silc_packet_stream_unref(ps);
676 silc_dlist_uninit(streams);
679 /* Create new packet stream */
681 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
682 SilcSchedule schedule,
689 SILC_LOG_DEBUG(("Creating new packet stream"));
691 if (!engine || !stream)
694 ps = silc_calloc(1, sizeof(*ps));
699 silc_atomic_init32(&ps->refcnt, 1);
700 silc_mutex_alloc(&ps->lock);
702 /* Allocate out buffer */
703 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
705 silc_packet_stream_destroy(ps);
708 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
709 silc_buffer_reset(&ps->outbuf);
711 /* Initialize packet procesors list */
712 ps->process = silc_dlist_init();
714 silc_packet_stream_destroy(ps);
718 silc_mutex_lock(engine->lock);
720 /* Add per scheduler context */
721 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
723 ps->sc = silc_calloc(1, sizeof(*ps->sc));
725 silc_mutex_unlock(engine->lock);
726 silc_packet_stream_destroy(ps);
729 ps->sc->engine = engine;
730 ps->sc->schedule = schedule;
732 /* Allocate data input buffer */
733 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
737 silc_mutex_unlock(engine->lock);
738 silc_packet_stream_destroy(ps);
741 silc_buffer_reset(inbuf);
743 ps->sc->inbufs = silc_dlist_init();
744 if (!ps->sc->inbufs) {
745 silc_buffer_free(inbuf);
748 silc_mutex_unlock(engine->lock);
749 silc_packet_stream_destroy(ps);
752 silc_dlist_add(ps->sc->inbufs, inbuf);
754 /* Add to per scheduler context hash table */
755 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
756 silc_buffer_free(inbuf);
757 silc_dlist_del(ps->sc->inbufs, inbuf);
760 silc_mutex_unlock(engine->lock);
761 silc_packet_stream_destroy(ps);
765 ps->sc->stream_count++;
767 /* Add the packet stream to engine */
768 silc_list_add(engine->streams, ps);
770 /* If this is UDP stream, allocate UDP remote stream hash table */
771 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
773 silc_hash_table_alloc(NULL, 0, silc_hash_string_case, NULL,
774 silc_hash_string_case_compare, NULL,
775 silc_packet_engine_hash_destr, NULL, TRUE);
777 silc_mutex_unlock(engine->lock);
779 /* Set IO notifier callback. This schedules this stream for I/O. */
780 if (!silc_stream_set_notifier(ps->stream, schedule,
781 silc_packet_stream_io, ps)) {
782 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
783 silc_packet_stream_destroy(ps);
787 SILC_LOG_DEBUG(("Created packet stream %p", 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_init32(&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_int32(&stream->refcnt, 1) > 0) {
889 if (stream->destroyed)
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 */
906 engine = stream->sc->engine;
907 silc_mutex_lock(engine->lock);
908 silc_list_del(engine->streams, stream);
910 /* 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);
918 /* Destroy the underlaying stream */
920 silc_stream_destroy(stream->stream);
922 /* Delete from UDP remote hash table */
924 engine = stream->sc->engine;
925 silc_snprintf(tuple, sizeof(tuple), "%d%s",
926 stream->remote_udp->remote_port,
927 stream->remote_udp->remote_ip);
928 silc_mutex_lock(engine->lock);
929 silc_hash_table_del(engine->udp_remote, tuple);
930 silc_mutex_unlock(engine->lock);
932 silc_free(stream->remote_udp->remote_ip);
933 silc_free(stream->remote_udp);
935 /* Unreference the underlaying packet stream */
936 silc_packet_stream_unref((SilcPacketStream)stream->stream);
939 /* Clear and free buffers */
940 silc_buffer_clear(&stream->outbuf);
941 silc_buffer_purge(&stream->outbuf);
943 if (stream->process) {
945 silc_dlist_start(stream->process);
946 while ((p = silc_dlist_get(stream->process))) {
949 silc_dlist_del(stream->process, p);
951 silc_dlist_uninit(stream->process);
954 /* Destroy ciphers and HMACs */
955 if (stream->send_key[0])
956 silc_cipher_free(stream->send_key[0]);
957 if (stream->receive_key[0])
958 silc_cipher_free(stream->receive_key[0]);
959 if (stream->send_hmac[0])
960 silc_hmac_free(stream->send_hmac[0]);
961 if (stream->receive_hmac[0])
962 silc_hmac_free(stream->receive_hmac[0]);
963 if (stream->send_key[1])
964 silc_cipher_free(stream->send_key[1]);
965 if (stream->receive_key[1])
966 silc_cipher_free(stream->receive_key[1]);
967 if (stream->send_hmac[1])
968 silc_hmac_free(stream->send_hmac[1]);
969 if (stream->receive_hmac[1])
970 silc_hmac_free(stream->receive_hmac[1]);
973 silc_free(stream->src_id);
974 silc_free(stream->dst_id);
976 silc_atomic_uninit32(&stream->refcnt);
977 silc_mutex_free(stream->lock);
981 /* Return TRUE if the stream is valid */
983 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
985 return stream->destroyed == FALSE;
988 /* Marks as router stream */
990 void silc_packet_stream_set_router(SilcPacketStream stream)
992 stream->is_router = TRUE;
995 /* Mark to include IV in ciphertext */
997 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
999 stream->iv_included = TRUE;
1002 /* Links `callbacks' to `stream' for specified packet types */
1004 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1005 const SilcPacketCallbacks *callbacks,
1006 void *callback_context,
1007 int priority, va_list ap)
1009 SilcPacketProcess p, e;
1010 SilcInt32 packet_type;
1013 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1017 if (!callbacks->packet_receive)
1020 p = silc_calloc(1, sizeof(*p));
1024 p->priority = priority;
1025 p->callbacks = callbacks;
1026 p->callback_context = callback_context;
1028 silc_mutex_lock(stream->lock);
1030 if (!stream->process) {
1031 stream->process = silc_dlist_init();
1032 if (!stream->process) {
1033 silc_mutex_unlock(stream->lock);
1039 /* According to priority set the procesor to correct position. First
1040 entry has the highest priority */
1041 silc_dlist_start(stream->process);
1042 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1043 if (p->priority > e->priority) {
1044 silc_dlist_insert(stream->process, p);
1049 silc_dlist_add(stream->process, p);
1051 /* Get packet types to process */
1054 packet_type = va_arg(ap, SilcInt32);
1056 if (packet_type == SILC_PACKET_ANY)
1059 if (packet_type == -1)
1062 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1064 silc_mutex_unlock(stream->lock);
1068 p->types[i - 1] = (SilcPacketType)packet_type;
1072 p->types[i - 1] = 0;
1074 silc_mutex_unlock(stream->lock);
1076 silc_packet_stream_ref(stream);
1081 /* Links `callbacks' to `stream' for specified packet types */
1083 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1084 const SilcPacketCallbacks *callbacks,
1085 void *callback_context,
1091 va_start(ap, priority);
1092 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1099 /* Unlinks `callbacks' from `stream'. */
1101 void silc_packet_stream_unlink(SilcPacketStream stream,
1102 const SilcPacketCallbacks *callbacks,
1103 void *callback_context)
1105 SilcPacketProcess p;
1107 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1108 callbacks, stream));
1110 silc_mutex_lock(stream->lock);
1112 silc_dlist_start(stream->process);
1113 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1114 if (p->callbacks == callbacks &&
1115 p->callback_context == callback_context) {
1116 silc_dlist_del(stream->process, p);
1117 silc_free(p->types);
1122 if (!silc_dlist_count(stream->process)) {
1123 silc_dlist_uninit(stream->process);
1124 stream->process = NULL;
1127 silc_mutex_unlock(stream->lock);
1129 silc_packet_stream_unref(stream);
1132 /* Returns TRUE if stream is UDP stream */
1134 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1136 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1139 /* Return packet sender IP and port for UDP packet stream */
1141 SilcBool silc_packet_get_sender(SilcPacket packet,
1142 const char **sender_ip,
1143 SilcUInt16 *sender_port)
1145 if (!packet->stream->remote_udp)
1148 *sender_ip = packet->stream->remote_udp->remote_ip;
1149 *sender_port = packet->stream->remote_udp->remote_port;
1154 /* Reference packet stream */
1156 void silc_packet_stream_ref(SilcPacketStream stream)
1158 silc_atomic_add_int32(&stream->refcnt, 1);
1159 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1160 silc_atomic_get_int32(&stream->refcnt) - 1,
1161 silc_atomic_get_int32(&stream->refcnt)));
1164 /* Unreference packet stream */
1166 void silc_packet_stream_unref(SilcPacketStream stream)
1168 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1169 silc_atomic_get_int32(&stream->refcnt),
1170 silc_atomic_get_int32(&stream->refcnt) - 1));
1171 if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0)
1173 silc_atomic_add_int32(&stream->refcnt, 1);
1174 silc_packet_stream_destroy(stream);
1179 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1181 return stream->sc->engine;
1184 /* Set application context for packet stream */
1186 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1188 silc_mutex_lock(stream->lock);
1189 stream->stream_context = stream_context;
1190 silc_mutex_unlock(stream->lock);
1193 /* Return application context from packet stream */
1195 void *silc_packet_get_context(SilcPacketStream stream)
1198 silc_mutex_lock(stream->lock);
1199 context = stream->stream_context;
1200 silc_mutex_unlock(stream->lock);
1204 /* Change underlaying stream */
1206 void silc_packet_stream_set_stream(SilcPacketStream ps,
1210 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1211 ps->stream = stream;
1212 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1216 /* Return underlaying stream */
1218 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1220 return stream->stream;
1225 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1226 SilcCipher receive_key, SilcHmac send_hmac,
1227 SilcHmac receive_hmac, SilcBool rekey)
1229 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1231 /* If doing rekey, send REKEY_DONE packet */
1233 /* This will take stream lock. */
1234 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1235 stream->src_id_type, stream->src_id,
1236 stream->src_id_len, stream->dst_id_type,
1237 stream->dst_id, stream->dst_id_len,
1238 NULL, 0, stream->send_key[0],
1239 stream->send_hmac[0]))
1242 /* Write the packet to the stream */
1243 if (!silc_packet_stream_write(stream, TRUE))
1246 silc_mutex_lock(stream->lock);
1249 /* In case IV Included is set, save the old keys */
1250 if (stream->iv_included) {
1251 if (stream->send_key[1] && send_key) {
1252 silc_cipher_free(stream->send_key[1]);
1253 stream->send_key[1] = stream->send_key[0];
1255 if (stream->receive_key[1] && receive_key) {
1256 silc_cipher_free(stream->receive_key[1]);
1257 stream->receive_key[1] = stream->receive_key[0];
1259 if (stream->send_hmac[1] && send_hmac) {
1260 silc_hmac_free(stream->send_hmac[1]);
1261 stream->send_hmac[1] = stream->send_hmac[0];
1263 if (stream->receive_hmac[1] && receive_hmac) {
1264 silc_hmac_free(stream->receive_hmac[1]);
1265 stream->receive_hmac[1] = stream->receive_hmac[0];
1268 if (stream->send_key[0] && send_key)
1269 silc_cipher_free(stream->send_key[0]);
1270 if (stream->receive_key[0] && receive_key)
1271 silc_cipher_free(stream->receive_key[0]);
1272 if (stream->send_hmac[0] && send_hmac)
1273 silc_hmac_free(stream->send_hmac[0]);
1274 if (stream->receive_hmac[0] && receive_hmac)
1275 silc_hmac_free(stream->receive_hmac[0]);
1280 stream->send_key[0] = send_key;
1282 stream->receive_key[0] = receive_key;
1284 stream->send_hmac[0] = send_hmac;
1286 stream->receive_hmac[0] = receive_hmac;
1288 silc_mutex_unlock(stream->lock);
1292 /* Return current ciphers from packet stream */
1294 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1295 SilcCipher *send_key,
1296 SilcCipher *receive_key,
1297 SilcHmac *send_hmac,
1298 SilcHmac *receive_hmac)
1300 if (!stream->send_key[0] && !stream->receive_key[0] &&
1301 !stream->send_hmac[0] && !stream->receive_hmac[0])
1304 silc_mutex_lock(stream->lock);
1307 *send_key = stream->send_key[0];
1309 *receive_key = stream->receive_key[0];
1311 *send_hmac = stream->send_hmac[0];
1313 *receive_hmac = stream->receive_hmac[0];
1315 silc_mutex_unlock(stream->lock);
1320 /* Set SILC IDs to packet stream */
1322 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1323 SilcIdType src_id_type, const void *src_id,
1324 SilcIdType dst_id_type, const void *dst_id)
1327 unsigned char tmp[32];
1330 if (!src_id && !dst_id)
1333 silc_mutex_lock(stream->lock);
1336 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1338 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1339 silc_mutex_unlock(stream->lock);
1342 tmp_id = silc_memdup(tmp, len);
1344 silc_mutex_unlock(stream->lock);
1347 silc_free(stream->src_id);
1348 stream->src_id = tmp_id;
1349 stream->src_id_type = src_id_type;
1350 stream->src_id_len = len;
1354 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1356 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1357 silc_mutex_unlock(stream->lock);
1360 tmp_id = silc_memdup(tmp, len);
1362 silc_mutex_unlock(stream->lock);
1365 silc_free(stream->dst_id);
1366 stream->dst_id = tmp_id;
1367 stream->dst_id_type = dst_id_type;
1368 stream->dst_id_len = len;
1371 silc_mutex_unlock(stream->lock);
1376 /* Return IDs from the packet stream */
1378 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1379 SilcBool *src_id_set, SilcID *src_id,
1380 SilcBool *dst_id_set, SilcID *dst_id)
1382 if (src_id && stream->src_id)
1383 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1384 stream->src_id_type, src_id))
1387 if (stream->src_id && src_id_set)
1390 if (dst_id && stream->dst_id)
1391 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1392 stream->dst_id_type, dst_id))
1395 if (stream->dst_id && dst_id_set)
1401 /* Adds Security ID (SID) */
1403 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1405 if (!stream->iv_included)
1408 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1416 void silc_packet_free(SilcPacket packet)
1418 SilcPacketStream stream = packet->stream;
1420 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1422 /* Check for double free */
1423 SILC_ASSERT(packet->stream != NULL);
1425 packet->stream = NULL;
1426 packet->src_id = packet->dst_id = NULL;
1427 silc_buffer_reset(&packet->buffer);
1429 silc_mutex_lock(stream->sc->engine->lock);
1431 /* Put the packet back to freelist */
1432 silc_list_add(stream->sc->engine->packet_pool, packet);
1433 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1434 silc_list_start(stream->sc->engine->packet_pool);
1436 silc_mutex_unlock(stream->sc->engine->lock);
1439 /****************************** Packet Sending ******************************/
1441 /* Prepare outgoing data buffer for packet sending. Returns the
1442 pointer to that buffer into the `packet'. */
1444 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1449 unsigned char *oldptr;
1450 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1454 /* Allocate more space if needed */
1455 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1456 if (!silc_buffer_realloc(&stream->outbuf,
1457 silc_buffer_truelen(&stream->outbuf) + totlen))
1461 /* Pull data area for the new packet, and return pointer to the start of
1462 the data area and save the pointer in to the `packet'. MAC is pulled
1463 later after it's computed. */
1464 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1465 silc_buffer_set(packet, oldptr, totlen);
1466 silc_buffer_push_tail(packet, mac_len);
1471 /* Increments counter when encrypting in counter mode. */
1473 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1475 unsigned char *ret_iv)
1477 unsigned char *iv = silc_cipher_get_iv(cipher);
1478 SilcUInt32 pc1, pc2;
1480 /* Reset block counter */
1481 memset(iv + 12, 0, 4);
1483 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1484 if (stream->iv_included) {
1486 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1487 ret_iv[1] = ret_iv[0] + iv[4];
1488 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1489 ret_iv[3] = ret_iv[0] + ret_iv[2];
1491 /* Increment 32-bit packet counter */
1492 SILC_GET32_MSB(pc1, iv + 8);
1494 SILC_PUT32_MSB(pc1, ret_iv + 4);
1496 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1498 /* Set new IV to counter block */
1499 memcpy(iv + 4, ret_iv, 8);
1501 /* Increment 64-bit packet counter */
1502 SILC_GET32_MSB(pc1, iv + 4);
1503 SILC_GET32_MSB(pc2, iv + 8);
1506 SILC_PUT32_MSB(pc1, iv + 4);
1507 SILC_PUT32_MSB(pc2, iv + 8);
1510 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1513 /* Internal routine to assemble outgoing packet. Assembles and encrypts
1514 the packet. The silc_packet_stream_write needs to be called to send it
1515 after this returns TRUE. */
1517 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1518 SilcPacketType type,
1519 SilcPacketFlags flags,
1520 SilcIdType src_id_type,
1521 unsigned char *src_id,
1522 SilcUInt32 src_id_len,
1523 SilcIdType dst_id_type,
1524 unsigned char *dst_id,
1525 SilcUInt32 dst_id_len,
1526 const unsigned char *data,
1527 SilcUInt32 data_len,
1531 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1532 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1533 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1535 SilcBufferStruct packet;
1537 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1538 "data len %d", silc_get_packet_name(type), stream->send_psn,
1539 flags, src_id_type, dst_id_type, data_len));
1541 /* Get the true length of the packet. This is saved as payload length
1542 into the packet header. This does not include the length of the
1544 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1545 src_id_len + dst_id_len));
1546 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1547 src_id_len + dst_id_len);
1549 /* If using CTR mode, increment the counter */
1550 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1552 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1554 /* If IV is included, the SID, IV and sequence number is added to packet */
1555 if (stream->iv_included && cipher) {
1556 psnlen = sizeof(psn);
1558 iv[0] = stream->sid;
1561 /* If IV is included, the SID, IV and sequence number is added to packet */
1562 if (stream->iv_included && cipher) {
1563 psnlen = sizeof(psn);
1564 ivlen = block_len + 1;
1565 iv[0] = stream->sid;
1566 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1570 /* We automatically figure out the packet structure from the packet
1571 type and flags, and calculate correct length. Private messages with
1572 private keys and channel messages are special packets as their
1573 payload is encrypted already. */
1574 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1575 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1576 /* Padding is calculated from header + IDs */
1578 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1579 psnlen), block_len, padlen);
1581 /* Length to encrypt, header + IDs + padding. */
1582 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1585 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1586 if (stream->sc->engine->local_is_router && stream->is_router) {
1587 /* Channel messages between routers are encrypted as normal packets.
1588 Padding is calculated from true length of the packet. */
1590 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1592 enclen += padlen + psnlen;
1594 /* Padding is calculated from header + IDs */
1596 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1597 psnlen), block_len, padlen);
1599 /* Length to encrypt, header + IDs + padding. */
1600 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1604 /* Padding is calculated from true length of the packet */
1605 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1606 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1608 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1610 enclen += padlen + psnlen;
1613 /* Remove implementation specific flags */
1614 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1616 /* Get random padding */
1617 for (i = 0; i < padlen; i++) tmppad[i] =
1618 silc_rng_get_byte_fast(stream->sc->engine->rng);
1620 silc_mutex_lock(stream->lock);
1622 if (silc_unlikely(stream->destroyed)) {
1623 SILC_LOG_DEBUG(("Stream %p is destroyed, cannot send packet", stream));
1624 silc_mutex_unlock(stream->lock);
1628 /* Get packet pointer from the outgoing buffer */
1629 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1630 + psnlen, hmac, &packet))) {
1631 silc_mutex_unlock(stream->lock);
1635 SILC_PUT32_MSB(stream->send_psn, psn);
1637 /* Create the packet. This creates the SILC header, adds padding, and
1638 the actual packet data. */
1639 i = silc_buffer_format(&packet,
1640 SILC_STR_DATA(iv, ivlen),
1641 SILC_STR_DATA(psn, psnlen),
1642 SILC_STR_UI_SHORT(truelen),
1643 SILC_STR_UI_CHAR(flags),
1644 SILC_STR_UI_CHAR(type),
1645 SILC_STR_UI_CHAR(padlen),
1646 SILC_STR_UI_CHAR(0),
1647 SILC_STR_UI_CHAR(src_id_len),
1648 SILC_STR_UI_CHAR(dst_id_len),
1649 SILC_STR_UI_CHAR(src_id_type),
1650 SILC_STR_DATA(src_id, src_id_len),
1651 SILC_STR_UI_CHAR(dst_id_type),
1652 SILC_STR_DATA(dst_id, dst_id_len),
1653 SILC_STR_DATA(tmppad, padlen),
1654 SILC_STR_DATA(data, data_len),
1656 if (silc_unlikely(i < 0)) {
1657 silc_mutex_unlock(stream->lock);
1661 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1662 silc_buffer_data(&packet), silc_buffer_len(&packet));
1664 /* Encrypt the packet */
1665 if (silc_likely(cipher)) {
1666 SILC_LOG_DEBUG(("Encrypting packet"));
1667 silc_cipher_set_iv(cipher, NULL);
1668 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1669 packet.data + ivlen, enclen,
1671 SILC_LOG_ERROR(("Packet encryption failed"));
1672 silc_mutex_unlock(stream->lock);
1678 if (silc_likely(hmac)) {
1681 /* MAC is computed from the entire encrypted packet data, and put
1682 to the end of the packet. */
1683 silc_hmac_init(hmac);
1684 silc_hmac_update(hmac, psn, sizeof(psn));
1685 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1686 silc_hmac_final(hmac, packet.tail, &mac_len);
1687 silc_buffer_pull_tail(&packet, mac_len);
1694 /* Sends a packet */
1696 SilcBool silc_packet_send(SilcPacketStream stream,
1697 SilcPacketType type, SilcPacketFlags flags,
1698 const unsigned char *data, SilcUInt32 data_len)
1702 ret = silc_packet_send_raw(stream, type, flags,
1703 stream->src_id_type,
1706 stream->dst_id_type,
1710 stream->send_key[0],
1711 stream->send_hmac[0]);
1713 /* Write the packet to the stream */
1714 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1717 /* Sends a packet, extended routine */
1719 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1720 SilcPacketType type, SilcPacketFlags flags,
1721 SilcIdType src_id_type, void *src_id,
1722 SilcIdType dst_id_type, void *dst_id,
1723 const unsigned char *data, SilcUInt32 data_len,
1724 SilcCipher cipher, SilcHmac hmac)
1726 unsigned char src_id_data[32], dst_id_data[32];
1727 SilcUInt32 src_id_len, dst_id_len;
1731 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1732 sizeof(src_id_data), &src_id_len))
1735 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1736 sizeof(dst_id_data), &dst_id_len))
1739 ret = silc_packet_send_raw(stream, type, flags,
1740 src_id ? src_id_type : stream->src_id_type,
1741 src_id ? src_id_data : stream->src_id,
1742 src_id ? src_id_len : stream->src_id_len,
1743 dst_id ? dst_id_type : stream->dst_id_type,
1744 dst_id ? dst_id_data : stream->dst_id,
1745 dst_id ? dst_id_len : stream->dst_id_len,
1747 cipher ? cipher : stream->send_key[0],
1748 hmac ? hmac : stream->send_hmac[0]);
1750 /* Write the packet to the stream */
1751 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1754 /* Sends packet after formatting the arguments to buffer */
1756 SilcBool silc_packet_send_va(SilcPacketStream stream,
1757 SilcPacketType type, SilcPacketFlags flags, ...)
1759 SilcBufferStruct buf;
1763 va_start(va, flags);
1765 memset(&buf, 0, sizeof(buf));
1766 if (silc_buffer_format_vp(&buf, va) < 0) {
1771 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1772 silc_buffer_len(&buf));
1774 silc_buffer_purge(&buf);
1780 /* Sends packet after formatting the arguments to buffer, extended routine */
1782 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1783 SilcPacketType type, SilcPacketFlags flags,
1784 SilcIdType src_id_type, void *src_id,
1785 SilcIdType dst_id_type, void *dst_id,
1786 SilcCipher cipher, SilcHmac hmac, ...)
1788 SilcBufferStruct buf;
1794 memset(&buf, 0, sizeof(buf));
1795 if (silc_buffer_format_vp(&buf, va) < 0) {
1800 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1801 dst_id_type, dst_id, silc_buffer_data(&buf),
1802 silc_buffer_len(&buf), cipher, hmac);
1804 silc_buffer_purge(&buf);
1810 /***************************** Packet Receiving *****************************/
1812 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1814 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1815 const unsigned char *data,
1816 SilcUInt32 data_len,
1817 const unsigned char *packet_mac,
1818 const unsigned char *packet_seq,
1819 SilcUInt32 sequence)
1822 if (silc_likely(hmac)) {
1823 unsigned char mac[32], psn[4];
1826 SILC_LOG_DEBUG(("Verifying MAC"));
1828 /* Compute HMAC of packet */
1829 silc_hmac_init(hmac);
1832 SILC_PUT32_MSB(sequence, psn);
1833 silc_hmac_update(hmac, psn, 4);
1835 silc_hmac_update(hmac, packet_seq, 4);
1837 silc_hmac_update(hmac, data, data_len);
1838 silc_hmac_final(hmac, mac, &mac_len);
1840 /* Compare the MAC's */
1841 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1842 SILC_LOG_DEBUG(("MAC failed"));
1846 SILC_LOG_DEBUG(("MAC is Ok"));
1852 /* Increments/sets counter when decrypting in counter mode. */
1854 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1856 unsigned char *packet_iv)
1858 SilcUInt32 pc1, pc2;
1860 /* If IV Included flag, set the IV from packet to block counter. */
1861 if (stream->iv_included) {
1862 memcpy(iv + 4, packet_iv, 8);
1864 /* Increment 64-bit packet counter. */
1865 SILC_GET32_MSB(pc1, iv + 4);
1866 SILC_GET32_MSB(pc2, iv + 8);
1869 SILC_PUT32_MSB(pc1, iv + 4);
1870 SILC_PUT32_MSB(pc2, iv + 8);
1873 /* Reset block counter */
1874 memset(iv + 12, 0, 4);
1876 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1879 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1880 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1882 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1883 SilcUInt32 sequence, SilcBuffer buffer,
1886 if (normal == TRUE) {
1887 if (silc_likely(cipher)) {
1888 /* Decrypt rest of the packet */
1889 SILC_LOG_DEBUG(("Decrypting the packet"));
1890 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1892 silc_buffer_len(buffer), NULL)))
1898 /* Decrypt rest of the header plus padding */
1899 if (silc_likely(cipher)) {
1901 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1903 SILC_LOG_DEBUG(("Decrypting the header"));
1905 /* Padding length + src id len + dst id len + header length - 16
1906 bytes already decrypted, gives the rest of the encrypted packet */
1907 silc_buffer_push(buffer, block_len);
1908 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1909 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1911 silc_buffer_pull(buffer, block_len);
1913 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1914 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1918 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1919 buffer->data, len, NULL)))
1927 /* Parses the packet. This is called when a whole packet is ready to be
1928 parsed. The buffer sent must be already decrypted before calling this
1931 static inline SilcBool silc_packet_parse(SilcPacket packet)
1933 SilcBuffer buffer = &packet->buffer;
1934 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1935 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1938 SILC_LOG_DEBUG(("Parsing incoming packet"));
1940 /* Parse the buffer. This parses the SILC header of the packet. */
1941 ret = silc_buffer_unformat(buffer,
1944 SILC_STR_UI_CHAR(&src_id_len),
1945 SILC_STR_UI_CHAR(&dst_id_len),
1946 SILC_STR_UI_CHAR(&src_id_type),
1948 if (silc_unlikely(ret == -1)) {
1949 if (!packet->stream->udp &&
1950 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1951 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1955 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1956 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1957 if (!packet->stream->udp &&
1958 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1959 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1960 packet->src_id_len, packet->dst_id_len));
1964 ret = silc_buffer_unformat(buffer,
1966 SILC_STR_DATA(&packet->src_id, src_id_len),
1967 SILC_STR_UI_CHAR(&dst_id_type),
1968 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1969 SILC_STR_OFFSET(padlen),
1971 if (silc_unlikely(ret == -1)) {
1972 if (!packet->stream->udp &&
1973 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1974 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1978 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1979 dst_id_type > SILC_ID_CHANNEL)) {
1980 if (!packet->stream->udp &&
1981 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1982 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1983 src_id_type, dst_id_type));
1987 packet->src_id_len = src_id_len;
1988 packet->dst_id_len = dst_id_len;
1989 packet->src_id_type = src_id_type;
1990 packet->dst_id_type = dst_id_type;
1992 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1993 silc_buffer_len(buffer)), buffer->head,
1994 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1996 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1997 silc_get_packet_name(packet->type), packet->flags));
2002 /* Dispatch packet to application. Called with stream->lock locked.
2003 Returns FALSE if the stream was destroyed while dispatching a packet. */
2005 static SilcBool silc_packet_dispatch(SilcPacket packet)
2007 SilcPacketStream stream = packet->stream;
2008 SilcPacketProcess p;
2009 SilcBool default_sent = FALSE;
2012 /* Dispatch packet to all packet processors that want it */
2014 if (silc_likely(!stream->process)) {
2015 /* Send to default processor as no others exist */
2016 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2017 silc_mutex_unlock(stream->lock);
2018 if (silc_unlikely(!stream->sc->engine->callbacks->
2019 packet_receive(stream->sc->engine, stream, packet,
2020 stream->sc->engine->callback_context,
2021 stream->stream_context)))
2022 silc_packet_free(packet);
2023 silc_mutex_lock(stream->lock);
2024 return stream->destroyed == FALSE;
2027 silc_dlist_start(stream->process);
2028 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2030 /* If priority is 0 or less, we send to default processor first
2031 because default processor has 0 priority */
2032 if (!default_sent && p->priority <= 0) {
2033 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2034 default_sent = TRUE;
2035 silc_mutex_unlock(stream->lock);
2036 if (stream->sc->engine->callbacks->
2037 packet_receive(stream->sc->engine, stream, packet,
2038 stream->sc->engine->callback_context,
2039 stream->stream_context)) {
2040 silc_mutex_lock(stream->lock);
2041 return stream->destroyed == FALSE;
2043 silc_mutex_lock(stream->lock);
2046 /* Send to processor */
2048 /* Send all packet types */
2049 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2050 silc_mutex_unlock(stream->lock);
2051 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2052 p->callback_context,
2053 stream->stream_context)) {
2054 silc_mutex_lock(stream->lock);
2055 return stream->destroyed == FALSE;
2057 silc_mutex_lock(stream->lock);
2059 /* Send specific types */
2060 for (pt = p->types; *pt; pt++) {
2061 if (*pt != packet->type)
2063 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2064 silc_mutex_unlock(stream->lock);
2065 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2066 p->callback_context,
2067 stream->stream_context)) {
2068 silc_mutex_lock(stream->lock);
2069 return stream->destroyed == FALSE;
2071 silc_mutex_lock(stream->lock);
2077 if (!default_sent) {
2078 /* Send to default processor as it has not been sent yet */
2079 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2080 silc_mutex_unlock(stream->lock);
2081 if (stream->sc->engine->callbacks->
2082 packet_receive(stream->sc->engine, stream, packet,
2083 stream->sc->engine->callback_context,
2084 stream->stream_context)) {
2085 silc_mutex_lock(stream->lock);
2086 return stream->destroyed == FALSE;
2088 silc_mutex_lock(stream->lock);
2091 /* If we got here, no one wanted the packet, so drop it */
2092 silc_packet_free(packet);
2093 return stream->destroyed == FALSE;
2096 /* Process incoming data and parse packets. Called with stream->lock
2099 static void silc_packet_read_process(SilcPacketStream stream)
2106 SilcUInt16 packetlen;
2107 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2108 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2109 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2113 /* Get inbuf. If there is already some data for this stream in the buffer
2114 we already have it. Otherwise get the current one from list, it will
2115 include the data. */
2116 inbuf = stream->inbuf;
2118 silc_dlist_start(stream->sc->inbufs);
2119 inbuf = silc_dlist_get(stream->sc->inbufs);
2122 /* Parse the packets from the data */
2123 while (silc_buffer_len(inbuf) > 0) {
2125 cipher = stream->receive_key[0];
2126 hmac = stream->receive_hmac[0];
2129 if (silc_unlikely(silc_buffer_len(inbuf) <
2130 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2131 SILC_PACKET_MIN_HEADER_LEN))) {
2132 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2133 silc_dlist_del(stream->sc->inbufs, inbuf);
2134 stream->inbuf = inbuf;
2138 if (silc_likely(hmac))
2139 mac_len = silc_hmac_len(hmac);
2143 /* Decrypt first block of the packet to get the length field out */
2144 if (silc_likely(cipher)) {
2145 block_len = silc_cipher_get_block_len(cipher);
2147 if (stream->iv_included) {
2148 /* SID, IV and sequence number is included in the ciphertext */
2149 sid = (SilcUInt8)inbuf->data[0];
2151 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2152 /* Set the CTR mode IV from packet to counter block */
2153 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2154 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2157 /* Get IV from packet */
2158 memcpy(iv, inbuf->data + 1, block_len);
2159 ivlen = block_len + 1;
2163 /* Check SID, and get correct decryption key */
2164 if (sid != stream->sid) {
2165 /* If SID is recent get the previous key and use it */
2166 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2167 stream->receive_key[1] && !stream->receive_hmac[1]) {
2168 cipher = stream->receive_key[1];
2169 hmac = stream->receive_hmac[1];
2171 /* The SID is unknown, drop rest of the data in buffer */
2172 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2174 silc_mutex_unlock(stream->lock);
2175 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2176 silc_mutex_lock(stream->lock);
2181 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2183 /* If using CTR mode, increment the counter */
2184 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2185 silc_packet_receive_ctr_increment(stream, iv, NULL);
2188 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2189 silc_cipher_set_iv(cipher, NULL);
2190 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2193 if (stream->iv_included) {
2194 /* Take sequence number from packet */
2195 packet_seq = header;
2199 /* Unencrypted packet */
2200 block_len = SILC_PACKET_MIN_HEADER_LEN;
2201 header = inbuf->data;
2204 /* Get packet length and full packet length with padding */
2205 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2208 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2209 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2210 SILC_LOG_ERROR(("Received too short packet"));
2211 silc_mutex_unlock(stream->lock);
2212 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2213 silc_mutex_lock(stream->lock);
2214 memset(tmp, 0, sizeof(tmp));
2218 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2219 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2221 paddedlen + mac_len - silc_buffer_len(inbuf)));
2222 memset(tmp, 0, sizeof(tmp));
2223 silc_dlist_del(stream->sc->inbufs, inbuf);
2224 stream->inbuf = inbuf;
2228 /* Check MAC of the packet */
2229 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2231 inbuf->data + ivlen +
2232 paddedlen, packet_seq,
2233 stream->receive_psn))) {
2234 silc_mutex_unlock(stream->lock);
2235 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2236 silc_mutex_lock(stream->lock);
2237 memset(tmp, 0, sizeof(tmp));
2242 packet = silc_packet_alloc(stream->sc->engine);
2243 if (silc_unlikely(!packet)) {
2244 silc_mutex_unlock(stream->lock);
2245 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2246 silc_mutex_lock(stream->lock);
2247 memset(tmp, 0, sizeof(tmp));
2250 packet->stream = stream;
2252 /* Allocate more space to packet buffer, if needed */
2253 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2254 if (!silc_buffer_realloc(&packet->buffer,
2255 silc_buffer_truelen(&packet->buffer) +
2257 silc_buffer_truelen(&packet->buffer)))) {
2258 silc_mutex_unlock(stream->lock);
2259 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2260 silc_mutex_lock(stream->lock);
2261 silc_packet_free(packet);
2262 memset(tmp, 0, sizeof(tmp));
2267 /* Parse packet header */
2268 packet->flags = (SilcPacketFlags)header[2];
2269 packet->type = (SilcPacketType)header[3];
2271 if (stream->sc->engine->local_is_router) {
2272 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2273 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2275 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2276 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2277 stream->is_router == TRUE))
2280 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2281 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2283 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2287 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2288 stream->receive_psn, paddedlen + ivlen + mac_len),
2289 inbuf->data, paddedlen + ivlen + mac_len);
2291 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2292 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2293 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2294 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2295 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2296 psnlen + (block_len - psnlen)),
2297 paddedlen - ivlen - psnlen - (block_len - psnlen));
2298 if (silc_likely(cipher)) {
2299 silc_cipher_set_iv(cipher, iv);
2300 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2301 &packet->buffer, normal);
2302 if (silc_unlikely(ret < 0)) {
2303 silc_mutex_unlock(stream->lock);
2304 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2305 silc_mutex_lock(stream->lock);
2306 silc_packet_free(packet);
2307 memset(tmp, 0, sizeof(tmp));
2311 stream->receive_psn++;
2313 silc_buffer_push(&packet->buffer, block_len);
2315 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2316 silc_buffer_pull(inbuf, paddedlen + mac_len);
2318 /* Parse the packet */
2319 if (silc_unlikely(!silc_packet_parse(packet))) {
2320 silc_mutex_unlock(stream->lock);
2321 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2322 silc_mutex_lock(stream->lock);
2323 silc_packet_free(packet);
2324 memset(tmp, 0, sizeof(tmp));
2328 /* Dispatch the packet to application */
2329 if (!silc_packet_dispatch(packet))
2334 /* Add inbuf back to free list, if we owned it. */
2335 if (stream->inbuf) {
2336 silc_dlist_add(stream->sc->inbufs, inbuf);
2337 stream->inbuf = NULL;
2340 silc_buffer_reset(inbuf);
2343 /****************************** Packet Waiting ******************************/
2345 /* Packet wait receive callback */
2347 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2348 SilcPacketStream stream,
2350 void *callback_context,
2351 void *stream_context);
2353 /* Packet waiting callbacks */
2354 static const SilcPacketCallbacks silc_packet_wait_cbs =
2356 silc_packet_wait_packet_receive, NULL, NULL
2359 /* Packet waiting context */
2361 SilcMutex wait_lock;
2363 SilcList packet_queue;
2364 unsigned char id[28];
2365 unsigned int id_type : 2;
2366 unsigned int id_len : 5;
2367 unsigned int stopped : 1;
2370 /* Packet wait receive callback */
2373 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2374 SilcPacketStream stream,
2376 void *callback_context,
2377 void *stream_context)
2379 SilcPacketWait pw = callback_context;
2381 /* If source ID is specified check for it */
2383 if (pw->id_type != packet->src_id_type ||
2384 memcmp(pw->id, packet->src_id, pw->id_len))
2388 /* Signal the waiting thread for a new packet */
2389 silc_mutex_lock(pw->wait_lock);
2391 if (silc_unlikely(pw->stopped)) {
2392 silc_mutex_unlock(pw->wait_lock);
2396 silc_list_add(pw->packet_queue, packet);
2397 silc_cond_broadcast(pw->wait_cond);
2399 silc_mutex_unlock(pw->wait_lock);
2404 /* Initialize packet waiting */
2406 void *silc_packet_wait_init(SilcPacketStream stream,
2407 const SilcID *source_id, ...)
2413 pw = silc_calloc(1, sizeof(*pw));
2417 /* Allocate mutex and conditional variable */
2418 if (!silc_mutex_alloc(&pw->wait_lock)) {
2422 if (!silc_cond_alloc(&pw->wait_cond)) {
2423 silc_mutex_free(pw->wait_lock);
2428 /* Link to the packet stream for the requested packet types */
2429 va_start(ap, source_id);
2430 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2434 silc_cond_free(pw->wait_cond);
2435 silc_mutex_free(pw->wait_lock);
2440 /* Initialize packet queue */
2441 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2445 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2446 sizeof(pw->id), &id_len);
2447 pw->id_type = source_id->type;
2448 pw->id_len = id_len;
2454 /* Uninitialize packet waiting */
2456 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2458 SilcPacketWait pw = waiter;
2461 /* Signal any threads to stop waiting */
2462 silc_mutex_lock(pw->wait_lock);
2464 silc_cond_broadcast(pw->wait_cond);
2465 silc_mutex_unlock(pw->wait_lock);
2466 silc_thread_yield();
2468 /* Re-acquire lock and free resources */
2469 silc_mutex_lock(pw->wait_lock);
2470 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2472 /* Free any remaining packets */
2473 silc_list_start(pw->packet_queue);
2474 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2475 silc_packet_free(packet);
2477 silc_mutex_unlock(pw->wait_lock);
2478 silc_cond_free(pw->wait_cond);
2479 silc_mutex_free(pw->wait_lock);
2483 /* Blocks thread until a packet has been received. */
2485 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2487 SilcPacketWait pw = waiter;
2488 SilcBool ret = FALSE;
2490 silc_mutex_lock(pw->wait_lock);
2492 /* Wait here until packet has arrived */
2493 while (silc_list_count(pw->packet_queue) == 0) {
2494 if (silc_unlikely(pw->stopped)) {
2495 silc_mutex_unlock(pw->wait_lock);
2498 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2502 silc_list_start(pw->packet_queue);
2503 *return_packet = silc_list_get(pw->packet_queue);
2504 silc_list_del(pw->packet_queue, *return_packet);
2506 silc_mutex_unlock(pw->wait_lock);
2508 return ret == TRUE ? 1 : 0;
2511 /************************** Packet Stream Wrapper ***************************/
2513 /* Packet stream wrapper receive callback */
2515 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2516 SilcPacketStream stream,
2518 void *callback_context,
2519 void *stream_context);
2521 const SilcStreamOps silc_packet_stream_ops;
2523 /* Packet stream wrapper context */
2525 const SilcStreamOps *ops;
2526 SilcPacketStream stream;
2528 void *waiter; /* Waiter context in blocking mode */
2529 SilcPacketWrapCoder coder;
2530 void *coder_context;
2532 SilcStreamNotifier callback;
2535 SilcPacketType type;
2536 SilcPacketFlags flags;
2537 unsigned int closed : 1;
2538 unsigned int blocking : 1;
2539 unsigned int read_more : 1;
2540 } *SilcPacketWrapperStream;
2542 /* Packet wrapper callbacks */
2543 static const SilcPacketCallbacks silc_packet_wrap_cbs =
2545 silc_packet_wrap_packet_receive, NULL, NULL
2548 /* Packet stream wrapper receive callback, non-blocking mode */
2551 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2552 SilcPacketStream stream,
2554 void *callback_context,
2555 void *stream_context)
2557 SilcPacketWrapperStream pws = callback_context;
2559 if (pws->closed || !pws->callback)
2562 silc_mutex_lock(pws->lock);
2563 silc_list_add(pws->in_queue, packet);
2564 silc_mutex_unlock(pws->lock);
2566 /* Call notifier callback */
2567 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2572 /* Task callback to notify more data is available for reading */
2574 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2576 SilcPacketWrapperStream pws = context;
2578 if (pws->closed || !pws->callback)
2581 /* Call notifier callback */
2582 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2585 /* Read SILC packet */
2587 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2590 SilcPacketWrapperStream pws = stream;
2592 SilcBool read_more = FALSE;
2598 if (pws->blocking) {
2599 /* Block until packet is received */
2600 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2605 /* Non-blocking mode */
2606 silc_mutex_lock(pws->lock);
2607 if (!silc_list_count(pws->in_queue)) {
2608 silc_mutex_unlock(pws->lock);
2612 silc_list_start(pws->in_queue);
2613 packet = silc_list_get(pws->in_queue);
2614 silc_list_del(pws->in_queue, packet);
2615 silc_mutex_unlock(pws->lock);
2618 /* Call decoder if set */
2619 if (pws->coder && !pws->read_more)
2620 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2621 pws->coder_context);
2623 len = silc_buffer_len(&packet->buffer);
2624 if (len > buf_len) {
2630 memcpy(buf, packet->buffer.data, len);
2632 if (read_more && !pws->blocking) {
2633 /* More data will be available (in blocking mode not supported). */
2634 silc_buffer_pull(&packet->buffer, len);
2635 silc_list_insert(pws->in_queue, NULL, packet);
2636 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2637 silc_packet_wrap_read_more, pws, 0, 0);
2638 pws->read_more = TRUE;
2642 pws->read_more = FALSE;
2643 silc_packet_free(packet);
2647 /* Write SILC packet */
2649 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2650 SilcUInt32 data_len)
2652 SilcPacketWrapperStream pws = stream;
2653 SilcBool ret = FALSE;
2655 /* Call encoder if set */
2657 silc_buffer_reset(pws->encbuf);
2658 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2659 pws->coder_context);
2662 /* Send the SILC packet */
2664 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2665 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2666 silc_buffer_len(pws->encbuf)),
2667 SILC_STR_DATA(data, data_len),
2671 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2680 SilcBool silc_packet_wrap_close(SilcStream stream)
2682 SilcPacketWrapperStream pws = stream;
2687 if (pws->blocking) {
2688 /* Close packet waiter */
2689 silc_packet_wait_uninit(pws->waiter, pws->stream);
2693 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2700 /* Destroy wrapper stream */
2702 void silc_packet_wrap_destroy(SilcStream stream)
2705 SilcPacketWrapperStream pws = stream;
2708 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2710 silc_stream_close(stream);
2711 silc_list_start(pws->in_queue);
2712 while ((packet = silc_list_get(pws->in_queue)))
2713 silc_packet_free(packet);
2715 silc_mutex_free(pws->lock);
2717 silc_buffer_free(pws->encbuf);
2718 silc_packet_stream_unref(pws->stream);
2723 /* Link stream to receive packets */
2725 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2726 SilcSchedule schedule,
2727 SilcStreamNotifier callback,
2730 SilcPacketWrapperStream pws = stream;
2732 if (pws->closed || pws->blocking)
2735 /* Link to receive packets */
2737 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2738 100000, pws->type, -1);
2740 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2742 pws->callback = callback;
2743 pws->context = context;
2748 /* Return schedule */
2750 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2755 /* Wraps packet stream into SilcStream. */
2757 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2758 SilcPacketType type,
2759 SilcPacketFlags flags,
2760 SilcBool blocking_mode,
2761 SilcPacketWrapCoder coder,
2764 SilcPacketWrapperStream pws;
2766 pws = silc_calloc(1, sizeof(*pws));
2770 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2772 pws->ops = &silc_packet_stream_ops;
2773 pws->stream = stream;
2776 pws->blocking = blocking_mode;
2778 pws->coder_context = context;
2780 /* Allocate small amount for encoder buffer. */
2782 pws->encbuf = silc_buffer_alloc(8);
2784 if (pws->blocking) {
2785 /* Blocking mode. Use packet waiter to do the thing. */
2786 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2792 /* Non-blocking mode */
2793 silc_mutex_alloc(&pws->lock);
2794 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2797 silc_packet_stream_ref(stream);
2799 return (SilcStream)pws;
2802 const SilcStreamOps silc_packet_stream_ops =
2804 silc_packet_wrap_read,
2805 silc_packet_wrap_write,
2806 silc_packet_wrap_close,
2807 silc_packet_wrap_destroy,
2808 silc_packet_wrap_notifier,
2809 silc_packet_wrap_get_schedule,