5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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 ***************************/
29 struct SilcPacketEngineStruct {
30 SilcRng rng; /* RNG for engine */
31 SilcPacketCallbacks *callbacks; /* Packet callbacks */
32 void *callback_context; /* Context for callbacks */
33 SilcList streams; /* All streams in engine */
34 SilcList packet_pool; /* Free list for received packets */
35 SilcMutex lock; /* Engine lock */
36 SilcBool local_is_router;
39 /* Packet procesor context */
40 typedef struct SilcPacketProcessStruct {
41 SilcInt32 priority; /* Priority */
42 SilcPacketType *types; /* Packets to process */
43 SilcPacketCallbacks *callbacks; /* Callbacks or NULL */
44 void *callback_context;
48 struct SilcPacketStreamStruct {
49 struct SilcPacketStreamStruct *next;
50 SilcPacketEngine engine; /* Packet engine */
51 SilcStream stream; /* Underlaying stream */
52 SilcMutex lock; /* Stream lock */
53 SilcDList process; /* Packet processors, it set */
54 void *stream_context; /* Stream context */
55 SilcBufferStruct inbuf; /* In buffer */
56 SilcBufferStruct outbuf; /* Out buffer */
57 SilcCipher send_key[2]; /* Sending key */
58 SilcHmac send_hmac[2]; /* Sending HMAC */
59 SilcCipher receive_key[2]; /* Receiving key */
60 SilcHmac receive_hmac[2]; /* Receiving HMAC */
61 unsigned char *src_id; /* Source ID */
62 unsigned char *dst_id; /* Destination ID */
63 SilcUInt32 send_psn; /* Sending sequence */
64 SilcUInt32 receive_psn; /* Receiving sequence */
65 SilcAtomic8 refcnt; /* Reference counter */
66 unsigned int src_id_len : 6;
67 unsigned int src_id_type : 2;
68 unsigned int dst_id_len : 6;
69 unsigned int dst_id_type : 2;
70 unsigned int is_router : 1; /* Set if router stream */
71 unsigned int destroyed : 1; /* Set if destroyed */
72 unsigned int iv_included : 1; /* Set if IV included */
73 SilcUInt8 sid; /* Security ID, set if IV included */
76 /* Initial size of stream buffers */
77 #define SILC_PACKET_DEFAULT_SIZE 1024
79 /* Header length without source and destination ID's. */
80 #define SILC_PACKET_HEADER_LEN 10
82 /* Minimum length of SILC Packet Header. */
83 #define SILC_PACKET_MIN_HEADER_LEN 16
84 #define SILC_PACKET_MIN_HEADER_LEN_IV 32 + 1
86 /* Maximum padding length */
87 #define SILC_PACKET_MAX_PADLEN 128
89 /* Default padding length */
90 #define SILC_PACKET_DEFAULT_PADLEN 16
92 /* Minimum packet length */
93 #define SILC_PACKET_MIN_LEN (SILC_PACKET_HEADER_LEN + 1)
95 /* Returns true length of the packet. */
96 #define SILC_PACKET_LENGTH(__packetdata, __ret_truelen, __ret_paddedlen) \
98 SILC_GET16_MSB((__ret_truelen), (__packetdata)); \
99 (__ret_paddedlen) = (__ret_truelen) + (SilcUInt8)(__packetdata)[4]; \
102 /* Calculates the data length with given header length. This macro
103 can be used to check whether the data_len with header_len exceeds
104 SILC_PACKET_MAX_LEN. If it does, this returns the new data_len
105 so that the SILC_PACKET_MAX_LEN is not exceeded. If the data_len
106 plus header_len fits SILC_PACKET_MAX_LEN the returned data length
107 is the data_len given as argument. */
108 #define SILC_PACKET_DATALEN(data_len, header_len) \
109 ((data_len + header_len) > SILC_PACKET_MAX_LEN ? \
110 data_len - ((data_len + header_len) - SILC_PACKET_MAX_LEN) : data_len)
112 /* Calculates the length of the padding in the packet. */
113 #define SILC_PACKET_PADLEN(__packetlen, __blocklen, __padlen) \
115 __padlen = (SILC_PACKET_DEFAULT_PADLEN - (__packetlen) % \
116 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
118 __padlen += ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN); \
121 /* Returns the length of the padding up to the maximum length, which
123 #define SILC_PACKET_PADLEN_MAX(__packetlen, __blocklen, __padlen) \
125 __padlen = (SILC_PACKET_MAX_PADLEN - (__packetlen) % \
126 ((__blocklen) ? (__blocklen) : SILC_PACKET_DEFAULT_PADLEN)); \
130 #define SILC_PACKET_CALLBACK_EOS(s) \
132 (s)->engine->callbacks->eos((s)->engine, s, \
133 (s)->engine->callback_context, \
134 (s)->stream_context); \
138 #define SILC_PACKET_CALLBACK_ERROR(s, err) \
140 (s)->engine->callbacks->error((s)->engine, s, err, \
141 (s)->engine->callback_context, \
142 (s)->stream_context); \
146 /************************ Static utility functions **************************/
148 static void silc_packet_read_process(SilcPacketStream stream);
150 /* Our stream IO notifier callback. */
152 static void silc_packet_stream_io(SilcStream stream, SilcStreamStatus status,
155 SilcPacketStream ps = context;
158 silc_mutex_lock(ps->lock);
161 silc_mutex_unlock(ps->lock);
167 case SILC_STREAM_CAN_WRITE:
168 if (!silc_buffer_headlen(&ps->outbuf)) {
169 silc_mutex_unlock(ps->lock);
173 SILC_LOG_DEBUG(("Writing pending data to stream"));
175 /* Write pending data to stream */
176 while (silc_buffer_len(&ps->outbuf) > 0) {
177 ret = silc_stream_write(ps->stream, ps->outbuf.data,
178 silc_buffer_len(&ps->outbuf));
181 silc_buffer_reset(&ps->outbuf);
182 silc_mutex_unlock(ps->lock);
183 SILC_PACKET_CALLBACK_EOS(ps);
189 silc_buffer_reset(&ps->outbuf);
190 silc_mutex_unlock(ps->lock);
191 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_WRITE);
196 /* Cannot write now, write later. */
197 silc_mutex_unlock(ps->lock);
202 silc_buffer_pull(&ps->outbuf, ret);
205 silc_buffer_reset(&ps->outbuf);
207 silc_mutex_unlock(ps->lock);
210 case SILC_STREAM_CAN_READ:
211 SILC_LOG_DEBUG(("Reading data from stream"));
213 /* Make sure we have fair amount of free space in inbuf */
214 if (silc_buffer_taillen(&ps->inbuf) < SILC_PACKET_DEFAULT_SIZE)
215 if (!silc_buffer_realloc(&ps->inbuf, silc_buffer_truelen(&ps->inbuf) +
216 SILC_PACKET_DEFAULT_SIZE * 2)) {
217 silc_mutex_unlock(ps->lock);
221 /* Read data from stream */
222 ret = silc_stream_read(ps->stream, ps->inbuf.tail,
223 silc_buffer_taillen(&ps->inbuf));
227 silc_buffer_reset(&ps->inbuf);
228 silc_mutex_unlock(ps->lock);
229 SILC_PACKET_CALLBACK_EOS(ps);
235 silc_buffer_reset(&ps->inbuf);
236 silc_mutex_unlock(ps->lock);
237 SILC_PACKET_CALLBACK_ERROR(ps, SILC_PACKET_ERR_READ);
242 /* Cannot read now, do it later. */
243 silc_buffer_pull(&ps->inbuf, silc_buffer_len(&ps->inbuf));
244 silc_mutex_unlock(ps->lock);
248 /* Now process the data */
249 silc_buffer_pull_tail(&ps->inbuf, ret);
250 silc_packet_read_process(ps);
252 silc_mutex_unlock(ps->lock);
256 silc_mutex_unlock(ps->lock);
261 /* Allocate packet */
263 static SilcPacket silc_packet_alloc(SilcPacketEngine engine)
267 SILC_LOG_DEBUG(("Packet pool count %d",
268 silc_list_count(engine->packet_pool)));
270 silc_mutex_lock(engine->lock);
272 /* Get packet from freelist or allocate new one. */
273 packet = silc_list_get(engine->packet_pool);
277 silc_mutex_unlock(engine->lock);
279 packet = silc_calloc(1, sizeof(*packet));
283 SILC_LOG_DEBUG(("Allocating new packet %p", packet));
285 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
290 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
291 silc_buffer_reset(&packet->buffer);
296 SILC_LOG_DEBUG(("Get packet %p", packet));
298 /* Delete from freelist */
299 silc_list_del(engine->packet_pool, packet);
301 silc_mutex_unlock(engine->lock);
307 /******************************** Packet API ********************************/
309 /* Allocate new packet engine */
312 silc_packet_engine_start(SilcRng rng, SilcBool router,
313 SilcPacketCallbacks *callbacks,
314 void *callback_context)
316 SilcPacketEngine engine;
321 SILC_LOG_DEBUG(("Starting new packet engine"));
325 if (!callbacks->packet_receive || !callbacks->eos || !callbacks->error)
328 engine = silc_calloc(1, sizeof(*engine));
333 engine->local_is_router = router;
334 engine->callbacks = callbacks;
335 engine->callback_context = callback_context;
336 silc_list_init(engine->streams, struct SilcPacketStreamStruct, next);
337 silc_mutex_alloc(&engine->lock);
339 /* Allocate packet free list */
340 silc_list_init(engine->packet_pool, struct SilcPacketStruct, next);
341 for (i = 0; i < 5; i++) {
342 packet = silc_calloc(1, sizeof(*packet));
346 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
349 silc_buffer_set(&packet->buffer, tmp, SILC_PACKET_DEFAULT_SIZE);
350 silc_buffer_reset(&packet->buffer);
352 silc_list_add(engine->packet_pool, packet);
354 silc_list_start(engine->packet_pool);
359 /* Stop packet engine */
361 void silc_packet_engine_stop(SilcPacketEngine engine)
364 SILC_LOG_DEBUG(("Stopping packet engine"));
374 /* Create new packet stream */
376 SilcPacketStream silc_packet_stream_create(SilcPacketEngine engine,
377 SilcSchedule schedule,
383 SILC_LOG_DEBUG(("Creating new packet stream"));
385 if (!engine || !stream)
388 ps = silc_calloc(1, sizeof(*ps));
394 silc_atomic_init8(&ps->refcnt, 1);
396 /* Allocate buffers */
397 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
400 silc_buffer_set(&ps->inbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
401 silc_buffer_reset(&ps->inbuf);
402 tmp = silc_malloc(SILC_PACKET_DEFAULT_SIZE);
405 silc_buffer_set(&ps->outbuf, tmp, SILC_PACKET_DEFAULT_SIZE);
406 silc_buffer_reset(&ps->outbuf);
408 /* Initialize packet procesors list */
409 ps->process = silc_dlist_init();
411 /* Set IO notifier callback */
412 silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
414 silc_mutex_alloc(&ps->lock);
417 silc_mutex_lock(engine->lock);
418 silc_list_add(engine->streams, ps);
419 silc_mutex_unlock(engine->lock);
424 /* Destroy packet stream */
426 void silc_packet_stream_destroy(SilcPacketStream stream)
431 if (silc_atomic_get_int8(&stream->refcnt) > 1) {
432 stream->destroyed = TRUE;
436 SILC_LOG_DEBUG(("Destroying packet stream %p", stream));
438 /* Delete from engine */
439 silc_mutex_lock(stream->engine->lock);
440 silc_list_del(stream->engine->streams, stream);
441 silc_mutex_unlock(stream->engine->lock);
443 /* Clear and free buffers */
444 silc_buffer_clear(&stream->inbuf);
445 silc_buffer_clear(&stream->outbuf);
446 silc_buffer_purge(&stream->inbuf);
447 silc_buffer_purge(&stream->outbuf);
451 /* Destroy the underlaying stream */
452 silc_stream_destroy(stream->stream);
454 silc_atomic_uninit8(&stream->refcnt);
455 silc_dlist_uninit(stream->process);
456 silc_mutex_free(stream->lock);
460 /* Marks as router stream */
462 void silc_packet_stream_set_router(SilcPacketStream stream)
464 stream->is_router = TRUE;
467 /* Mark to include IV in ciphertext */
469 void silc_packet_stream_set_iv_included(SilcPacketStream stream)
471 stream->iv_included = TRUE;
474 /* Links `callbacks' to `stream' for specified packet types */
476 static SilcBool silc_packet_stream_link_va(SilcPacketStream stream,
477 SilcPacketCallbacks *callbacks,
478 void *callback_context,
479 int priority, va_list ap)
481 SilcPacketProcess p, e;
482 SilcInt32 packet_type;
485 SILC_LOG_DEBUG(("Linking callbacks %p to stream %p", callbacks, stream));
489 if (!callbacks->packet_receive)
492 p = silc_calloc(1, sizeof(*p));
496 p->priority = priority;
497 p->callbacks = callbacks;
498 p->callback_context = callback_context;
500 silc_mutex_lock(stream->lock);
502 if (!stream->process) {
503 stream->process = silc_dlist_init();
504 if (!stream->process) {
505 silc_mutex_unlock(stream->lock);
510 /* According to priority set the procesor to correct position. First
511 entry has the highest priority */
512 silc_dlist_start(stream->process);
513 while ((e = silc_dlist_get(stream->process)) != SILC_LIST_END) {
514 if (p->priority > e->priority) {
515 silc_dlist_insert(stream->process, p);
520 silc_dlist_add(stream->process, p);
522 /* Get packet types to process */
525 packet_type = va_arg(ap, SilcInt32);
527 if (packet_type == SILC_PACKET_ANY)
530 if (packet_type == -1)
533 p->types = silc_realloc(p->types, sizeof(*p->types) * (i + 1));
535 silc_mutex_unlock(stream->lock);
539 p->types[i - 1] = (SilcPacketType)packet_type;
545 silc_mutex_unlock(stream->lock);
547 silc_packet_stream_ref(stream);
552 /* Links `callbacks' to `stream' for specified packet types */
554 SilcBool silc_packet_stream_link(SilcPacketStream stream,
555 SilcPacketCallbacks *callbacks,
556 void *callback_context,
562 va_start(ap, priority);
563 ret = silc_packet_stream_link_va(stream, callbacks, callback_context,
570 /* Unlinks `callbacks' from `stream'. */
572 void silc_packet_stream_unlink(SilcPacketStream stream,
573 SilcPacketCallbacks *callbacks,
574 void *callback_context)
578 SILC_LOG_DEBUG(("Unlinking callbacks %p from stream %p",
581 silc_mutex_lock(stream->lock);
583 silc_dlist_start(stream->process);
584 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END)
585 if (p->callbacks == callbacks &&
586 p->callback_context == callback_context) {
587 silc_dlist_del(stream->process, p);
592 if (!silc_dlist_count(stream->process)) {
593 silc_dlist_uninit(stream->process);
594 stream->process = NULL;
597 silc_mutex_unlock(stream->lock);
599 silc_packet_stream_unref(stream);
602 /* Reference packet stream */
604 void silc_packet_stream_ref(SilcPacketStream stream)
606 silc_atomic_add_int8(&stream->refcnt, 1);
609 /* Unreference packet stream */
611 void silc_packet_stream_unref(SilcPacketStream stream)
613 if (silc_atomic_sub_int8(&stream->refcnt, 1) == 0)
614 silc_packet_stream_destroy(stream);
619 SilcPacketEngine silc_packet_get_engine(SilcPacketStream stream)
621 return stream->engine;
624 /* Set application context for packet stream */
626 void silc_packet_set_context(SilcPacketStream stream, void *stream_context)
628 silc_mutex_lock(stream->lock);
629 stream->stream_context = stream_context;
630 silc_mutex_unlock(stream->lock);
633 /* Return application context from packet stream */
635 void *silc_packet_get_context(SilcPacketStream stream)
638 silc_mutex_lock(stream->lock);
639 context = stream->stream_context;
640 silc_mutex_unlock(stream->lock);
644 /* Change underlaying stream */
646 void silc_packet_stream_set_stream(SilcPacketStream ps,
648 SilcSchedule schedule)
651 silc_stream_set_notifier(ps->stream, schedule, NULL, NULL);
653 silc_stream_set_notifier(ps->stream, schedule, silc_packet_stream_io, ps);
656 /* Return underlaying stream */
658 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
660 return stream->stream;
663 /* Set ciphers for packet stream */
665 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
668 SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
670 silc_mutex_lock(stream->lock);
672 /* In case IV Included is set, save the old key */
673 if (stream->iv_included) {
674 if (stream->send_key[1]) {
675 silc_cipher_free(stream->send_key[1]);
676 stream->send_key[1] = stream->send_key[0];
678 if (stream->receive_key[1]) {
679 silc_cipher_free(stream->receive_key[1]);
680 stream->receive_key[1] = stream->receive_key[0];
683 if (stream->send_key[0])
684 silc_cipher_free(stream->send_key[0]);
685 if (stream->send_key[1])
686 silc_cipher_free(stream->receive_key[0]);
689 stream->send_key[0] = send;
690 stream->receive_key[0] = receive;
692 silc_mutex_unlock(stream->lock);
695 /* Return current ciphers from packet stream */
697 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
700 if (!stream->send_key[0] && !stream->receive_key[0])
703 silc_mutex_lock(stream->lock);
706 *send = stream->send_key[0];
708 *receive = stream->receive_key[0];
710 silc_mutex_unlock(stream->lock);
715 /* Set HMACs for packet stream */
717 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
720 SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
722 silc_mutex_lock(stream->lock);
724 /* In case IV Included is set, save the old HMAC */
725 if (stream->iv_included) {
726 if (stream->send_hmac[1]) {
727 silc_hmac_free(stream->send_hmac[1]);
728 stream->send_hmac[1] = stream->send_hmac[0];
730 if (stream->receive_hmac[1]) {
731 silc_hmac_free(stream->receive_hmac[1]);
732 stream->receive_hmac[1] = stream->receive_hmac[0];
735 if (stream->send_hmac[0])
736 silc_hmac_free(stream->send_hmac[0]);
737 if (stream->receive_hmac[0])
738 silc_hmac_free(stream->receive_hmac[0]);
741 stream->send_hmac[0] = send;
742 stream->receive_hmac[0] = receive;
744 silc_mutex_unlock(stream->lock);
747 /* Return current HMACs from packet stream */
749 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
752 if (!stream->send_hmac[0] && !stream->receive_hmac[0])
755 silc_mutex_lock(stream->lock);
758 *send = stream->send_hmac[0];
760 *receive = stream->receive_hmac[0];
762 silc_mutex_unlock(stream->lock);
767 /* Set SILC IDs to packet stream */
769 SilcBool silc_packet_set_ids(SilcPacketStream stream,
770 SilcIdType src_id_type, const void *src_id,
771 SilcIdType dst_id_type, const void *dst_id)
774 unsigned char tmp[32];
776 if (!src_id && !dst_id)
779 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
781 silc_mutex_lock(stream->lock);
784 silc_free(stream->src_id);
785 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
786 silc_mutex_unlock(stream->lock);
789 stream->src_id = silc_memdup(tmp, len);
790 if (!stream->src_id) {
791 silc_mutex_unlock(stream->lock);
794 stream->src_id_type = src_id_type;
795 stream->src_id_len = len;
799 silc_free(stream->dst_id);
800 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
801 silc_mutex_unlock(stream->lock);
804 stream->dst_id = silc_memdup(tmp, len);
805 if (!stream->dst_id) {
806 silc_mutex_unlock(stream->lock);
809 stream->dst_id_type = dst_id_type;
810 stream->dst_id_len = len;
813 silc_mutex_unlock(stream->lock);
818 /* Adds Security ID (SID) */
820 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
822 if (!stream->iv_included)
825 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
833 void silc_packet_free(SilcPacket packet)
835 SilcPacketStream stream = packet->stream;
837 SILC_LOG_DEBUG(("Freeing packet %p", packet));
839 /* Check for double free */
840 SILC_ASSERT(packet->stream != NULL);
842 packet->stream = NULL;
843 packet->src_id = packet->dst_id = NULL;
844 silc_buffer_reset(&packet->buffer);
846 silc_mutex_lock(stream->engine->lock);
848 /* Put the packet back to freelist */
849 silc_list_add(stream->engine->packet_pool, packet);
850 if (silc_list_count(stream->engine->packet_pool) == 1)
851 silc_list_start(stream->engine->packet_pool);
853 silc_mutex_unlock(stream->engine->lock);
856 /****************************** Packet Sending ******************************/
858 /* Prepare outgoing data buffer for packet sending. Returns the
859 pointer to that buffer into the `packet'. */
861 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
866 unsigned char *oldptr;
867 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
871 /* Allocate more space if needed */
872 if (silc_buffer_taillen(&stream->outbuf) < totlen) {
873 if (!silc_buffer_realloc(&stream->outbuf,
874 silc_buffer_truelen(&stream->outbuf) + totlen))
878 /* Pull data area for the new packet, and return pointer to the start of
879 the data area and save the pointer in to the `packet'. MAC is pulled
880 later after it's computed. */
881 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
882 silc_buffer_set(packet, oldptr, totlen);
883 silc_buffer_push_tail(packet, mac_len);
888 /* Internal routine to send packet */
890 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
892 SilcPacketFlags flags,
893 SilcIdType src_id_type,
894 unsigned char *src_id,
895 SilcUInt32 src_id_len,
896 SilcIdType dst_id_type,
897 unsigned char *dst_id,
898 SilcUInt32 dst_id_len,
899 const unsigned char *data,
904 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
905 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
906 int i, enclen, truelen, padlen, ivlen = 0, psnlen = 0;
907 SilcBufferStruct packet;
909 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d, "
910 "data len %d", silc_get_packet_name(type), stream->send_psn,
911 flags, src_id_type, dst_id_type, data_len));
913 /* Get the true length of the packet. This is saved as payload length
914 into the packet header. This does not include the length of the
916 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
917 src_id_len + dst_id_len));
918 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
919 src_id_len + dst_id_len);
921 /* If IV is included, the SID, IV and sequence number is added to packet */
922 if (stream->iv_included && cipher) {
923 psnlen = sizeof(psn);
924 ivlen = block_len + 1;
926 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
929 /* We automatically figure out the packet structure from the packet
930 type and flags, and calculate correct length. Private messages with
931 private keys and channel messages are special packets as their
932 payload is encrypted already. */
933 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
934 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
935 type == SILC_PACKET_CHANNEL_MESSAGE) {
937 /* Padding is calculated from header + IDs */
938 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
939 psnlen), block_len, padlen);
941 /* Length to encrypt, header + IDs + padding. */
942 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
946 /* Padding is calculated from true length of the packet */
947 if (flags & SILC_PACKET_FLAG_LONG_PAD)
948 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
950 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
952 enclen += padlen + psnlen;
955 /* Remove implementation specific flags */
956 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
958 /* Get random padding */
959 for (i = 0; i < padlen; i++) tmppad[i] =
960 silc_rng_get_byte_fast(stream->engine->rng);
962 silc_mutex_lock(stream->lock);
964 /* Get packet pointer from the outgoing buffer */
965 if (!silc_packet_send_prepare(stream, truelen + padlen + ivlen + psnlen,
967 silc_mutex_unlock(stream->lock);
971 SILC_PUT32_MSB(stream->send_psn, psn);
973 /* Create the packet. This creates the SILC header, adds padding, and
974 the actual packet data. */
975 i = silc_buffer_format(&packet,
976 SILC_STR_DATA(iv, ivlen),
977 SILC_STR_DATA(psn, psnlen),
978 SILC_STR_UI_SHORT(truelen),
979 SILC_STR_UI_CHAR(flags),
980 SILC_STR_UI_CHAR(type),
981 SILC_STR_UI_CHAR(padlen),
983 SILC_STR_UI_CHAR(src_id_len),
984 SILC_STR_UI_CHAR(dst_id_len),
985 SILC_STR_UI_CHAR(src_id_type),
986 SILC_STR_DATA(src_id, src_id_len),
987 SILC_STR_UI_CHAR(dst_id_type),
988 SILC_STR_DATA(dst_id, dst_id_len),
989 SILC_STR_DATA(tmppad, padlen),
990 SILC_STR_DATA(data, data_len),
993 silc_mutex_unlock(stream->lock);
997 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
998 silc_buffer_data(&packet), silc_buffer_len(&packet));
1000 /* Encrypt the packet */
1002 SILC_LOG_DEBUG(("Encrypting packet"));
1003 if (!silc_cipher_encrypt(cipher, packet.data + ivlen,
1004 packet.data + ivlen, enclen, NULL)) {
1005 SILC_LOG_ERROR(("Packet encryption failed"));
1006 silc_mutex_unlock(stream->lock);
1015 /* MAC is computed from the entire encrypted packet data, and put
1016 to the end of the packet. */
1017 silc_hmac_init(hmac);
1018 silc_hmac_update(hmac, psn, sizeof(psn));
1019 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1020 silc_hmac_final(hmac, packet.tail, &mac_len);
1021 silc_buffer_pull_tail(&packet, mac_len);
1025 /* Write the packet to the stream */
1026 while (silc_buffer_len(&stream->outbuf) > 0) {
1027 i = silc_stream_write(stream->stream, stream->outbuf.data,
1028 silc_buffer_len(&stream->outbuf));
1031 silc_buffer_reset(&stream->outbuf);
1032 silc_mutex_unlock(stream->lock);
1033 SILC_PACKET_CALLBACK_EOS(stream);
1039 silc_buffer_reset(&stream->outbuf);
1040 silc_mutex_unlock(stream->lock);
1041 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
1046 /* Cannot write now, write later. */
1047 silc_mutex_unlock(stream->lock);
1052 silc_buffer_pull(&stream->outbuf, i);
1054 silc_buffer_reset(&stream->outbuf);
1056 silc_mutex_unlock(stream->lock);
1060 /* Sends a packet */
1062 SilcBool silc_packet_send(SilcPacketStream stream,
1063 SilcPacketType type, SilcPacketFlags flags,
1064 const unsigned char *data, SilcUInt32 data_len)
1066 return silc_packet_send_raw(stream, type, flags,
1067 stream->src_id_type,
1070 stream->dst_id_type,
1074 stream->send_key[0],
1075 stream->send_hmac[0]);
1078 /* Sends a packet, extended routine */
1080 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1081 SilcPacketType type, SilcPacketFlags flags,
1082 SilcIdType src_id_type, void *src_id,
1083 SilcIdType dst_id_type, void *dst_id,
1084 const unsigned char *data, SilcUInt32 data_len,
1085 SilcCipher cipher, SilcHmac hmac)
1087 unsigned char src_id_data[32], dst_id_data[32];
1088 SilcUInt32 src_id_len, dst_id_len;
1091 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1092 sizeof(src_id_data), &src_id_len))
1095 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1096 sizeof(dst_id_data), &dst_id_len))
1099 return silc_packet_send_raw(stream, type, flags,
1100 src_id ? src_id_type : stream->src_id_type,
1101 src_id ? src_id_data : stream->src_id,
1102 src_id ? src_id_len : stream->src_id_len,
1103 dst_id ? dst_id_type : stream->dst_id_type,
1104 dst_id ? dst_id_data : stream->dst_id,
1105 dst_id ? dst_id_len : stream->dst_id_len,
1107 cipher ? cipher : stream->send_key[0],
1108 hmac ? hmac : stream->send_hmac[0]);
1111 /* Sends packet after formatting the arguments to buffer */
1113 SilcBool silc_packet_send_va(SilcPacketStream stream,
1114 SilcPacketType type, SilcPacketFlags flags, ...)
1116 SilcBufferStruct buf;
1120 va_start(va, flags);
1122 memset(&buf, 0, sizeof(buf));
1123 if (silc_buffer_format_vp(&buf, va) < 0) {
1128 ret = silc_packet_send(stream, type, flags, silc_buffer_data(&buf),
1129 silc_buffer_len(&buf));
1131 silc_buffer_purge(&buf);
1137 /* Sends packet after formatting the arguments to buffer, extended routine */
1139 SilcBool silc_packet_send_va_ext(SilcPacketStream stream,
1140 SilcPacketType type, SilcPacketFlags flags,
1141 SilcIdType src_id_type, void *src_id,
1142 SilcIdType dst_id_type, void *dst_id,
1143 SilcCipher cipher, SilcHmac hmac, ...)
1145 SilcBufferStruct buf;
1151 memset(&buf, 0, sizeof(buf));
1152 if (silc_buffer_format_vp(&buf, va) < 0) {
1157 ret = silc_packet_send_ext(stream, type, flags, src_id_type, src_id,
1158 dst_id_type, dst_id, silc_buffer_data(&buf),
1159 silc_buffer_len(&buf), cipher, hmac);
1161 silc_buffer_purge(&buf);
1167 /***************************** Packet Receiving *****************************/
1169 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1171 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1172 const unsigned char *data,
1173 SilcUInt32 data_len,
1174 const unsigned char *packet_mac,
1175 const unsigned char *packet_seq,
1176 SilcUInt32 sequence)
1180 unsigned char mac[32], psn[4];
1183 SILC_LOG_DEBUG(("Verifying MAC"));
1185 /* Compute HMAC of packet */
1186 silc_hmac_init(hmac);
1189 SILC_PUT32_MSB(sequence, psn);
1190 silc_hmac_update(hmac, psn, 4);
1192 silc_hmac_update(hmac, packet_seq, 4);
1194 silc_hmac_update(hmac, data, data_len);
1195 silc_hmac_final(hmac, mac, &mac_len);
1197 /* Compare the MAC's */
1198 if (memcmp(packet_mac, mac, mac_len)) {
1199 SILC_LOG_DEBUG(("MAC failed"));
1203 SILC_LOG_DEBUG(("MAC is Ok"));
1209 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1210 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1212 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1213 SilcUInt32 sequence, SilcBuffer buffer,
1216 if (normal == TRUE) {
1218 /* Decrypt rest of the packet */
1219 SILC_LOG_DEBUG(("Decrypting the packet"));
1220 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1221 silc_buffer_len(buffer), NULL))
1227 /* Decrypt rest of the header plus padding */
1230 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1232 SILC_LOG_DEBUG(("Decrypting the header"));
1234 /* Padding length + src id len + dst id len + header length - 16
1235 bytes already decrypted, gives the rest of the encrypted packet */
1236 silc_buffer_push(buffer, block_len);
1237 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1238 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1240 silc_buffer_pull(buffer, block_len);
1242 if (len > silc_buffer_len(buffer)) {
1243 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1247 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1256 /* Parses the packet. This is called when a whole packet is ready to be
1257 parsed. The buffer sent must be already decrypted before calling this
1260 static SilcBool silc_packet_parse(SilcPacket packet)
1262 SilcBuffer buffer = &packet->buffer;
1263 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1264 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1267 SILC_LOG_DEBUG(("Parsing incoming packet"));
1269 /* Parse the buffer. This parses the SILC header of the packet. */
1270 ret = silc_buffer_unformat(buffer,
1273 SILC_STR_UI_CHAR(&src_id_len),
1274 SILC_STR_UI_CHAR(&dst_id_len),
1275 SILC_STR_UI_CHAR(&src_id_type),
1278 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1282 if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1283 dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1284 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1285 packet->src_id_len, packet->dst_id_len));
1289 ret = silc_buffer_unformat(buffer,
1291 SILC_STR_DATA(&packet->src_id, src_id_len),
1292 SILC_STR_UI_CHAR(&dst_id_type),
1293 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1294 SILC_STR_OFFSET(padlen),
1297 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1301 if (src_id_type > SILC_ID_CHANNEL ||
1302 dst_id_type > SILC_ID_CHANNEL) {
1303 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1304 src_id_type, dst_id_type));
1308 packet->src_id_len = src_id_len;
1309 packet->dst_id_len = dst_id_len;
1310 packet->src_id_type = src_id_type;
1311 packet->dst_id_type = dst_id_type;
1313 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1314 silc_buffer_len(buffer)), buffer->head,
1315 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1317 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1318 silc_get_packet_name(packet->type)));
1323 /* Dispatch packet to application. Called with stream->lock locked. */
1325 static void silc_packet_dispatch(SilcPacket packet)
1327 SilcPacketStream stream = packet->stream;
1328 SilcPacketProcess p;
1329 SilcBool default_sent = FALSE;
1332 /* Parse the packet */
1333 if (!silc_packet_parse(packet)) {
1334 silc_mutex_unlock(stream->lock);
1335 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1336 silc_mutex_lock(stream->lock);
1337 silc_packet_free(packet);
1341 /* Dispatch packet to all packet processors that want it */
1343 if (!stream->process) {
1344 /* Send to default processor as no others exist */
1345 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1346 silc_mutex_unlock(stream->lock);
1347 if (!stream->engine->callbacks->
1348 packet_receive(stream->engine, stream, packet,
1349 stream->engine->callback_context,
1350 stream->stream_context))
1351 silc_packet_free(packet);
1352 silc_mutex_lock(stream->lock);
1356 silc_dlist_start(stream->process);
1357 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1359 /* If priority is 0 or less, we send to default processor first
1360 because default processor has 0 priority */
1361 if (!default_sent && p->priority <= 0) {
1362 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1363 default_sent = TRUE;
1364 silc_mutex_unlock(stream->lock);
1365 if (stream->engine->callbacks->
1366 packet_receive(stream->engine, stream, packet,
1367 stream->engine->callback_context,
1368 stream->stream_context)) {
1369 silc_mutex_lock(stream->lock);
1372 silc_mutex_lock(stream->lock);
1375 /* Send to processor */
1377 /* Send all packet types */
1378 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1379 silc_mutex_unlock(stream->lock);
1380 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1381 p->callback_context,
1382 stream->stream_context)) {
1383 silc_mutex_lock(stream->lock);
1386 silc_mutex_lock(stream->lock);
1388 /* Send specific types */
1389 for (pt = p->types; *pt; pt++) {
1390 if (*pt != packet->type)
1392 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1393 silc_mutex_unlock(stream->lock);
1394 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1395 p->callback_context,
1396 stream->stream_context)) {
1397 silc_mutex_lock(stream->lock);
1400 silc_mutex_lock(stream->lock);
1406 if (!default_sent) {
1407 /* Send to default processor as it has not been sent yet */
1408 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1409 silc_mutex_unlock(stream->lock);
1410 if (stream->engine->callbacks->
1411 packet_receive(stream->engine, stream, packet,
1412 stream->engine->callback_context,
1413 stream->stream_context)) {
1414 silc_mutex_lock(stream->lock);
1417 silc_mutex_lock(stream->lock);
1420 /* If we got here, no one wanted the packet, so drop it */
1421 silc_packet_free(packet);
1424 /* Process incoming data and parse packets. Called with stream->lock
1427 static void silc_packet_read_process(SilcPacketStream stream)
1433 SilcUInt16 packetlen;
1434 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1435 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1436 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1440 /* Parse the packets from the data */
1441 while (silc_buffer_len(&stream->inbuf) > 0) {
1443 cipher = stream->receive_key[0];
1444 hmac = stream->receive_hmac[0];
1447 if (silc_buffer_len(&stream->inbuf) <
1448 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1449 SILC_PACKET_MIN_HEADER_LEN)) {
1450 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1455 mac_len = silc_hmac_len(hmac);
1459 /* Decrypt first block of the packet to get the length field out */
1461 block_len = silc_cipher_get_block_len(cipher);
1463 if (stream->iv_included) {
1464 /* SID, IV and sequence number is included in the ciphertext */
1465 sid = (SilcUInt8)stream->inbuf.data[0];
1466 memcpy(iv, stream->inbuf.data + 1, block_len);
1467 ivlen = block_len + 1;
1470 /* Check SID, and get correct decryption key */
1471 if (sid != stream->sid) {
1472 /* If SID is recent get the previous key and use it */
1473 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1474 stream->receive_key[1] && !stream->receive_hmac[1]) {
1475 cipher = stream->receive_key[1];
1476 hmac = stream->receive_hmac[1];
1478 /* The SID is unknown, drop rest of the data in buffer */
1479 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1481 silc_mutex_unlock(stream->lock);
1482 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1483 silc_mutex_lock(stream->lock);
1484 silc_buffer_reset(&stream->inbuf);
1489 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1492 silc_cipher_decrypt(cipher, stream->inbuf.data + ivlen, tmp,
1496 if (stream->iv_included) {
1497 /* Take sequence number from packet */
1498 packet_seq = header;
1502 block_len = SILC_PACKET_MIN_HEADER_LEN;
1503 header = stream->inbuf.data;
1506 /* Get packet length and full packet length with padding */
1507 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1510 if (packetlen < SILC_PACKET_MIN_LEN) {
1511 SILC_LOG_ERROR(("Received too short packet"));
1512 silc_mutex_unlock(stream->lock);
1513 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1514 silc_mutex_lock(stream->lock);
1515 memset(tmp, 0, sizeof(tmp));
1516 silc_buffer_reset(&stream->inbuf);
1520 if (silc_buffer_len(&stream->inbuf) < paddedlen + ivlen + mac_len) {
1521 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1523 paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1524 memset(tmp, 0, sizeof(tmp));
1528 /* Check MAC of the packet */
1529 if (!silc_packet_check_mac(hmac, stream->inbuf.data,
1531 stream->inbuf.data + ivlen + paddedlen,
1532 packet_seq, stream->receive_psn)) {
1533 silc_mutex_unlock(stream->lock);
1534 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1535 silc_mutex_lock(stream->lock);
1536 memset(tmp, 0, sizeof(tmp));
1537 silc_buffer_reset(&stream->inbuf);
1542 packet = silc_packet_alloc(stream->engine);
1544 silc_mutex_unlock(stream->lock);
1545 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1546 silc_mutex_lock(stream->lock);
1547 memset(tmp, 0, sizeof(tmp));
1548 silc_buffer_reset(&stream->inbuf);
1551 packet->stream = stream;
1553 /* Allocate more space to packet buffer, if needed */
1554 if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1555 if (!silc_buffer_realloc(&packet->buffer,
1556 silc_buffer_truelen(&packet->buffer) +
1558 silc_buffer_truelen(&packet->buffer)))) {
1559 silc_mutex_unlock(stream->lock);
1560 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1561 silc_mutex_lock(stream->lock);
1562 silc_packet_free(packet);
1563 memset(tmp, 0, sizeof(tmp));
1564 silc_buffer_reset(&stream->inbuf);
1569 /* Parse packet header */
1570 packet->flags = (SilcPacketFlags)header[2];
1571 packet->type = (SilcPacketType)header[3];
1573 if (stream->engine->local_is_router) {
1574 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1575 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1577 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1578 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1579 stream->is_router == TRUE))
1582 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1583 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1585 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1589 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1590 stream->receive_psn, paddedlen + ivlen + mac_len),
1591 stream->inbuf.data, paddedlen + ivlen + mac_len);
1593 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1594 silc_buffer_pull_tail(&packet->buffer, paddedlen);
1595 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
1596 silc_buffer_pull(&packet->buffer, block_len - psnlen);
1597 silc_buffer_put(&packet->buffer, (stream->inbuf.data + ivlen +
1598 psnlen + (block_len - psnlen)),
1599 paddedlen - ivlen - psnlen - (block_len - psnlen));
1601 silc_cipher_set_iv(cipher, iv);
1602 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
1603 &packet->buffer, normal);
1605 silc_mutex_unlock(stream->lock);
1606 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1607 silc_mutex_lock(stream->lock);
1608 silc_packet_free(packet);
1609 memset(tmp, 0, sizeof(tmp));
1613 stream->receive_psn++;
1615 silc_buffer_push(&packet->buffer, block_len);
1617 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1618 silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1620 /* Dispatch the packet to application */
1621 silc_packet_dispatch(packet);
1624 silc_buffer_reset(&stream->inbuf);
1628 /****************************** Packet Waiting ******************************/
1630 /* Packet wait receive callback */
1632 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1633 SilcPacketStream stream,
1635 void *callback_context,
1636 void *stream_context);
1638 /* Packet waiting callbacks */
1639 static SilcPacketCallbacks silc_packet_wait_cbs =
1641 silc_packet_wait_packet_receive, NULL, NULL
1644 /* Packet waiting context */
1646 SilcMutex wait_lock;
1648 SilcList packet_queue;
1649 unsigned int stopped : 1;
1652 /* Packet wait receive callback */
1655 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1656 SilcPacketStream stream,
1658 void *callback_context,
1659 void *stream_context)
1661 SilcPacketWait pw = callback_context;
1663 /* Signal the waiting thread for a new packet */
1664 silc_mutex_lock(pw->wait_lock);
1667 silc_mutex_unlock(pw->wait_lock);
1671 silc_list_add(pw->packet_queue, packet);
1672 silc_cond_broadcast(pw->wait_cond);
1674 silc_mutex_unlock(pw->wait_lock);
1679 /* Initialize packet waiting */
1681 void *silc_packet_wait_init(SilcPacketStream stream, ...)
1687 pw = silc_calloc(1, sizeof(*pw));
1691 /* Allocate mutex and conditional variable */
1692 if (!silc_mutex_alloc(&pw->wait_lock)) {
1696 if (!silc_cond_alloc(&pw->wait_cond)) {
1697 silc_mutex_free(pw->wait_lock);
1702 /* Link to the packet stream for the requested packet types */
1703 va_start(ap, stream);
1704 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
1708 silc_cond_free(pw->wait_cond);
1709 silc_mutex_free(pw->wait_lock);
1714 /* Initialize packet queue */
1715 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
1720 /* Uninitialize packet waiting */
1722 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
1724 SilcPacketWait pw = waiter;
1727 /* Signal any threads to stop waiting */
1728 silc_mutex_lock(pw->wait_lock);
1730 silc_cond_broadcast(pw->wait_cond);
1731 silc_mutex_unlock(pw->wait_lock);
1733 /* Re-acquire lock and free resources */
1734 silc_mutex_lock(pw->wait_lock);
1735 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
1737 /* Free any remaining packets */
1738 silc_list_start(pw->packet_queue);
1739 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
1740 silc_packet_free(packet);
1742 silc_mutex_unlock(pw->wait_lock);
1743 silc_cond_free(pw->wait_cond);
1744 silc_mutex_free(pw->wait_lock);
1748 /* Blocks thread until a packet has been received. */
1750 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
1752 SilcPacketWait pw = waiter;
1753 SilcBool ret = FALSE;
1755 silc_mutex_lock(pw->wait_lock);
1757 /* Wait here until packet has arrived */
1758 while (silc_list_count(pw->packet_queue) == 0) {
1760 silc_mutex_unlock(pw->wait_lock);
1763 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
1767 silc_list_start(pw->packet_queue);
1768 *return_packet = silc_list_get(pw->packet_queue);
1769 silc_list_del(pw->packet_queue, *return_packet);
1771 silc_mutex_unlock(pw->wait_lock);
1773 return ret == TRUE ? 1 : 0;