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]);
1112 /***************************** Packet Receiving *****************************/
1114 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1116 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1117 const unsigned char *data,
1118 SilcUInt32 data_len,
1119 const unsigned char *packet_mac,
1120 const unsigned char *packet_seq,
1121 SilcUInt32 sequence)
1125 unsigned char mac[32], psn[4];
1128 SILC_LOG_DEBUG(("Verifying MAC"));
1130 /* Compute HMAC of packet */
1131 silc_hmac_init(hmac);
1134 SILC_PUT32_MSB(sequence, psn);
1135 silc_hmac_update(hmac, psn, 4);
1137 silc_hmac_update(hmac, packet_seq, 4);
1139 silc_hmac_update(hmac, data, data_len);
1140 silc_hmac_final(hmac, mac, &mac_len);
1142 /* Compare the MAC's */
1143 if (memcmp(packet_mac, mac, mac_len)) {
1144 SILC_LOG_DEBUG(("MAC failed"));
1148 SILC_LOG_DEBUG(("MAC is Ok"));
1154 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1155 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1157 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1158 SilcUInt32 sequence, SilcBuffer buffer,
1161 if (normal == TRUE) {
1163 /* Decrypt rest of the packet */
1164 SILC_LOG_DEBUG(("Decrypting the packet"));
1165 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1166 silc_buffer_len(buffer), NULL))
1172 /* Decrypt rest of the header plus padding */
1175 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1177 SILC_LOG_DEBUG(("Decrypting the header"));
1179 /* Padding length + src id len + dst id len + header length - 16
1180 bytes already decrypted, gives the rest of the encrypted packet */
1181 silc_buffer_push(buffer, block_len);
1182 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1183 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1185 silc_buffer_pull(buffer, block_len);
1187 if (len > silc_buffer_len(buffer)) {
1188 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1192 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1201 /* Parses the packet. This is called when a whole packet is ready to be
1202 parsed. The buffer sent must be already decrypted before calling this
1205 static SilcBool silc_packet_parse(SilcPacket packet)
1207 SilcBuffer buffer = &packet->buffer;
1208 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1209 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1212 SILC_LOG_DEBUG(("Parsing incoming packet"));
1214 /* Parse the buffer. This parses the SILC header of the packet. */
1215 ret = silc_buffer_unformat(buffer,
1218 SILC_STR_UI_CHAR(&src_id_len),
1219 SILC_STR_UI_CHAR(&dst_id_len),
1220 SILC_STR_UI_CHAR(&src_id_type),
1223 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1227 if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1228 dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1229 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1230 packet->src_id_len, packet->dst_id_len));
1234 ret = silc_buffer_unformat(buffer,
1236 SILC_STR_DATA(&packet->src_id, src_id_len),
1237 SILC_STR_UI_CHAR(&dst_id_type),
1238 SILC_STR_DATA(&packet->dst_id, dst_id_len),
1239 SILC_STR_OFFSET(padlen),
1242 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1246 if (src_id_type > SILC_ID_CHANNEL ||
1247 dst_id_type > SILC_ID_CHANNEL) {
1248 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1249 src_id_type, dst_id_type));
1253 packet->src_id_len = src_id_len;
1254 packet->dst_id_len = dst_id_len;
1255 packet->src_id_type = src_id_type;
1256 packet->dst_id_type = dst_id_type;
1258 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_headlen(buffer) +
1259 silc_buffer_len(buffer)), buffer->head,
1260 silc_buffer_headlen(buffer) + silc_buffer_len(buffer));
1262 SILC_LOG_DEBUG(("Incoming packet type: %d (%s)", packet->type,
1263 silc_get_packet_name(packet->type)));
1268 /* Dispatch packet to application. Called with stream->lock locked. */
1270 static void silc_packet_dispatch(SilcPacket packet)
1272 SilcPacketStream stream = packet->stream;
1273 SilcPacketProcess p;
1274 SilcBool default_sent = FALSE;
1277 /* Parse the packet */
1278 if (!silc_packet_parse(packet)) {
1279 silc_mutex_unlock(stream->lock);
1280 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1281 silc_mutex_lock(stream->lock);
1282 silc_packet_free(packet);
1286 /* Dispatch packet to all packet processors that want it */
1288 if (!stream->process) {
1289 /* Send to default processor as no others exist */
1290 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1291 silc_mutex_unlock(stream->lock);
1292 if (!stream->engine->callbacks->
1293 packet_receive(stream->engine, stream, packet,
1294 stream->engine->callback_context,
1295 stream->stream_context))
1296 silc_packet_free(packet);
1297 silc_mutex_lock(stream->lock);
1301 silc_dlist_start(stream->process);
1302 while ((p = silc_dlist_get(stream->process)) != SILC_LIST_END) {
1304 /* If priority is 0 or less, we send to default processor first
1305 because default processor has 0 priority */
1306 if (!default_sent && p->priority <= 0) {
1307 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1308 default_sent = TRUE;
1309 silc_mutex_unlock(stream->lock);
1310 if (stream->engine->callbacks->
1311 packet_receive(stream->engine, stream, packet,
1312 stream->engine->callback_context,
1313 stream->stream_context)) {
1314 silc_mutex_lock(stream->lock);
1317 silc_mutex_lock(stream->lock);
1320 /* Send to processor */
1322 /* Send all packet types */
1323 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1324 silc_mutex_unlock(stream->lock);
1325 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1326 p->callback_context,
1327 stream->stream_context)) {
1328 silc_mutex_lock(stream->lock);
1331 silc_mutex_lock(stream->lock);
1333 /* Send specific types */
1334 for (pt = p->types; *pt; pt++) {
1335 if (*pt != packet->type)
1337 SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
1338 silc_mutex_unlock(stream->lock);
1339 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1340 p->callback_context,
1341 stream->stream_context)) {
1342 silc_mutex_lock(stream->lock);
1345 silc_mutex_lock(stream->lock);
1351 if (!default_sent) {
1352 /* Send to default processor as it has not been sent yet */
1353 SILC_LOG_DEBUG(("Dispatching packet to default callbacks"));
1354 silc_mutex_unlock(stream->lock);
1355 if (stream->engine->callbacks->
1356 packet_receive(stream->engine, stream, packet,
1357 stream->engine->callback_context,
1358 stream->stream_context)) {
1359 silc_mutex_lock(stream->lock);
1362 silc_mutex_lock(stream->lock);
1365 /* If we got here, no one wanted the packet, so drop it */
1366 silc_packet_free(packet);
1369 /* Process incoming data and parse packets. Called with stream->lock
1372 static void silc_packet_read_process(SilcPacketStream stream)
1378 SilcUInt16 packetlen;
1379 SilcUInt32 paddedlen, mac_len, block_len, ivlen, psnlen;
1380 unsigned char tmp[SILC_PACKET_MIN_HEADER_LEN], *header;
1381 unsigned char iv[SILC_CIPHER_MAX_IV_SIZE], *packet_seq = NULL;
1382 SilcBool normal = TRUE;
1385 /* Parse the packets from the data */
1386 while (silc_buffer_len(&stream->inbuf) > 0) {
1388 cipher = stream->receive_key[0];
1389 hmac = stream->receive_hmac[0];
1391 if (silc_buffer_len(&stream->inbuf) <
1392 (stream->iv_included ? SILC_PACKET_MIN_HEADER_LEN_IV :
1393 SILC_PACKET_MIN_HEADER_LEN)) {
1394 SILC_LOG_DEBUG(("Partial packet in queue, waiting for the rest"));
1399 mac_len = silc_hmac_len(hmac);
1403 /* Decrypt first block of the packet to get the length field out */
1405 block_len = silc_cipher_get_block_len(cipher);
1407 if (stream->iv_included) {
1408 /* SID, IV and sequence number is included in the ciphertext */
1409 sid = (SilcUInt8)stream->inbuf.data[0];
1410 memcpy(iv, stream->inbuf.data + 1, block_len);
1411 ivlen = block_len + 1;
1414 /* Check SID, and get correct decryption key */
1415 if (sid != stream->sid) {
1416 /* If SID is recent get the previous key and use it */
1417 if (sid > 0 && stream->sid > 0 && stream->sid - 1 == sid &&
1418 stream->receive_key[1] && !stream->receive_hmac[1]) {
1419 cipher = stream->receive_key[1];
1420 hmac = stream->receive_hmac[1];
1422 /* The SID is unknown, drop rest of the data in buffer */
1423 SILC_LOG_DEBUG(("Unknown Security ID %d in packet, expected %d",
1425 silc_mutex_unlock(stream->lock);
1426 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_UNKNOWN_SID);
1427 silc_mutex_lock(stream->lock);
1428 silc_buffer_reset(&stream->inbuf);
1433 memcpy(iv, silc_cipher_get_iv(cipher), block_len);
1436 silc_cipher_decrypt(cipher, stream->inbuf.data + ivlen, tmp,
1440 if (stream->iv_included) {
1441 /* Take sequence number from packet */
1442 packet_seq = header;
1446 block_len = SILC_PACKET_MIN_HEADER_LEN;
1447 header = stream->inbuf.data;
1450 /* Get packet length and full packet length with padding */
1451 SILC_PACKET_LENGTH(header, packetlen, paddedlen);
1454 if (packetlen < SILC_PACKET_MIN_LEN) {
1455 SILC_LOG_ERROR(("Received too short packet"));
1456 silc_mutex_unlock(stream->lock);
1457 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1458 silc_mutex_lock(stream->lock);
1459 memset(tmp, 0, sizeof(tmp));
1460 silc_buffer_reset(&stream->inbuf);
1464 if (silc_buffer_len(&stream->inbuf) < paddedlen + ivlen + mac_len) {
1465 SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
1467 paddedlen + mac_len - silc_buffer_len(&stream->inbuf)));
1468 memset(tmp, 0, sizeof(tmp));
1472 /* Check MAC of the packet */
1473 if (!silc_packet_check_mac(hmac, stream->inbuf.data,
1475 stream->inbuf.data + ivlen + paddedlen,
1476 packet_seq, stream->receive_psn)) {
1477 silc_mutex_unlock(stream->lock);
1478 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MAC_FAILED);
1479 silc_mutex_lock(stream->lock);
1480 memset(tmp, 0, sizeof(tmp));
1481 silc_buffer_reset(&stream->inbuf);
1486 packet = silc_packet_alloc(stream->engine);
1488 silc_mutex_unlock(stream->lock);
1489 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1490 silc_mutex_lock(stream->lock);
1491 memset(tmp, 0, sizeof(tmp));
1492 silc_buffer_reset(&stream->inbuf);
1496 /* Allocate more space to packet buffer, if needed */
1497 if (silc_buffer_truelen(&packet->buffer) < paddedlen) {
1498 if (!silc_buffer_realloc(&packet->buffer,
1499 silc_buffer_truelen(&packet->buffer) +
1501 silc_buffer_truelen(&packet->buffer)))) {
1502 silc_mutex_unlock(stream->lock);
1503 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_NO_MEMORY);
1504 silc_mutex_lock(stream->lock);
1505 silc_packet_free(packet);
1506 memset(tmp, 0, sizeof(tmp));
1507 silc_buffer_reset(&stream->inbuf);
1512 /* Parse packet header */
1513 packet->flags = (SilcPacketFlags)header[2];
1514 packet->type = (SilcPacketType)header[3];
1516 if (stream->engine->local_is_router) {
1517 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1518 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1520 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE ||
1521 (packet->type == SILC_PACKET_CHANNEL_MESSAGE &&
1522 stream->is_router == TRUE))
1525 if (packet->type == SILC_PACKET_PRIVATE_MESSAGE &&
1526 (packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY))
1528 else if (packet->type != SILC_PACKET_CHANNEL_MESSAGE)
1532 SILC_LOG_HEXDUMP(("Incoming packet (%d) len %d",
1533 stream->receive_psn, paddedlen + ivlen + mac_len),
1534 stream->inbuf.data, paddedlen + ivlen + mac_len);
1536 /* Put the decrypted part, and rest of the encrypted data, and decrypt */
1537 silc_buffer_pull_tail(&packet->buffer, paddedlen);
1538 silc_buffer_put(&packet->buffer, header, block_len - psnlen);
1539 silc_buffer_pull(&packet->buffer, block_len - psnlen);
1540 silc_buffer_put(&packet->buffer, (stream->inbuf.data + ivlen +
1541 psnlen + (block_len - psnlen)),
1542 paddedlen - ivlen - psnlen - (block_len - psnlen));
1544 silc_cipher_set_iv(cipher, iv);
1545 ret = silc_packet_decrypt(cipher, hmac, stream->receive_psn,
1546 &packet->buffer, normal);
1548 silc_mutex_unlock(stream->lock);
1549 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_DECRYPTION_FAILED);
1550 silc_mutex_lock(stream->lock);
1551 silc_packet_free(packet);
1552 memset(tmp, 0, sizeof(tmp));
1556 stream->receive_psn++;
1558 silc_buffer_push(&packet->buffer, block_len);
1560 /* Pull the packet from inbuf thus we'll get the next one in the inbuf. */
1561 silc_buffer_pull(&stream->inbuf, paddedlen + mac_len);
1563 /* Dispatch the packet to application */
1564 packet->stream = stream;
1565 silc_packet_dispatch(packet);
1568 silc_buffer_reset(&stream->inbuf);
1572 /****************************** Packet Waiting ******************************/
1574 /* Packet wait receive callback */
1576 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1577 SilcPacketStream stream,
1579 void *callback_context,
1580 void *stream_context);
1582 /* Packet waiting callbacks */
1583 static SilcPacketCallbacks silc_packet_wait_cbs =
1585 silc_packet_wait_packet_receive, NULL, NULL
1588 /* Packet waiting context */
1590 SilcMutex wait_lock;
1592 SilcList packet_queue;
1593 unsigned int stopped : 1;
1596 /* Packet wait receive callback */
1599 silc_packet_wait_packet_receive(SilcPacketEngine engine,
1600 SilcPacketStream stream,
1602 void *callback_context,
1603 void *stream_context)
1605 SilcPacketWait pw = callback_context;
1607 /* Signal the waiting thread for a new packet */
1608 silc_mutex_lock(pw->wait_lock);
1611 silc_mutex_unlock(pw->wait_lock);
1615 silc_list_add(pw->packet_queue, packet);
1616 silc_cond_broadcast(pw->wait_cond);
1618 silc_mutex_unlock(pw->wait_lock);
1623 /* Initialize packet waiting */
1625 void *silc_packet_wait_init(SilcPacketStream stream, ...)
1631 pw = silc_calloc(1, sizeof(*pw));
1635 /* Allocate mutex and conditional variable */
1636 if (!silc_mutex_alloc(&pw->wait_lock)) {
1640 if (!silc_cond_alloc(&pw->wait_cond)) {
1641 silc_mutex_free(pw->wait_lock);
1646 /* Link to the packet stream for the requested packet types */
1647 va_start(ap, stream);
1648 ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
1652 silc_cond_free(pw->wait_cond);
1653 silc_mutex_free(pw->wait_lock);
1658 /* Initialize packet queue */
1659 silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
1664 /* Uninitialize packet waiting */
1666 void silc_packet_wait_uninit(void *waiter, SilcPacketStream stream)
1668 SilcPacketWait pw = waiter;
1671 /* Signal any threads to stop waiting */
1672 silc_mutex_lock(pw->wait_lock);
1674 silc_cond_broadcast(pw->wait_cond);
1675 silc_mutex_unlock(pw->wait_lock);
1677 /* Re-acquire lock and free resources */
1678 silc_mutex_lock(pw->wait_lock);
1679 silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
1681 /* Free any remaining packets */
1682 silc_list_start(pw->packet_queue);
1683 while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
1684 silc_packet_free(packet);
1686 silc_mutex_unlock(pw->wait_lock);
1687 silc_cond_free(pw->wait_cond);
1688 silc_mutex_free(pw->wait_lock);
1692 /* Blocks thread until a packet has been received. */
1694 int silc_packet_wait(void *waiter, int timeout, SilcPacket *return_packet)
1696 SilcPacketWait pw = waiter;
1697 SilcBool ret = FALSE;
1699 silc_mutex_lock(pw->wait_lock);
1701 /* Wait here until packet has arrived */
1702 while (silc_list_count(pw->packet_queue) == 0) {
1704 silc_mutex_unlock(pw->wait_lock);
1707 ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
1711 silc_list_start(pw->packet_queue);
1712 *return_packet = silc_list_get(pw->packet_queue);
1713 silc_list_del(pw->packet_queue, *return_packet);
1715 silc_mutex_unlock(pw->wait_lock);
1717 return ret == TRUE ? 1 : 0;