Implement a Full Domain Hash (FDH) for RSA signatures and blind signatures
[oweals/gnunet.git] / src / util / server_mst.c
index bf9a3a0072cccc79fae5eb1bc86a7205522f941c..0a686a079e6323e44ef949a774fd4c6ef991c21c 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2010 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2010 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
  */
 
 #include "platform.h"
  */
 
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
-#include "gnunet_time_lib.h"
+#include "gnunet_util_lib.h"
 
 
-#define DEBUG_SERVER_MST GNUNET_NO
 
 #if HAVE_UNALIGNED_64_ACCESS
 #define ALIGN_FACTOR 4
 
 #if HAVE_UNALIGNED_64_ACCESS
 #define ALIGN_FACTOR 4
@@ -39,6 +34,8 @@
 #define ALIGN_FACTOR 8
 #endif
 
 #define ALIGN_FACTOR 8
 #endif
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
 
 /**
  * Handle to a message stream tokenizer.
 
 /**
  * Handle to a message stream tokenizer.
@@ -50,21 +47,16 @@ struct GNUNET_SERVER_MessageStreamTokenizer
    * Function to call on completed messages.
    */
   GNUNET_SERVER_MessageTokenizerCallback cb;
    * Function to call on completed messages.
    */
   GNUNET_SERVER_MessageTokenizerCallback cb;
-  
+
   /**
    * Closure for cb.
    */
   void *cb_cls;
 
   /**
    * Closure for cb.
    */
   void *cb_cls;
 
-  /**
-   * Client to pass to cb.
-   */
-  void *client_identity;
-
   /**
    * Size of the buffer (starting at 'hdr').
    */
   /**
    * Size of the buffer (starting at 'hdr').
    */
-  size_t maxbuf;
+  size_t curr_buf;
 
   /**
    * How many bytes in buffer have we already processed?
 
   /**
    * How many bytes in buffer have we already processed?
@@ -79,7 +71,7 @@ struct GNUNET_SERVER_MessageStreamTokenizer
   /**
    * Beginning of the buffer.  Typed like this to force alignment.
    */
   /**
    * Beginning of the buffer.  Typed like this to force alignment.
    */
-  struct GNUNET_MessageHeader hdr;
+  struct GNUNET_MessageHeader *hdr;
 
 };
 
 
 };
 
@@ -88,25 +80,19 @@ struct GNUNET_SERVER_MessageStreamTokenizer
 /**
  * Create a message stream tokenizer.
  *
 /**
  * Create a message stream tokenizer.
  *
- * @param maxbuf maximum message size to support (typically
- *    GNUNET_SERVER_MAX_MESSAGE_SIZE)
- * @param client_identity ID of client for which this is a buffer,
- *        can be NULL (will be passed back to 'cb')
  * @param cb function to call on completed messages
  * @param cb function to call on completed messages
- * @param cb_cls closure for cb
+ * @param cb_cls closure for @a cb
  * @return handle to tokenizer
  */
 struct GNUNET_SERVER_MessageStreamTokenizer *
  * @return handle to tokenizer
  */
 struct GNUNET_SERVER_MessageStreamTokenizer *
-GNUNET_SERVER_mst_create (size_t maxbuf,
-                         void *client_identity,
-                         GNUNET_SERVER_MessageTokenizerCallback cb,
-                         void *cb_cls)
+GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
+                          void *cb_cls)
 {
   struct GNUNET_SERVER_MessageStreamTokenizer *ret;
 
 {
   struct GNUNET_SERVER_MessageStreamTokenizer *ret;
 
-  ret = GNUNET_malloc (maxbuf + sizeof (struct GNUNET_SERVER_MessageStreamTokenizer));
-  ret->maxbuf = maxbuf;
-  ret->client_identity = client_identity;
+  ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
+  ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
+  ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
   ret->cb = cb;
   ret->cb_cls = cb_cls;
   return ret;
   ret->cb = cb;
   ret->cb_cls = cb_cls;
   return ret;
@@ -118,21 +104,21 @@ GNUNET_SERVER_mst_create (size_t maxbuf,
  * callback for all complete messages.
  *
  * @param mst tokenizer to use
  * callback for all complete messages.
  *
  * @param mst tokenizer to use
+ * @param client_identity ID of client for which this is a buffer
  * @param buf input data to add
  * @param buf input data to add
- * @param size number of bytes in buf
- * @param purge should any excess bytes in the buffer be discarded 
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
  *       (i.e. for packet-based services like UDP)
  * @param one_shot only call callback once, keep rest of message in buffer
  *       (i.e. for packet-based services like UDP)
  * @param one_shot only call callback once, keep rest of message in buffer
- * @return GNUNET_OK if we are done processing (need more data)
- *         GNUNET_NO if one_shot was set and we have another message ready
- *         GNUNET_SYSERR if the data stream is corrupt
+ * @return #GNUNET_OK if we are done processing (need more data)
+ *         #GNUNET_NO if @a one_shot was set and we have another message ready
+ *         #GNUNET_SYSERR if the data stream is corrupt
  */
 int
 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
  */
 int
 GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
-                          const char *buf,
-                          size_t size,
-                          int purge,
-                          int one_shot)
+                           void *client_identity,
+                           const char *buf, size_t size,
+                           int purge, int one_shot)
 {
   const struct GNUNET_MessageHeader *hdr;
   size_t delta;
 {
   const struct GNUNET_MessageHeader *hdr;
   size_t delta;
@@ -142,153 +128,170 @@ GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
   unsigned long offset;
   int ret;
 
   unsigned long offset;
   int ret;
 
-#if DEBUG_SERVER_MST
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Server-mst receives %u bytes with %u bytes already in private buffer\n",
-             (unsigned int) size,
-             (unsigned int) (mst->pos - mst->off));
-#endif
+  GNUNET_assert (mst->off <= mst->pos);
+  GNUNET_assert (mst->pos <= mst->curr_buf);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server-mst receives %u bytes with %u bytes already in private buffer\n",
+       (unsigned int) size, (unsigned int) (mst->pos - mst->off));
   ret = GNUNET_OK;
   ret = GNUNET_OK;
-  ibuf = (char*) &mst->hdr;
+  ibuf = (char *) mst->hdr;
   while (mst->pos > 0)
   while (mst->pos > 0)
+  {
+do_align:
+    GNUNET_assert (mst->pos >= mst->off);
+    if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
+        (0 != (mst->off % ALIGN_FACTOR)))
+    {
+      /* need to align or need more space */
+      mst->pos -= mst->off;
+      memmove (ibuf, &ibuf[mst->off], mst->pos);
+      mst->off = 0;
+    }
+    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+    {
+      delta =
+          GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
+                      (mst->pos - mst->off), size);
+      memcpy (&ibuf[mst->pos], buf, delta);
+      mst->pos += delta;
+      buf += delta;
+      size -= delta;
+    }
+    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+    {
+      if (purge)
+      {
+        mst->off = 0;
+        mst->pos = 0;
+      }
+      return GNUNET_OK;
+    }
+    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+    want = ntohs (hdr->size);
+    if (want < sizeof (struct GNUNET_MessageHeader))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+    if ( (mst->curr_buf - mst->off < want) &&
+        (mst->off > 0) )
+    {
+      /* can get more space by moving */
+      mst->pos -= mst->off;
+      memmove (ibuf, &ibuf[mst->off], mst->pos);
+      mst->off = 0;
+    }
+    if (mst->curr_buf < want)
+    {
+      /* need to get more space by growing buffer */
+      GNUNET_assert (0 == mst->off);
+      mst->hdr = GNUNET_realloc (mst->hdr, want);
+      ibuf = (char *) mst->hdr;
+      mst->curr_buf = want;
+    }
+    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+    if (mst->pos - mst->off < want)
+    {
+      delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
+      GNUNET_assert (mst->pos + delta <= mst->curr_buf);
+      memcpy (&ibuf[mst->pos], buf, delta);
+      mst->pos += delta;
+      buf += delta;
+      size -= delta;
+    }
+    if (mst->pos - mst->off < want)
+    {
+      if (purge)
+      {
+        mst->off = 0;
+        mst->pos = 0;
+      }
+      return GNUNET_OK;
+    }
+    if (one_shot == GNUNET_SYSERR)
     {
     {
-    do_align:
-      if ( (mst->maxbuf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
-          (0 != (mst->off % ALIGN_FACTOR)) )
-       {
-         /* need to align or need more space */
-         mst->pos -= mst->off;
-         memmove (ibuf,
-                  &ibuf[mst->off],
-                  mst->pos);
-         mst->off = 0;
-       }
-      if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
-       {
-         delta = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - (mst->pos - mst->off),
-                             size);
-         memcpy (&ibuf[mst->pos],
-                 buf,
-                 delta);
-         mst->pos += delta;
-         buf += delta;
-         size -= delta;
-       }
-      if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
-       {
-         if (purge)
-           {
-             mst->off = 0;    
-             mst->pos = 0;
-           }
-         return GNUNET_OK;
-       }
-      hdr = (const struct GNUNET_MessageHeader*) &ibuf[mst->off];
+      /* cannot call callback again, but return value saying that
+       * we have another full message in the buffer */
+      ret = GNUNET_NO;
+      goto copy;
+    }
+    if (one_shot == GNUNET_YES)
+      one_shot = GNUNET_SYSERR;
+    mst->off += want;
+    if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+      return GNUNET_SYSERR;
+    if (mst->off == mst->pos)
+    {
+      /* reset to beginning of buffer, it's free right now! */
+      mst->off = 0;
+      mst->pos = 0;
+    }
+  }
+  GNUNET_assert (0 == mst->pos);
+  while (size > 0)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server-mst has %u bytes left in inbound buffer\n",
+         (unsigned int) size);
+    if (size < sizeof (struct GNUNET_MessageHeader))
+      break;
+    offset = (unsigned long) buf;
+    need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
+    if (GNUNET_NO == need_align)
+    {
+      /* can try to do zero-copy and process directly from original buffer */
+      hdr = (const struct GNUNET_MessageHeader *) buf;
       want = ntohs (hdr->size);
       if (want < sizeof (struct GNUNET_MessageHeader))
       want = ntohs (hdr->size);
       if (want < sizeof (struct GNUNET_MessageHeader))
-       {
-         GNUNET_break_op (0);
-         return GNUNET_SYSERR;
-       }
-      if (mst->maxbuf - mst->off < want)
-       {
-         /* need more space */
-         mst->pos -= mst->off;
-         memmove (ibuf,
-                  &ibuf[mst->off],
-                  mst->pos);
-         mst->off = 0;
-       }
-      if (mst->pos - mst->off < want)
-       {
-         delta = GNUNET_MIN (want - (mst->pos - mst->off),
-                             size);
-         memcpy (&ibuf[mst->pos],
-                 buf,
-                 delta);
-         mst->pos += delta;
-         buf += delta;
-         size -= delta;
-       }
-      if (mst->pos - mst->off < want)
-       {
-         if (purge)
-           {
-             mst->off = 0;    
-             mst->pos = 0;
-           }
-         return GNUNET_OK;
-       }
+      {
+        GNUNET_break_op (0);
+        mst->off = 0;
+        return GNUNET_SYSERR;
+      }
+      if (size < want)
+        break;                  /* or not: buffer incomplete, so copy to private buffer... */
       if (one_shot == GNUNET_SYSERR)
       if (one_shot == GNUNET_SYSERR)
-       {
-         /* cannot call callback again, but return value saying that
-            we have another full message in the buffer */
-         ret = GNUNET_NO;
-         goto copy;
-       }
+      {
+        /* cannot call callback again, but return value saying that
+         * we have another full message in the buffer */
+        ret = GNUNET_NO;
+        goto copy;
+      }
       if (one_shot == GNUNET_YES)
       if (one_shot == GNUNET_YES)
-       one_shot = GNUNET_SYSERR;
-      mst->cb (mst->cb_cls, mst->client_identity, hdr);
-      mst->off += want;
-      if (mst->off == mst->pos)
-       {
-         /* reset to beginning of buffer, it's free right now! */
-         mst->off = 0;
-         mst->pos = 0;
-       }
+        one_shot = GNUNET_SYSERR;
+      if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+        return GNUNET_SYSERR;
+      buf += want;
+      size -= want;
     }
     }
-  while (size > 0)
+    else
     {
     {
-#if DEBUG_SERVER_MST
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Server-mst has %u bytes left in inbound buffer\n",
-                 (unsigned int) size);
-#endif
-      if (size < sizeof (struct GNUNET_MessageHeader))
-       break;
-      offset = (unsigned long) buf;
-      need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
-      if (GNUNET_NO == need_align)
-       {
-         /* can try to do zero-copy and process directly from original buffer */
-         hdr = (const struct GNUNET_MessageHeader *) buf;
-         want = ntohs (hdr->size);
-         if (size < want)
-           break; /* or not, buffer incomplete, so copy to private buffer... */
-         if (one_shot == GNUNET_SYSERR)
-           {
-             /* cannot call callback again, but return value saying that
-                we have another full message in the buffer */
-             ret = GNUNET_NO;
-             goto copy;
-           }
-         if (one_shot == GNUNET_YES)
-           one_shot = GNUNET_SYSERR;
-         mst->cb (mst->cb_cls, mst->client_identity, hdr);
-         buf += want;
-         size -= want;
-       }
-      else
-       {
-         /* need to copy to private buffer to align;
-            yes, we go a bit more spagetti than usual here */
-         goto do_align;
-       }
+      /* need to copy to private buffer to align;
+       * yes, we go a bit more spagetti than usual here */
+      goto do_align;
     }
     }
- copy:
-  if ( (size > 0) && (! purge) )
+  }
+copy:
+  if ((size > 0) && (!purge))
+  {
+    if (size + mst->pos > mst->curr_buf)
     {
     {
-      GNUNET_assert (mst->pos + size <= mst->maxbuf);
-      memcpy (&ibuf[mst->pos], buf, size);
-      mst->pos += size;
+      mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
+      ibuf = (char *) mst->hdr;
+      mst->curr_buf = size + mst->pos;
     }
     }
+    GNUNET_assert (size + mst->pos <= mst->curr_buf);
+    memcpy (&ibuf[mst->pos], buf, size);
+    mst->pos += size;
+  }
   if (purge)
   if (purge)
-    mst->off = 0;    
-#if DEBUG_SERVER_MST
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Server-mst leaves %u bytes in private buffer\n",
-             (unsigned int) (mst->pos - mst->off));
-#endif
+  {
+    mst->off = 0;
+    mst->pos = 0;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server-mst leaves %u bytes in private buffer\n",
+       (unsigned int) (mst->pos - mst->off));
   return ret;
 }
 
   return ret;
 }
 
@@ -301,6 +304,7 @@ GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
 void
 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
 {
 void
 GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
 {
+  GNUNET_free (mst->hdr);
   GNUNET_free (mst);
 }
 
   GNUNET_free (mst);
 }