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 SilcAtomic refcnt; /* Reference counter */
51 SilcPacketEngine engine; /* Packet engine */
52 SilcStream stream; /* Underlaying stream */
53 SilcMutex lock; /* Stream lock */
54 SilcDList process; /* Packet processors, it set */
55 void *stream_context; /* Stream context */
56 SilcBufferStruct inbuf; /* In buffer */
57 SilcBufferStruct outbuf; /* Out buffer */
58 SilcUInt32 send_psn; /* Sending sequence */
59 SilcCipher send_key[2]; /* Sending key */
60 SilcHmac send_hmac[2]; /* Sending HMAC */
61 SilcUInt32 receive_psn; /* Receiving sequence */
62 SilcCipher receive_key[2]; /* Receiving key */
63 SilcHmac receive_hmac[2]; /* Receiving HMAC */
64 unsigned char *src_id; /* Source ID */
65 unsigned char *dst_id; /* Destination ID */
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_init(&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_int(&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_uninit(&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_int(&stream->refcnt, 1);
609 /* Unreference packet stream */
611 void silc_packet_stream_unref(SilcPacketStream stream)
613 if (silc_atomic_sub_int(&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 /* Return underlaying stream */
646 SilcStream silc_packet_stream_get_stream(SilcPacketStream stream)
648 return stream->stream;
651 /* Set ciphers for packet stream */
653 void silc_packet_set_ciphers(SilcPacketStream stream, SilcCipher send,
656 SILC_LOG_DEBUG(("Setting new ciphers to packet stream"));
658 silc_mutex_lock(stream->lock);
660 /* In case IV Included is set, save the old key */
661 if (stream->iv_included) {
662 if (stream->send_key[1]) {
663 silc_cipher_free(stream->send_key[1]);
664 stream->send_key[1] = stream->send_key[0];
666 if (stream->receive_key[1]) {
667 silc_cipher_free(stream->receive_key[1]);
668 stream->receive_key[1] = stream->receive_key[0];
671 stream->send_key[0] = send;
672 stream->receive_key[0] = receive;
674 if (stream->send_key[0])
675 silc_cipher_free(stream->send_key[0]);
676 if (stream->send_key[1])
677 silc_cipher_free(stream->receive_key[0]);
679 stream->send_key[0] = send;
680 stream->receive_key[0] = receive;
683 silc_mutex_unlock(stream->lock);
686 /* Return current ciphers from packet stream */
688 SilcBool silc_packet_get_ciphers(SilcPacketStream stream, SilcCipher *send,
691 if (!stream->send_key[0] && !stream->receive_key[0])
694 silc_mutex_lock(stream->lock);
697 *send = stream->send_key[0];
699 *receive = stream->receive_key[0];
701 silc_mutex_unlock(stream->lock);
706 /* Set HMACs for packet stream */
708 void silc_packet_set_hmacs(SilcPacketStream stream, SilcHmac send,
711 SILC_LOG_DEBUG(("Setting new HMACs to packet stream"));
713 silc_mutex_lock(stream->lock);
715 /* In case IV Included is set, save the old HMAC */
716 if (stream->iv_included) {
717 if (stream->send_hmac[1]) {
718 silc_hmac_free(stream->send_hmac[1]);
719 stream->send_hmac[1] = stream->send_hmac[0];
721 if (stream->receive_hmac[1]) {
722 silc_hmac_free(stream->receive_hmac[1]);
723 stream->receive_hmac[1] = stream->receive_hmac[0];
726 stream->send_hmac[0] = send;
727 stream->receive_hmac[0] = receive;
729 if (stream->send_hmac[0])
730 silc_hmac_free(stream->send_hmac[0]);
731 if (stream->receive_hmac[0])
732 silc_hmac_free(stream->receive_hmac[0]);
734 stream->send_hmac[0] = send;
735 stream->receive_hmac[0] = receive;
738 silc_mutex_unlock(stream->lock);
741 /* Return current HMACs from packet stream */
743 SilcBool silc_packet_get_hmacs(SilcPacketStream stream, SilcHmac *send,
746 if (!stream->send_hmac[0] && !stream->receive_hmac[0])
749 silc_mutex_lock(stream->lock);
752 *send = stream->send_hmac[0];
754 *receive = stream->receive_hmac[0];
756 silc_mutex_unlock(stream->lock);
761 /* Set SILC IDs to packet stream */
763 SilcBool silc_packet_set_ids(SilcPacketStream stream,
764 SilcIdType src_id_type, const void *src_id,
765 SilcIdType dst_id_type, const void *dst_id)
768 unsigned char tmp[32];
770 if (!src_id && !dst_id)
773 SILC_LOG_DEBUG(("Setting new IDs to packet stream"));
775 silc_mutex_lock(stream->lock);
778 silc_free(stream->src_id);
779 if (!silc_id_id2str(src_id, src_id_type, tmp, sizeof(tmp), &len)) {
780 silc_mutex_unlock(stream->lock);
783 stream->src_id = silc_memdup(tmp, len);
784 if (!stream->src_id) {
785 silc_mutex_unlock(stream->lock);
788 stream->src_id_type = src_id_type;
789 stream->src_id_len = len;
793 silc_free(stream->dst_id);
794 if (!silc_id_id2str(dst_id, dst_id_type, tmp, sizeof(tmp), &len)) {
795 silc_mutex_unlock(stream->lock);
798 stream->dst_id = silc_memdup(tmp, len);
799 if (!stream->dst_id) {
800 silc_mutex_unlock(stream->lock);
803 stream->dst_id_type = dst_id_type;
804 stream->dst_id_len = len;
807 silc_mutex_unlock(stream->lock);
812 /* Adds Security ID (SID) */
814 SilcBool silc_packet_set_sid(SilcPacketStream stream, SilcUInt8 sid)
816 if (!stream->iv_included)
819 SILC_LOG_DEBUG(("Set packet stream %p SID to %d", stream, sid));
827 void silc_packet_free(SilcPacket packet)
829 SilcPacketStream stream = packet->stream;
831 SILC_LOG_DEBUG(("Freeing packet %p", packet));
833 #if defined(SILC_DEBUG)
834 /* Check for double free */
835 assert(packet->stream != NULL);
836 #endif /* SILC_DEBUG */
838 silc_mutex_lock(stream->engine->lock);
840 packet->stream = NULL;
841 packet->src_id = packet->dst_id = NULL;
842 silc_buffer_reset(&packet->buffer);
844 /* Put the packet back to freelist */
845 silc_list_add(stream->engine->packet_pool, packet);
846 if (silc_list_count(stream->engine->packet_pool) == 1)
847 silc_list_start(stream->engine->packet_pool);
849 silc_mutex_unlock(stream->engine->lock);
852 /****************************** Packet Sending ******************************/
854 /* Prepare outgoing data buffer for packet sending. Returns the
855 pointer to that buffer into the `packet'. */
857 static SilcBool silc_packet_send_prepare(SilcPacketStream stream,
862 unsigned char *oldptr;
863 unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
867 /* Allocate more space if needed */
868 if (silc_buffer_taillen(&stream->outbuf) < totlen) {
869 if (!silc_buffer_realloc(&stream->outbuf,
870 silc_buffer_truelen(&stream->outbuf) + totlen))
874 /* Pull data area for the new packet, and return pointer to the start of
875 the data area and save the pointer in to the `packet'. MAC is pulled
876 later after it's computed. */
877 oldptr = silc_buffer_pull_tail(&stream->outbuf, totlen);
878 silc_buffer_set(packet, oldptr, totlen);
879 silc_buffer_push_tail(packet, mac_len);
884 /* Internal routine to send packet */
886 static SilcBool silc_packet_send_raw(SilcPacketStream stream,
888 SilcPacketFlags flags,
889 SilcIdType src_id_type,
890 unsigned char *src_id,
891 SilcUInt32 src_id_len,
892 SilcIdType dst_id_type,
893 unsigned char *dst_id,
894 SilcUInt32 dst_id_len,
895 const unsigned char *data,
900 unsigned char tmppad[SILC_PACKET_MAX_PADLEN], iv[33], psn[4];
901 int block_len = (cipher ? silc_cipher_get_block_len(cipher) : 0);
902 int i, enclen, truelen, padlen, ivlen = 0, psnlen = 0;
903 SilcBufferStruct packet;
905 SILC_LOG_DEBUG(("Sending packet %s (%d) flags %d, src %d dst %d,"
906 "data len %d", silc_get_packet_name(type), stream->send_psn,
907 flags, src_id_type, dst_id_type, data_len));
909 /* Get the true length of the packet. This is saved as payload length
910 into the packet header. This does not include the length of the
912 data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
913 src_id_len + dst_id_len));
914 enclen = truelen = (data_len + SILC_PACKET_HEADER_LEN +
915 src_id_len + dst_id_len);
917 /* If IV is included, the SID, IV and sequence number is added to packet */
918 if (stream->iv_included && cipher) {
919 psnlen = sizeof(psn);
920 ivlen = block_len + 1;
922 memcpy(iv + 1, silc_cipher_get_iv(cipher), block_len);
925 /* We automatically figure out the packet structure from the packet
926 type and flags, and calculate correct length. Private messages with
927 private keys and channel messages are special packets as their
928 payload is encrypted already. */
929 if ((type == SILC_PACKET_PRIVATE_MESSAGE &&
930 flags & SILC_PACKET_FLAG_PRIVMSG_KEY) ||
931 type == SILC_PACKET_CHANNEL_MESSAGE) {
933 /* Padding is calculated from header + IDs */
934 SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
935 psnlen), block_len, padlen);
937 /* Length to encrypt, header + IDs + padding. */
938 enclen = (SILC_PACKET_HEADER_LEN + src_id_len + dst_id_len +
942 /* Padding is calculated from true length of the packet */
943 if (flags & SILC_PACKET_FLAG_LONG_PAD)
944 SILC_PACKET_PADLEN_MAX(truelen + psnlen, block_len, padlen);
946 SILC_PACKET_PADLEN(truelen + psnlen, block_len, padlen);
948 enclen += padlen + psnlen;
951 /* Remove implementation specific flags */
952 flags &= ~(SILC_PACKET_FLAG_LONG_PAD);
954 /* Get random padding */
955 for (i = 0; i < padlen; i++) tmppad[i] =
956 silc_rng_get_byte_fast(stream->engine->rng);
958 silc_mutex_lock(stream->lock);
960 /* Get packet pointer from the outgoing buffer */
961 if (!silc_packet_send_prepare(stream, truelen + padlen + ivlen + psnlen,
963 silc_mutex_unlock(stream->lock);
967 SILC_PUT32_MSB(stream->send_psn, psn);
969 /* Create the packet. This creates the SILC header, adds padding, and
970 the actual packet data. */
971 i = silc_buffer_format(&packet,
972 SILC_STR_UI_XNSTRING(iv, ivlen),
973 SILC_STR_UI_XNSTRING(psn, psnlen),
974 SILC_STR_UI_SHORT(truelen),
975 SILC_STR_UI_CHAR(flags),
976 SILC_STR_UI_CHAR(type),
977 SILC_STR_UI_CHAR(padlen),
979 SILC_STR_UI_CHAR(src_id_len),
980 SILC_STR_UI_CHAR(dst_id_len),
981 SILC_STR_UI_CHAR(src_id_type),
982 SILC_STR_UI_XNSTRING(src_id, src_id_len),
983 SILC_STR_UI_CHAR(dst_id_type),
984 SILC_STR_UI_XNSTRING(dst_id, dst_id_len),
985 SILC_STR_UI_XNSTRING(tmppad, padlen),
986 SILC_STR_UI_XNSTRING(data, data_len),
989 silc_mutex_unlock(stream->lock);
993 SILC_LOG_HEXDUMP(("Assembled packet, len %d", silc_buffer_len(&packet)),
994 silc_buffer_data(&packet), silc_buffer_len(&packet));
996 /* Encrypt the packet */
998 SILC_LOG_DEBUG(("Encrypting packet"));
999 if (!silc_cipher_encrypt(cipher, packet.data + ivlen,
1000 packet.data + ivlen, enclen, NULL)) {
1001 SILC_LOG_ERROR(("Packet encryption failed"));
1002 silc_mutex_unlock(stream->lock);
1011 /* MAC is computed from the entire encrypted packet data, and put
1012 to the end of the packet. */
1013 silc_hmac_init(hmac);
1014 silc_hmac_update(hmac, psn, sizeof(psn));
1015 silc_hmac_update(hmac, packet.data, silc_buffer_len(&packet));
1016 silc_hmac_final(hmac, packet.tail, &mac_len);
1017 silc_buffer_pull_tail(&packet, mac_len);
1021 /* Write the packet to the stream */
1022 while (silc_buffer_len(&stream->outbuf) > 0) {
1023 i = silc_stream_write(stream->stream, stream->outbuf.data,
1024 silc_buffer_len(&stream->outbuf));
1027 silc_buffer_reset(&stream->outbuf);
1028 silc_mutex_unlock(stream->lock);
1029 SILC_PACKET_CALLBACK_EOS(stream);
1035 silc_buffer_reset(&stream->outbuf);
1036 silc_mutex_unlock(stream->lock);
1037 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_WRITE);
1042 /* Cannot write now, write later. */
1043 silc_mutex_unlock(stream->lock);
1048 silc_buffer_pull(&stream->outbuf, i);
1050 silc_buffer_reset(&stream->outbuf);
1052 silc_mutex_unlock(stream->lock);
1056 /* Sends a packet */
1058 SilcBool silc_packet_send(SilcPacketStream stream,
1059 SilcPacketType type, SilcPacketFlags flags,
1060 const unsigned char *data, SilcUInt32 data_len)
1062 return silc_packet_send_raw(stream, type, flags,
1063 stream->src_id_type,
1066 stream->dst_id_type,
1070 stream->send_key[0],
1071 stream->send_hmac[0]);
1074 /* Sends a packet, extended routine */
1076 SilcBool silc_packet_send_ext(SilcPacketStream stream,
1077 SilcPacketType type, SilcPacketFlags flags,
1078 SilcIdType src_id_type, void *src_id,
1079 SilcIdType dst_id_type, void *dst_id,
1080 const unsigned char *data, SilcUInt32 data_len,
1081 SilcCipher cipher, SilcHmac hmac)
1083 unsigned char src_id_data[32], dst_id_data[32];
1084 SilcUInt32 src_id_len, dst_id_len;
1087 if (!silc_id_id2str(src_id, src_id_type, src_id_data,
1088 sizeof(src_id_data), &src_id_len))
1091 if (!silc_id_id2str(dst_id, dst_id_type, dst_id_data,
1092 sizeof(dst_id_data), &dst_id_len))
1095 return silc_packet_send_raw(stream, type, flags,
1096 src_id ? src_id_type : stream->src_id_type,
1097 src_id ? src_id_data : stream->src_id,
1098 src_id ? src_id_len : stream->src_id_len,
1099 dst_id ? dst_id_type : stream->dst_id_type,
1100 dst_id ? dst_id_data : stream->dst_id,
1101 dst_id ? dst_id_len : stream->dst_id_len,
1103 cipher ? cipher : stream->send_key[0],
1104 hmac ? hmac : stream->send_hmac[0]);
1108 /***************************** Packet Receiving *****************************/
1110 /* Checks MAC in the packet. Returns TRUE if MAC is Ok. */
1112 static SilcBool silc_packet_check_mac(SilcHmac hmac,
1113 const unsigned char *data,
1114 SilcUInt32 data_len,
1115 const unsigned char *packet_mac,
1116 const unsigned char *packet_seq,
1117 SilcUInt32 sequence)
1121 unsigned char mac[32], psn[4];
1124 SILC_LOG_DEBUG(("Verifying MAC"));
1126 /* Compute HMAC of packet */
1127 silc_hmac_init(hmac);
1130 SILC_PUT32_MSB(sequence, psn);
1131 silc_hmac_update(hmac, psn, 4);
1133 silc_hmac_update(hmac, packet_seq, 4);
1135 silc_hmac_update(hmac, data, data_len);
1136 silc_hmac_final(hmac, mac, &mac_len);
1138 /* Compare the MAC's */
1139 if (memcmp(packet_mac, mac, mac_len)) {
1140 SILC_LOG_DEBUG(("MAC failed"));
1144 SILC_LOG_DEBUG(("MAC is Ok"));
1150 /* Decrypts SILC packet. Handles both normal and special packet decryption.
1151 Return 0 when packet is normal and 1 when it it special, -1 on error. */
1153 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
1154 SilcUInt32 sequence, SilcBuffer buffer,
1157 if (normal == TRUE) {
1159 /* Decrypt rest of the packet */
1160 SILC_LOG_DEBUG(("Decrypting the packet"));
1161 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1162 silc_buffer_len(buffer), NULL))
1168 /* Decrypt rest of the header plus padding */
1171 SilcUInt32 block_len = silc_cipher_get_block_len(cipher);
1173 SILC_LOG_DEBUG(("Decrypting the header"));
1175 /* Padding length + src id len + dst id len + header length - 16
1176 bytes already decrypted, gives the rest of the encrypted packet */
1177 silc_buffer_push(buffer, block_len);
1178 len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
1179 (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
1181 silc_buffer_pull(buffer, block_len);
1183 if (len > silc_buffer_len(buffer)) {
1184 SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
1188 if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
1197 /* Parses the packet. This is called when a whole packet is ready to be
1198 parsed. The buffer sent must be already decrypted before calling this
1201 static SilcBool silc_packet_parse(SilcPacket packet)
1203 SilcBuffer buffer = &packet->buffer;
1204 SilcUInt8 padlen = (SilcUInt8)buffer->data[4];
1205 SilcUInt8 src_id_len, dst_id_len, src_id_type, dst_id_type;
1208 SILC_LOG_DEBUG(("Parsing incoming packet"));
1210 /* Parse the buffer. This parses the SILC header of the packet. */
1211 len = silc_buffer_unformat(buffer,
1213 SILC_STR_UI_CHAR(&src_id_len),
1214 SILC_STR_UI_CHAR(&dst_id_len),
1215 SILC_STR_UI_CHAR(&src_id_type),
1218 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1222 if (src_id_len > SILC_PACKET_MAX_ID_LEN ||
1223 dst_id_len > SILC_PACKET_MAX_ID_LEN) {
1224 SILC_LOG_ERROR(("Bad ID lengths in packet (%d and %d)",
1225 packet->src_id_len, packet->dst_id_len));
1229 ret = silc_buffer_unformat(buffer,
1230 SILC_STR_OFFSET(len),
1231 SILC_STR_UI_XNSTRING(&packet->src_id,
1233 SILC_STR_UI_CHAR(&dst_id_type),
1234 SILC_STR_UI_XNSTRING(&packet->dst_id,
1236 SILC_STR_OFFSET(padlen),
1239 SILC_LOG_ERROR(("Malformed packet header, packet dropped"));
1243 if (src_id_type > SILC_ID_CHANNEL ||
1244 dst_id_type > SILC_ID_CHANNEL) {
1245 SILC_LOG_ERROR(("Bad ID types in packet (%d and %d)",
1246 src_id_type, dst_id_type));
1250 packet->src_id_len = src_id_len;
1251 packet->dst_id_len = dst_id_len;
1252 packet->src_id_type = src_id_type;
1253 packet->dst_id_type = dst_id_type;
1255 SILC_LOG_HEXDUMP(("Parsed packet, len %d", silc_buffer_len(buffer)),
1256 buffer->data, silc_buffer_len(buffer));
1258 /* Pull SILC header and padding from packet to get the data payload */
1259 silc_buffer_pull(buffer, SILC_PACKET_HEADER_LEN +
1260 packet->src_id_len + packet->dst_id_len + padlen);
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(packet->stream->lock);
1280 SILC_PACKET_CALLBACK_ERROR(stream, SILC_PACKET_ERR_MALFORMED);
1281 silc_mutex_lock(packet->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(packet->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(packet->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(packet->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(packet->stream->lock);
1317 silc_mutex_lock(packet->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(packet->stream->lock);
1325 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1326 p->callback_context,
1327 stream->stream_context)) {
1328 silc_mutex_lock(packet->stream->lock);
1331 silc_mutex_lock(packet->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(packet->stream->lock);
1339 if (p->callbacks->packet_receive(stream->engine, stream, packet,
1340 p->callback_context,
1341 stream->stream_context)) {
1342 silc_mutex_lock(packet->stream->lock);
1345 silc_mutex_lock(packet->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(packet->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(packet->stream->lock);
1362 silc_mutex_lock(packet->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;