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 SilcPacketCallbacks *callbacks; /* Packet callbacks */
44 void *callback_context; /* Context for callbacks */
45 SilcList streams; /* All streams in engine */
46 SilcList packet_pool; /* Free list for received packets */
47 SilcHashTable udp_remote; /* UDP remote streams, or NULL */
48 unsigned int local_is_router : 1;
51 /* Packet processor context */
52 typedef struct SilcPacketProcessStruct {
53 SilcPacketType *types; /* Packets to process */
54 SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
55 void *callback_context;
56 SilcInt32 priority; /* Priority */
59 /* UDP remote stream tuple */
61 char *remote_ip; /* Remote IP address */
62 SilcUInt16 remote_port; /* Remote port */
63 } *SilcPacketRemoteUDP;
66 struct SilcPacketStreamStruct {
67 struct SilcPacketStreamStruct *next;
68 SilcPacketEngineContext sc; /* Per scheduler context */
69 SilcStream stream; /* Underlaying stream */
70 SilcMutex lock; /* Packet stream lock */
71 SilcDList process; /* Packet processors, or NULL */
72 SilcPacketRemoteUDP remote_udp; /* UDP remote stream tuple, or NULL */
73 void *stream_context; /* Stream context */
74 SilcBufferStruct outbuf; /* Out buffer */
75 SilcBuffer inbuf; /* Inbuf from inbuf list or NULL */
76 SilcCipher send_key[2]; /* Sending key */
77 SilcHmac send_hmac[2]; /* Sending HMAC */
78 SilcCipher receive_key[2]; /* Receiving key */
79 SilcHmac receive_hmac[2]; /* Receiving HMAC */
80 unsigned char *src_id; /* Source ID */
81 unsigned char *dst_id; /* Destination ID */
82 SilcUInt32 send_psn; /* Sending sequence */
83 SilcUInt32 receive_psn; /* Receiving sequence */
84 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 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(0, silc_hash_ptr, NULL, NULL, NULL,
563 silc_packet_engine_context_destr,
565 if (!engine->contexts) {
571 engine->local_is_router = router;
572 engine->callbacks = callbacks;
573 engine->callback_context = callback_context;
574 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
575 silc_mutex_alloc(&engine->lock);
577 /* Allocate packet free list */
578 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
579 for (i = 0; i < 5; i++) {
580 packet = silc_calloc(1, sizeof(*packet));
582 silc_packet_engine_stop(engine);
586 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
588 silc_packet_engine_stop(engine);
591 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
592 silc_buffer_reset(&packet->buffer);
594 silc_list_add(engine->packet_pool, packet);
596 silc_list_start(engine->packet_pool);
601 /* Stop packet engine */
603 void silc_packet_engine_stop(SilcPacketEngine engine)
607 SILC_LOG_DEBUG(("Stopping packet engine"));
612 /* Free packet free list */
613 silc_list_start(engine->packet_pool);
614 while ((packet = silc_list_get(engine->packet_pool))) {
615 silc_buffer_purge(&packet->buffer);
619 silc_hash_table_free(engine->contexts);
620 silc_mutex_free(engine->lock);
624 static const char * const packet_error[] = {
625 "Cannot read from stream",
626 "Cannot write to stream",
628 "Packet decryption failed",
630 "Packet is malformed",
631 "System out of memory",
634 /* Return packet error string */
636 const char *silc_packet_error_string(SilcPacketError error)
638 if (error < SILC_PACKET_ERR_READ || error > SILC_PACKET_ERR_NO_MEMORY)
639 return "<invalid error code>";
640 return packet_error[error];
643 /* Return list of packet streams in the engine */
645 SilcDList silc_packet_engine_get_streams(SilcPacketEngine engine)
650 list = silc_dlist_init();
654 silc_mutex_lock(engine->lock);
655 silc_list_start(engine->streams);
656 while ((ps = silc_list_get(engine->streams))) {
657 silc_packet_stream_ref(ps);
658 silc_dlist_add(list, ps);
660 silc_mutex_unlock(engine->lock);
665 /* Free list returned by silc_packet_engine_get_streams */
667 void silc_packet_engine_free_streams_list(SilcDList streams)
671 silc_dlist_start(streams);
672 while ((ps = silc_dlist_get(streams)))
673 silc_packet_stream_unref(ps);
675 silc_dlist_uninit(streams);
678 /* Create new packet stream */
680 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
681 SilcSchedule schedule,
688 SILC_LOG_DEBUG(("Creating new packet stream"));
690 if (!engine || !stream)
693 ps = silc_calloc(1, sizeof(*ps));
698 silc_atomic_init32(&ps->refcnt, 1);
699 silc_mutex_alloc(&ps->lock);
701 /* Allocate out buffer */
702 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
704 silc_packet_stream_destroy(ps);
707 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
708 silc_buffer_reset(&ps->outbuf);
710 /* Initialize packet procesors list */
711 ps->process = silc_dlist_init();
713 silc_packet_stream_destroy(ps);
717 silc_mutex_lock(engine->lock);
719 /* Add per scheduler context */
720 if (!silc_hash_table_find(engine->contexts, schedule, NULL,
722 ps->sc = silc_calloc(1, sizeof(*ps->sc));
724 silc_mutex_unlock(engine->lock);
725 silc_packet_stream_destroy(ps);
728 ps->sc->engine = engine;
729 ps->sc->schedule = schedule;
731 /* Allocate data input buffer */
732 inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE * 65);
736 silc_mutex_unlock(engine->lock);
737 silc_packet_stream_destroy(ps);
740 silc_buffer_reset(inbuf);
742 ps->sc->inbufs = silc_dlist_init();
743 if (!ps->sc->inbufs) {
744 silc_buffer_free(inbuf);
747 silc_mutex_unlock(engine->lock);
748 silc_packet_stream_destroy(ps);
751 silc_dlist_add(ps->sc->inbufs, inbuf);
753 /* Add to per scheduler context hash table */
754 if (!silc_hash_table_add(engine->contexts, schedule, ps->sc)) {
755 silc_buffer_free(inbuf);
756 silc_dlist_del(ps->sc->inbufs, inbuf);
759 silc_mutex_unlock(engine->lock);
760 silc_packet_stream_destroy(ps);
764 ps->sc->stream_count++;
766 /* Add the packet stream to engine */
767 silc_list_add(engine->streams, ps);
769 /* If this is UDP stream, allocate UDP remote stream hash table */
770 if (!engine->udp_remote && silc_socket_stream_is_udp(stream, NULL))
771 engine->udp_remote = silc_hash_table_alloc(0, silc_hash_string, NULL,
772 silc_hash_string_compare, NULL,
773 silc_packet_engine_hash_destr,
776 silc_mutex_unlock(engine->lock);
778 /* Set IO notifier callback. This schedules this stream for I/O. */
779 if (!silc_stream_set_notifier(ps->stream, schedule,
780 silc_packet_stream_io, ps)) {
781 SILC_LOG_DEBUG(("Cannot set stream notifier for packet stream"));
782 silc_packet_stream_destroy(ps);
786 SILC_LOG_DEBUG(("Created packet stream %p", ps));
791 /* Add new remote packet stream for UDP packet streams */
793 SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
794 const char *remote_ip,
795 SilcUInt16 remote_port,
798 SilcPacketEngine engine = stream->sc->engine;
803 SILC_LOG_DEBUG(("Adding UDP remote %s:%d to packet stream %p",
804 remote_ip, remote_port, stream));
806 if (!stream || !remote_ip || !remote_port)
809 if (!silc_socket_stream_is_udp(stream->stream, NULL)) {
810 SILC_LOG_ERROR(("Stream is not UDP stream, cannot add remote IP"));
814 ps = silc_calloc(1, sizeof(*ps));
819 silc_atomic_init32(&ps->refcnt, 1);
820 silc_mutex_alloc(&ps->lock);
822 /* Set the UDP packet stream as underlaying stream */
823 silc_packet_stream_ref(stream);
824 ps->stream = (SilcStream)stream;
827 /* Allocate out buffer */
828 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
830 silc_packet_stream_destroy(ps);
833 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
834 silc_buffer_reset(&ps->outbuf);
836 /* Initialize packet procesors list */
837 ps->process = silc_dlist_init();
839 silc_packet_stream_destroy(ps);
843 /* Add to engine with this IP and port pair */
844 tuple = silc_format("%d%s", remote_port, remote_ip);
845 silc_mutex_lock(engine->lock);
846 if (!tuple || !silc_hash_table_add(engine->udp_remote, tuple, ps)) {
847 silc_mutex_unlock(engine->lock);
848 silc_packet_stream_destroy(ps);
851 silc_mutex_unlock(engine->lock);
853 /* Save remote IP and port pair */
854 ps->remote_udp = silc_calloc(1, sizeof(*ps->remote_udp));
855 if (!ps->remote_udp) {
856 silc_packet_stream_destroy(ps);
859 ps->remote_udp->remote_port = remote_port;
860 ps->remote_udp->remote_ip = strdup(remote_ip);
861 if (!ps->remote_udp->remote_ip) {
862 silc_packet_stream_destroy(ps);
867 /* Inject packet to the new stream */
869 silc_packet_stream_ref(ps);
870 silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
871 silc_packet_stream_inject_packet, packet,
878 /* Destroy packet stream */
880 void silc_packet_stream_destroy(SilcPacketStream stream)
882 SilcPacketEngine engine;
887 if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0) {
888 if (stream->destroyed)
890 stream->destroyed = TRUE;
892 SILC_LOG_DEBUG(("Marking packet stream %p destroyed", stream));
894 /* Close the underlaying stream */
895 if (!stream->udp && stream->stream)
896 silc_stream_close(stream->stream);
900 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
903 /* Delete from engine */
905 engine = stream->sc->engine;
906 silc_mutex_lock(engine->lock);
907 silc_list_del(engine->streams, stream);
909 /* Remove per scheduler context, if it is not used anymore */
910 stream->sc->stream_count--;
911 if (!stream->sc->stream_count)
912 silc_hash_table_del(engine->contexts, stream->sc->schedule);
914 silc_mutex_unlock(engine->lock);
917 /* Destroy the underlaying stream */
919 silc_stream_destroy(stream->stream);
921 /* Delete from UDP remote hash table */
923 engine = stream->sc->engine;
924 silc_snprintf(tuple, sizeof(tuple), "%d%s",
925 stream->remote_udp->remote_port,
926 stream->remote_udp->remote_ip);
927 silc_mutex_lock(engine->lock);
928 silc_hash_table_del(engine->udp_remote, tuple);
929 silc_mutex_unlock(engine->lock);
931 silc_free(stream->remote_udp->remote_ip);
932 silc_free(stream->remote_udp);
934 /* Unreference the underlaying packet stream */
935 silc_packet_stream_unref((SilcPacketStream)stream->stream);
938 /* Clear and free buffers */
939 silc_buffer_clear(&stream->outbuf);
940 silc_buffer_purge(&stream->outbuf);
942 if (stream->process) {
944 silc_dlist_start(stream->process);
945 while ((p = silc_dlist_get(stream->process))) {
948 silc_dlist_del(stream->process, p);
950 silc_dlist_uninit(stream->process);
953 /* Destroy ciphers and HMACs */
954 if (stream->send_key[0])
955 silc_cipher_free(stream->send_key[0]);
956 if (stream->receive_key[0])
957 silc_cipher_free(stream->receive_key[0]);
958 if (stream->send_hmac[0])
959 silc_hmac_free(stream->send_hmac[0]);
960 if (stream->receive_hmac[0])
961 silc_hmac_free(stream->receive_hmac[0]);
962 if (stream->send_key[1])
963 silc_cipher_free(stream->send_key[1]);
964 if (stream->receive_key[1])
965 silc_cipher_free(stream->receive_key[1]);
966 if (stream->send_hmac[1])
967 silc_hmac_free(stream->send_hmac[1]);
968 if (stream->receive_hmac[1])
969 silc_hmac_free(stream->receive_hmac[1]);
972 silc_free(stream->src_id);
973 silc_free(stream->dst_id);
975 silc_atomic_uninit32(&stream->refcnt);
976 silc_mutex_free(stream->lock);
980 /* Return TRUE if the stream is valid */
982 SilcBool silc_packet_stream_is_valid(SilcPacketStream stream)
984 return stream->destroyed == FALSE;
987 /* Marks as router stream */
989 void silc_packet_stream_set_router(SilcPacketStream stream)
991 stream->is_router = TRUE;
994 /* Mark to include IV in ciphertext */
996 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
998 stream->iv_included = TRUE;
1001 /* Links `callbacks' to `stream' for specified packet types */
1003 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
1004 SilcPacketCallbacks *callbacks,
1005 void *callback_context,
1006 int priority, va_list ap)
1008 SilcPacketProcess p, e;
1009 SilcInt32 packet_type;
1012 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
1016 if (!callbacks->packet_receive)
1019 p = silc_calloc(1, sizeof(*p));
1023 p->priority = priority;
1024 p->callbacks = callbacks;
1025 p->callback_context = callback_context;
1027 silc_mutex_lock(stream->lock);
1029 if (!stream->process) {
1030 stream->process = silc_dlist_init();
1031 if (!stream->process) {
1032 silc_mutex_unlock(stream->lock);
1038 /* According to priority set the procesor to correct position. First
1039 entry has the highest priority */
1040 silc_dlist_start(stream->process);
1041 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1042 if (p->priority > e->priority) {
1043 silc_dlist_insert(stream->process, p);
1048 silc_dlist_add(stream->process, p);
1050 /* Get packet types to process */
1053 packet_type = va_arg(ap, SilcInt32);
1055 if (packet_type == SILC_PACKET_ANY)
1058 if (packet_type == -1)
1061 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
1063 silc_mutex_unlock(stream->lock);
1067 p->types[i - 1] = (SilcPacketType)packet_type;
1071 p->types[i - 1] = 0;
1073 silc_mutex_unlock(stream->lock);
1075 silc_packet_stream_ref(stream);
1080 /* Links `callbacks' to `stream' for specified packet types */
1082 SilcBool silc_packet_stream_link(SilcPacketStream stream,
1083 SilcPacketCallbacks *callbacks,
1084 void *callback_context,
1090 va_start(ap, priority);
1091 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
1098 /* Unlinks `callbacks' from `stream'. */
1100 void silc_packet_stream_unlink(SilcPacketStream stream,
1101 SilcPacketCallbacks *callbacks,
1102 void *callback_context)
1104 SilcPacketProcess p;
1106 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
1107 callbacks, stream));
1109 silc_mutex_lock(stream->lock);
1111 silc_dlist_start(stream->process);
1112 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
1113 if (p->callbacks == callbacks &&
1114 p->callback_context == callback_context) {
1115 silc_dlist_del(stream->process, p);
1116 silc_free(p->types);
1121 if (!silc_dlist_count(stream->process)) {
1122 silc_dlist_uninit(stream->process);
1123 stream->process = NULL;
1126 silc_mutex_unlock(stream->lock);
1128 silc_packet_stream_unref(stream);
1131 /* Returns TRUE if stream is UDP stream */
1133 SilcBool silc_packet_stream_is_udp(SilcPacketStream stream)
1135 return stream->udp || silc_socket_stream_is_udp(stream->stream, NULL);
1138 /* Return packet sender IP and port for UDP packet stream */
1140 SilcBool silc_packet_get_sender(SilcPacket packet,
1141 const char **sender_ip,
1142 SilcUInt16 *sender_port)
1144 if (!packet->stream->remote_udp)
1147 *sender_ip = packet->stream->remote_udp->remote_ip;
1148 *sender_port = packet->stream->remote_udp->remote_port;
1153 /* Reference packet stream */
1155 void silc_packet_stream_ref(SilcPacketStream stream)
1157 silc_atomic_add_int32(&stream->refcnt, 1);
1158 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1159 silc_atomic_get_int32(&stream->refcnt) - 1,
1160 silc_atomic_get_int32(&stream->refcnt)));
1163 /* Unreference packet stream */
1165 void silc_packet_stream_unref(SilcPacketStream stream)
1167 SILC_LOG_DEBUG(("Stream %p, refcnt %d->%d", stream,
1168 silc_atomic_get_int32(&stream->refcnt),
1169 silc_atomic_get_int32(&stream->refcnt) - 1));
1170 if (silc_atomic_sub_int32(&stream->refcnt, 1) > 0)
1172 silc_atomic_add_int32(&stream->refcnt, 1);
1173 silc_packet_stream_destroy(stream);
1178 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
1180 return stream->sc->engine;
1183 /* Set application context for packet stream */
1185 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
1187 silc_mutex_lock(stream->lock);
1188 stream->stream_context = stream_context;
1189 silc_mutex_unlock(stream->lock);
1192 /* Return application context from packet stream */
1194 void *silc_packet_get_context(SilcPacketStream stream)
1197 silc_mutex_lock(stream->lock);
1198 context = stream->stream_context;
1199 silc_mutex_unlock(stream->lock);
1203 /* Change underlaying stream */
1205 void silc_packet_stream_set_stream(SilcPacketStream ps,
1209 silc_stream_set_notifier(ps->stream, ps->sc->schedule, NULL, NULL);
1210 ps->stream = stream;
1211 silc_stream_set_notifier(ps->stream, ps->sc->schedule, silc_packet_stream_io,
1215 /* Return underlaying stream */
1217 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
1219 return stream->stream;
1224 SilcBool silc_packet_set_keys(SilcPacketStream stream, SilcCipher send_key,
1225 SilcCipher receive_key, SilcHmac send_hmac,
1226 SilcHmac receive_hmac, SilcBool rekey)
1228 SILC_LOG_DEBUG(("Setting new keys to packet stream %p", stream));
1230 /* If doing rekey, send REKEY_DONE packet */
1232 /* This will take stream lock. */
1233 if (!silc_packet_send_raw(stream, SILC_PACKET_REKEY_DONE, 0,
1234 stream->src_id_type, stream->src_id,
1235 stream->src_id_len, stream->dst_id_type,
1236 stream->dst_id, stream->dst_id_len,
1237 NULL, 0, stream->send_key[0],
1238 stream->send_hmac[0]))
1241 /* Write the packet to the stream */
1242 if (!silc_packet_stream_write(stream, TRUE))
1245 silc_mutex_lock(stream->lock);
1248 /* In case IV Included is set, save the old keys */
1249 if (stream->iv_included) {
1250 if (stream->send_key[1] && send_key) {
1251 silc_cipher_free(stream->send_key[1]);
1252 stream->send_key[1] = stream->send_key[0];
1254 if (stream->receive_key[1] && receive_key) {
1255 silc_cipher_free(stream->receive_key[1]);
1256 stream->receive_key[1] = stream->receive_key[0];
1258 if (stream->send_hmac[1] && send_hmac) {
1259 silc_hmac_free(stream->send_hmac[1]);
1260 stream->send_hmac[1] = stream->send_hmac[0];
1262 if (stream->receive_hmac[1] && receive_hmac) {
1263 silc_hmac_free(stream->receive_hmac[1]);
1264 stream->receive_hmac[1] = stream->receive_hmac[0];
1267 if (stream->send_key[0] && send_key)
1268 silc_cipher_free(stream->send_key[0]);
1269 if (stream->receive_key[0] && receive_key)
1270 silc_cipher_free(stream->receive_key[0]);
1271 if (stream->send_hmac[0] && send_hmac)
1272 silc_hmac_free(stream->send_hmac[0]);
1273 if (stream->receive_hmac[0] && receive_hmac)
1274 silc_hmac_free(stream->receive_hmac[0]);
1279 stream->send_key[0] = send_key;
1281 stream->receive_key[0] = receive_key;
1283 stream->send_hmac[0] = send_hmac;
1285 stream->receive_hmac[0] = receive_hmac;
1287 silc_mutex_unlock(stream->lock);
1291 /* Return current ciphers from packet stream */
1293 SilcBool silc_packet_get_keys(SilcPacketStream stream,
1294 SilcCipher *send_key,
1295 SilcCipher *receive_key,
1296 SilcHmac *send_hmac,
1297 SilcHmac *receive_hmac)
1299 if (!stream->send_key[0] && !stream->receive_key[0] &&
1300 !stream->send_hmac[0] && !stream->receive_hmac[0])
1303 silc_mutex_lock(stream->lock);
1306 *send_key = stream->send_key[0];
1308 *receive_key = stream->receive_key[0];
1310 *send_hmac = stream->send_hmac[0];
1312 *receive_hmac = stream->receive_hmac[0];
1314 silc_mutex_unlock(stream->lock);
1319 /* Set SILC IDs to packet stream */
1321 SilcBool silc_packet_set_ids(SilcPacketStream stream,
1322 SilcIdType src_id_type, const void *src_id,
1323 SilcIdType dst_id_type, const void *dst_id)
1326 unsigned char tmp[32];
1328 if (!src_id && !dst_id)
1331 silc_mutex_lock(stream->lock);
1334 SILC_LOG_DEBUG(("Setting source ID to packet stream %p", stream));
1336 silc_free(stream->src_id);
1337 stream->src_id = NULL;
1338 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
1339 silc_mutex_unlock(stream->lock);
1342 stream->src_id = silc_memdup(tmp, len);
1343 if (!stream->src_id) {
1344 silc_mutex_unlock(stream->lock);
1347 stream->src_id_type = src_id_type;
1348 stream->src_id_len = len;
1352 SILC_LOG_DEBUG(("Setting destination ID to packet stream %p", stream));
1354 silc_free(stream->dst_id);
1355 stream->dst_id = NULL;
1356 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
1357 silc_mutex_unlock(stream->lock);
1360 stream->dst_id = silc_memdup(tmp, len);
1361 if (!stream->dst_id) {
1362 silc_mutex_unlock(stream->lock);
1365 stream->dst_id_type = dst_id_type;
1366 stream->dst_id_len = len;
1369 silc_mutex_unlock(stream->lock);
1374 /* Return IDs from the packet stream */
1376 SilcBool silc_packet_get_ids(SilcPacketStream stream,
1377 SilcBool *src_id_set, SilcID *src_id,
1378 SilcBool *dst_id_set, SilcID *dst_id)
1380 if (src_id && stream->src_id)
1381 if (!silc_id_str2id2(stream->src_id, stream->src_id_len,
1382 stream->src_id_type, src_id))
1385 if (stream->src_id && src_id_set)
1388 if (dst_id && stream->dst_id)
1389 if (!silc_id_str2id2(stream->dst_id, stream->dst_id_len,
1390 stream->dst_id_type, dst_id))
1393 if (stream->dst_id && dst_id_set)
1399 /* Adds Security ID (SID) */
1401 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
1403 if (!stream->iv_included)
1406 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
1414 void silc_packet_free(SilcPacket packet)
1416 SilcPacketStream stream = packet->stream;
1418 SILC_LOG_DEBUG(("Freeing packet %p", packet));
1420 /* Check for double free */
1421 SILC_ASSERT(packet->stream != NULL);
1423 packet->stream = NULL;
1424 packet->src_id = packet->dst_id = NULL;
1425 silc_buffer_reset(&packet->buffer);
1427 silc_mutex_lock(stream->sc->engine->lock);
1429 /* Put the packet back to freelist */
1430 silc_list_add(stream->sc->engine->packet_pool, packet);
1431 if (silc_list_count(stream->sc->engine->packet_pool) == 1)
1432 silc_list_start(stream->sc->engine->packet_pool);
1434 silc_mutex_unlock(stream->sc->engine->lock);
1437 /****************************** Packet Sending ******************************/
1439 /* Prepare outgoing data buffer for packet sending. Returns the
1440 pointer to that buffer into the `packet'. */
1442 static inline SilcBool silc_packet_send_prepare(SilcPacketStream stream,
1447 unsigned char *oldptr;
1448 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
1452 /* Allocate more space if needed */
1453 if (silc_unlikely(silc_buffer_taillen(&stream->outbuf) < totlen)) {
1454 if (!silc_buffer_realloc(&stream->outbuf,
1455 silc_buffer_truelen(&stream->outbuf) + totlen))
1459 /* Pull data area for the new packet, and return pointer to the start of
1460 the data area and save the pointer in to the `packet'. MAC is pulled
1461 later after it's computed. */
1462 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
1463 silc_buffer_set(packet, oldptr, totlen);
1464 silc_buffer_push_tail(packet, mac_len);
1469 /* Increments counter when encrypting in counter mode. */
1471 static inline void silc_packet_send_ctr_increment(SilcPacketStream stream,
1473 unsigned char *ret_iv)
1475 unsigned char *iv = silc_cipher_get_iv(cipher);
1476 SilcUInt32 pc1, pc2;
1478 /* Reset block counter */
1479 memset(iv + 12, 0, 4);
1481 /* If IV Included flag, return the 64-bit IV for inclusion in packet */
1482 if (stream->iv_included) {
1484 ret_iv[0] = silc_rng_get_byte_fast(stream->sc->engine->rng);
1485 ret_iv[1] = ret_iv[0] + iv[4];
1486 ret_iv[2] = ret_iv[0] ^ ret_iv[1];
1487 ret_iv[3] = ret_iv[0] + ret_iv[2];
1489 /* Increment 32-bit packet counter */
1490 SILC_GET32_MSB(pc1, iv + 8);
1492 SILC_PUT32_MSB(pc1, ret_iv + 4);
1494 SILC_LOG_HEXDUMP(("IV"), ret_iv, 8);
1496 /* Set new nonce to counter block */
1497 memcpy(iv + 4, ret_iv, 8);
1499 /* Increment 64-bit packet counter */
1500 SILC_GET32_MSB(pc1, iv + 4);
1501 SILC_GET32_MSB(pc2, iv + 8);
1504 SILC_PUT32_MSB(pc1, iv + 4);
1505 SILC_PUT32_MSB(pc2, iv + 8);
1508 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1511 /* Internal routine to assemble outgoing packet. Assembles and encryptes
1512 the packet. The silc_packet_stream_write needs to be called to send it
1513 after this returns TRUE. */
1515 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
1516 SilcPacketType type,
1517 SilcPacketFlags flags,
1518 SilcIdType src_id_type,
1519 unsigned char *src_id,
1520 SilcUInt32 src_id_len,
1521 SilcIdType dst_id_type,
1522 unsigned char *dst_id,
1523 SilcUInt32 dst_id_len,
1524 const unsigned char *data,
1525 SilcUInt32 data_len,
1529 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
1530 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
1531 int i, enclen, truelen, padlen = 0, ivlen = 0, psnlen = 0;
1533 SilcBufferStruct packet;
1535 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
1536 "data len %d", silc_get_packet_name(type), stream->send_psn,
1537 flags, src_id_type, dst_id_type, data_len));
1539 /* Get the true length of the packet. This is saved as payload length
1540 into the packet header. This does not include the length of the
1542 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
1543 src_id_len + dst_id_len));
1544 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
1545 src_id_len + dst_id_len);
1547 /* If using CTR mode, increment the counter */
1548 ctr = (cipher && silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR);
1550 silc_packet_send_ctr_increment(stream, cipher, iv + 1);
1552 /* If IV is included, the SID, IV and sequence number is added to packet */
1553 if (stream->iv_included && cipher) {
1554 psnlen = sizeof(psn);
1556 iv[0] = stream->sid;
1559 /* If IV is included, the SID, IV and sequence number is added to packet */
1560 if (stream->iv_included && cipher) {
1561 psnlen = sizeof(psn);
1562 ivlen = block_len + 1;
1563 iv[0] = stream->sid;
1564 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
1568 /* We automatically figure out the packet structure from the packet
1569 type and flags, and calculate correct length. Private messages with
1570 private keys and channel messages are special packets as their
1571 payload is encrypted already. */
1572 if (type == SILC_PACKET_PRIVATE_MESSAGE &&
1573 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) {
1574 /* Padding is calculated from header + IDs */
1576 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1577 psnlen), block_len, padlen);
1579 /* Length to encrypt, header + IDs + padding. */
1580 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1583 } else if (type == SILC_PACKET_CHANNEL_MESSAGE) {
1584 if (stream->sc->engine->local_is_router && stream->is_router) {
1585 /* Channel messages between routers are encrypted as normal packets.
1586 Padding is calculated from true length of the packet. */
1588 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1590 enclen += padlen + psnlen;
1592 /* Padding is calculated from header + IDs */
1594 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1595 psnlen), block_len, padlen);
1597 /* Length to encrypt, header + IDs + padding. */
1598 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
1602 /* Padding is calculated from true length of the packet */
1603 if (flags & SILC_PACKET_FLAG_LONG_PAD)
1604 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
1606 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
1608 enclen += padlen + psnlen;
1611 /* Remove implementation specific flags */
1612 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
1614 /* Get random padding */
1615 for (i = 0; i < padlen; i++) tmppad[i] =
1616 silc_rng_get_byte_fast(stream->sc->engine->rng);
1618 silc_mutex_lock(stream->lock);
1620 /* Get packet pointer from the outgoing buffer */
1621 if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
1622 + psnlen, hmac, &packet))) {
1623 silc_mutex_unlock(stream->lock);
1627 SILC_PUT32_MSB(stream->send_psn, psn);
1629 /* Create the packet. This creates the SILC header, adds padding, and
1630 the actual packet data. */
1631 i = silc_buffer_format(&packet,
1632 SILC_STR_DATA(iv, ivlen),
1633 SILC_STR_DATA(psn, psnlen),
1634 SILC_STR_UI_SHORT(truelen),
1635 SILC_STR_UI_CHAR(flags),
1636 SILC_STR_UI_CHAR(type),
1637 SILC_STR_UI_CHAR(padlen),
1638 SILC_STR_UI_CHAR(0),
1639 SILC_STR_UI_CHAR(src_id_len),
1640 SILC_STR_UI_CHAR(dst_id_len),
1641 SILC_STR_UI_CHAR(src_id_type),
1642 SILC_STR_DATA(src_id, src_id_len),
1643 SILC_STR_UI_CHAR(dst_id_type),
1644 SILC_STR_DATA(dst_id, dst_id_len),
1645 SILC_STR_DATA(tmppad, padlen),
1646 SILC_STR_DATA(data, data_len),
1648 if (silc_unlikely(i < 0)) {
1649 silc_mutex_unlock(stream->lock);
1653 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
1654 silc_buffer_data(&packet), silc_buffer_len(&packet));
1656 /* Encrypt the packet */
1657 if (silc_likely(cipher)) {
1658 SILC_LOG_DEBUG(("Encrypting packet"));
1659 silc_cipher_set_iv(cipher, NULL);
1660 if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen,
1661 packet.data + ivlen, enclen,
1663 SILC_LOG_ERROR(("Packet encryption failed"));
1664 silc_mutex_unlock(stream->lock);
1670 if (silc_likely(hmac)) {
1673 /* MAC is computed from the entire encrypted packet data, and put
1674 to the end of the packet. */
1675 silc_hmac_init(hmac);
1676 silc_hmac_update(hmac, psn, sizeof(psn));
1677 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1678 silc_hmac_final(hmac, packet.tail, &mac_len);
1679 silc_buffer_pull_tail(&packet, mac_len);
1686 /* Sends a packet */
1688 SilcBool silc_packet_send(SilcPacketStream stream,
1689 SilcPacketType type, SilcPacketFlags flags,
1690 const unsigned char *data, SilcUInt32 data_len)
1694 ret = silc_packet_send_raw(stream, type, flags,
1695 stream->src_id_type,
1698 stream->dst_id_type,
1702 stream->send_key[0],
1703 stream->send_hmac[0]);
1705 /* Write the packet to the stream */
1706 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1709 /* Sends a packet, extended routine */
1711 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1712 SilcPacketType type, SilcPacketFlags flags,
1713 SilcIdType src_id_type, void *src_id,
1714 SilcIdType dst_id_type, void *dst_id,
1715 const unsigned char *data, SilcUInt32 data_len,
1716 SilcCipher cipher, SilcHmac hmac)
1718 unsigned char src_id_data[32], dst_id_data[32];
1719 SilcUInt32 src_id_len, dst_id_len;
1723 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1724 sizeof(src_id_data), &src_id_len))
1727 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1728 sizeof(dst_id_data), &dst_id_len))
1731 ret = silc_packet_send_raw(stream, type, flags,
1732 src_id ? src_id_type : stream->src_id_type,
1733 src_id ? src_id_data : stream->src_id,
1734 src_id ? src_id_len : stream->src_id_len,
1735 dst_id ? dst_id_type : stream->dst_id_type,
1736 dst_id ? dst_id_data : stream->dst_id,
1737 dst_id ? dst_id_len : stream->dst_id_len,
1739 cipher ? cipher : stream->send_key[0],
1740 hmac ? hmac : stream->send_hmac[0]);
1742 /* Write the packet to the stream */
1743 return ret ? silc_packet_stream_write(stream, FALSE) : FALSE;
1746 /* Sends packet after formatting the arguments to buffer */
1748 SilcBool silc_packet_send_va(SilcPacketStream stream,
1749 SilcPacketType type, SilcPacketFlags flags, ...)
1751 SilcBufferStruct buf;
1755 va_start(va, flags);
1757 memset(&buf, 0, sizeof(buf));
1758 if (silc_buffer_format_vp(&buf, va) < 0) {
1763 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1764 silc_buffer_len(&buf));
1766 silc_buffer_purge(&buf);
1772 /* Sends packet after formatting the arguments to buffer, extended routine */
1774 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1775 SilcPacketType type, SilcPacketFlags flags,
1776 SilcIdType src_id_type, void *src_id,
1777 SilcIdType dst_id_type, void *dst_id,
1778 SilcCipher cipher, SilcHmac hmac, ...)
1780 SilcBufferStruct buf;
1786 memset(&buf, 0, sizeof(buf));
1787 if (silc_buffer_format_vp(&buf, va) < 0) {
1792 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1793 dst_id_type, dst_id, silc_buffer_data(&buf),
1794 silc_buffer_len(&buf), cipher, hmac);
1796 silc_buffer_purge(&buf);
1802 /***************************** Packet Receiving *****************************/
1804 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1806 static inline SilcBool silc_packet_check_mac(SilcHmac hmac,
1807 const unsigned char *data,
1808 SilcUInt32 data_len,
1809 const unsigned char *packet_mac,
1810 const unsigned char *packet_seq,
1811 SilcUInt32 sequence)
1814 if (silc_likely(hmac)) {
1815 unsigned char mac[32], psn[4];
1818 SILC_LOG_DEBUG(("Verifying MAC"));
1820 /* Compute HMAC of packet */
1821 silc_hmac_init(hmac);
1824 SILC_PUT32_MSB(sequence, psn);
1825 silc_hmac_update(hmac, psn, 4);
1827 silc_hmac_update(hmac, packet_seq, 4);
1829 silc_hmac_update(hmac, data, data_len);
1830 silc_hmac_final(hmac, mac, &mac_len);
1832 /* Compare the MAC's */
1833 if (silc_unlikely(memcmp(packet_mac, mac, mac_len))) {
1834 SILC_LOG_DEBUG(("MAC failed"));
1838 SILC_LOG_DEBUG(("MAC is Ok"));
1844 /* Increments/sets counter when decrypting in counter mode. */
1846 static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream,
1848 unsigned char *packet_iv)
1850 SilcUInt32 pc1, pc2;
1852 /* If IV Included flag, set the IV from packet to block counter. */
1853 if (stream->iv_included) {
1854 memcpy(iv + 4, packet_iv, 8);
1856 /* Increment 64-bit packet counter. */
1857 SILC_GET32_MSB(pc1, iv + 4);
1858 SILC_GET32_MSB(pc2, iv + 8);
1861 SILC_PUT32_MSB(pc1, iv + 4);
1862 SILC_PUT32_MSB(pc2, iv + 8);
1865 /* Reset block counter */
1866 memset(iv + 12, 0, 4);
1868 SILC_LOG_HEXDUMP(("Counter Block"), iv, 16);
1871 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1872 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1874 static inline int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1875 SilcUInt32 sequence, SilcBuffer buffer,
1878 if (normal == TRUE) {
1879 if (silc_likely(cipher)) {
1880 /* Decrypt rest of the packet */
1881 SILC_LOG_DEBUG(("Decrypting the packet"));
1882 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1884 silc_buffer_len(buffer), NULL)))
1890 /* Decrypt rest of the header plus padding */
1891 if (silc_likely(cipher)) {
1893 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1895 SILC_LOG_DEBUG(("Decrypting the header"));
1897 /* Padding length + src id len + dst id len + header length - 16
1898 bytes already decrypted, gives the rest of the encrypted packet */
1899 silc_buffer_push(buffer, block_len);
1900 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1901 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1903 silc_buffer_pull(buffer, block_len);
1905 if (silc_unlikely(len > silc_buffer_len(buffer))) {
1906 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1910 if (silc_unlikely(!silc_cipher_decrypt(cipher, buffer->data,
1911 buffer->data, len, NULL)))
1919 /* Parses the packet. This is called when a whole packet is ready to be
1920 parsed. The buffer sent must be already decrypted before calling this
1923 static inline SilcBool silc_packet_parse(SilcPacket packet)
1925 SilcBuffer buffer = &packet->buffer;
1926 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1927 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1930 SILC_LOG_DEBUG(("Parsing incoming packet"));
1932 /* Parse the buffer. This parses the SILC header of the packet. */
1933 ret = silc_buffer_unformat(buffer,
1936 SILC_STR_UI_CHAR(&src_id_len),
1937 SILC_STR_UI_CHAR(&dst_id_len),
1938 SILC_STR_UI_CHAR(&src_id_type),
1940 if (silc_unlikely(ret == -1)) {
1941 if (!packet->stream->udp &&
1942 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1943 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1947 if (silc_unlikely(src_id_len > SILC_PACKET_MAX_ID_LEN ||
1948 dst_id_len > SILC_PACKET_MAX_ID_LEN)) {
1949 if (!packet->stream->udp &&
1950 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1951 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1952 packet->src_id_len, packet->dst_id_len));
1956 ret = silc_buffer_unformat(buffer,
1958 SILC_STR_DATA(&packet->src_id, src_id_len),
1959 SILC_STR_UI_CHAR(&dst_id_type),
1960 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1961 SILC_STR_OFFSET(padlen),
1963 if (silc_unlikely(ret == -1)) {
1964 if (!packet->stream->udp &&
1965 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1966 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1970 if (silc_unlikely(src_id_type > SILC_ID_CHANNEL ||
1971 dst_id_type > SILC_ID_CHANNEL)) {
1972 if (!packet->stream->udp &&
1973 !silc_socket_stream_is_udp(packet->stream->stream, NULL))
1974 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1975 src_id_type, dst_id_type));
1979 packet->src_id_len = src_id_len;
1980 packet->dst_id_len = dst_id_len;
1981 packet->src_id_type = src_id_type;
1982 packet->dst_id_type = dst_id_type;
1984 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1985 silc_buffer_len(buffer)), buffer->head,
1986 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1988 SILC_LOG_DEBUG(("Incoming packet type: %d (%s), flags %d", packet->type,
1989 silc_get_packet_name(packet->type), packet->flags));
1994 /* Dispatch packet to application. Called with stream->lock locked.
1995 Returns FALSE if the stream was destroyed while dispatching a packet. */
1997 static SilcBool silc_packet_dispatch(SilcPacket packet)
1999 SilcPacketStream stream = packet->stream;
2000 SilcPacketProcess p;
2001 SilcBool default_sent = FALSE;
2004 /* Dispatch packet to all packet processors that want it */
2006 if (silc_likely(!stream->process)) {
2007 /* Send to default processor as no others exist */
2008 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2009 silc_mutex_unlock(stream->lock);
2010 if (silc_unlikely(!stream->sc->engine->callbacks->
2011 packet_receive(stream->sc->engine, stream, packet,
2012 stream->sc->engine->callback_context,
2013 stream->stream_context)))
2014 silc_packet_free(packet);
2015 silc_mutex_lock(stream->lock);
2016 return stream->destroyed == FALSE;
2019 silc_dlist_start(stream->process);
2020 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
2022 /* If priority is 0 or less, we send to default processor first
2023 because default processor has 0 priority */
2024 if (!default_sent && p->priority <= 0) {
2025 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2026 default_sent = TRUE;
2027 silc_mutex_unlock(stream->lock);
2028 if (stream->sc->engine->callbacks->
2029 packet_receive(stream->sc->engine, stream, packet,
2030 stream->sc->engine->callback_context,
2031 stream->stream_context)) {
2032 silc_mutex_lock(stream->lock);
2033 return stream->destroyed == FALSE;
2035 silc_mutex_lock(stream->lock);
2038 /* Send to processor */
2040 /* Send all packet types */
2041 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2042 silc_mutex_unlock(stream->lock);
2043 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2044 p->callback_context,
2045 stream->stream_context)) {
2046 silc_mutex_lock(stream->lock);
2047 return stream->destroyed == FALSE;
2049 silc_mutex_lock(stream->lock);
2051 /* Send specific types */
2052 for (pt = p->types; *pt; pt++) {
2053 if (*pt != packet->type)
2055 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
2056 silc_mutex_unlock(stream->lock);
2057 if (p->callbacks->packet_receive(stream->sc->engine, stream, packet,
2058 p->callback_context,
2059 stream->stream_context)) {
2060 silc_mutex_lock(stream->lock);
2061 return stream->destroyed == FALSE;
2063 silc_mutex_lock(stream->lock);
2069 if (!default_sent) {
2070 /* Send to default processor as it has not been sent yet */
2071 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
2072 silc_mutex_unlock(stream->lock);
2073 if (stream->sc->engine->callbacks->
2074 packet_receive(stream->sc->engine, stream, packet,
2075 stream->sc->engine->callback_context,
2076 stream->stream_context)) {
2077 silc_mutex_lock(stream->lock);
2078 return stream->destroyed == FALSE;
2080 silc_mutex_lock(stream->lock);
2083 /* If we got here, no one wanted the packet, so drop it */
2084 silc_packet_free(packet);
2085 return stream->destroyed == FALSE;
2088 /* Process incoming data and parse packets. Called with stream->lock
2091 static void silc_packet_read_process(SilcPacketStream stream)
2098 SilcUInt16 packetlen;
2099 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
2100 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
2101 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
2105 /* Get inbuf. If there is already some data for this stream in the buffer
2106 we already have it. Otherwise get the current one from list, it will
2107 include the data. */
2108 inbuf = stream->inbuf;
2110 silc_dlist_start(stream->sc->inbufs);
2111 inbuf = silc_dlist_get(stream->sc->inbufs);
2114 /* Parse the packets from the data */
2115 while (silc_buffer_len(inbuf) > 0) {
2117 cipher = stream->receive_key[0];
2118 hmac = stream->receive_hmac[0];
2121 if (silc_unlikely(silc_buffer_len(inbuf) <
2122 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
2123 SILC_PACKET_MIN_HEADER_LEN))) {
2124 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
2125 silc_dlist_del(stream->sc->inbufs, inbuf);
2126 stream->inbuf = inbuf;
2130 if (silc_likely(hmac))
2131 mac_len = silc_hmac_len(hmac);
2135 /* Decrypt first block of the packet to get the length field out */
2136 if (silc_likely(cipher)) {
2137 block_len = silc_cipher_get_block_len(cipher);
2139 if (stream->iv_included) {
2140 /* SID, IV and sequence number is included in the ciphertext */
2141 sid = (SilcUInt8)inbuf->data[0];
2143 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) {
2144 /* Set the CTR mode IV from packet to counter block */
2145 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2146 silc_packet_receive_ctr_increment(stream, iv, inbuf->data + 1);
2149 /* Get IV from packet */
2150 memcpy(iv, inbuf->data + 1, block_len);
2151 ivlen = block_len + 1;
2155 /* Check SID, and get correct decryption key */
2156 if (sid != stream->sid) {
2157 /* If SID is recent get the previous key and use it */
2158 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
2159 stream->receive_key[1] && !stream->receive_hmac[1]) {
2160 cipher = stream->receive_key[1];
2161 hmac = stream->receive_hmac[1];
2163 /* The SID is unknown, drop rest of the data in buffer */
2164 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
2166 silc_mutex_unlock(stream->lock);
2167 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
2168 silc_mutex_lock(stream->lock);
2173 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
2175 /* If using CTR mode, increment the counter */
2176 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2177 silc_packet_receive_ctr_increment(stream, iv, NULL);
2180 if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR)
2181 silc_cipher_set_iv(cipher, NULL);
2182 silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv);
2185 if (stream->iv_included) {
2186 /* Take sequence number from packet */
2187 packet_seq = header;
2191 /* Unencrypted packet */
2192 block_len = SILC_PACKET_MIN_HEADER_LEN;
2193 header = inbuf->data;
2196 /* Get packet length and full packet length with padding */
2197 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
2200 if (silc_unlikely(packetlen < SILC_PACKET_MIN_LEN)) {
2201 if (!stream->udp && !silc_socket_stream_is_udp(stream->stream, NULL))
2202 SILC_LOG_ERROR(("Received too short packet"));
2203 silc_mutex_unlock(stream->lock);
2204 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2205 silc_mutex_lock(stream->lock);
2206 memset(tmp, 0, sizeof(tmp));
2210 if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
2211 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
2213 paddedlen + mac_len - silc_buffer_len(inbuf)));
2214 memset(tmp, 0, sizeof(tmp));
2215 silc_dlist_del(stream->sc->inbufs, inbuf);
2216 stream->inbuf = inbuf;
2220 /* Check MAC of the packet */
2221 if (silc_unlikely(!silc_packet_check_mac(hmac, inbuf->data,
2223 inbuf->data + ivlen +
2224 paddedlen, packet_seq,
2225 stream->receive_psn))) {
2226 silc_mutex_unlock(stream->lock);
2227 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
2228 silc_mutex_lock(stream->lock);
2229 memset(tmp, 0, sizeof(tmp));
2234 packet = silc_packet_alloc(stream->sc->engine);
2235 if (silc_unlikely(!packet)) {
2236 silc_mutex_unlock(stream->lock);
2237 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2238 silc_mutex_lock(stream->lock);
2239 memset(tmp, 0, sizeof(tmp));
2242 packet->stream = stream;
2244 /* Allocate more space to packet buffer, if needed */
2245 if (silc_unlikely(silc_buffer_truelen(&packet->buffer) < paddedlen)) {
2246 if (!silc_buffer_realloc(&packet->buffer,
2247 silc_buffer_truelen(&packet->buffer) +
2249 silc_buffer_truelen(&packet->buffer)))) {
2250 silc_mutex_unlock(stream->lock);
2251 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
2252 silc_mutex_lock(stream->lock);
2253 silc_packet_free(packet);
2254 memset(tmp, 0, sizeof(tmp));
2259 /* Parse packet header */
2260 packet->flags = (SilcPacketFlags)header[2];
2261 packet->type = (SilcPacketType)header[3];
2263 if (stream->sc->engine->local_is_router) {
2264 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
2265 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
2267 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
2268 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
2269 stream->is_router == TRUE))
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)
2279 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
2280 stream->receive_psn, paddedlen + ivlen + mac_len),
2281 inbuf->data, paddedlen + ivlen + mac_len);
2283 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
2284 silc_buffer_pull_tail(&packet->buffer, paddedlen);
2285 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
2286 silc_buffer_pull(&packet->buffer, block_len - psnlen);
2287 silc_buffer_put(&packet->buffer, (inbuf->data + ivlen +
2288 psnlen + (block_len - psnlen)),
2289 paddedlen - ivlen - psnlen - (block_len - psnlen));
2290 if (silc_likely(cipher)) {
2291 silc_cipher_set_iv(cipher, iv);
2292 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
2293 &packet->buffer, normal);
2294 if (silc_unlikely(ret < 0)) {
2295 silc_mutex_unlock(stream->lock);
2296 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
2297 silc_mutex_lock(stream->lock);
2298 silc_packet_free(packet);
2299 memset(tmp, 0, sizeof(tmp));
2303 stream->receive_psn++;
2305 silc_buffer_push(&packet->buffer, block_len);
2307 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
2308 silc_buffer_pull(inbuf, paddedlen + mac_len);
2310 /* Parse the packet */
2311 if (silc_unlikely(!silc_packet_parse(packet))) {
2312 silc_mutex_unlock(stream->lock);
2313 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
2314 silc_mutex_lock(stream->lock);
2315 silc_packet_free(packet);
2316 memset(tmp, 0, sizeof(tmp));
2320 /* Dispatch the packet to application */
2321 if (!silc_packet_dispatch(packet))
2326 /* Add inbuf back to free list, if we owned it. */
2327 if (stream->inbuf) {
2328 silc_dlist_add(stream->sc->inbufs, inbuf);
2329 stream->inbuf = NULL;
2332 silc_buffer_reset(inbuf);
2335 /****************************** Packet Waiting ******************************/
2337 /* Packet wait receive callback */
2339 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2340 SilcPacketStream stream,
2342 void *callback_context,
2343 void *stream_context);
2345 /* Packet waiting callbacks */
2346 static SilcPacketCallbacks silc_packet_wait_cbs =
2348 silc_packet_wait_packet_receive, NULL, NULL
2351 /* Packet waiting context */
2353 SilcMutex wait_lock;
2355 SilcList packet_queue;
2356 unsigned char id[28];
2357 unsigned int id_type : 2;
2358 unsigned int id_len : 5;
2359 unsigned int stopped : 1;
2362 /* Packet wait receive callback */
2365 silc_packet_wait_packet_receive(SilcPacketEngine engine,
2366 SilcPacketStream stream,
2368 void *callback_context,
2369 void *stream_context)
2371 SilcPacketWait pw = callback_context;
2373 /* If source ID is specified check for it */
2375 if (pw->id_type != packet->src_id_type ||
2376 memcmp(pw->id, packet->src_id, pw->id_len))
2380 /* Signal the waiting thread for a new packet */
2381 silc_mutex_lock(pw->wait_lock);
2383 if (silc_unlikely(pw->stopped)) {
2384 silc_mutex_unlock(pw->wait_lock);
2388 silc_list_add(pw->packet_queue, packet);
2389 silc_cond_broadcast(pw->wait_cond);
2391 silc_mutex_unlock(pw->wait_lock);
2396 /* Initialize packet waiting */
2398 void *silc_packet_wait_init(SilcPacketStream stream,
2399 const SilcID *source_id, ...)
2405 pw = silc_calloc(1, sizeof(*pw));
2409 /* Allocate mutex and conditional variable */
2410 if (!silc_mutex_alloc(&pw->wait_lock)) {
2414 if (!silc_cond_alloc(&pw->wait_cond)) {
2415 silc_mutex_free(pw->wait_lock);
2420 /* Link to the packet stream for the requested packet types */
2421 va_start(ap, source_id);
2422 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
2426 silc_cond_free(pw->wait_cond);
2427 silc_mutex_free(pw->wait_lock);
2432 /* Initialize packet queue */
2433 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
2437 silc_id_id2str(SILC_ID_GET_ID(*source_id), source_id->type, pw->id,
2438 sizeof(pw->id), &id_len);
2439 pw->id_type = source_id->type;
2440 pw->id_len = id_len;
2446 /* Uninitialize packet waiting */
2448 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
2450 SilcPacketWait pw = waiter;
2453 /* Signal any threads to stop waiting */
2454 silc_mutex_lock(pw->wait_lock);
2456 silc_cond_broadcast(pw->wait_cond);
2457 silc_mutex_unlock(pw->wait_lock);
2458 silc_thread_yield();
2460 /* Re-acquire lock and free resources */
2461 silc_mutex_lock(pw->wait_lock);
2462 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
2464 /* Free any remaining packets */
2465 silc_list_start(pw->packet_queue);
2466 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
2467 silc_packet_free(packet);
2469 silc_mutex_unlock(pw->wait_lock);
2470 silc_cond_free(pw->wait_cond);
2471 silc_mutex_free(pw->wait_lock);
2475 /* Blocks thread until a packet has been received. */
2477 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
2479 SilcPacketWait pw = waiter;
2480 SilcBool ret = FALSE;
2482 silc_mutex_lock(pw->wait_lock);
2484 /* Wait here until packet has arrived */
2485 while (silc_list_count(pw->packet_queue) == 0) {
2486 if (silc_unlikely(pw->stopped)) {
2487 silc_mutex_unlock(pw->wait_lock);
2490 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
2494 silc_list_start(pw->packet_queue);
2495 *return_packet = silc_list_get(pw->packet_queue);
2496 silc_list_del(pw->packet_queue, *return_packet);
2498 silc_mutex_unlock(pw->wait_lock);
2500 return ret == TRUE ? 1 : 0;
2503 /************************** Packet Stream Wrapper ***************************/
2505 /* Packet stream wrapper receive callback */
2507 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2508 SilcPacketStream stream,
2510 void *callback_context,
2511 void *stream_context);
2513 const SilcStreamOps silc_packet_stream_ops;
2515 /* Packet stream wrapper context */
2517 const SilcStreamOps *ops;
2518 SilcPacketStream stream;
2520 void *waiter; /* Waiter context in blocking mode */
2521 SilcPacketWrapCoder coder;
2522 void *coder_context;
2524 SilcStreamNotifier callback;
2527 SilcPacketType type;
2528 SilcPacketFlags flags;
2529 unsigned int closed : 1;
2530 unsigned int blocking : 1;
2531 unsigned int read_more : 1;
2532 } *SilcPacketWrapperStream;
2534 /* Packet wrapper callbacks */
2535 static SilcPacketCallbacks silc_packet_wrap_cbs =
2537 silc_packet_wrap_packet_receive, NULL, NULL
2540 /* Packet stream wrapper receive callback, non-blocking mode */
2543 silc_packet_wrap_packet_receive(SilcPacketEngine engine,
2544 SilcPacketStream stream,
2546 void *callback_context,
2547 void *stream_context)
2549 SilcPacketWrapperStream pws = callback_context;
2551 if (pws->closed || !pws->callback)
2554 silc_mutex_lock(pws->lock);
2555 silc_list_add(pws->in_queue, packet);
2556 silc_mutex_unlock(pws->lock);
2558 /* Call notifier callback */
2559 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2564 /* Task callback to notify more data is available for reading */
2566 SILC_TASK_CALLBACK(silc_packet_wrap_read_more)
2568 SilcPacketWrapperStream pws = context;
2570 if (pws->closed || !pws->callback)
2573 /* Call notifier callback */
2574 pws->callback((SilcStream)pws, SILC_STREAM_CAN_READ, pws->context);
2577 /* Read SILC packet */
2579 int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
2582 SilcPacketWrapperStream pws = stream;
2584 SilcBool read_more = FALSE;
2590 if (pws->blocking) {
2591 /* Block until packet is received */
2592 if ((silc_packet_wait(pws->waiter, 0, &packet)) < 0)
2597 /* Non-blocking mode */
2598 silc_mutex_lock(pws->lock);
2599 if (!silc_list_count(pws->in_queue)) {
2600 silc_mutex_unlock(pws->lock);
2604 silc_list_start(pws->in_queue);
2605 packet = silc_list_get(pws->in_queue);
2606 silc_list_del(pws->in_queue, packet);
2607 silc_mutex_unlock(pws->lock);
2610 /* Call decoder if set */
2611 if (pws->coder && !pws->read_more)
2612 pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
2613 pws->coder_context);
2615 len = silc_buffer_len(&packet->buffer);
2616 if (len > buf_len) {
2622 memcpy(buf, packet->buffer.data, len);
2624 if (read_more && !pws->blocking) {
2625 /* More data will be available (in blocking mode not supported). */
2626 silc_buffer_pull(&packet->buffer, len);
2627 silc_list_insert(pws->in_queue, NULL, packet);
2628 silc_schedule_task_add_timeout(pws->stream->sc->schedule,
2629 silc_packet_wrap_read_more, pws, 0, 0);
2630 pws->read_more = TRUE;
2634 pws->read_more = FALSE;
2635 silc_packet_free(packet);
2639 /* Write SILC packet */
2641 int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
2642 SilcUInt32 data_len)
2644 SilcPacketWrapperStream pws = stream;
2645 SilcBool ret = FALSE;
2647 /* Call encoder if set */
2649 silc_buffer_reset(pws->encbuf);
2650 ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
2651 pws->coder_context);
2654 /* Send the SILC packet */
2656 if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
2657 SILC_STR_DATA(silc_buffer_data(pws->encbuf),
2658 silc_buffer_len(pws->encbuf)),
2659 SILC_STR_DATA(data, data_len),
2663 if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
2672 SilcBool silc_packet_wrap_close(SilcStream stream)
2674 SilcPacketWrapperStream pws = stream;
2679 if (pws->blocking) {
2680 /* Close packet waiter */
2681 silc_packet_wait_uninit(pws->waiter, pws->stream);
2685 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2692 /* Destroy wrapper stream */
2694 void silc_packet_wrap_destroy(SilcStream stream)
2697 SilcPacketWrapperStream pws = stream;
2700 SILC_LOG_DEBUG(("Destroying wrapped packet stream %p", pws));
2702 silc_stream_close(stream);
2703 silc_list_start(pws->in_queue);
2704 while ((packet = silc_list_get(pws->in_queue)))
2705 silc_packet_free(packet);
2707 silc_mutex_free(pws->lock);
2709 silc_buffer_free(pws->encbuf);
2710 silc_packet_stream_unref(pws->stream);
2715 /* Link stream to receive packets */
2717 SilcBool silc_packet_wrap_notifier(SilcStream stream,
2718 SilcSchedule schedule,
2719 SilcStreamNotifier callback,
2722 SilcPacketWrapperStream pws = stream;
2724 if (pws->closed || pws->blocking)
2727 /* Link to receive packets */
2729 silc_packet_stream_link(pws->stream, &silc_packet_wrap_cbs, pws,
2730 100000, pws->type, -1);
2732 silc_packet_stream_unlink(pws->stream, &silc_packet_wrap_cbs, pws);
2734 pws->callback = callback;
2735 pws->context = context;
2740 /* Return schedule */
2742 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
2747 /* Wraps packet stream into SilcStream. */
2749 SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
2750 SilcPacketType type,
2751 SilcPacketFlags flags,
2752 SilcBool blocking_mode,
2753 SilcPacketWrapCoder coder,
2756 SilcPacketWrapperStream pws;
2758 pws = silc_calloc(1, sizeof(*pws));
2762 SILC_LOG_DEBUG(("Wrapping packet stream %p to stream %p", stream, pws));
2764 pws->ops = &silc_packet_stream_ops;
2765 pws->stream = stream;
2768 pws->blocking = blocking_mode;
2770 pws->coder_context = context;
2772 /* Allocate small amount for encoder buffer. */
2774 pws->encbuf = silc_buffer_alloc(8);
2776 if (pws->blocking) {
2777 /* Blocking mode. Use packet waiter to do the thing. */
2778 pws->waiter = silc_packet_wait_init(pws->stream, NULL, pws->type, -1);
2784 /* Non-blocking mode */
2785 silc_mutex_alloc(&pws->lock);
2786 silc_list_init(pws->in_queue, struct SilcPacketStruct, next);
2789 silc_packet_stream_ref(stream);
2791 return (SilcStream)pws;
2794 const SilcStreamOps silc_packet_stream_ops =
2796 silc_packet_wrap_read,
2797 silc_packet_wrap_write,
2798 silc_packet_wrap_close,
2799 silc_packet_wrap_destroy,
2800 silc_packet_wrap_notifier,
2801 silc_packet_wrap_get_schedule,