silccore: packet injection and stream wrap improvements
authorPekka Riikonen <priikone@silcnet.org>
Mon, 28 Apr 2014 19:31:35 +0000 (22:31 +0300)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 28 Apr 2014 19:31:35 +0000 (22:31 +0300)
Add silc_packet_stream_inject to allow injecting of packets to the
specified packet stream.

Add support for specifying the source and destination ids for the
wrapped packet stream allowing to use them in packet sending and using
them in packet reception to take only packets with the specified ids.

The semantics of CAN_WRITE and CAN_READ of wrapped packet stream coder
function has been changed to allow the coder to filter out packets it
does not want or to handle errors in coding.

lib/silccore/silcpacket.c
lib/silccore/silcpacket.h

index 8391858e77f32f0c6152e7a7c3b7a9c6bbe94063..e24832e1ba676e4158839e42a910b74508277ece 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2009 Pekka Riikonen
+  Copyright (C) 1997 - 2014 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -162,7 +162,8 @@ do {                                                                        \
                                    (s)->stream_context);               \
 } while(0)
 
-static SilcBool silc_packet_dispatch(SilcPacket packet);
+static SilcBool silc_packet_dispatch(SilcPacket packet,
+                                    SilcPacketReceiveCb ignore_handler);
 static void silc_packet_read_process(SilcPacketStream stream);
 static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
                                            SilcPacketType type,
@@ -191,7 +192,7 @@ SILC_TASK_CALLBACK(silc_packet_stream_inject_packet)
 
   silc_mutex_lock(stream->lock);
   if (!stream->destroyed)
-    silc_packet_dispatch(packet);
+    silc_packet_dispatch(packet, NULL);
   silc_mutex_unlock(stream->lock);
   silc_packet_stream_unref(stream);
 }
@@ -871,16 +872,25 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
 
   if (packet) {
     /* Inject packet to the new stream */
-    packet->stream = ps;
-    silc_packet_stream_ref(ps);
-    silc_schedule_task_add_timeout(silc_stream_get_schedule(stream->stream),
-                                  silc_packet_stream_inject_packet, packet,
-                                  0, 0);
+    silc_packet_stream_inject(ps, packet);
   }
 
   return ps;
 }
 
+/* Inject packet to packet stream */
+
+SilcBool silc_packet_stream_inject(SilcPacketStream stream,
+                                  SilcPacket packet)
+{
+  packet->stream = stream;
+  silc_packet_stream_ref(stream);
+  return !!silc_schedule_task_add_timeout(
+                               silc_stream_get_schedule(stream->stream),
+                               silc_packet_stream_inject_packet, packet,
+                               0, 0);
+}
+
 /* Destroy packet stream */
 
 void silc_packet_stream_destroy(SilcPacketStream stream)
@@ -1627,6 +1637,7 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
   /* Get packet pointer from the outgoing buffer */
   if (silc_unlikely(!silc_packet_send_prepare(stream, truelen + padlen + ivlen
                                              + psnlen, hmac, &packet))) {
+    SILC_LOG_ERROR(("Error preparing for packet sending"));
     silc_mutex_unlock(stream->lock);
     return FALSE;
   }
@@ -1653,6 +1664,7 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream,
                         SILC_STR_DATA(data, data_len),
                         SILC_STR_END);
   if (silc_unlikely(i < 0)) {
+    SILC_LOG_ERROR(("Error encoding outgoing packet"));
     silc_mutex_unlock(stream->lock);
     return FALSE;
   }
@@ -2007,7 +2019,8 @@ static inline SilcBool silc_packet_parse(SilcPacket packet)
 /* Dispatch packet to application.  Called with stream->lock locked.
    Returns FALSE if the stream was destroyed while dispatching a packet. */
 
-static SilcBool silc_packet_dispatch(SilcPacket packet)
+static SilcBool silc_packet_dispatch(SilcPacket packet,
+                                    SilcPacketReceiveCb ignore_handler)
 {
   SilcPacketStream stream = packet->stream;
   SilcPacketProcess p;
@@ -2063,7 +2076,8 @@ static SilcBool silc_packet_dispatch(SilcPacket packet)
     } else {
       /* Send specific types */
       for (pt = p->types; *pt; pt++) {
-       if (*pt != packet->type)
+       if (*pt != packet->type || 
+           ignore_handler == p->callbacks->packet_receive)
          continue;
        SILC_LOG_DEBUG(("Dispatching packet to %p callbacks", p->callbacks));
        silc_mutex_unlock(stream->lock);
@@ -2244,8 +2258,10 @@ static void silc_packet_read_process(SilcPacketStream stream)
     }
 
     if (silc_buffer_len(inbuf) < paddedlen + ivlen + mac_len) {
-      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest "
-                     "(%d bytes)",
+      SILC_LOG_DEBUG(("Received partial packet (%d %s flags:%x normal:%d "
+                     "len:%u paddedlen:%u), waiting for the rest (%d bytes)",
+                     type, silc_get_packet_name(type), flags,
+                     normal, packetlen, paddedlen,
                      paddedlen + mac_len - silc_buffer_len(inbuf)));
       memset(tmp, 0, sizeof(tmp));
       silc_dlist_del(stream->sc->inbufs, inbuf);
@@ -2347,7 +2363,7 @@ static void silc_packet_read_process(SilcPacketStream stream)
     }
 
     /* Dispatch the packet to application */
-    if (!silc_packet_dispatch(packet))
+    if (!silc_packet_dispatch(packet, NULL))
       break;
   }
 
@@ -2555,6 +2571,10 @@ typedef struct {
   SilcList in_queue;
   SilcPacketType type;
   SilcPacketFlags flags;
+  void *src_id;
+  void *dst_id;
+  SilcIdType src_id_type;
+  SilcIdType dst_id_type;
   unsigned int closed        : 1;
   unsigned int blocking      : 1;
   unsigned int read_more     : 1;
@@ -2576,10 +2596,24 @@ silc_packet_wrap_packet_receive(SilcPacketEngine engine,
                                void *stream_context)
 {
   SilcPacketWrapperStream pws = callback_context;
+  SilcID id;
 
   if (pws->closed || !pws->callback)
     return FALSE;
 
+  /* If dst_id was set, the incoming packet must use that id as its
+     source id.  This will not work if the id is channel id because
+     the source is never the channel id, but will work with other ids. */
+  if ((pws->dst_id && pws->dst_id_type != SILC_ID_CHANNEL)) {
+    silc_id_str2id2(packet->src_id, packet->src_id_len,
+                   packet->src_id_type, &id);
+    if (!SILC_ID_COMPARE_TYPE(pws->dst_id, SILC_ID_GET_ID(id),
+                             packet->src_id_len)) {
+      SILC_LOG_DEBUG(("Packet is not from wanted sender"));
+      return FALSE;
+    }
+  }
+
   silc_mutex_lock(pws->lock);
   silc_list_add(pws->in_queue, packet);
   silc_mutex_unlock(pws->lock);
@@ -2610,7 +2644,7 @@ int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
 {
   SilcPacketWrapperStream pws = stream;
   SilcPacket packet;
-  SilcBool read_more = FALSE;
+  SilcBool read_more = FALSE, ret = TRUE;
   int len;
 
   if (pws->closed)
@@ -2638,8 +2672,17 @@ int silc_packet_wrap_read(SilcStream stream, unsigned char *buf,
 
   /* Call decoder if set */
   if (pws->coder && !pws->read_more)
-    pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
-              pws->coder_context);
+    ret = pws->coder(stream, SILC_STREAM_CAN_READ, &packet->buffer,
+                    pws->coder_context);
+
+  if (!ret) {
+    /* If error occurred during decoding (or handler doesn't want this
+       packet), we'll reprocess this packet and try to give it to some
+       other handler that may want it.  For this stream nothing was
+       received. */
+    silc_packet_dispatch(packet, silc_packet_wrap_packet_receive);
+    return -1;
+  }
 
   len = silc_buffer_len(&packet->buffer);
   if (len > buf_len) {
@@ -2671,29 +2714,39 @@ int silc_packet_wrap_write(SilcStream stream, const unsigned char *data,
                           SilcUInt32 data_len)
 {
   SilcPacketWrapperStream pws = stream;
-  SilcBool ret = FALSE;
+  SilcBool ret = TRUE;
 
-  /* Call encoder if set */
-  if (pws->coder) {
-    silc_buffer_reset(pws->encbuf);
-    ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
-                    pws->coder_context);
+  if (!pws->coder) {
+    if (!silc_packet_send_ext(pws->stream, pws->type, pws->flags,
+                             pws->src_id_type, pws->src_id,
+                             pws->dst_id_type, pws->dst_id,
+                             data, data_len, NULL, NULL))
+      return -2;
+    return data_len;
   }
 
+  silc_buffer_reset(pws->encbuf);
+  if (!silc_buffer_enlarge(pws->encbuf, data_len + 16))
+    return -2;
+  silc_buffer_pull(pws->encbuf, 16);    /* Room for adding headers */
+  silc_buffer_put(pws->encbuf, data, data_len);
+
+  ret = pws->coder(stream, SILC_STREAM_CAN_WRITE, pws->encbuf,
+                  pws->coder_context);
+
   /* Send the SILC packet */
   if (ret) {
-    if (!silc_packet_send_va(pws->stream, pws->type, pws->flags,
-                            SILC_STR_DATA(silc_buffer_data(pws->encbuf),
-                                          silc_buffer_len(pws->encbuf)),
-                            SILC_STR_DATA(data, data_len),
-                            SILC_STR_END))
-      return -2;
-  } else {
-    if (!silc_packet_send(pws->stream, pws->type, pws->flags, data, data_len))
+    if (!silc_packet_send_ext(pws->stream, pws->type, pws->flags,
+                             pws->src_id_type, pws->src_id,
+                             pws->dst_id_type, pws->dst_id,
+                             silc_buffer_datalen(pws->encbuf),
+                             NULL, NULL))
       return -2;
+    return data_len;
   }
 
-  return data_len;
+  /* Error */
+  return -2;
 }
 
 /* Close stream */
@@ -2770,7 +2823,8 @@ SilcBool silc_packet_wrap_notifier(SilcStream stream,
 
 SilcSchedule silc_packet_wrap_get_schedule(SilcStream stream)
 {
-  return NULL;
+  SilcPacketWrapperStream pws = stream;
+  return silc_stream_get_schedule(pws->stream->stream);
 }
 
 /* Wraps packet stream into SilcStream. */
@@ -2779,6 +2833,8 @@ SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
                                    SilcPacketType type,
                                    SilcPacketFlags flags,
                                   SilcBool blocking_mode,
+                                  SilcIdType src_id_type, void *src_id,
+                                  SilcIdType dst_id_type, void *dst_id,
                                   SilcPacketWrapCoder coder,
                                   void *context)
 {
@@ -2798,6 +2854,24 @@ SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
   pws->coder = coder;
   pws->coder_context = context;
 
+  if (src_id) {
+    pws->src_id = silc_id_dup(src_id, src_id_type);
+    if (!pws->src_id) {
+      silc_free(pws);
+      return NULL;
+    }
+    pws->src_id_type = src_id_type;
+  }
+
+  if (dst_id) {
+    pws->dst_id = silc_id_dup(dst_id, dst_id_type);
+    if (!pws->dst_id) {
+      silc_free(pws);
+      return NULL;
+    }
+    pws->dst_id_type = dst_id_type;
+  }
+
   /* Allocate small amount for encoder buffer. */
   if (pws->coder)
     pws->encbuf = silc_buffer_alloc(8);
index 72046d768ef8f26237c70f29d054d1bbf57ec646..497a68a6812ddba3d835f324b2aed5baddffd59b 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2009 Pekka Riikonen
+  Copyright (C) 1997 - 2014 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -511,6 +511,24 @@ SilcPacketStream silc_packet_stream_add_remote(SilcPacketStream stream,
                                               SilcUInt16 remote_port,
                                               SilcPacket packet);
 
+/****f* silccore/SilcPacketAPI/silc_packet_stream_inject
+ *
+ * SYNOPSIS
+ *
+ * SilcBool silc_packet_stream_inject(SilcPacketStream stream,
+ *                                    SilcPacket packet);
+ *
+ * DESCRIPTION
+ *
+ *    This function can be used to inject the `packet' to the given
+ *    packet `stream'.  The packet will appear in the packet stream's
+ *    packet handler(s).  If this returns FALSE the packet was not
+ *    injected.
+ *
+ ***/
+SilcBool silc_packet_stream_inject(SilcPacketStream stream,
+                                  SilcPacket packet);
+
 /****f* silccore/SilcPacketAPI/silc_packet_stream_destroy
  *
  * SYNOPSIS
@@ -689,18 +707,26 @@ void silc_packet_stream_unlink(SilcPacketStream stream,
  *
  * DESCRIPTION
  *
- *    The encoder/decoder callback for silc_packet_stream_wrap.  If the
- *    `status' is SILC_STREAM_CAN_WRITE then additional data can be added
- *    to `buffer'.  It is added before the data that is written with
- *    silc_stream_write.  The silc_buffer_enlarge should be called to verify
- *    there is enough room in `buffer' before adding data to it.  The `buffer'
- *    must not be freed.
+ *    The encoder/decoder callback for silc_packet_stream_wrap.
  *
- *    If the `status' is SILC_STREAM_CAN_READ then data from the `buffer'
- *    may be read before it is passed to readed when silc_stream_read is
- *    called.  The `buffer' may be advanced also to hide data in it.
+ *    If the `status' is SILC_STREAM_CAN_WRITE then additional data can
+ *    be added to `buffer' which contains the data that is being written
+ *    to the stream.  There is at least 16 bytes of free space in head
+ *    space of the buffer in case new headers need to be added. 
+ *    The silc_buffer_enlarge should be called to verify that there is
+ *    enough room before adding data to it.  The `buffer' must not be freed.
+ *    If the return value is FALSE the encoding failed and the packet is
+ *    not sent at all and the stream will receive error.  Return TRUE if
+ *    the encoding succeeded.
  *
- *    This function returns FALSE in case of error.
+ *    If the `status' is SILC_STREAM_CAN_READ then data from the `buffer'
+ *    may be read before it is passed to reader when silc_stream_read is
+ *    called.  The `buffer' may be advanced also to hide data in it.  If
+ *    return value is FALSE the decoding failed (or the packet is ignored)
+ *    and the packet will not be processed by the wrapped packet stream.
+ *    If there are other packet streams wanting the same packet, they will
+ *    get it, and if not the packet will drop.  Return TRUE if decoding
+ *    succeeded.
  *
  ***/
 typedef SilcBool (*SilcPacketWrapCoder)(SilcStream stream,
@@ -716,6 +742,8 @@ typedef SilcBool (*SilcPacketWrapCoder)(SilcStream stream,
  *                                       SilcPacketType type,
  *                                       SilcPacketFlags flags,
  *                                       SilcBool blocking_mode,
+ *                                       SilcIdType src_id_type, void *src_id,
+ *                                       SilcIdType dst_id_type, void *dst_id,
  *                                       SilcPacketWrapCoder coder,
  *                                       void *context);
  *
@@ -742,6 +770,10 @@ typedef SilcBool (*SilcPacketWrapCoder)(SilcStream stream,
  *    once returns one complete SILC packet data payload (which is of type of
  *    `type').
  *
+ *    If src_id and/or dst_id are set they will be used as the ids in the
+ *    sent SILC packets.  If the dst_id is set then the stream will receive
+ *    packets only originating from that id.
+ *
  *    The `coder' is optional encoder/decoder callback which the packet engine
  *    will call if it is non-NULL.  It can be used to encode additional data
  *    into each packet when silc_stream_write is called or decode data before
@@ -757,6 +789,8 @@ SilcStream silc_packet_stream_wrap(SilcPacketStream stream,
                                   SilcPacketType type,
                                   SilcPacketFlags flags,
                                   SilcBool blocking_mode,
+                                  SilcIdType src_id_type, void *src_id,
+                                  SilcIdType dst_id_type, void *dst_id,
                                   SilcPacketWrapCoder coder,
                                   void *context);