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 SilcBufferStruct inbuf; /* Data input buffer */
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 SilcCipher send_key[2]; /* Sending key */
76 SilcHmac send_hmac[2]; /* Sending HMAC */
77 SilcCipher receive_key[2]; /* Receiving key */
78 SilcHmac receive_hmac[2]; /* Receiving HMAC */
79 unsigned char *src_id; /* Source ID */
80 unsigned char *dst_id; /* Destination ID */
81 SilcUInt32 send_psn; /* Sending sequence */
82 SilcUInt32 receive_psn; /* Receiving sequence */
83 SilcAtomic8 refcnt; /* Reference counter */
84 SilcUInt8 sid; /* Security ID, set if IV included */
85 unsigned int src_id_len : 6;
86 unsigned int src_id_type : 2;
87 unsigned int dst_id_len : 6;
88 unsigned int dst_id_type : 2;
89 unsigned int is_router : 1; /* Set if router stream */
90 unsigned int destroyed : 1; /* Set if destroyed */
91 unsigned int iv_included : 1; /* Set if IV included */
92 unsigned int udp : 1; /* UDP remote stream */
95 /* Initial size of stream buffers */
96 #define SILC_PACKET_DEFAULT_SIZE 1024
98 /* Header length without source and destination ID's. */
99 #define SILC_PACKET_HEADER_LEN 10
101 /* Minimum length of SILC Packet Header. */
102 #define SILC_PACKET_MIN_HEADER_LEN 16
103 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
105 /* Maximum padding length */
106 #define SILC_PACKET_MAX_PADLEN 128
108 /* Default padding length */
109 #define SILC_PACKET_DEFAULT_PADLEN 16
111 /* Minimum packet length */
112 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
114 /* Returns true length of the packet. */
115 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
117 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
118 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
121 /* Calculates the data length with given header length. This macro
122 can be used to check whether the data_len with header_len exceeds
123 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
124 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
125 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
126 is the data_len given as argument. */
127 #define SILC_PACKET_DATALEN(data_len, header_len) \
128 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
129 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
131 /* Calculates the length of the padding in the packet. */
132 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
134 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
135 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
137 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
140 /* Returns the length of the padding up to the maximum length, which
142 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
144 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
145 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
149 #define SILC_PACKET_CALLBACK_EOS(s) \
151 (s)->sc->engine->callbacks->eos((s)->sc->engine, s, \
152 (s)->sc->engine->callback_context, \
153 (s)->stream_context); \
157 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
159 (s)->sc->engine->callbacks->error((s)->sc->engine, s, err, \
160 (s)->sc->engine->callback_context, \
161 (s)->stream_context); \
164 static SilcBool silc_packet_dispatch(SilcPacket packet);
165 static void silc_packet_read_process(SilcPacketStream stream);
166 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
168 SilcPacketFlags flags,
169 SilcIdType src_id_type,
170 unsigned char *src_id,
171 SilcUInt32 src_id_len,
172 SilcIdType dst_id_type,
173 unsigned char *dst_id,
174 SilcUInt32 dst_id_len,
175 const unsigned char *data,
180 /************************ Static utility functions **************************/
182 /* Injects packet to new stream created with silc_packet_stream_add_remote. */
184 SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
186 SilcPacket packet = context;
187 SilcPacketStream stream = packet->stream;
189 SILC_LOG_DEBUG(("Injecting packet %p to stream %p", packet, packet->stream));
191 silc_mutex_lock(stream->lock);
192 if (!stream->destroyed)
193 silc_packet_dispatch(packet);
194 silc_mutex_unlock(stream->lock);
195 silc_packet_stream_unref(stream);
198 /* Write data to the stream. Must be called with ps->lock locked. Unlocks
199 the lock inside this function, unless no_unlock is TRUE. Unlocks always
200 in case it returns FALSE. */
202 static inline SilcBool silc_packet_stream_write(SilcPacketStream ps,
210 stream = ((SilcPacketStream)ps->stream)->stream;
214 if (ps->udp && silc_socket_stream_is_udp(stream, &connected)) {
216 /* Connectionless UDP stream */
217 while (silc_buffer_len(&ps->outbuf) > 0) {
218 i = silc_net_udp_send(stream, ps->remote_udp->remote_ip,
219 ps->remote_udp->remote_port,
220 ps->outbuf.data, silc_buffer_len(&ps->outbuf));
221 if (silc_unlikely(i == -2)) {
223 silc_buffer_reset(&ps->outbuf);
224 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
228 if (silc_unlikely(i == -1)) {
229 /* Cannot write now, write later. */
231 silc_mutex_unlock(ps->lock);
236 silc_buffer_pull(&ps->outbuf, i);
239 silc_buffer_reset(&ps->outbuf);
241 silc_mutex_unlock(ps->lock);
247 /* Write the data to the stream */
248 while (silc_buffer_len(&ps->outbuf) > 0) {
249 i = silc_stream_write(stream, ps->outbuf.data,
250 silc_buffer_len(&ps->outbuf));
251 if (silc_unlikely(i == 0)) {
253 silc_buffer_reset(&ps->outbuf);
254 silc_mutex_unlock(ps->lock);
255 SILC_PACKET_CALLBACK_EOS(ps);
259 if (silc_unlikely(i == -2)) {
261 silc_buffer_reset(&ps->outbuf);
262 silc_mutex_unlock(ps->lock);
263 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
267 if (silc_unlikely(i == -1)) {
268 /* Cannot write now, write later. */
270 silc_mutex_unlock(ps->lock);
275 silc_buffer_pull(&ps->outbuf, i);
278 silc_buffer_reset(&ps->outbuf);
280 silc_mutex_unlock(ps->lock);
285 /* Reads data from stream. Must be called with ps->lock locked. If this
286 returns FALSE the lock has been unlocked. If this returns packet stream
287 to `ret_ps' its lock has been acquired and `ps' lock has been unlocked.
288 It is returned if the stream is UDP and remote UDP stream exists for
289 the sender of the packet. */
291 static inline SilcBool silc_packet_stream_read(SilcPacketStream ps,
292 SilcPacketStream *ret_ps)
300 inbuf = &ps->sc->inbuf;
302 /* Make sure there is enough room to read */
303 if (SILC_PACKET_DEFAULT_SIZE * 2 > silc_buffer_taillen(inbuf))
304 silc_buffer_realloc(inbuf, silc_buffer_truelen(inbuf) +
305 (SILC_PACKET_DEFAULT_SIZE * 2));
307 if (silc_socket_stream_is_udp(stream, &connected)) {
309 /* Connectionless UDP stream, read one UDP packet */
310 char remote_ip[64], tuple[64];
312 SilcPacketStream remote;
314 ret = silc_net_udp_receive(stream, remote_ip, sizeof(remote_ip),
315 &remote_port, inbuf->tail,
316 silc_buffer_taillen(inbuf));
318 if (silc_unlikely(ret < 0)) {
319 silc_mutex_unlock(ps->lock);
321 /* Cannot read now, do it later. */
322 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
327 silc_buffer_reset(inbuf);
328 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
332 /* See if remote packet stream exist for this sender */
333 silc_snprintf(tuple, sizeof(tuple), "%d%s", remote_port, remote_ip);
334 silc_mutex_lock(ps->sc->engine->lock);
335 if (silc_hash_table_find(ps->sc->engine->udp_remote, tuple, NULL,
337 silc_mutex_unlock(ps->sc->engine->lock);
338 SILC_LOG_DEBUG(("UDP packet from %s:%d for stream %p", remote_ip,
339 remote_port, remote));
340 silc_mutex_unlock(ps->lock);
341 silc_mutex_lock(remote->lock);
345 silc_mutex_unlock(ps->sc->engine->lock);
348 if (!ps->remote_udp) {
349 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
350 if (silc_unlikely(!ps->remote_udp)) {
351 silc_mutex_unlock(ps->lock);
352 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_NO_MEMORY);
357 /* Save sender IP and port */
358 silc_free(ps->remote_udp->remote_ip);
359 ps->remote_udp->remote_ip = strdup(remote_ip);
360 ps->remote_udp->remote_port = remote_port;
362 silc_buffer_pull_tail(inbuf, ret);
367 /* Read data from the stream */
368 ret = silc_stream_read(stream, inbuf->tail, silc_buffer_taillen(inbuf));
369 if (silc_unlikely(ret <= 0)) {
370 silc_mutex_unlock(ps->lock);
373 silc_buffer_reset(inbuf);
374 SILC_PACKET_CALLBACK_EOS(ps);
379 /* Cannot read now, do it later. */
380 silc_buffer_pull(inbuf, silc_buffer_len(inbuf));
385 silc_buffer_reset(inbuf);
386 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
390 silc_buffer_pull_tail(inbuf, ret);
394 /* Our stream IO notifier callback. */
396 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
399 SilcPacketStream remote = NULL, ps = context;
401 silc_mutex_lock(ps->lock);
403 if (silc_unlikely(ps->destroyed)) {
404 silc_mutex_unlock(ps->lock);
409 case SILC_STREAM_CAN_READ:
410 /* Reading is locked also with stream->lock because we may be reading
411 at the same time other thread is writing to same underlaying stream. */
412 SILC_LOG_DEBUG(("Reading data from stream %p, ps %p", ps->stream, ps));
414 /* Read data from stream */
415 if (!silc_packet_stream_read(ps, &remote))
418 /* Now process the data */
419 silc_packet_stream_ref(ps);
421 silc_packet_read_process(ps);
422 silc_mutex_unlock(ps->lock);
424 silc_packet_read_process(remote);
425 silc_mutex_unlock(remote->lock);
427 silc_packet_stream_unref(ps);
430 case SILC_STREAM_CAN_WRITE:
431 SILC_LOG_DEBUG(("Writing pending data to stream %p, ps %p",
434 if (silc_unlikely(!silc_buffer_headlen(&ps->outbuf))) {
435 silc_mutex_unlock(ps->lock);
439 /* Write pending data to stream */
440 silc_packet_stream_write(ps, FALSE);
444 silc_mutex_unlock(ps->lock);
449 /* Allocate packet */
451 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
455 SILC_LOG_DEBUG(("Packet pool count %d",
456 silc_list_count(engine->packet_pool)));
458 silc_mutex_lock(engine->lock);
460 /* Get packet from freelist or allocate new one. */
461 packet = silc_list_get(engine->packet_pool);
465 silc_mutex_unlock(engine->lock);
467 packet = silc_calloc(1, sizeof(*packet));
468 if (silc_unlikely(!packet))
471 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
473 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
474 if (silc_unlikely(!tmp)) {
478 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
479 silc_buffer_reset(&packet->buffer);
484 SILC_LOG_DEBUG(("Get packet %p", packet));
486 /* Delete from freelist */
487 silc_list_del(engine->packet_pool, packet);
489 silc_mutex_unlock(engine->lock);
494 /* UDP remote stream hash table destructor */
496 static void silc_packet_engine_hash_destr(void *key, void *context,
502 /* Per scheduler context hash table destructor */
504 static void silc_packet_engine_context_destr(void *key, void *context,
507 SilcPacketEngineContext sc = context;
508 silc_buffer_clear(&sc->inbuf);
509 silc_buffer_purge(&sc->inbuf);
514 /******************************** Packet API ********************************/
516 /* Allocate new packet engine */
519 silc_packet_engine_start(SilcRng rng, SilcBool router,
520 SilcPacketCallbacks *callbacks,
521 void *callback_context)
523 SilcPacketEngine engine;
528 SILC_LOG_DEBUG(("Starting new packet engine"));
532 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
535 engine = silc_calloc(1, sizeof(*engine));
539 engine->contexts = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
540 silc_packet_engine_context_destr,
542 if (!engine->contexts) {
548 engine->local_is_router = router;
549 engine->callbacks = callbacks;
550 engine->callback_context = callback_context;
551 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
552 silc_mutex_alloc(&engine->lock);
554 /* Allocate packet free list */
555 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
556 for (i = 0; i < 5; i++) {
557 packet = silc_calloc(1, sizeof(*packet));
559 silc_packet_engine_stop(engine);
563 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
565 silc_packet_engine_stop(engine);
568 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
569 silc_buffer_reset(&packet->buffer);
571 silc_list_add(engine->packet_pool, packet);
573 silc_list_start(engine->packet_pool);
578 /* Stop packet engine */
580 void silc_packet_engine_stop(SilcPacketEngine engine)
583 SILC_LOG_DEBUG(("Stopping packet engine"));
593 /* Create new packet stream */
595 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
596 SilcSchedule schedule,
602 SILC_LOG_DEBUG(("Creating new packet stream"));
604 if (!engine || !stream)
607 ps = silc_calloc(1, sizeof(*ps));
612 silc_atomic_init8(&ps->refcnt, 1);
613 silc_mutex_alloc(&ps->lock);
615 /* Allocate out buffer */
616 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
618 silc_packet_stream_destroy(ps);
621 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
622 silc_buffer_reset(&ps->outbuf);
624 /* Initialize packet procesors list */
625 ps->process = silc_dlist_init();
627 silc_packet_stream_destroy(ps);
631 silc_mutex_lock(engine->lock);
633 /* Add per scheduler context */
634 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
636 ps->sc = silc_calloc(1, sizeof(*ps->sc));
638 silc_packet_stream_destroy(ps);
639 silc_mutex_unlock(engine->lock);
642 ps->sc->engine = engine;
643 ps->sc->schedule = schedule;
645 /* Allocate data input buffer */
646 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE * 31);
650 silc_packet_stream_destroy(ps);
651 silc_mutex_unlock(engine->lock);
654 silc_buffer_set(&ps->sc->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE * 31);
655 silc_buffer_reset(&ps->sc->inbuf);
657 /* Add to per scheduler context hash table */
658 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
659 silc_buffer_purge(&ps->sc->inbuf);
662 silc_packet_stream_destroy(ps);
663 silc_mutex_unlock(engine->lock);
667 ps->sc->stream_count++;
669 /* Add the packet stream to engine */
670 silc_list_add(engine->streams, ps);
672 /* If this is UDP stream, allocate UDP remote stream hash table */
673 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
674 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
675 silc_hash_string_compare, NULL,
676 silc_packet_engine_hash_destr,
679 silc_mutex_unlock(engine->lock);
681 /* Set IO notifier callback. This schedules this stream for I/O. */
682 if (!silc_stream_set_notifier(ps->stream, schedule,
683 silc_packet_stream_io, ps)) {
684 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
685 silc_packet_stream_destroy(ps);
692 /* Add new remote packet stream for UDP packet streams */
694 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
695 const char *remote_ip,
696 SilcUInt16 remote_port,
699 SilcPacketEngine engine = stream->sc->engine;
704 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
705 remote_ip, remote_port, stream));
707 if (!stream || !remote_ip || !remote_port)
710 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
711 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
715 ps = silc_calloc(1, sizeof(*ps));
720 silc_atomic_init8(&ps->refcnt, 1);
721 silc_mutex_alloc(&ps->lock);
723 /* Set the UDP packet stream as underlaying stream */
724 silc_packet_stream_ref(stream);
725 ps->stream = (SilcStream)stream;
728 /* Allocate out buffer */
729 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
731 silc_packet_stream_destroy(ps);
734 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
735 silc_buffer_reset(&ps->outbuf);
737 /* Initialize packet procesors list */
738 ps->process = silc_dlist_init();
740 silc_packet_stream_destroy(ps);
744 /* Add to engine with this IP and port pair */
745 tuple = silc_format("%d%s", remote_port, remote_ip);
746 silc_mutex_lock(engine->lock);
747 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
748 silc_mutex_unlock(engine->lock);
749 silc_packet_stream_destroy(ps);
752 silc_mutex_unlock(engine->lock);
754 /* Save remote IP and port pair */
755 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
756 if (!ps->remote_udp) {
757 silc_packet_stream_destroy(ps);
760 ps->remote_udp->remote_port = remote_port;
761 ps->remote_udp->remote_ip = strdup(remote_ip);
762 if (!ps->remote_udp->remote_ip) {
763 silc_packet_stream_destroy(ps);
768 /* Inject packet to the new stream */
770 silc_packet_stream_ref(ps);
771 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
772 silc_packet_stream_inject_packet, packet,
779 /* Destroy packet stream */
781 void silc_packet_stream_destroy(SilcPacketStream stream)
786 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0) {
787 stream->destroyed = TRUE;
789 /* Close the underlaying stream */
790 if (!stream->udp && stream->stream)
791 silc_stream_close(stream->stream);
795 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
798 /* Delete from engine */
799 silc_mutex_lock(stream->sc->engine->lock);
800 silc_list_del(stream->sc->engine->streams, stream);
802 /* Remove per scheduler context, if it is not used anymore */
804 stream->sc->stream_count--;
805 if (!stream->sc->stream_count)
806 silc_hash_table_del(stream->sc->engine->contexts,
807 stream->sc->schedule);
809 silc_mutex_unlock(stream->sc->engine->lock);
811 /* Destroy the underlaying stream */
813 silc_stream_destroy(stream->stream);
815 /* Delete from UDP remote hash table */
817 silc_snprintf(tuple, sizeof(tuple), "%d%s", stream->remote_udp->remote_port,
818 stream->remote_udp->remote_ip);
819 silc_mutex_lock(stream->sc->engine->lock);
820 silc_hash_table_del(stream->sc->engine->udp_remote, tuple);
821 silc_mutex_unlock(stream->sc->engine->lock);
823 silc_free(stream->remote_udp->remote_ip);
824 silc_free(stream->remote_udp);
826 /* Unreference the underlaying packet stream */
827 silc_packet_stream_unref((SilcPacketStream)stream->stream);
830 /* Clear and free buffers */
831 silc_buffer_clear(&stream->outbuf);
832 silc_buffer_purge(&stream->outbuf);
834 if (stream->process) {
836 silc_dlist_start(stream->process);
837 while ((p = silc_dlist_get(stream->process))) {
840 silc_dlist_del(stream->process, p);
842 silc_dlist_uninit(stream->process);
847 silc_atomic_uninit8(&stream->refcnt);
848 silc_mutex_free(stream->lock);
852 /* Marks as router stream */
854 void silc_packet_stream_set_router(SilcPacketStream stream)
856 stream->is_router = TRUE;
859 /* Mark to include IV in ciphertext */
861 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
863 stream->iv_included = TRUE;
866 /* Links `callbacks' to `stream' for specified packet types */
868 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
869 SilcPacketCallbacks *callbacks,
870 void *callback_context,
871 int priority, va_list ap)
873 SilcPacketProcess p, e;
874 SilcInt32 packet_type;
877 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
881 if (!callbacks->packet_receive)
884 p = silc_calloc(1, sizeof(*p));
888 p->priority = priority;
889 p->callbacks = callbacks;
890 p->callback_context = callback_context;
892 silc_mutex_lock(stream->lock);
894 if (!stream->process) {
895 stream->process = silc_dlist_init();
896 if (!stream->process) {
897 silc_mutex_unlock(stream->lock);
902 /* According to priority set the procesor to correct position. First
903 entry has the highest priority */
904 silc_dlist_start(stream->process);
905 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
906 if (p->priority > e->priority) {
907 silc_dlist_insert(stream->process, p);
912 silc_dlist_add(stream->process, p);
914 /* Get packet types to process */
917 packet_type = va_arg(ap, SilcInt32);
919 if (packet_type == SILC_PACKET_ANY)
922 if (packet_type == -1)
925 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
927 silc_mutex_unlock(stream->lock);
931 p->types[i - 1] = (SilcPacketType)packet_type;
937 silc_mutex_unlock(stream->lock);
939 silc_packet_stream_ref(stream);
944 /* Links `callbacks' to `stream' for specified packet types */
946 SilcBool silc_packet_stream_link(SilcPacketStream stream,
947 SilcPacketCallbacks *callbacks,
948 void *callback_context,
954 va_start(ap, priority);
955 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
962 /* Unlinks `callbacks' from `stream'. */
964 void silc_packet_stream_unlink(SilcPacketStream stream,
965 SilcPacketCallbacks *callbacks,
966 void *callback_context)
970 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
973 silc_mutex_lock(stream->lock);
975 silc_dlist_start(stream->process);
976 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
977 if (p->callbacks == callbacks &&
978 p->callback_context == callback_context) {
979 silc_dlist_del(stream->process, p);
985 if (!silc_dlist_count(stream->process)) {
986 silc_dlist_uninit(stream->process);
987 stream->process = NULL;
990 silc_mutex_unlock(stream->lock);
992 silc_packet_stream_unref(stream);
995 /* Returns TRUE if stream is UDP stream */
997 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
999 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1002 /* Return packet sender IP and port for UDP packet stream */
1004 SilcBool silc_packet_get_sender(SilcPacket packet,
1005 const char **sender_ip,
1006 SilcUInt16 *sender_port)
1008 if (!packet->stream->remote_udp)
1011 *sender_ip = packet->stream->remote_udp->remote_ip;
1012 *sender_port = packet->stream->remote_udp->remote_port;
1017 /* Reference packet stream */
1019 void silc_packet_stream_ref(SilcPacketStream stream)
1021 silc_atomic_add_int8(&stream->refcnt, 1);
1022 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1023 silc_atomic_get_int8(&stream->refcnt) - 1,
1024 silc_atomic_get_int8(&stream->refcnt)));
1027 /* Unreference packet stream */
1029 void silc_packet_stream_unref(SilcPacketStream stream)
1031 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1032 silc_atomic_get_int8(&stream->refcnt),
1033 silc_atomic_get_int8(&stream->refcnt) - 1));
1034 if (silc_atomic_sub_int8(&stream->refcnt, 1) > 0)
1036 silc_atomic_add_int8(&stream->refcnt, 1);
1037 silc_packet_stream_destroy(stream);
1042 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1044 return stream->sc->engine;
1047 /* Set application context for packet stream */
1049 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1051 silc_mutex_lock(stream->lock);
1052 stream->stream_context = stream_context;
1053 silc_mutex_unlock(stream->lock);
1056 /* Return application context from packet stream */
1058 void *silc_packet_get_context(SilcPacketStream stream)
1061 silc_mutex_lock(stream->lock);
1062 context = stream->stream_context;
1063 silc_mutex_unlock(stream->lock);
1067 /* Change underlaying stream */
1069 void silc_packet_stream_set_stream(SilcPacketStream ps,
1073 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1074 ps->stream = stream;
1075 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1079 /* Return underlaying stream */
1081 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1083 return stream->stream;
1088 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1089 SilcCipher receive_key, SilcHmac send_hmac,
1090 SilcHmac receive_hmac, SilcBool rekey)
1092 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1094 /* If doing rekey, send REKEY_DONE packet */
1096 /* This will take stream lock. */
1097 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1098 stream->src_id_type, stream->src_id,
1099 stream->src_id_len, stream->dst_id_type,
1100 stream->dst_id, stream->dst_id_len,
1101 NULL, 0, stream->send_key[0],
1102 stream->send_hmac[0]))
1105 /* Write the packet to the stream */
1106 if (!silc_packet_stream_write(stream, TRUE))
1109 silc_mutex_lock(stream->lock);
1112 /* In case IV Included is set, save the old keys */
1113 if (stream->iv_included) {
1114 if (stream->send_key[1] && send_key) {
1115 silc_cipher_free(stream->send_key[1]);
1116 stream->send_key[1] = stream->send_key[0];
1118 if (stream->receive_key[1] && receive_key) {
1119 silc_cipher_free(stream->receive_key[1]);
1120 stream->receive_key[1] = stream->receive_key[0];
1122 if (stream->send_hmac[1] && send_hmac) {
1123 silc_hmac_free(stream->send_hmac[1]);
1124 stream->send_hmac[1] = stream->send_hmac[0];
1126 if (stream->receive_hmac[1] && receive_hmac) {
1127 silc_hmac_free(stream->receive_hmac[1]);
1128 stream->receive_hmac[1] = stream->receive_hmac[0];
1131 if (stream->send_key[0] && send_key)
1132 silc_cipher_free(stream->send_key[0]);
1133 if (stream->send_key[1] && receive_key)
1134 silc_cipher_free(stream->receive_key[0]);
1135 if (stream->send_hmac[0] && send_hmac)
1136 silc_hmac_free(stream->send_hmac[0]);
1137 if (stream->receive_hmac[0] && receive_hmac)
1138 silc_hmac_free(stream->receive_hmac[0]);
1143 stream->send_key[0] = send_key;
1145 stream->receive_key[0] = receive_key;
1147 stream->send_hmac[0] = send_hmac;
1149 stream->receive_hmac[0] = receive_hmac;
1151 silc_mutex_unlock(stream->lock);
1155 /* Return current ciphers from packet stream */
1157 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1158 SilcCipher *send_key,
1159 SilcCipher *receive_key,
1160 SilcHmac *send_hmac,
1161 SilcHmac *receive_hmac)
1163 if (!stream->send_key[0] && !stream->receive_key[0] &&
1164 !stream->send_hmac[0] && !stream->receive_hmac[0])
1167 silc_mutex_lock(stream->lock);
1170 *send_key = stream->send_key[0];
1172 *receive_key = stream->receive_key[0];
1174 *send_hmac = stream->send_hmac[0];
1176 *receive_hmac = stream->receive_hmac[0];
1178 silc_mutex_unlock(stream->lock);
1183 /* Set SILC IDs to packet stream */
1185 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1186 SilcIdType src_id_type, const void *src_id,
1187 SilcIdType dst_id_type, const void *dst_id)
1190 unsigned char tmp[32];
1192 if (!src_id && !dst_id)
1195 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
1197 silc_mutex_lock(stream->lock);
1200 silc_free(stream->src_id);
1201 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1202 silc_mutex_unlock(stream->lock);
1205 stream->src_id = silc_memdup(tmp, len);
1206 if (!stream->src_id) {
1207 silc_mutex_unlock(stream->lock);
1210 stream->src_id_type = src_id_type;
1211 stream->src_id_len = len;
1215 silc_free(stream->dst_id);
1216 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1217 silc_mutex_unlock(stream->lock);
1220 stream->dst_id = silc_memdup(tmp, len);
1221 if (!stream->dst_id) {
1222 silc_mutex_unlock(stream->lock);
1225 stream->dst_id_type = dst_id_type;
1226 stream->dst_id_len = len;
1229 silc_mutex_unlock(stream->lock);
1234 /* Adds Security ID (SID) */
1236 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1238 if (!stream->iv_included)
1241 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1249 void silc_packet_free(SilcPacket packet)
1251 SilcPacketStream stream = packet->stream;
1253 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1255 /* Check for double free */
1256 SILC_ASSERT(packet->stream != NULL);
1258 packet->stream = NULL;
1259 packet->src_id = packet->dst_id = NULL;
1260 silc_buffer_reset(&packet->buffer);
1262 silc_mutex_lock(stream->sc->engine->lock);
1264 /* Put the packet back to freelist */
1265 silc_list_add(stream->sc->engine->packet_pool, packet);
1266 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1267 silc_list_start(stream->sc->engine->packet_pool);
1269 silc_mutex_unlock(stream->sc->engine->lock);
1272 /****************************** Packet Sending ******************************/
1274 /* Prepare outgoing data buffer for packet sending. Returns the
1275 pointer to that buffer into the `packet'. */
1277 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1282 unsigned char *oldptr;
1283 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1287 /* Allocate more space if needed */
1288 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1289 if (!silc_buffer_realloc(&stream->outbuf,
1290 silc_buffer_truelen(&stream->outbuf) + totlen))
1294 /* Pull data area for the new packet, and return pointer to the start of
1295 the data area and save the pointer in to the `packet'. MAC is pulled
1296 later after it's computed. */
1297 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1298 silc_buffer_set(packet, oldptr, totlen);
1299 silc_buffer_push_tail(packet, mac_len);
1304 /* Increments counter when encrypting in counter mode. */
1306 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1308 unsigned char *ret_iv)
1310 unsigned char *iv = silc_cipher_get_iv(cipher);
1313 /* Increment packet counter */
1314 SILC_GET32_MSB(pc, iv + 8);
1316 SILC_PUT32_MSB(pc, iv + 8);
1318 /* Reset block counter */
1319 memset(iv + 12, 0, 4);
1321 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1322 if (stream->iv_included) {
1324 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1325 ret_iv[1] = ret_iv[0] + iv[4];
1326 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1327 ret_iv[3] = ret_iv[0] + ret_iv[2];
1328 SILC_PUT32_MSB(pc, ret_iv + 4);
1329 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1331 /* Set new nonce to counter block */
1332 memcpy(iv + 4, ret_iv, 4);
1335 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1338 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1339 the packet. The silc_packet_stream_write needs to be called to send it
1340 after this returns TRUE. */
1342 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1343 SilcPacketType type,
1344 SilcPacketFlags flags,
1345 SilcIdType src_id_type,
1346 unsigned char *src_id,
1347 SilcUInt32 src_id_len,
1348 SilcIdType dst_id_type,
1349 unsigned char *dst_id,
1350 SilcUInt32 dst_id_len,
1351 const unsigned char *data,
1352 SilcUInt32 data_len,
1356 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1357 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1358 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1360 SilcBufferStruct packet;
1362 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1363 "data len %d", silc_get_packet_name(type), stream->send_psn,
1364 flags, src_id_type, dst_id_type, data_len));
1366 /* Get the true length of the packet. This is saved as payload length
1367 into the packet header. This does not include the length of the
1369 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1370 src_id_len + dst_id_len));
1371 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1372 src_id_len + dst_id_len);
1374 /* If using CTR mode, increment the counter */
1375 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1377 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1379 /* If IV is included, the SID, IV and sequence number is added to packet */
1380 if (stream->iv_included && cipher) {
1381 psnlen = sizeof(psn);
1383 iv[0] = stream->sid;
1386 /* If IV is included, the SID, IV and sequence number is added to packet */
1387 if (stream->iv_included && cipher) {
1388 psnlen = sizeof(psn);
1389 ivlen = block_len + 1;
1390 iv[0] = stream->sid;
1391 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1395 /* We automatically figure out the packet structure from the packet
1396 type and flags, and calculate correct length. Private messages with
1397 private keys and channel messages are special packets as their
1398 payload is encrypted already. */
1399 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
1400 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
1401 type == SILC_PACKET_CHANNEL_MESSAGE) {
1403 /* Padding is calculated from header + IDs */
1405 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1406 psnlen), block_len, padlen);
1408 /* Length to encrypt, header + IDs + padding. */
1409 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1413 /* Padding is calculated from true length of the packet */
1414 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1415 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1417 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1419 enclen += padlen + psnlen;
1422 /* Remove implementation specific flags */
1423 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1425 /* Get random padding */
1426 for (i = 0; i < padlen; i++) tmppad[i] =
1427 silc_rng_get_byte_fast(stream->sc->engine->rng);
1429 silc_mutex_lock(stream->lock);
1431 /* Get packet pointer from the outgoing buffer */
1432 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1433 + psnlen, hmac, &packet))) {
1434 silc_mutex_unlock(stream->lock);
1438 SILC_PUT32_MSB(stream->send_psn, psn);
1440 /* Create the packet. This creates the SILC header, adds padding, and
1441 the actual packet data. */
1442 i = silc_buffer_format(&packet,
1443 SILC_STR_DATA(iv, ivlen),
1444 SILC_STR_DATA(psn, psnlen),
1445 SILC_STR_UI_SHORT(truelen),
1446 SILC_STR_UI_CHAR(flags),
1447 SILC_STR_UI_CHAR(type),
1448 SILC_STR_UI_CHAR(padlen),
1449 SILC_STR_UI_CHAR(0),
1450 SILC_STR_UI_CHAR(src_id_len),
1451 SILC_STR_UI_CHAR(dst_id_len),
1452 SILC_STR_UI_CHAR(src_id_type),
1453 SILC_STR_DATA(src_id, src_id_len),
1454 SILC_STR_UI_CHAR(dst_id_type),
1455 SILC_STR_DATA(dst_id, dst_id_len),
1456 SILC_STR_DATA(tmppad, padlen),
1457 SILC_STR_DATA(data, data_len),
1459 if (silc_unlikely(i < 0)) {
1460 silc_mutex_unlock(stream->lock);
1464 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1465 silc_buffer_data(&packet), silc_buffer_len(&packet));
1467 /* Encrypt the packet */
1468 if (silc_likely(cipher)) {
1469 SILC_LOG_DEBUG(("Encrypting packet"));
1470 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1471 packet.data + ivlen, enclen,
1473 SILC_LOG_ERROR(("Packet encryption failed"));
1474 silc_mutex_unlock(stream->lock);
1480 if (silc_likely(hmac)) {
1483 /* MAC is computed from the entire encrypted packet data, and put
1484 to the end of the packet. */
1485 silc_hmac_init(hmac);
1486 silc_hmac_update(hmac, psn, sizeof(psn));
1487 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1488 silc_hmac_final(hmac, packet.tail, &mac_len);
1489 silc_buffer_pull_tail(&packet, mac_len);
1496 /* Sends a packet */
1498 SilcBool silc_packet_send(SilcPacketStream stream,
1499 SilcPacketType type, SilcPacketFlags flags,
1500 const unsigned char *data, SilcUInt32 data_len)
1504 ret = silc_packet_send_raw(stream, type, flags,
1505 stream->src_id_type,
1508 stream->dst_id_type,
1512 stream->send_key[0],
1513 stream->send_hmac[0]);
1515 /* Write the packet to the stream */
1516 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1519 /* Sends a packet, extended routine */
1521 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1522 SilcPacketType type, SilcPacketFlags flags,
1523 SilcIdType src_id_type, void *src_id,
1524 SilcIdType dst_id_type, void *dst_id,
1525 const unsigned char *data, SilcUInt32 data_len,
1526 SilcCipher cipher, SilcHmac hmac)
1528 unsigned char src_id_data[32], dst_id_data[32];
1529 SilcUInt32 src_id_len, dst_id_len;
1533 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1534 sizeof(src_id_data), &src_id_len))
1537 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1538 sizeof(dst_id_data), &dst_id_len))
1541 ret = silc_packet_send_raw(stream, type, flags,
1542 src_id ? src_id_type : stream->src_id_type,
1543 src_id ? src_id_data : stream->src_id,
1544 src_id ? src_id_len : stream->src_id_len,
1545 dst_id ? dst_id_type : stream->dst_id_type,
1546 dst_id ? dst_id_data : stream->dst_id,
1547 dst_id ? dst_id_len : stream->dst_id_len,
1549 cipher ? cipher : stream->send_key[0],
1550 hmac ? hmac : stream->send_hmac[0]);
1552 /* Write the packet to the stream */
1553 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1556 /* Sends packet after formatting the arguments to buffer */
1558 SilcBool silc_packet_send_va(SilcPacketStream stream,
1559 SilcPacketType type, SilcPacketFlags flags, ...)
1561 SilcBufferStruct buf;
1565 va_start(va, flags);
1567 memset(&buf, 0, sizeof(buf));
1568 if (silc_buffer_format_vp(&buf, va) < 0) {
1573 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1574 silc_buffer_len(&buf));
1576 silc_buffer_purge(&buf);
1582 /* Sends packet after formatting the arguments to buffer, extended routine */
1584 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1585 SilcPacketType type, SilcPacketFlags flags,
1586 SilcIdType src_id_type, void *src_id,
1587 SilcIdType dst_id_type, void *dst_id,
1588 SilcCipher cipher, SilcHmac hmac, ...)
1590 SilcBufferStruct buf;
1596 memset(&buf, 0, sizeof(buf));
1597 if (silc_buffer_format_vp(&buf, va) < 0) {
1602 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1603 dst_id_type, dst_id, silc_buffer_data(&buf),
1604 silc_buffer_len(&buf), cipher, hmac);
1606 silc_buffer_purge(&buf);
1612 /***************************** Packet Receiving *****************************/
1614 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1616 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1617 const unsigned char *data,
1618 SilcUInt32 data_len,
1619 const unsigned char *packet_mac,
1620 const unsigned char *packet_seq,
1621 SilcUInt32 sequence)
1624 if (silc_likely(hmac)) {
1625 unsigned char mac[32], psn[4];
1628 SILC_LOG_DEBUG(("Verifying MAC"));
1630 /* Compute HMAC of packet */
1631 silc_hmac_init(hmac);
1634 SILC_PUT32_MSB(sequence, psn);
1635 silc_hmac_update(hmac, psn, 4);
1637 silc_hmac_update(hmac, packet_seq, 4);
1639 silc_hmac_update(hmac, data, data_len);
1640 silc_hmac_final(hmac, mac, &mac_len);
1642 /* Compare the MAC's */
1643 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1644 SILC_LOG_DEBUG(("MAC failed"));
1648 SILC_LOG_DEBUG(("MAC is Ok"));
1654 /* Increments/sets counter when decrypting in counter mode. */
1656 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1658 unsigned char *packet_iv)
1662 /* If IV Included flag, set the IV from packet to block counter. */
1663 if (stream->iv_included) {
1664 memcpy(iv + 4, packet_iv, 8);
1666 /* Increment packet counter */
1667 SILC_GET32_MSB(pc, iv + 8);
1669 SILC_PUT32_MSB(pc, iv + 8);
1672 /* Reset block counter */
1673 memset(iv + 12, 0, 4);
1675 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1678 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1679 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1681 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1682 SilcUInt32 sequence, SilcBuffer buffer,
1685 if (normal == TRUE) {
1686 if (silc_likely(cipher)) {
1687 /* Decrypt rest of the packet */
1688 SILC_LOG_DEBUG(("Decrypting the packet"));
1689 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1691 silc_buffer_len(buffer), NULL)))
1697 /* Decrypt rest of the header plus padding */
1698 if (silc_likely(cipher)) {
1700 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1702 SILC_LOG_DEBUG(("Decrypting the header"));
1704 /* Padding length + src id len + dst id len + header length - 16
1705 bytes already decrypted, gives the rest of the encrypted packet */
1706 silc_buffer_push(buffer, block_len);
1707 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1708 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1710 silc_buffer_pull(buffer, block_len);
1712 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1713 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1717 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1718 buffer->data, len, NULL)))
1726 /* Parses the packet. This is called when a whole packet is ready to be
1727 parsed. The buffer sent must be already decrypted before calling this
1730 static inline SilcBool silc_packet_parse(SilcPacket packet)
1732 SilcBuffer buffer = &packet->buffer;
1733 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1734 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1737 SILC_LOG_DEBUG(("Parsing incoming packet"));
1739 /* Parse the buffer. This parses the SILC header of the packet. */
1740 ret = silc_buffer_unformat(buffer,
1743 SILC_STR_UI_CHAR(&src_id_len),
1744 SILC_STR_UI_CHAR(&dst_id_len),
1745 SILC_STR_UI_CHAR(&src_id_type),
1747 if (silc_unlikely(ret == -1)) {
1748 if (!packet->stream->udp &&
1749 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1750 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1754 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1755 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1756 if (!packet->stream->udp &&
1757 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1758 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1759 packet->src_id_len, packet->dst_id_len));
1763 ret = silc_buffer_unformat(buffer,
1765 SILC_STR_DATA(&packet->src_id, src_id_len),
1766 SILC_STR_UI_CHAR(&dst_id_type),
1767 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1768 SILC_STR_OFFSET(padlen),
1770 if (silc_unlikely(ret == -1)) {
1771 if (!packet->stream->udp &&
1772 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1773 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1777 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1778 dst_id_type > SILC_ID_CHANNEL)) {
1779 if (!packet->stream->udp &&
1780 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1781 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1782 src_id_type, dst_id_type));
1786 packet->src_id_len = src_id_len;
1787 packet->dst_id_len = dst_id_len;
1788 packet->src_id_type = src_id_type;
1789 packet->dst_id_type = dst_id_type;
1791 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1792 silc_buffer_len(buffer)), buffer->head,
1793 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1795 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1796 silc_get_packet_name(packet->type)));
1801 /* Dispatch packet to application. Called with stream->lock locked.
1802 Returns FALSE if the stream was destroyed while dispatching a packet. */
1804 static SilcBool silc_packet_dispatch(SilcPacket packet)
1806 SilcPacketStream stream = packet->stream;
1807 SilcPacketProcess p;
1808 SilcBool default_sent = FALSE;
1811 /* Dispatch packet to all packet processors that want it */
1813 if (silc_likely(!stream->process)) {
1814 /* Send to default processor as no others exist */
1815 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1816 silc_mutex_unlock(stream->lock);
1817 if (silc_unlikely(!stream->sc->engine->callbacks->
1818 packet_receive(stream->sc->engine, stream, packet,
1819 stream->sc->engine->callback_context,
1820 stream->stream_context)))
1821 silc_packet_free(packet);
1822 silc_mutex_lock(stream->lock);
1823 return stream->destroyed == FALSE;
1826 silc_dlist_start(stream->process);
1827 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1829 /* If priority is 0 or less, we send to default processor first
1830 because default processor has 0 priority */
1831 if (!default_sent && p->priority <= 0) {
1832 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1833 default_sent = TRUE;
1834 silc_mutex_unlock(stream->lock);
1835 if (stream->sc->engine->callbacks->
1836 packet_receive(stream->sc->engine, stream, packet,
1837 stream->sc->engine->callback_context,
1838 stream->stream_context)) {
1839 silc_mutex_lock(stream->lock);
1840 return stream->destroyed == FALSE;
1842 silc_mutex_lock(stream->lock);
1845 /* Send to processor */
1847 /* Send all packet types */
1848 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1849 silc_mutex_unlock(stream->lock);
1850 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1851 p->callback_context,
1852 stream->stream_context)) {
1853 silc_mutex_lock(stream->lock);
1854 return stream->destroyed == FALSE;
1856 silc_mutex_lock(stream->lock);
1858 /* Send specific types */
1859 for (pt = p->types; *pt; pt++) {
1860 if (*pt != packet->type)
1862 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1863 silc_mutex_unlock(stream->lock);
1864 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
1865 p->callback_context,
1866 stream->stream_context)) {
1867 silc_mutex_lock(stream->lock);
1868 return stream->destroyed == FALSE;
1870 silc_mutex_lock(stream->lock);
1876 if (!default_sent) {
1877 /* Send to default processor as it has not been sent yet */
1878 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1879 silc_mutex_unlock(stream->lock);
1880 if (stream->sc->engine->callbacks->
1881 packet_receive(stream->sc->engine, stream, packet,
1882 stream->sc->engine->callback_context,
1883 stream->stream_context)) {
1884 silc_mutex_lock(stream->lock);
1885 return stream->destroyed == FALSE;
1887 silc_mutex_lock(stream->lock);
1890 /* If we got here, no one wanted the packet, so drop it */
1891 silc_packet_free(packet);
1892 return stream->destroyed == FALSE;
1895 /* Process incoming data and parse packets. Called with stream->lock
1898 static void silc_packet_read_process(SilcPacketStream stream)
1900 SilcBuffer inbuf = &stream->sc->inbuf;
1905 SilcUInt16 packetlen;
1906 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1907 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1908 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1912 /* Parse the packets from the data */
1913 while (silc_buffer_len(inbuf) > 0) {
1915 cipher = stream->receive_key[0];
1916 hmac = stream->receive_hmac[0];
1919 if (silc_unlikely(silc_buffer_len(inbuf) <
1920 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1921 SILC_PACKET_MIN_HEADER_LEN))) {
1922 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1926 if (silc_likely(hmac))
1927 mac_len = silc_hmac_len(hmac);
1931 /* Decrypt first block of the packet to get the length field out */
1932 if (silc_likely(cipher)) {
1933 block_len = silc_cipher_get_block_len(cipher);
1935 if (stream->iv_included) {
1936 /* SID, IV and sequence number is included in the ciphertext */
1937 sid = (SilcUInt8)inbuf->data[0];
1939 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
1940 /* Set the CTR mode IV from packet to counter block */
1941 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1942 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
1945 /* Get IV from packet */
1946 memcpy(iv, inbuf->data + 1, block_len);
1947 ivlen = block_len + 1;
1951 /* Check SID, and get correct decryption key */
1952 if (sid != stream->sid) {
1953 /* If SID is recent get the previous key and use it */
1954 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1955 stream->receive_key[1] && !stream->receive_hmac[1]) {
1956 cipher = stream->receive_key[1];
1957 hmac = stream->receive_hmac[1];
1959 /* The SID is unknown, drop rest of the data in buffer */
1960 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1962 silc_mutex_unlock(stream->lock);
1963 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1964 silc_mutex_lock(stream->lock);
1965 silc_buffer_reset(inbuf);
1970 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1972 /* If using CTR mode, increment the counter */
1973 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
1974 silc_packet_receive_ctr_increment(stream, iv, NULL);
1977 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp,
1981 if (stream->iv_included) {
1982 /* Take sequence number from packet */
1983 packet_seq = header;
1987 /* Unencrypted packet */
1988 block_len = SILC_PACKET_MIN_HEADER_LEN;
1989 header = inbuf->data;
1992 /* Get packet length and full packet length with padding */
1993 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1996 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
1997 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
1998 SILC_LOG_ERROR(("Received too short packet"));
1999 silc_mutex_unlock(stream->lock);
2000 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2001 silc_mutex_lock(stream->lock);
2002 memset(tmp, 0, sizeof(tmp));
2003 silc_buffer_reset(inbuf);
2007 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2008 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2010 paddedlen + mac_len - silc_buffer_len(inbuf)));
2011 memset(tmp, 0, sizeof(tmp));
2015 /* Check MAC of the packet */
2016 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2018 inbuf->data + ivlen +
2019 paddedlen, packet_seq,
2020 stream->receive_psn))) {
2021 silc_mutex_unlock(stream->lock);
2022 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2023 silc_mutex_lock(stream->lock);
2024 memset(tmp, 0, sizeof(tmp));
2025 silc_buffer_reset(inbuf);
2030 packet = silc_packet_alloc(stream->sc->engine);
2031 if (silc_unlikely(!packet)) {
2032 silc_mutex_unlock(stream->lock);
2033 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2034 silc_mutex_lock(stream->lock);
2035 memset(tmp, 0, sizeof(tmp));
2036 silc_buffer_reset(inbuf);
2039 packet->stream = stream;
2041 /* Allocate more space to packet buffer, if needed */
2042 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2043 if (!silc_buffer_realloc(&packet->buffer,
2044 silc_buffer_truelen(&packet->buffer) +
2046 silc_buffer_truelen(&packet->buffer)))) {
2047 silc_mutex_unlock(stream->lock);
2048 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2049 silc_mutex_lock(stream->lock);
2050 silc_packet_free(packet);
2051 memset(tmp, 0, sizeof(tmp));
2052 silc_buffer_reset(inbuf);
2057 /* Parse packet header */
2058 packet->flags = (SilcPacketFlags)header[2];
2059 packet->type = (SilcPacketType)header[3];
2061 if (stream->sc->engine->local_is_router) {
2062 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2063 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2065 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2066 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2067 stream->is_router == TRUE))
2070 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2071 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2073 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
2077 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2078 stream->receive_psn, paddedlen + ivlen + mac_len),
2079 inbuf->data, paddedlen + ivlen + mac_len);
2081 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2082 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2083 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2084 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2085 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2086 psnlen + (block_len - psnlen)),
2087 paddedlen - ivlen - psnlen - (block_len - psnlen));
2088 if (silc_likely(cipher)) {
2089 silc_cipher_set_iv(cipher, iv);
2090 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2091 &packet->buffer, normal);
2092 if (silc_unlikely(ret < 0)) {
2093 silc_mutex_unlock(stream->lock);
2094 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2095 silc_mutex_lock(stream->lock);
2096 silc_packet_free(packet);
2097 memset(tmp, 0, sizeof(tmp));
2101 stream->receive_psn++;
2103 silc_buffer_push(&packet->buffer, block_len);
2105 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2106 silc_buffer_pull(inbuf, paddedlen + mac_len);
2108 /* Parse the packet */
2109 if (silc_unlikely(!silc_packet_parse(packet))) {
2110 silc_mutex_unlock(stream->lock);
2111 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2112 silc_mutex_lock(stream->lock);
2113 silc_packet_free(packet);
2114 memset(tmp, 0, sizeof(tmp));
2118 /* Dispatch the packet to application */
2119 if (!silc_packet_dispatch(packet))
2123 silc_buffer_reset(inbuf);
2126 /****************************** Packet Waiting ******************************/
2128 /* Packet wait receive callback */
2130 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2131 SilcPacketStream stream,
2133 void *callback_context,
2134 void *stream_context);
2136 /* Packet waiting callbacks */
2137 static SilcPacketCallbacks silc_packet_wait_cbs =
2139 silc_packet_wait_packet_receive, NULL, NULL
2142 /* Packet waiting context */
2144 SilcMutex wait_lock;
2146 SilcList packet_queue;
2147 unsigned int stopped : 1;
2150 /* Packet wait receive callback */
2153 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2154 SilcPacketStream stream,
2156 void *callback_context,
2157 void *stream_context)
2159 SilcPacketWait pw = callback_context;
2161 /* Signal the waiting thread for a new packet */
2162 silc_mutex_lock(pw->wait_lock);
2164 if (silc_unlikely(pw->stopped)) {
2165 silc_mutex_unlock(pw->wait_lock);
2169 silc_list_add(pw->packet_queue, packet);
2170 silc_cond_broadcast(pw->wait_cond);
2172 silc_mutex_unlock(pw->wait_lock);
2177 /* Initialize packet waiting */
2179 void *silc_packet_wait_init(SilcPacketStream stream, ...)
2185 pw = silc_calloc(1, sizeof(*pw));
2189 /* Allocate mutex and conditional variable */
2190 if (!silc_mutex_alloc(&pw->wait_lock)) {
2194 if (!silc_cond_alloc(&pw->wait_cond)) {
2195 silc_mutex_free(pw->wait_lock);
2200 /* Link to the packet stream for the requested packet types */
2201 va_start(ap, stream);
2202 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2206 silc_cond_free(pw->wait_cond);
2207 silc_mutex_free(pw->wait_lock);
2212 /* Initialize packet queue */
2213 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2218 /* Uninitialize packet waiting */
2220 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2222 SilcPacketWait pw = waiter;
2225 /* Signal any threads to stop waiting */
2226 silc_mutex_lock(pw->wait_lock);
2228 silc_cond_broadcast(pw->wait_cond);
2229 silc_mutex_unlock(pw->wait_lock);
2231 /* Re-acquire lock and free resources */
2232 silc_mutex_lock(pw->wait_lock);
2233 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2235 /* Free any remaining packets */
2236 silc_list_start(pw->packet_queue);
2237 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2238 silc_packet_free(packet);
2240 silc_mutex_unlock(pw->wait_lock);
2241 silc_cond_free(pw->wait_cond);
2242 silc_mutex_free(pw->wait_lock);
2246 /* Blocks thread until a packet has been received. */
2248 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2250 SilcPacketWait pw = waiter;
2251 SilcBool ret = FALSE;
2253 silc_mutex_lock(pw->wait_lock);
2255 /* Wait here until packet has arrived */
2256 while (silc_list_count(pw->packet_queue) == 0) {
2257 if (silc_unlikely(pw->stopped)) {
2258 silc_mutex_unlock(pw->wait_lock);
2261 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2265 silc_list_start(pw->packet_queue);
2266 *return_packet = silc_list_get(pw->packet_queue);
2267 silc_list_del(pw->packet_queue, *return_packet);
2269 silc_mutex_unlock(pw->wait_lock);
2271 return ret == TRUE ? 1 : 0;
2274 /************************** Packet Stream Wrapper ***************************/
2276 /* Packet stream wrapper receive callback */
2278 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2279 SilcPacketStream stream,
2281 void *callback_context,
2282 void *stream_context);
2284 const SilcStreamOps silc_packet_stream_ops;
2286 /* Packet stream wrapper context */
2288 const SilcStreamOps *ops;
2289 SilcPacketStream stream;
2291 void *waiter; /* Waiter context in blocking mode */
2292 SilcPacketWrapCoder coder;
2293 void *coder_context;
2295 SilcStreamNotifier callback;
2298 SilcPacketType type;
2299 SilcPacketFlags flags;
2300 unsigned int closed : 1;
2301 unsigned int blocking : 1;
2302 unsigned int read_more : 1;
2303 } *SilcPacketWrapperStream;
2305 /* Packet wrapper callbacks */
2306 static SilcPacketCallbacks silc_packet_wrap_cbs =
2308 silc_packet_wrap_packet_receive, NULL, NULL
2311 /* Packet stream wrapper receive callback, non-blocking mode */
2314 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2315 SilcPacketStream stream,
2317 void *callback_context,
2318 void *stream_context)
2320 SilcPacketWrapperStream pws = callback_context;
2322 if (pws->closed || !pws->callback)
2325 silc_mutex_lock(pws->lock);
2326 silc_list_add(pws->in_queue, packet);
2327 silc_mutex_unlock(pws->lock);
2329 /* Call notifier callback */
2330 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2335 /* Task callback to notify more data is available for reading */
2337 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2339 SilcPacketWrapperStream pws = context;
2341 if (pws->closed || !pws->callback)
2344 /* Call notifier callback */
2345 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2348 /* Read SILC packet */
2350 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2353 SilcPacketWrapperStream pws = stream;
2355 SilcBool read_more = FALSE;
2361 if (pws->blocking) {
2362 /* Block until packet is received */
2363 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2368 /* Non-blocking mode */
2369 silc_mutex_lock(pws->lock);
2370 if (!silc_list_count(pws->in_queue)) {
2371 silc_mutex_unlock(pws->lock);
2375 silc_list_start(pws->in_queue);
2376 packet = silc_list_get(pws->in_queue);
2377 silc_list_del(pws->in_queue, packet);
2378 silc_mutex_unlock(pws->lock);
2381 /* Call decoder if set */
2382 if (pws->coder && !pws->read_more)
2383 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2384 pws->coder_context);
2386 len = silc_buffer_len(&packet->buffer);
2387 if (len > buf_len) {
2393 memcpy(buf, packet->buffer.data, len);
2395 if (read_more && !pws->blocking) {
2396 /* More data will be available (in blocking mode not supported). */
2397 silc_buffer_pull(&packet->buffer, len);
2398 silc_list_insert(pws->in_queue, NULL, packet);
2399 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2400 silc_packet_wrap_read_more, pws, 0, 0);
2401 pws->read_more = TRUE;
2405 pws->read_more = FALSE;
2406 silc_packet_free(packet);
2410 /* Write SILC packet */
2412 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2413 SilcUInt32 data_len)
2415 SilcPacketWrapperStream pws = stream;
2416 SilcBool ret = FALSE;
2418 /* Call decoder if set */
2420 silc_buffer_reset(pws->encbuf);
2421 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2422 pws->coder_context);
2425 /* Send the SILC packet */
2427 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2428 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2429 silc_buffer_len(pws->encbuf)),
2430 SILC_STR_DATA(data, data_len),
2434 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2443 SilcBool silc_packet_wrap_close(SilcStream stream)
2445 SilcPacketWrapperStream pws = stream;
2450 if (pws->blocking) {
2451 /* Close packet waiter */
2452 silc_packet_wait_uninit(pws->waiter, pws->stream);
2456 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2463 /* Destroy wrapper stream */
2465 void silc_packet_wrap_destroy(SilcStream stream)
2468 SilcPacketWrapperStream pws = stream;
2471 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2473 silc_stream_close(stream);
2474 silc_list_start(pws->in_queue);
2475 while ((packet = silc_list_get(pws->in_queue)))
2476 silc_packet_free(packet);
2478 silc_mutex_free(pws->lock);
2480 silc_buffer_free(pws->encbuf);
2481 silc_packet_stream_unref(pws->stream);
2486 /* Link stream to receive packets */
2488 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2489 SilcSchedule schedule,
2490 SilcStreamNotifier callback,
2493 SilcPacketWrapperStream pws = stream;
2495 if (pws->closed || pws->blocking)
2498 /* Link to receive packets */
2500 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2501 100000, pws->type, -1);
2503 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2505 pws->callback = callback;
2506 pws->context = context;
2511 /* Return schedule */
2513 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2518 /* Wraps packet stream into SilcStream. */
2520 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2521 SilcPacketType type,
2522 SilcPacketFlags flags,
2523 SilcBool blocking_mode,
2524 SilcPacketWrapCoder coder,
2527 SilcPacketWrapperStream pws;
2529 pws = silc_calloc(1, sizeof(*pws));
2533 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2535 pws->ops = &silc_packet_stream_ops;
2536 pws->stream = stream;
2539 pws->blocking = blocking_mode;
2541 pws->coder_context = context;
2543 /* Allocate small amount for encoder buffer. */
2545 pws->encbuf = silc_buffer_alloc(8);
2547 if (pws->blocking) {
2548 /* Blocking mode. Use packet waiter to do the thing. */
2549 pws->waiter = silc_packet_wait_init(pws->stream, pws->type, -1);
2555 /* Non-blocking mode */
2556 if (!silc_mutex_alloc(&pws->lock)) {
2561 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2564 silc_packet_stream_ref(stream);
2566 return (SilcStream)pws;
2569 const SilcStreamOps silc_packet_stream_ops =
2571 silc_packet_wrap_read,
2572 silc_packet_wrap_write,
2573 silc_packet_wrap_close,
2574 silc_packet_wrap_destroy,
2575 silc_packet_wrap_notifier,
2576 silc_packet_wrap_get_schedule,