+
+
+/****************************** Packet Waiting ******************************/
+
+/* Packet wait receive callback */
+static SilcBool
+silc_packet_wait_packet_receive(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ SilcPacket packet,
+ void *callback_context,
+ void *stream_context);
+
+/* Packet waiting callbacks */
+static SilcPacketCallbacks silc_packet_wait_cbs =
+{
+ silc_packet_wait_packet_receive, NULL, NULL
+};
+
+/* Packet waiting context */
+typedef struct {
+ SilcMutex wait_lock;
+ SilcCond wait_cond;
+ SilcList packet_queue;
+ SilcBool waiting;
+} *SilcPacketWait;
+
+/* Packet wait receive callback */
+
+static SilcBool
+silc_packet_wait_packet_receive(SilcPacketEngine engine,
+ SilcPacketStream stream,
+ SilcPacket packet,
+ void *callback_context,
+ void *stream_context)
+{
+ SilcPacketWait pw = callback_context;
+
+ /* Signal the waiting thread for a new packet */
+ silc_mutex_lock(pw->wait_lock);
+
+ if (!pw->waiting) {
+ silc_mutex_unlock(pw->wait_lock);
+ return FALSE;
+ }
+
+ silc_list_add(pw->packet_queue, packet);
+ silc_cond_broadcast(pw->wait_cond);
+
+ silc_mutex_unlock(pw->wait_lock);
+
+ return TRUE;
+}
+
+/* Initialize packet waiting */
+
+void *silc_packet_wait_init(SilcPacketStream stream, ...)
+{
+ SilcPacketWait pw;
+ SilcBool ret;
+ va_list ap;
+
+ pw = silc_calloc(1, sizeof(*pw));
+ if (!pw)
+ return NULL;
+
+ /* Allocate mutex and conditional variable */
+ if (!silc_mutex_alloc(&pw->wait_lock)) {
+ silc_free(pw);
+ return NULL;
+ }
+ if (!silc_cond_alloc(&pw->wait_cond)) {
+ silc_mutex_free(pw->wait_lock);
+ silc_free(pw);
+ return NULL;
+ }
+
+ /* Link to the packet stream for the requested packet types */
+ va_start(ap, stream);
+ ret = silc_packet_stream_link_va(stream, &silc_packet_wait_cbs, pw,
+ 10000000, ap);
+ va_end(ap);
+ if (!ret) {
+ silc_cond_free(pw->wait_cond);
+ silc_mutex_free(pw->wait_lock);
+ silc_free(pw);
+ return NULL;
+ }
+
+ /* Initialize packet queue */
+ silc_list_init(pw->packet_queue, struct SilcPacketStruct, next);
+
+ return (void *)pw;
+}
+
+/* Uninitialize packet waiting */
+
+void silc_packet_wait_uninit(void *context, SilcPacketStream stream)
+{
+ SilcPacketWait pw = context;
+ SilcPacket packet;
+
+ silc_mutex_lock(pw->wait_lock);
+ silc_packet_stream_unlink(stream, &silc_packet_wait_cbs, pw);
+
+ /* Free any remaining packets */
+ silc_list_start(pw->packet_queue);
+ while ((packet = silc_list_get(pw->packet_queue)) != SILC_LIST_END)
+ silc_packet_free(packet);
+
+ silc_mutex_unlock(pw->wait_lock);
+
+ silc_cond_free(pw->wait_cond);
+ silc_mutex_free(pw->wait_lock);
+ silc_free(pw);
+}
+
+/* Blocks thread until a packet has been received. */
+
+int silc_packet_wait(void *context, int timeout, SilcPacket *return_packet)
+{
+ SilcPacketWait pw = context;
+ SilcBool ret = FALSE;
+
+ silc_mutex_lock(pw->wait_lock);
+
+ /* Wait here until packet has arrived */
+ pw->waiting = TRUE;
+ while (silc_list_count(pw->packet_queue) == 0)
+ ret = silc_cond_timedwait(pw->wait_cond, pw->wait_lock, timeout);
+
+ /* Return packet */
+ silc_list_start(pw->packet_queue);
+ *return_packet = silc_list_get(pw->packet_queue);
+ silc_list_del(pw->packet_queue, *return_packet);
+
+ silc_mutex_unlock(pw->wait_lock);
+
+ return ret == TRUE ? 1 : 0;
+}