gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r8809 - in gnunet: . src src/arm src/datacache src/datastor


From: gnunet
Subject: [GNUnet-SVN] r8809 - in gnunet: . src src/arm src/datacache src/datastore src/fs src/hostlist src/include src/testing src/topology src/transport src/util
Date: Wed, 29 Jul 2009 02:05:52 -0600

Author: grothoff
Date: 2009-07-29 02:05:52 -0600 (Wed, 29 Jul 2009)
New Revision: 8809

Added:
   gnunet/src/fs/
   gnunet/src/fs/Makefile.am
   gnunet/src/fs/fs.h
   gnunet/src/fs/fs_getopt.c
   gnunet/src/fs/fs_uri.c
   gnunet/src/fs/test_fs_getopt.c
   gnunet/src/fs/test_fs_uri.c
   gnunet/src/testing/test_testing.c
   gnunet/src/testing/test_testing_data.conf
Modified:
   gnunet/TODO
   gnunet/src/Makefile.am
   gnunet/src/arm/arm.h
   gnunet/src/arm/gnunet-service-arm.c
   gnunet/src/datacache/plugin_datacache_sqlite.c
   gnunet/src/datastore/gnunet-service-datastore.c
   gnunet/src/hostlist/hostlist-client.c
   gnunet/src/hostlist/hostlist-server.c
   gnunet/src/include/gnunet_configuration_lib.h
   gnunet/src/include/gnunet_container_lib.h
   gnunet/src/include/gnunet_testing_lib.h
   gnunet/src/testing/Makefile.am
   gnunet/src/testing/testing.c
   gnunet/src/testing/testing_group.c
   gnunet/src/topology/gnunet-daemon-topology.c
   gnunet/src/transport/gnunet-service-transport.c
   gnunet/src/util/configuration.c
   gnunet/src/util/container_meta_data.c
   gnunet/src/util/crypto_ksk.c
   gnunet/src/util/disk.c
Log:
travelhacking

Modified: gnunet/TODO
===================================================================
--- gnunet/TODO 2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/TODO 2009-07-29 08:05:52 UTC (rev 8809)
@@ -16,20 +16,21 @@
 PHASE #2: (Goal: recover basic file-sharing functionality)
 * TESTING (needed for DV, DHT, Topology)
   - implement library for local testing
-    + check API for hostname specification;
-      maybe use space-separated list instead?
     + modify configuration to allow controlling
       connections for non-local starts
-    + starting of groups of peers (and auto-setting
-      of PORT options)
-    + testbed creation with topology
-    + testbed with churn
+    + CORE service does not start with valid peer ID (all zeross)
+      -- testcase fails!
+    + consider changing API for peer-group termination
+      to call continuation when done
+    + testbed creation with topology (needs working F2F topology) [Nate]
+    + testbed with churn [Nate]
   - implement testcases for library
-    + test basic peer start
+    + get test for basic peer start to work!
     + test basic peer connect
     + test group start
-    + test topology creation
-    + test churn generation
+    + test basic peer re-configure [Nate]
+    + test topology creation [Nate]
+    + test churn generation [Nate]
 * TOPOLOGY:
   - implement testcases (needs TESTING)
 * HOSTLIST:

Modified: gnunet/src/Makefile.am
===================================================================
--- gnunet/src/Makefile.am      2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/Makefile.am      2009-07-29 08:05:52 UTC (rev 8809)
@@ -18,10 +18,10 @@
   statistics \
   datacache \
   datastore \
-  testing \
   template \
   transport \
   core \
+  testing \
   $(HOSTLIST_DIR) \
   topology 
 

Modified: gnunet/src/arm/arm.h
===================================================================
--- gnunet/src/arm/arm.h        2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/arm/arm.h        2009-07-29 08:05:52 UTC (rev 8809)
@@ -27,6 +27,6 @@
 
 #include "gnunet_common.h"
 
-#define DEBUG_ARM GNUNET_NO
+#define DEBUG_ARM GNUNET_YES
 
 #endif

Modified: gnunet/src/arm/gnunet-service-arm.c
===================================================================
--- gnunet/src/arm/gnunet-service-arm.c 2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/arm/gnunet-service-arm.c 2009-07-29 08:05:52 UTC (rev 8809)
@@ -167,6 +167,8 @@
 {
   uint16_t *res;
 
+  if (NULL == client)
+    return;
 #if DEBUG_ARM
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Telling client that service `%s' is now %s\n",
@@ -387,7 +389,8 @@
   sl->mtime = sbuf.st_mtime;
   running = sl;
   start_process (sl);
-  signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
+  if (NULL != client)
+    signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
 }
 
 

Modified: gnunet/src/datacache/plugin_datacache_sqlite.c
===================================================================
--- gnunet/src/datacache/plugin_datacache_sqlite.c      2009-07-27 21:38:38 UTC 
(rev 8808)
+++ gnunet/src/datacache/plugin_datacache_sqlite.c      2009-07-29 08:05:52 UTC 
(rev 8809)
@@ -405,7 +405,10 @@
   struct GNUNET_DATACACHE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 
-  UNLINK (plugin->fn);
+  if (0 != UNLINK (plugin->fn))
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                             "unlink", 
+                             plugin->fn);
   GNUNET_free (plugin->fn);
   sqlite3_close (plugin->dbh);
   GNUNET_free (plugin);

Modified: gnunet/src/datastore/gnunet-service-datastore.c
===================================================================
--- gnunet/src/datastore/gnunet-service-datastore.c     2009-07-27 21:38:38 UTC 
(rev 8808)
+++ gnunet/src/datastore/gnunet-service-datastore.c     2009-07-29 08:05:52 UTC 
(rev 8809)
@@ -527,7 +527,8 @@
   sm->header.size = htons(sizeof(struct StatusMessage) + slen);
   sm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_STATUS);
   sm->status = htonl(code);
-  memcpy (&sm[1], msg, slen);  
+  if (slen > 0)
+    memcpy (&sm[1], msg, slen);  
   transmit (client, &sm->header, NULL, NULL, GNUNET_YES);
 }
 

Added: gnunet/src/fs/Makefile.am
===================================================================
--- gnunet/src/fs/Makefile.am                           (rev 0)
+++ gnunet/src/fs/Makefile.am   2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,61 @@
+INCLUDES = -I$(top_srcdir)/src/include
+
+if MINGW
+ WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols 
+endif
+
+if USE_COVERAGE
+  AM_CFLAGS = --coverage -O0
+  XLIB = -lgcov
+endif
+
+
+lib_LTLIBRARIES = libgnunetfs.la
+
+libgnunetfs_la_SOURCES = \
+  fs_getopt.c \
+  fs_uri.c 
+libgnunetfs_la_LIBADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(GN_LIBINTL) $(XLIB)
+libgnunetfs_la_LDFLAGS = \
+  $(GN_LIB_LDFLAGS)  $(WINFLAGS) \
+  -version-info 0:0:0
+
+
+#bin_PROGRAMS = \ 
+# gnunet-directory \
+# gnunet-download \
+# gnunet-pseudonym \
+# gnunet-search \
+# gnunet-share \
+# gnunet-unindex 
+
+#gnunet_directory_SOURCES = \
+# gnunet-directory.c         
+#gnunet_directory_LDADD = \
+#  $(top_builddir)/src/fs/libgnunetfs.la \
+#  $(top_builddir)/src/util/libgnunetutil.la \
+#  $(GN_LIBINTL)
+
+
+check_PROGRAMS = \
+ test_fs_getopt \
+ test_fs_uri
+
+TESTS = $(check_PROGRAMS)
+
+test_fs_uri_SOURCES = \
+ test_fs_uri.c
+test_fs_LDADD = \
+  $(top_builddir)/src/fs/libgnunetfs.la  \
+  $(top_builddir)/src/util/libgnunetutil.la  
+
+test_fs_getopt_SOURCES = \
+ test_fs_getopt.c
+test_fs_LDADD = \
+  $(top_builddir)/src/fs/libgnunetfs.la  \
+  $(top_builddir)/src/util/libgnunetutil.la  
+
+#EXTRA_DIST = \
+#  test_fs_data.conf

Added: gnunet/src/fs/fs.h
===================================================================
--- gnunet/src/fs/fs.h                          (rev 0)
+++ gnunet/src/fs/fs.h  2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,128 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and 
other contributing authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+
+/**
+ * @file fs/fs.h
+ * @brief definitions for the entire fs module
+ * @author Igor Wronsky, Christian Grothoff
+ */
+#ifndef FS_H
+#define FS_H
+
+/**
+ * @brief content hash key
+ */
+struct ContentHashKey 
+{
+  GNUNET_HashCode key;
+  GNUNET_HashCode query;
+};
+
+
+/**
+ * @brief complete information needed
+ * to download a file.
+ */
+struct FileIdentifier
+{
+
+  /**
+   * Total size of the file in bytes. (network byte order (!))
+   */
+  unsigned long long file_length;
+
+  /**
+   * Query and key of the top GNUNET_EC_IBlock.
+   */
+  struct ContentHashKey chk;
+
+};
+
+
+/**
+ * Information about a file and its location
+ * (peer claiming to share the file).
+ */
+struct Location
+{
+  /**
+   * Information about the shared file.
+   */
+  struct FileIdentifier fi;
+
+  /**
+   * Identity of the peer sharing the file.
+   */
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer;
+
+  /**
+   * Time when the HELLO *and* this location URI
+   * expire (they expire together!).
+   */
+  struct GNUNET_TIME_Absolute expirationTime;
+
+  /**
+   * RSA signature over the GNUNET_EC_FileIdentifier,
+   * GNUNET_hash of the peer and expiration time.
+   */
+  struct GNUNET_CRYPTO_RsaSignature contentSignature;
+
+};
+
+enum uri_types
+{ chk, sks, ksk, loc };
+
+/**
+ * A Universal Resource Identifier (URI), opaque.
+ */
+struct GNUNET_FS_Uri
+{
+  enum uri_types type;
+  union
+  {
+    struct
+    {
+      /**
+       * Keywords start with a '+' if they are
+       * mandatory (in which case the '+' is NOT
+       * part of the keyword) and with a
+       * simple space if they are optional
+       * (in which case the space is ALSO not
+       * part of the actual keyword).
+       *
+       * Double-quotes to protect spaces and
+       * %-encoding are NOT used internally
+       * (only in URI-strings).
+       */
+      char **keywords;
+      unsigned int keywordCount;
+    } ksk;
+    struct
+    {
+      GNUNET_HashCode namespace;
+      char *identifier;
+    } sks;
+    struct FileIdentifier chk;
+    struct Location loc;
+  } data;
+
+};
+
+#endif

Added: gnunet/src/fs/fs_getopt.c
===================================================================
--- gnunet/src/fs/fs_getopt.c                           (rev 0)
+++ gnunet/src/fs/fs_getopt.c   2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,192 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and 
other contributing authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+
+/**
+ * @file fs/fs_getopt.c
+ * @brief helper functions for command-line argument processing
+ * @author Igor Wronsky, Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_fs_lib.h"
+
+
+
+/* ******************** command-line option parsing API 
*********************** */
+
+/**
+ * Command-line option parser function that allows the user
+ * to specify one or more '-k' options with keywords.  Each
+ * specified keyword will be added to the URI.  A pointer to
+ * the URI must be passed as the "scls" argument.
+ *
+ * @param ctx command line processor context
+ * @param scls must be of type "struct GNUNET_FS_Uri **"
+ * @param option name of the option (typically 'k')
+ * @param value command line argument given
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_FS_getopt_configure_set_keywords 
(GNUNET_GETOPT_CommandLineProcessorContext* ctx, 
+                                        void *scls,
+                                        const char *option,
+                                        const char *value)
+{
+  struct GNUNET_FS_Uri **uri = scls;
+  struct GNUNET_FS_Uri *u = *uri;
+  char *val;
+  size_t slen;
+
+  if (u == NULL)
+    {
+      u = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI));
+      *uri = u;
+      u->type = ksk;
+      u->data.ksk.keywordCount = 0;
+      u->data.ksk.keywords = NULL;
+    }
+  else
+    {
+      GNUNET_assert (u->type == ksk);
+    }
+  slen = strlen (value);
+  if (slen == 0)
+    return GNUNET_SYSERR;       /* cannot be empty */
+  if (value[0] == '+')
+    {
+      /* simply preserve the "mandatory" flag */
+      if (slen < 2)
+        return GNUNET_SYSERR;   /* empty keywords not allowed */
+      if ((value[1] == '"') && (slen > 3) && (value[slen - 1] == '"'))
+        {
+          /* remove the quotes, keep the '+' */
+          val = GNUNET_malloc (slen - 1);
+          val[0] = '+';
+          memcpy (&val[1], &value[2], slen - 3);
+          val[slen - 2] = '\0';
+        }
+      else
+        {
+          /* no quotes, just keep the '+' */
+          val = GNUNET_strdup (value);
+        }
+    }
+  else
+    {
+      if ((value[0] == '"') && (slen > 2) && (value[slen - 1] == '"'))
+        {
+          /* remove the quotes, add a space */
+          val = GNUNET_malloc (slen);
+          val[0] = ' ';
+          memcpy (&val[1], &value[1], slen - 2);
+          val[slen - 1] = '\0';
+        }
+      else
+        {
+          /* add a space to indicate "not mandatory" */
+          val = GNUNET_malloc (slen + 2);
+          strcpy (val, " ");
+          strcat (val, value);
+        }
+    }
+  GNUNET_array_grow (u->data.ksk.keywords,
+                     u->data.ksk.keywordCount, u->data.ksk.keywordCount + 1);
+  u->data.ksk.keywords[u->data.ksk.keywordCount - 1] = val;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Command-line option parser function that allows the user to specify
+ * one or more '-m' options with metadata.  Each specified entry of
+ * the form "type=value" will be added to the metadata.  A pointer to
+ * the metadata must be passed as the "scls" argument.
+ *
+ * @param ctx command line processor context
+ * @param scls must be of type "struct GNUNET_MetaData **"
+ * @param option name of the option (typically 'k')
+ * @param value command line argument given
+ * @return GNUNET_OK on success
+ */
+int
+GNUNET_FS_getopt_configure_set_metadata 
(GNUNET_GETOPT_CommandLineProcessorContext* ctx, 
+                                        void *scls,
+                                        const char *option,
+                                        const char *value)
+
+{
+  struct GNUNET_CONTAINER_MetaData **mm = scls;
+  EXTRACTOR_KeywordType type;
+  const char *typename;
+  const char *typename_i18n;
+  struct GNUNET_CONTAINER_MetaData *meta;
+  char *tmp;
+
+  meta = *mm;
+  if (meta == NULL)
+    {
+      meta = GNUNET_CONTAINER_meta_data_create ();
+      *mm = meta;
+    }
+
+  tmp = GNUNET_STRINGS_to_utf8 (NULL, value, strlen (value),
+#if ENABLE_NLS
+                               nl_langinfo (CODESET)
+#else
+                               "utf-8"
+#endif
+    );
+  type = EXTRACTOR_getHighestKeywordTypeNumber ();
+  while (type > 0)
+    {
+      type--;
+      typename = EXTRACTOR_getKeywordTypeAsString (type);
+      typename_i18n = dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, typename);
+      if ((strlen (tmp) >= strlen (typename) + 1) &&
+          (tmp[strlen (typename)] == ':') &&
+          (0 == strncmp (typename, tmp, strlen (typename))))
+        {
+          GNUNET_CONTAINER_meta_data_insert (meta, type, &tmp[strlen 
(typename) + 1]);
+          GNUNET_free (tmp);
+          tmp = NULL;
+          break;
+        }
+      if ((strlen (tmp) >= strlen (typename_i18n) + 1) &&
+          (tmp[strlen (typename_i18n)] == ':') &&
+          (0 == strncmp (typename_i18n, tmp, strlen (typename_i18n))))
+        {
+          GNUNET_CONTAINER_meta_data_insert (meta, type,
+                                            &tmp[strlen (typename_i18n) + 1]);
+          GNUNET_free (tmp);
+          tmp = NULL;
+          break;
+        }
+    }
+  if (tmp != NULL)
+    {
+      GNUNET_CONTAINER_meta_data_insert (meta, EXTRACTOR_UNKNOWN, tmp);
+      GNUNET_free (tmp);
+      printf (_
+              ("Unknown metadata type in metadata option `%s'.  Using metadata 
type `unknown' instead.\n"),
+              value);
+    }
+  return GNUNET_OK;
+}
+
+/* end of fs_getopt.c */

Added: gnunet/src/fs/fs_uri.c
===================================================================
--- gnunet/src/fs/fs_uri.c                              (rev 0)
+++ gnunet/src/fs/fs_uri.c      2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,1317 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and 
other contributing authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+
+/**
+ * @file fs/fs_uri.c
+ * @brief Parses and produces uri strings.
+ * @author Igor Wronsky, Christian Grothoff
+ *
+ * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
+ * The specific structure of "IDENTIFIER" depends on the module and
+ * maybe differenciated into additional subcategories if applicable.
+ * This module only deals with ecrs identifiers (MODULE = "ecrs").
+ * <p>
+ *
+ * This module only parses URIs for the AFS module.  The ECRS URIs fall
+ * into four categories, "chk", "sks", "ksk" and "loc".  The first three
+ * categories were named in analogy (!) to Freenet, but they do NOT
+ * work in exactly the same way.  They are very similar from the user's
+ * point of view (unique file identifier, subspace, keyword), but the
+ * implementation is rather different in pretty much every detail.
+ * The concrete URI formats are:
+ *
+ * <ul><li>
+ *
+ * First, there are URIs that identify a file.  They have the format
+ * "gnunet://ecrs/chk/HEX1.HEX2.SIZE".  These URIs can be used to
+ * download the file.  The description, filename, mime-type and other
+ * meta-data is NOT part of the file-URI since a URI uniquely
+ * identifies a resource (and the contents of the file would be the
+ * same even if it had a different description).
+ *
+ * </li><li>
+ *
+ * The second category identifies entries in a namespace.  The format
+ * is "gnunet://ecrs/sks/NAMESPACE/IDENTIFIER" where the namespace
+ * should be given in HEX.  Applications may allow using a nickname
+ * for the namespace if the nickname is not ambiguous.  The identifier
+ * can be either an ASCII sequence or a HEX-encoding.  If the
+ * identifier is in ASCII but the format is ambiguous and could denote
+ * a HEX-string a "/" is appended to indicate ASCII encoding.
+ *
+ * </li> <li>
+ *
+ * The third category identifies ordinary searches.  The format is
+ * "gnunet://ecrs/ksk/KEYWORD[+KEYWORD]*".  Using the "+" syntax
+ * it is possible to encode searches with the boolean "AND" operator.
+ * "+" is used since it indicates a commutative 'and' operation and
+ * is unlikely to be used in a keyword by itself.
+ *
+ * </li><li>
+ *
+ * The last category identifies a datum on a specific machine.  The
+ * format is "gnunet://ecrs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME".  PEER is
+ * the BinName of the public key of the peer storing the datum.  The
+ * signature (SIG) certifies that this peer has this content.
+ * HEX1, HEX2 and SIZE correspond to a 'chk' URI.
+ *
+ * </li></ul>
+ *
+ * The encoding for hexadecimal values is defined in the hashing.c
+ * module in the gnunetutil library and discussed there.
+ * <p>
+ */
+#include "platform.h"
+#include "gnunet_fs_lib.h"
+#include "fs.h"
+
+
+/**
+ * Get a unique key from a URI.  This is for putting URIs
+ * into HashMaps.  The key may change between FS implementations.
+ *
+ * @param uri uri to convert to a unique key
+ * @param key wherer to store the unique key
+ */
+void 
+GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri,
+                     GNUNET_HashCode * key)
+{
+  switch (uri->type)
+    {
+    case chk:
+      *key = uri->data.fi.chk.query;
+      return;
+    case sks:
+      GNUNET_hash (uri->data.sks.identifier,
+                   strlen (uri->data.sks.identifier), key);
+      break;
+    case ksk:
+      if (uri->data.ksk.keywordCount > 0)
+        GNUNET_hash (uri->data.ksk.keywords[0],
+                     strlen (uri->data.ksk.keywords[0]), key);
+      break;
+    case loc:
+      GNUNET_hash (&uri->data.loc.fi,
+                   sizeof (GNUNET_EC_FileIdentifier) +
+                   sizeof (GNUNET_RSA_PublicKey), key);
+      break;
+    default:
+      memset (key, 0, sizeof (GNUNET_HashCode));
+      break;
+    }
+}
+
+
+/**
+ * Convert a URI to a UTF-8 String.
+ *
+ * @param uri uri to convert to a string
+ * @return the UTF-8 string
+ */
+char *
+GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri);
+
+
+/**
+ * Convert keyword URI to a human readable format
+ * (i.e. the search query that was used in the first place)
+ *
+ * @param uri ksk uri to convert to a string 
+ * @return string with the keywords
+ */
+char *
+GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri);
+
+/**
+ * Convert a UTF-8 String to a URI.
+ *
+ * @param uri string to parse
+ * @param emsg where to store the parser error message (if any)
+ * @return NULL on error
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_parse (const char *uri,
+                    char **emsg);
+
+/**
+ * Free URI.
+ *
+ * @param uri uri to free
+ */
+void 
+GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri)
+{
+  unsigned int i;
+
+  GNUNET_assert (uri != NULL);
+  switch (uri->type)
+    {
+    case ksk:
+      for (i = 0; i < uri->data.ksk.keywordCount; i++)
+        GNUNET_free (uri->data.ksk.keywords[i]);
+      GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount,
+                         0);
+      break;
+    case sks:
+      GNUNET_free (uri->data.sks.identifier);
+      break;
+    case loc:
+      break;
+    default:
+      /* do nothing */
+      break;
+    }
+  GNUNET_free (uri);
+}
+
+/**
+ * How many keywords are ANDed in this keyword URI?
+ *
+ * @param uri ksk uri to get the number of keywords from
+ * @return 0 if this is not a keyword URI
+ */
+unsigned int 
+GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri)
+{
+  if (uri->type != ksk)
+    return 0;
+  return uri->data.ksk.keywordCount;
+}
+
+
+/**
+ * Iterate over all keywords in this keyword URI.
+ *
+ * @param uri ksk uri to get the keywords from
+ * @param iterator function to call on each keyword
+ * @param iterator_cls closure for iterator
+ * @return -1 if this is not a keyword URI, otherwise number of
+ *   keywords iterated over until iterator aborted
+ */
+int 
+GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri,
+                               GNUNET_FS_KeywordIterator iterator, 
+                               void *iterator_cls)
+{
+  unsigned int i;
+  char *keyword;
+
+  if (uri->type != ksk)
+    return -1;
+  if (iterator == NULL)
+    return uri->data.ksk.keywordCount;
+  for (i = 0; i < uri->data.ksk.keywordCount; i++)
+    {
+      keyword = uri->data.ksk.keywords[i];
+      /* first character of keyword indicates
+         if it is mandatory or not */
+      if (GNUNET_OK != iterator (&keyword[1], keyword[0] == '+', cls))
+        return i;
+    }
+  return i;
+}
+
+
+/**
+ * Obtain the identity of the peer offering the data
+ *
+ * @param uri the location URI to inspect
+ * @param peer where to store the identify of the peer (presumably) offering 
the content
+ * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK
+ */
+int
+GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri,
+                                    struct GNUNET_PeerIdentity * peer)
+{
+  if (uri->type != loc)
+    return GNUNET_SYSERR;
+  GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey),
+               &peer->hashPubKey);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Obtain the URI of the content itself.
+ *
+ * @param uri location URI to get the content URI from
+ * @return NULL if argument is not a location URI
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri)
+{
+  struct GNUNET_ECRS_Uri *ret;
+
+  if (uri->type != loc)
+    return NULL;
+  ret = GNUNET_malloc (sizeof (struct GNUNET_ECRS_Uri));
+  ret->type = chk;
+  ret->data.chk = uri->data.loc.fi;
+  return ret;
+}
+
+
+/**
+ * Construct a location URI (this peer will be used for the location).
+ *
+ * @param baseURI content offered by the sender
+ * @param cfg configuration information (used to find our hostkey)
+ * @param expiration_time how long will the content be offered?
+ * @return the location URI, NULL on error
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri,
+                         struct GNUNET_CONFIGURATION_Handle *cfg,
+                         struct GNUNET_TIME_Absolute expiration_time);
+
+
+/**
+ * Canonicalize keyword URI.  Performs operations such
+ * as decapitalization and removal of certain characters.
+ * (useful for search).
+ *
+ * @param uri the URI to canonicalize 
+ * @return canonicalized version of the URI, NULL on error
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri);
+
+
+/**
+ * Merge the sets of keywords from two KSK URIs.
+ * (useful for merging the canonicalized keywords with
+ * the original keywords for sharing).
+ *
+ * @param u1 first uri
+ * @param u2 second uri
+ * @return merged URI, NULL on error
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1,
+                        const struct GNUNET_FS_Uri *u2);
+
+
+/**
+ * Duplicate URI.
+ *
+ * @param uri the URI to duplicate
+ * @return copy of the URI
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri)
+{
+  struct GNUNET_ECRS_URI *ret;
+  unsigned int i;
+
+  ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+  memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri));
+  switch (ret->type)
+    {
+    case ksk:
+      if (ret->data.ksk.keywordCount > 0)
+        {
+          ret->data.ksk.keywords
+            = GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *));
+          for (i = 0; i < ret->data.ksk.keywordCount; i++)
+            ret->data.ksk.keywords[i] =
+              GNUNET_strdup (uri->data.ksk.keywords[i]);
+        }
+      else
+        ret->data.ksk.keywords = NULL;  /* just to be sure */
+      break;
+    case sks:
+      ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier);
+      break;
+    case loc:
+      break;
+    default:
+      break;
+    }
+  return ret;
+}
+
+
+/**
+ * Create an FS URI from a single user-supplied string of keywords.
+ * The string is broken up at spaces into individual keywords.
+ * Keywords that start with "+" are mandatory.  Double-quotes can
+ * be used to prevent breaking up strings at spaces (and also
+ * to specify non-mandatory keywords starting with "+").
+ *
+ * Keywords must contain a balanced number of double quotes and
+ * double quotes can not be used in the actual keywords (for
+ * example, the string '""foo bar""' will be turned into two
+ * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'.
+ *
+ * @param keywords the keyword string
+ * @return an FS URI for the given keywords, NULL
+ *  if keywords is not legal (i.e. empty).
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_ksk_create (const char *keywords);
+
+
+/**
+ * Create an FS URI from a user-supplied command line of keywords.
+ * Arguments should start with "+" to indicate mandatory
+ * keywords.
+ *
+ * @param argc number of keywords
+ * @param argv keywords (double quotes are not required for
+ *             keywords containing spaces; however, double
+ *             quotes are required for keywords starting with
+ *             "+"); there is no mechanism for having double
+ *             quotes in the actual keywords (if the user
+ *             did specifically specify double quotes, the
+ *             caller should convert each double quote
+ *             into two single quotes).
+ * @return an FS URI for the given keywords, NULL
+ *  if keywords is not legal (i.e. empty).
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_ksk_create_from_args (unsigned int argc,
+                                   const char **argv);
+
+
+/**
+ * Test if two URIs are equal.
+ *
+ * @param u1 one of the URIs
+ * @param u2 the other URI
+ * @return GNUNET_YES if the URIs are equal
+ */
+int 
+GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1,
+                         const struct GNUNET_FS_Uri *u2)
+{
+  int ret;
+  unsigned int i;
+  unsigned int j;
+
+  GNUNET_assert (uri1 != NULL);
+  GNUNET_assert (uri2 != NULL);
+  if (uri1->type != uri2->type)
+    return GNUNET_NO;
+  switch (uri1->type)
+    {
+    case chk:
+      if (0 == memcmp (&uri1->data.chk,
+                       &uri2->data.chk,
+                      sizeof (struct FileIdentifier)))
+        return GNUNET_YES;
+      return GNUNET_NO;
+    case sks:
+      if ((0 == memcmp (&uri1->data.sks.namespace,
+                        &uri2->data.sks.namespace,
+                        sizeof (GNUNET_HashCode))) &&
+          (0 == strcmp (uri1->data.sks.identifier,
+                        uri2->data.sks.identifier)))
+
+        return GNUNET_YES;
+      return GNUNET_NO;
+    case ksk:
+      if (uri1->data.ksk.keywordCount != uri2->data.ksk.keywordCount)
+        return GNUNET_NO;
+      for (i = 0; i < uri1->data.ksk.keywordCount; i++)
+        {
+          ret = GNUNET_NO;
+          for (j = 0; j < uri2->data.ksk.keywordCount; j++)
+            {
+              if (0 == strcmp (uri1->data.ksk.keywords[i],
+                               uri2->data.ksk.keywords[j]))
+                {
+                  ret = GNUNET_YES;
+                  break;
+                }
+            }
+          if (ret == GNUNET_NO)
+            return GNUNET_NO;
+        }
+      return GNUNET_YES;
+    case loc:
+      if (memcmp (&uri1->data.loc,
+                  &uri2->data.loc,
+                  sizeof (struct FileIdentifier) +
+                  sizeof (GNUNET_RSA_PublicKey) +
+                  sizeof (struct GNUNET_TIME_Absolute) +
+                  sizeof (unsigned short) + sizeof (unsigned short)) != 0)
+        return GNUNET_NO;
+      return GNUNET_YES;
+    default:
+      return GNUNET_NO;
+    }
+}
+
+
+/**
+ * Is this a namespace URI?
+ *
+ * @param uri the uri to check
+ * @return GNUNET_YES if this is an SKS uri
+ */
+int
+GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri)
+{
+  return uri->type == sks;
+}
+
+
+/**
+ * Get the ID of a namespace from the given
+ * namespace URI.
+ *
+ * @param uri the uri to get the namespace ID from
+ * @param nsid where to store the ID of the namespace
+ * @return GNUNET_OK on success
+ */
+int 
+GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri,
+                                GNUNET_HashCode * nsid)
+{
+  if (! GNUNET_FS_uri_test_sks (uri))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+  *id = uri->data.sks.namespace;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Get the content identifier of an SKS URI.
+ *
+ * @param uri the sks uri
+ * @return NULL on error (not a valid SKS URI)
+ */
+char *
+GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri)
+{
+  if (!GNUNET_FS_uri_test_sks (uri))
+    {
+      GNUNET_break (0);
+      return NULL;
+    }
+  return GNUNET_strdup (uri->data.sks.identifier);
+}
+
+
+/**
+ * Convert namespace URI to a human readable format
+ * (using the namespace description, if available).
+ *
+ * @param cfg configuration to use
+ * @param uri SKS uri to convert
+ * @return NULL on error (not an SKS URI)
+ */
+char *
+GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg,
+                                  const struct GNUNET_FS_Uri *uri);
+
+
+/**
+ * Is this a keyword URI?
+ *
+ * @param uri the uri
+ * @return GNUNET_YES if this is a KSK uri
+ */
+int 
+GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri)
+{
+#if EXTRA_CHECKS
+  unsigned int i;
+
+  if (uri->type == ksk)
+    {
+      for (i = uri->data.ksk.keywordCount - 1; i >= 0; i--)
+        GNUNET_assert (uri->data.ksk.keywords[i] != NULL);
+    }
+#endif
+  return uri->type == ksk;
+}
+
+
+/**
+ * Is this a file (or directory) URI?
+ *
+ * @param uri the uri to check
+ * @return GNUNET_YES if this is a CHK uri
+ */
+int 
+GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri)
+{
+  return uri->type == chk;
+}
+
+
+/**
+ * What is the size of the file that this URI
+ * refers to?
+ *
+ * @param uri the CHK URI to inspect
+ * @return size of the file as specified in the CHK URI
+ */
+uint64_t 
+GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri)
+{
+  switch (uri->type)
+    {
+    case chk:
+      return GNUNET_ntohll (uri->data.chk.file_length);
+    case loc:
+      return GNUNET_ntohll (uri->data.loc.fi.file_length);
+    default:
+      GNUNET_assert (0);
+    }
+  return 0;                     /* unreachable */
+}
+
+
+/**
+ * Is this a location URI?
+ *
+ * @param uri the uri to check
+ * @return GNUNET_YES if this is a LOC uri
+ */
+int 
+GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri)
+{
+  return uri->type == loc;
+}
+
+
+/**
+ * Function called on each value in the meta data.
+ * Adds it to the URI.
+ *
+ * @param cls URI to update
+ * @param type type of the meta data
+ * @param data value of the meta data
+ * @return GNUNET_OK (always)
+ */
+static int
+gather_uri_data (void *cls,
+                EXTRACTOR_KeywordType type, 
+                const char *data)
+{
+  struct GNUNET_FS_Uri *uri = cls;
+  char *nkword;
+  int j;
+  
+  for (j = uri->data.ksk.keywordCount - 1; j >= 0; j--)
+    if (0 == strcmp (&uri->data.ksk.keywords[j][1], data))
+      return GNUNET_OK;
+  nkword = GNUNET_malloc (strlen (data) + 2);
+  strcpy (nkword, " ");         /* not mandatory */
+  strcat (nkword, data);
+  uri->data.ksk.keywords[uri->data.ksk.keywordCount++] = nkword;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Construct a keyword-URI from meta-data (take all entries
+ * in the meta-data and construct one large keyword URI
+ * that lists all keywords that can be found in the meta-data).
+ * @deprecated
+ */
+struct GNUNET_FS_Uri *
+GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_MetaData *md)
+{
+  struct GNUNET_FS_Uri *ret;
+
+  if (md == NULL)
+    return NULL;
+  ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+  ret->type = ksk;
+  ret->data.ksk.keywordCount = 0;
+  ret->data.ksk.keywords = NULL;
+  ret->data.ksk.keywords
+    = GNUNET_malloc (sizeof (char *) *
+                     GNUNET_meta_data_get_contents (md, NULL, NULL));
+  GNUNET_meta_data_get_contents (md, &gather_uri_data, ret);
+  return ret;
+
+}
+
+#if 0
+
+// old code...
+
+
+
+/**
+ * In URI-encoding, does the given character
+ * need to be encoded using %-encoding?
+ */
+static int
+needs_percent (char c)
+{
+  return (!((isalnum (c)) ||
+            (c == '-') || (c == '_') || (c == '.') || (c == '~')));
+}
+
+/**
+ * Generate a keyword URI.
+ * @return NULL on error (i.e. keywordCount == 0)
+ */
+static char *
+createKeywordURI (char **keywords, unsigned int keywordCount)
+{
+  size_t n;
+  char *ret;
+  unsigned int i;
+  unsigned int j;
+  unsigned int wpos;
+  size_t slen;
+  const char *keyword;
+
+  n =
+    keywordCount + strlen (GNUNET_ECRS_URI_PREFIX) +
+    strlen (GNUNET_ECRS_SEARCH_INFIX) + 1;
+  for (i = 0; i < keywordCount; i++)
+    {
+      keyword = keywords[i];
+      slen = strlen (keyword);
+      n += slen;
+      for (j = 0; j < slen; j++)
+        {
+          if ((j == 0) && (keyword[j] == ' '))
+            {
+              n--;
+              continue;         /* skip leading space */
+            }
+          if (needs_percent (keyword[j]))
+            n += 2;             /* will use %-encoding */
+        }
+    }
+  ret = GNUNET_malloc (n);
+  strcpy (ret, GNUNET_ECRS_URI_PREFIX);
+  strcat (ret, GNUNET_ECRS_SEARCH_INFIX);
+  wpos = strlen (ret);
+  for (i = 0; i < keywordCount; i++)
+    {
+      keyword = keywords[i];
+      slen = strlen (keyword);
+      for (j = 0; j < slen; j++)
+        {
+          if ((j == 0) && (keyword[j] == ' '))
+            continue;           /* skip leading space */
+          if (needs_percent (keyword[j]))
+            {
+              sprintf (&ret[wpos], "%%%02X", keyword[j]);
+              wpos += 3;
+            }
+          else
+            {
+              ret[wpos++] = keyword[j];
+            }
+        }
+      if (i != keywordCount - 1)
+        ret[wpos++] = '+';
+    }
+  return ret;
+}
+
+/**
+ * Generate a subspace URI.
+ */
+static char *
+createSubspaceURI (const GNUNET_HashCode * namespace, const char *identifier)
+{
+  size_t n;
+  char *ret;
+  GNUNET_EncName ns;
+
+  n =
+    sizeof (GNUNET_EncName) + strlen (GNUNET_ECRS_URI_PREFIX) +
+    strlen (GNUNET_ECRS_SUBSPACE_INFIX) + 1 + strlen (identifier);
+  ret = GNUNET_malloc (n);
+  GNUNET_hash_to_enc (namespace, &ns);
+  GNUNET_snprintf (ret, n,
+                   "%s%s%s/%s",
+                   GNUNET_ECRS_URI_PREFIX, GNUNET_ECRS_SUBSPACE_INFIX,
+                   (const char *) &ns, identifier);
+  return ret;
+}
+
+/**
+ * Generate a file URI.
+ */
+static char *
+createFileURI (const GNUNET_EC_FileIdentifier * fi)
+{
+  char *ret;
+  GNUNET_EncName keyhash;
+  GNUNET_EncName queryhash;
+  size_t n;
+
+  GNUNET_hash_to_enc (&fi->chk.key, &keyhash);
+  GNUNET_hash_to_enc (&fi->chk.query, &queryhash);
+
+  n =
+    strlen (GNUNET_ECRS_URI_PREFIX) + 2 * sizeof (GNUNET_EncName) + 8 + 16 +
+    32 + strlen (GNUNET_ECRS_FILE_INFIX);
+  ret = GNUNET_malloc (n);
+  GNUNET_snprintf (ret,
+                   n,
+                   "%s%s%s.%s.%llu",
+                   GNUNET_ECRS_URI_PREFIX,
+                   GNUNET_ECRS_FILE_INFIX,
+                   (char *) &keyhash, (char *) &queryhash,
+                   GNUNET_ntohll (fi->file_length));
+  return ret;
+}
+
+#include "bincoder.c"
+
+/**
+ * Create a (string) location URI from a Location.
+ */
+static char *
+createLocURI (const Location * loc)
+{
+  size_t n;
+  char *ret;
+  GNUNET_EncName keyhash;
+  GNUNET_EncName queryhash;
+  char *peerId;
+  char *peerSig;
+
+  GNUNET_hash_to_enc (&loc->fi.chk.key, &keyhash);
+  GNUNET_hash_to_enc (&loc->fi.chk.query, &queryhash);
+  n = 2148;
+  peerId = bin2enc (&loc->peer, sizeof (GNUNET_RSA_PublicKey));
+  peerSig = bin2enc (&loc->contentSignature, sizeof (GNUNET_RSA_Signature));
+  ret = GNUNET_malloc (n);
+  GNUNET_snprintf (ret,
+                   n,
+                   "%s%s%s.%s.%llu.%s.%s.%u",
+                   GNUNET_ECRS_URI_PREFIX,
+                   GNUNET_ECRS_LOCATION_INFIX,
+                   (char *) &keyhash,
+                   (char *) &queryhash,
+                   GNUNET_ntohll (loc->fi.file_length),
+                   peerId, peerSig, loc->expirationTime);
+  GNUNET_free (peerSig);
+  GNUNET_free (peerId);
+  return ret;
+}
+
+/**
+ * Convert a URI to a UTF-8 String.
+ */
+char *
+GNUNET_ECRS_uri_to_string (const struct GNUNET_ECRS_URI *uri)
+{
+  if (uri == NULL)
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return NULL;
+    }
+  switch (uri->type)
+    {
+    case ksk:
+      return createKeywordURI (uri->data.ksk.keywords,
+                               uri->data.ksk.keywordCount);
+    case sks:
+      return createSubspaceURI (&uri->data.sks.namespace,
+                                uri->data.sks.identifier);
+    case chk:
+      return createFileURI (&uri->data.fi);
+    case loc:
+      return createLocURI (&uri->data.loc);
+    default:
+      GNUNET_GE_BREAK (NULL, 0);
+      return NULL;
+    }
+}
+
+/**
+ * Convert keyword URI to a human readable format
+ * (i.e. the search query that was used in the first place)
+ */
+char *
+GNUNET_ECRS_ksk_uri_to_human_readable_string (const struct GNUNET_ECRS_URI
+                                              *uri)
+{
+  size_t n;
+  char *ret;
+  unsigned int i;
+  const char *keyword;
+  char **keywords;
+  unsigned int keywordCount;
+
+  if ((uri == NULL) || (uri->type != ksk))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      return NULL;
+    }
+  keywords = uri->data.ksk.keywords;
+  keywordCount = uri->data.ksk.keywordCount;
+  n = keywordCount + 1;
+  for (i = 0; i < keywordCount; i++)
+    {
+      keyword = keywords[i];
+      n += strlen (keyword) - 1;
+      if (NULL != strstr (&keyword[1], " "))
+        n += 2;
+      if (keyword[0] == '+')
+        n++;
+    }
+  ret = GNUNET_malloc (n);
+  strcpy (ret, "");
+  for (i = 0; i < keywordCount; i++)
+    {
+      keyword = keywords[i];
+      if (NULL != strstr (&keyword[1], " "))
+        {
+          strcat (ret, "\"");
+          if (keyword[0] == '+')
+            strcat (ret, keyword);
+          else
+            strcat (ret, &keyword[1]);
+          strcat (ret, "\"");
+        }
+      else
+        {
+          if (keyword[0] == '+')
+            strcat (ret, keyword);
+          else
+            strcat (ret, &keyword[1]);
+        }
+      strcat (ret, " ");
+    }
+  return ret;
+}
+
+/**
+ * Given a keyword with %-encoding (and possibly quotes to protect
+ * spaces), return a copy of the keyword without %-encoding and
+ * without double-quotes (%22).  Also, add a space at the beginning
+ * if there is not a '+'.
+ */
+static char *
+percent_decode_keyword (const char *in)
+{
+  char *out;
+  char *ret;
+  unsigned int rpos;
+  unsigned int wpos;
+  unsigned int hx;
+
+  out = GNUNET_strdup (in);
+  rpos = 0;
+  wpos = 0;
+  while (out[rpos] != '\0')
+    {
+      if (out[rpos] == '%')
+        {
+          if (1 != sscanf (&out[rpos + 1], "%2X", &hx))
+            {
+              GNUNET_free (out);
+              return NULL;
+            }
+          rpos += 3;
+          if (hx == '"')
+            continue;           /* skip double quote */
+          out[wpos++] = (char) hx;
+        }
+      else
+        {
+          out[wpos++] = out[rpos++];
+        }
+    }
+  out[wpos] = '\0';
+  if (out[0] == '+')
+    {
+      ret = GNUNET_strdup (out);
+    }
+  else
+    {
+      /* need to prefix with space */
+      ret = GNUNET_malloc (strlen (out) + 2);
+      strcpy (ret, " ");
+      strcat (ret, out);
+    }
+  GNUNET_free (out);
+  return ret;
+}
+
+/**
+ * Parses an ECRS search URI.
+ *
+ * @param uri an uri string
+ * @param keyword will be set to an array with the keywords
+ * @return GNUNET_SYSERR if this is not a search URI, otherwise
+ *  the number of keywords placed in the array
+ */
+static int
+parseKeywordURI (struct GNUNET_GE_Context *ectx, const char *uri,
+                 char ***keywords)
+{
+  unsigned int pos;
+  int ret;
+  int iret;
+  int i;
+  size_t slen;
+  char *dup;
+  int saw_quote;
+
+  GNUNET_GE_ASSERT (ectx, uri != NULL);
+
+  slen = strlen (uri);
+  pos = strlen (GNUNET_ECRS_URI_PREFIX);
+
+  if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
+    return GNUNET_SYSERR;
+  if (0 !=
+      strncmp (&uri[pos], GNUNET_ECRS_SEARCH_INFIX,
+               strlen (GNUNET_ECRS_SEARCH_INFIX)))
+    return GNUNET_SYSERR;
+  pos += strlen (GNUNET_ECRS_SEARCH_INFIX);
+  if (slen == pos)
+    {
+      /* no keywords */
+      (*keywords) = NULL;
+      return 0;
+    }
+  if ((uri[slen - 1] == '+') || (uri[pos] == '+'))
+    return GNUNET_SYSERR;       /* no keywords / malformed */
+
+  ret = 1;
+  saw_quote = 0;
+  for (i = pos; i < slen; i++)
+    {
+      if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22")))
+        {
+          saw_quote = (saw_quote + 1) % 2;
+          i += 3;
+          continue;
+        }
+      if ((uri[i] == '+') && (saw_quote == 0))
+        {
+          ret++;
+          if (uri[i - 1] == '+')
+            return GNUNET_SYSERR;       /* "++" not allowed */
+        }
+    }
+  if (saw_quote == 1)
+    return GNUNET_SYSERR;       /* quotes not balanced */
+  iret = ret;
+  dup = GNUNET_strdup (uri);
+  (*keywords) = GNUNET_malloc (ret * sizeof (char *));
+  for (i = 0; i < ret; i++)
+    (*keywords)[i] = NULL;
+  for (i = slen - 1; i >= pos; i--)
+    {
+      if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22")))
+        {
+          saw_quote = (saw_quote + 1) % 2;
+          i += 3;
+          continue;
+        }
+      if ((dup[i] == '+') && (saw_quote == 0))
+        {
+          (*keywords)[--ret] = percent_decode_keyword (&dup[i + 1]);
+          if (NULL == (*keywords)[ret])
+            goto CLEANUP;
+          dup[i] = '\0';
+        }
+    }
+  (*keywords)[--ret] = percent_decode_keyword (&dup[pos]);
+  if (NULL == (*keywords)[ret])
+    goto CLEANUP;
+  GNUNET_GE_ASSERT (ectx, ret == 0);
+  GNUNET_free (dup);
+  return iret;
+CLEANUP:
+  for (i = 0; i < ret; i++)
+    GNUNET_free_non_null ((*keywords)[i]);
+  GNUNET_free (*keywords);
+  *keywords = NULL;
+  GNUNET_free (dup);
+  return GNUNET_SYSERR;
+}
+
+/**
+ * Parses an AFS namespace / subspace identifier URI.
+ *
+ * @param uri an uri string
+ * @param namespace set to the namespace ID
+ * @param identifier set to the ID in the namespace
+ * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a namespace URI
+ */
+static int
+parseSubspaceURI (struct GNUNET_GE_Context *ectx,
+                  const char *uri,
+                  GNUNET_HashCode * namespace, char **identifier)
+{
+  unsigned int pos;
+  size_t slen;
+  char *up;
+
+  GNUNET_GE_ASSERT (ectx, uri != NULL);
+
+  slen = strlen (uri);
+  pos = strlen (GNUNET_ECRS_URI_PREFIX);
+
+  if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
+    return GNUNET_SYSERR;
+  if (0 != strncmp (&uri[pos],
+                    GNUNET_ECRS_SUBSPACE_INFIX,
+                    strlen (GNUNET_ECRS_SUBSPACE_INFIX)))
+    return GNUNET_SYSERR;
+  pos += strlen (GNUNET_ECRS_SUBSPACE_INFIX);
+  if ((slen < pos + sizeof (GNUNET_EncName) + 1) ||
+      (!((uri[pos + sizeof (GNUNET_EncName) - 1] == '/') ||
+         (uri[pos + sizeof (GNUNET_EncName) - 1] == '\\'))))
+    return GNUNET_SYSERR;
+
+  up = GNUNET_strdup (uri);
+  up[pos + sizeof (GNUNET_EncName) - 1] = '\0';
+  if ((GNUNET_OK != GNUNET_enc_to_hash (&up[pos], namespace)))
+    {
+      GNUNET_free (up);
+      return GNUNET_SYSERR;
+    }
+  *identifier = GNUNET_strdup (&up[pos + sizeof (GNUNET_EncName)]);
+  GNUNET_free (up);
+  return GNUNET_OK;
+}
+
+/**
+ * Parses an URI that identifies a file
+ *
+ * @param uri an uri string
+ * @param fi the file identifier
+ * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI
+ */
+static int
+parseFileURI (struct GNUNET_GE_Context *ectx, const char *uri,
+              GNUNET_EC_FileIdentifier * fi)
+{
+  unsigned int pos;
+  size_t slen;
+  char *dup;
+
+  GNUNET_GE_ASSERT (ectx, uri != NULL);
+
+  slen = strlen (uri);
+  pos = strlen (GNUNET_ECRS_URI_PREFIX);
+
+  if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
+    return GNUNET_SYSERR;
+  if (0 !=
+      strncmp (&uri[pos], GNUNET_ECRS_FILE_INFIX,
+               strlen (GNUNET_ECRS_FILE_INFIX)))
+    return GNUNET_SYSERR;
+  pos += strlen (GNUNET_ECRS_FILE_INFIX);
+  if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) ||
+      (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') ||
+      (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.'))
+    return GNUNET_SYSERR;
+
+  dup = GNUNET_strdup (uri);
+  dup[pos + sizeof (GNUNET_EncName) - 1] = '\0';
+  dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0';
+  if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos],
+                                        &fi->chk.key)) ||
+      (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)],
+                                        &fi->chk.query)) ||
+      (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2],
+                    "%llu", &fi->file_length)))
+    {
+      GNUNET_free (dup);
+      return GNUNET_SYSERR;
+    }
+  GNUNET_free (dup);
+  fi->file_length = GNUNET_htonll (fi->file_length);
+  return GNUNET_OK;
+}
+
+/**
+ * Parses an URI that identifies a location (and file).
+ * Also verifies validity of the location URI.
+ *
+ * @param uri an uri string
+ * @param loc where to store the location
+ * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI
+ */
+static int
+parseLocationURI (struct GNUNET_GE_Context *ectx, const char *uri,
+                  Location * loc)
+{
+  unsigned int pos;
+  unsigned int npos;
+  int ret;
+  size_t slen;
+  char *dup;
+  char *addr;
+
+
+  GNUNET_GE_ASSERT (ectx, uri != NULL);
+  addr = NULL;
+  slen = strlen (uri);
+  pos = strlen (GNUNET_ECRS_URI_PREFIX);
+
+  if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
+    return GNUNET_SYSERR;
+  if (0 != strncmp (&uri[pos],
+                    GNUNET_ECRS_LOCATION_INFIX,
+                    strlen (GNUNET_ECRS_LOCATION_INFIX)))
+    return GNUNET_SYSERR;
+  pos += strlen (GNUNET_ECRS_LOCATION_INFIX);
+  if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) ||
+      (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') ||
+      (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.'))
+    return GNUNET_SYSERR;
+
+  dup = GNUNET_strdup (uri);
+  dup[pos + sizeof (GNUNET_EncName) - 1] = '\0';
+  dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0';
+  npos = pos + sizeof (GNUNET_EncName) * 2;
+  while ((uri[npos] != '\0') && (uri[npos] != '.'))
+    npos++;
+  if (dup[npos] == '\0')
+    goto ERR;
+  dup[npos++] = '\0';
+  if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos],
+                                        &loc->fi.chk.key)) ||
+      (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)],
+                                        &loc->fi.chk.query)) ||
+      (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2],
+                    "%llu", &loc->fi.file_length)))
+    goto ERR;
+  loc->fi.file_length = GNUNET_htonll (loc->fi.file_length);
+  ret = enc2bin (&dup[npos], &loc->peer, sizeof (GNUNET_RSA_PublicKey));
+  if (ret == -1)
+    goto ERR;
+  npos += ret;
+  if (dup[npos++] != '.')
+    goto ERR;
+  ret =
+    enc2bin (&dup[npos], &loc->contentSignature,
+             sizeof (GNUNET_RSA_Signature));
+  if (ret == -1)
+    goto ERR;
+  npos += ret;
+  if (dup[npos++] != '.')
+    goto ERR;
+  if (1 != SSCANF (&dup[npos], "%u", &loc->expirationTime))
+    goto ERR;
+  /* Finally: verify sigs! */
+  if (GNUNET_OK != GNUNET_RSA_verify (&loc->fi,
+                                      sizeof (GNUNET_EC_FileIdentifier) +
+                                      sizeof (GNUNET_PeerIdentity) +
+                                      sizeof (GNUNET_Int32Time),
+                                      &loc->contentSignature, &loc->peer))
+    goto ERR;
+  GNUNET_free (dup);
+  return GNUNET_OK;
+ERR:
+  GNUNET_free (dup);
+  GNUNET_free_non_null (addr);
+  return GNUNET_SYSERR;
+}
+
+/**
+ * Convert a UTF-8 String to a URI.
+ */
+URI *
+GNUNET_ECRS_string_to_uri (struct GNUNET_GE_Context * ectx, const char *uri)
+{
+  URI *ret;
+  int len;
+
+  ret = GNUNET_malloc (sizeof (URI));
+  if (GNUNET_OK == parseFileURI (ectx, uri, &ret->data.fi))
+    {
+      ret->type = chk;
+      return ret;
+    }
+  if (GNUNET_OK == parseSubspaceURI (ectx,
+                                     uri,
+                                     &ret->data.sks.namespace,
+                                     &ret->data.sks.identifier))
+    {
+      ret->type = sks;
+      return ret;
+    }
+  if (GNUNET_OK == parseLocationURI (ectx, uri, &ret->data.loc))
+    {
+      ret->type = loc;
+      return ret;
+    }
+  len = parseKeywordURI (ectx, uri, &ret->data.ksk.keywords);
+  if (len < 0)
+    {
+      GNUNET_free (ret);
+      return NULL;
+    }
+  ret->type = ksk;
+  ret->data.ksk.keywordCount = len;
+  return ret;
+}
+
+
+
+/**
+ * Construct a location URI.
+ *
+ * @param baseURI content offered by the sender
+ * @param sender identity of the peer with the content
+ * @param expiration_time how long will the content be offered?
+ * @param proto transport protocol to reach the peer
+ * @param sas sender address size (for HELLO)
+ * @param address sas bytes of address information
+ * @param signer function to call for obtaining
+ *        RSA signatures for "sender".
+ * @return the location URI
+ */
+struct GNUNET_ECRS_URI *
+GNUNET_ECRS_location_to_uri (const struct GNUNET_ECRS_URI *baseUri,
+                             const GNUNET_RSA_PublicKey * sender,
+                             GNUNET_Int32Time expirationTime,
+                             GNUNET_ECRS_SignFunction signer,
+                             void *signer_cls)
+{
+  struct GNUNET_ECRS_URI *uri;
+
+  if (baseUri->type != chk)
+    return NULL;
+
+  uri = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI));
+  uri->type = loc;
+  uri->data.loc.fi = baseUri->data.fi;
+  uri->data.loc.peer = *sender;
+  uri->data.loc.expirationTime = expirationTime;
+  signer (signer_cls,
+          sizeof (GNUNET_EC_FileIdentifier) +
+          sizeof (GNUNET_PeerIdentity) +
+          sizeof (GNUNET_Int32Time),
+          &uri->data.loc.fi, &uri->data.loc.contentSignature);
+  return uri;
+}
+
+#endif
+
+/* end of uri.c */

Added: gnunet/src/fs/test_fs_getopt.c
===================================================================
--- gnunet/src/fs/test_fs_getopt.c                              (rev 0)
+++ gnunet/src/fs/test_fs_getopt.c      2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,33 @@
+/*
+     This file is part of GNUnet
+     (C) 2009 Christian Grothoff (and other contributing authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+/**
+ * @file fs/test_fs_getopt.c
+ * @brief test for fs_getopt.c
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_fs_lib.h"
+
+int
+main (int argc, char *argv[])
+{
+  fprintf (stderr, "WARNING: testcase not yet written.\n");
+  return 0;                     /* testcase passed */
+}

Added: gnunet/src/fs/test_fs_uri.c
===================================================================
--- gnunet/src/fs/test_fs_uri.c                         (rev 0)
+++ gnunet/src/fs/test_fs_uri.c 2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,255 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2006, 2007 Christian Grothoff (and other contributing 
authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+
+/**
+ * @file applications/fs/ecrs/uritest.c
+ * @brief Test for uri.c
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util.h"
+#include "gnunet_ecrs_lib.h"
+#include "ecrs.h"
+
+#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); 
return 1; }
+
+static int
+testKeyword ()
+{
+  char *uri;
+  struct GNUNET_ECRS_URI *ret;
+
+  if (NULL != GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/ksk/++"))
+    ABORT ();
+  ret = GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/ksk/foo+bar");
+  if (ret == NULL)
+    ABORT ();
+  if (!GNUNET_ECRS_uri_test_ksk (ret))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  if ((2 != ret->data.ksk.keywordCount) ||
+      (0 != strcmp (" foo", ret->data.ksk.keywords[0])) ||
+      (0 != strcmp (" bar", ret->data.ksk.keywords[1])))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+
+  uri = GNUNET_ECRS_uri_to_string (ret);
+  if (0 != strcmp (uri, "gnunet://ecrs/ksk/foo+bar"))
+    {
+      GNUNET_free (uri);
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  GNUNET_free (uri);
+  GNUNET_ECRS_uri_destroy (ret);
+  return 0;
+}
+
+static int
+testLocation ()
+{
+  struct GNUNET_ECRS_URI *uri;
+  char *uric;
+  struct GNUNET_ECRS_URI *uri2;
+  GNUNET_RSA_PublicKey pk;
+  struct GNUNET_RSA_PrivateKey *hk;
+  struct GNUNET_ECRS_URI *baseURI;
+
+  baseURI =
+    GNUNET_ECRS_string_to_uri (NULL,
+                               
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42");
+  hk = GNUNET_RSA_create_key ();
+  GNUNET_RSA_get_public_key (hk, &pk);
+  uri = GNUNET_ECRS_location_to_uri (baseURI,
+                                     &pk, 43,
+                                     (GNUNET_ECRS_SignFunction) &
+                                     GNUNET_RSA_sign, hk);
+  GNUNET_RSA_free_key (hk);
+  if (uri == NULL)
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_ECRS_uri_destroy (baseURI);
+      return 1;
+    }
+  if (!GNUNET_ECRS_uri_test_loc (uri))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_ECRS_uri_destroy (uri);
+      GNUNET_ECRS_uri_destroy (baseURI);
+      return 1;
+    }
+  uri2 = GNUNET_ECRS_uri_get_content_uri_from_loc (uri);
+  if (!GNUNET_ECRS_uri_test_equal (baseURI, uri2))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_ECRS_uri_destroy (uri);
+      GNUNET_ECRS_uri_destroy (uri2);
+      GNUNET_ECRS_uri_destroy (baseURI);
+      return 1;
+    }
+  GNUNET_ECRS_uri_destroy (uri2);
+  GNUNET_ECRS_uri_destroy (baseURI);
+  uric = GNUNET_ECRS_uri_to_string (uri);
+#if 0
+  /* not for the faint of heart: */
+  printf ("URI: `%s'\n", uric);
+#endif
+  uri2 = GNUNET_ECRS_string_to_uri (NULL, uric);
+  GNUNET_free (uric);
+  if (uri2 == NULL)
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_ECRS_uri_destroy (uri);
+      return 1;
+    }
+  if (GNUNET_YES != GNUNET_ECRS_uri_test_equal (uri, uri2))
+    {
+      GNUNET_GE_BREAK (NULL, 0);
+      GNUNET_ECRS_uri_destroy (uri);
+      GNUNET_ECRS_uri_destroy (uri2);
+      return 1;
+    }
+  GNUNET_ECRS_uri_destroy (uri2);
+  GNUNET_ECRS_uri_destroy (uri);
+  return 0;
+}
+
+static int
+testNamespace (int i)
+{
+  char *uri;
+  struct GNUNET_ECRS_URI *ret;
+
+  if (NULL !=
+      GNUNET_ECRS_string_to_uri (NULL,
+                                 
"gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK"))
+    ABORT ();
+  if (NULL !=
+      GNUNET_ECRS_string_to_uri (NULL,
+                                 
"gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test"))
+    ABORT ();
+  if (NULL != GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/sks/test"))
+    ABORT ();
+  ret =
+    GNUNET_ECRS_string_to_uri (NULL,
+                               
"gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test");
+  if (ret == NULL)
+    ABORT ();
+  if (GNUNET_ECRS_uri_test_ksk (ret))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  if (!GNUNET_ECRS_uri_test_sks (ret))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+
+  uri = GNUNET_ECRS_uri_to_string (ret);
+  if (0 != strcmp (uri,
+                   
"gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test"))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      GNUNET_free (uri);
+      ABORT ();
+    }
+  GNUNET_free (uri);
+  GNUNET_ECRS_uri_destroy (ret);
+  return 0;
+}
+
+static int
+testFile (int i)
+{
+  char *uri;
+  struct GNUNET_ECRS_URI *ret;
+
+  if (NULL !=
+      GNUNET_ECRS_string_to_uri (NULL,
+                                 
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42"))
+    ABORT ();
+  if (NULL !=
+      GNUNET_ECRS_string_to_uri (NULL,
+                                 
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000"))
+    ABORT ();
+  if (NULL !=
+      GNUNET_ECRS_string_to_uri (NULL,
+                                 
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH"))
+    ABORT ();
+  ret =
+    GNUNET_ECRS_string_to_uri (NULL,
+                               
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42");
+  if (ret == NULL)
+    ABORT ();
+  if (GNUNET_ECRS_uri_test_ksk (ret))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  if (GNUNET_ECRS_uri_test_sks (ret))
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  if (GNUNET_ntohll (ret->data.fi.file_length) != 42)
+    {
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+
+  uri = GNUNET_ECRS_uri_to_string (ret);
+  if (0 != strcmp (uri,
+                   
"gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42"))
+    {
+      GNUNET_free (uri);
+      GNUNET_ECRS_uri_destroy (ret);
+      ABORT ();
+    }
+  GNUNET_free (uri);
+  GNUNET_ECRS_uri_destroy (ret);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int failureCount = 0;
+  int i;
+
+  GNUNET_disable_entropy_gathering ();
+  failureCount += testKeyword ();
+  failureCount += testLocation ();
+  for (i = 0; i < 255; i++)
+    {
+      failureCount += testNamespace (i);
+      failureCount += testFile (i);
+    }
+  if (failureCount != 0)
+    return 1;
+  return 0;
+}
+
+/* end of uritest.c */

Modified: gnunet/src/hostlist/hostlist-client.c
===================================================================
--- gnunet/src/hostlist/hostlist-client.c       2009-07-27 21:38:38 UTC (rev 
8808)
+++ gnunet/src/hostlist/hostlist-client.c       2009-07-29 08:05:52 UTC (rev 
8809)
@@ -625,11 +625,12 @@
   cfg = c;
   sched = s;
   stats = st;
-  proxy = NULL;
-  GNUNET_CONFIGURATION_get_value_string (cfg,
-                                        "HOSTLIST",
-                                        "HTTP-PROXY", 
-                                        &proxy);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_string (cfg,
+                                            "HOSTLIST",
+                                            "HTTP-PROXY", 
+                                            &proxy))
+    proxy = NULL;
   *ch = &connect_handler;
   *dh = &disconnect_handler;
   GNUNET_STATISTICS_get (stats,

Modified: gnunet/src/hostlist/hostlist-server.c
===================================================================
--- gnunet/src/hostlist/hostlist-server.c       2009-07-27 21:38:38 UTC (rev 
8808)
+++ gnunet/src/hostlist/hostlist-server.c       2009-07-29 08:05:52 UTC (rev 
8809)
@@ -116,7 +116,10 @@
   size_t s;
   
   if (peer == NULL)
-    finish_response (results);
+    {
+      finish_response (results);
+      return;
+    }
   old = results->size;
   s = GNUNET_HELLO_size(hello);
   if (old + s >= GNUNET_MAX_MALLOC_CHECKED)

Modified: gnunet/src/include/gnunet_configuration_lib.h
===================================================================
--- gnunet/src/include/gnunet_configuration_lib.h       2009-07-27 21:38:38 UTC 
(rev 8808)
+++ gnunet/src/include/gnunet_configuration_lib.h       2009-07-29 08:05:52 UTC 
(rev 8809)
@@ -47,16 +47,27 @@
 
 /**
  * Create a new configuration object.
- *
- * @param component name of responsible component
+ * @return fresh configuration object
  */
 struct GNUNET_CONFIGURATION_Handle *GNUNET_CONFIGURATION_create (void);
 
+
 /**
+ * Duplicate an existing configuration object.
+ *
+ * @param c configuration to duplicate
+ * @return duplicate configuration
+ */
+struct GNUNET_CONFIGURATION_Handle *
+GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
  * Destroy configuration object.
  */
 void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg);
 
+
 /**
  * Load configuration.  This function will first parse the
  * defaults and then parse the specific configuration file
@@ -68,6 +79,7 @@
 int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
                                const char *filename);
 
+
 /**
  * Parse a configuration file, add all of the options in the
  * file to the configuration environment.
@@ -76,6 +88,7 @@
 int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
                                 const char *filename);
 
+
 /**
  * Write configuration file.
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
@@ -83,6 +96,7 @@
 int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
                                 const char *filename);
 
+
 /**
  * Test if there are configuration options that were
  * changed since the last save.
@@ -90,7 +104,34 @@
  */
 int GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle 
*cfg);
 
+
 /**
+ * Function to iterate over options.
+ *
+ * @param cls closure
+ * @param section name of the section
+ * @param option name of the option
+ * @param value value of the option
+ */
+typedef void (*GNUNET_CONFIGURATION_Iterator)(void *cls,
+                                             const char *section,
+                                             const char *option,
+                                             const char *value);
+
+
+/**
+ * Iterate over all options in the configuration.
+ *
+ * @param cfg configuration to inspect
+ * @param iter function to call on each option
+ * @param iter_cls closure for iter
+ */
+void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
+                                  GNUNET_CONFIGURATION_Iterator iter,
+                                  void *iter_cls);
+
+
+/**
  * Get a configuration value that should be a number.
  * @return GNUNET_OK on success, GNUNET_SYSERR on error
  */
@@ -240,6 +281,7 @@
                                                 const char *option,
                                                 const char *value);
 
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif

Modified: gnunet/src/include/gnunet_container_lib.h
===================================================================
--- gnunet/src/include/gnunet_container_lib.h   2009-07-27 21:38:38 UTC (rev 
8808)
+++ gnunet/src/include/gnunet_container_lib.h   2009-07-29 08:05:52 UTC (rev 
8809)
@@ -189,11 +189,15 @@
 
 /**
  * Iterator over meta data.
+ *
+ * @param cls closure
+ * @param type type of the meta data
+ * @param data value of the meta data
  * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
  */
-typedef int (*GNUNET_CONTAINER_MetaDataProcessor) (EXTRACTOR_KeywordType type,
-                                                   const char *data,
-                                                   void *closure);
+typedef int (*GNUNET_CONTAINER_MetaDataProcessor) (void *cls,
+                                                  EXTRACTOR_KeywordType type,
+                                                   const char *data);
 
 /**
  * Create a fresh MetaData token.

Modified: gnunet/src/include/gnunet_testing_lib.h
===================================================================
--- gnunet/src/include/gnunet_testing_lib.h     2009-07-27 21:38:38 UTC (rev 
8808)
+++ gnunet/src/include/gnunet_testing_lib.h     2009-07-29 08:05:52 UTC (rev 
8809)
@@ -85,7 +85,7 @@
  */
 struct GNUNET_TESTING_Daemon *
 GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
-                            struct GNUNET_CONFIGURATION_Handle *cfg,
+                            const struct GNUNET_CONFIGURATION_Handle *cfg,
                             const char *hostname,
                             GNUNET_TESTING_NotifyDaemonRunning cb,
                             void *cb_cls);
@@ -163,50 +163,17 @@
  * @param total number of daemons to start
  * @param cb function to call on each daemon that was started
  * @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- *        everything on localhost).
- * @param va Additional hosts can be specified using a NULL-terminated list of
- *        varargs, hosts will then be used round-robin from that
- *        list; va only contains anything if hostname != NULL.
+ * @param hostnames space-separated list of hostnames to use, 
+ *        NULL to use localhost only
  * @return NULL on error, otherwise handle to control peer group
  */
 struct GNUNET_TESTING_PeerGroup *
-GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched,
-                                const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                unsigned int total,
-                                GNUNET_TESTING_NotifyDaemonRunning cb,
-                                void *cb_cls,
-                                const char *hostname,
-                                va_list va);
-
-
-/**
- * Start count gnunetd processes with the same set of
- * transports and applications.  The port numbers will
- * be computed by adding delta each time (zero
- * times for the first peer).
- *
- * @param sched scheduler to use 
- * @param cfg configuration template to use
- * @param total number of daemons to start
- * @param timeout how long is this allowed to take?
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- *        everything on localhost). Additional
- *        hosts can be specified using a NULL-terminated list of
- *        varargs, hosts will then be used round-robin from that
- *        list.
- * @return NULL on error, otherwise handle to control peer group
- */
-struct GNUNET_TESTING_PeerGroup *
 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
-                             struct GNUNET_CONFIGURATION_Handle *cfg,
+                             const struct GNUNET_CONFIGURATION_Handle *cfg,
                              unsigned int total,
                              GNUNET_TESTING_NotifyDaemonRunning cb,
                              void *cb_cls,
-                             const char *hostname,
-                             ...);
+                             const char *hostnames);
 
 
 /**

Modified: gnunet/src/testing/Makefile.am
===================================================================
--- gnunet/src/testing/Makefile.am      2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/testing/Makefile.am      2009-07-29 08:05:52 UTC (rev 8809)
@@ -15,17 +15,20 @@
   testing.c  \
   testing_group.c \
   testing_testbed.c 
-libgnunettesting_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
+libgnunettesting_la_LIBADD = $(XLIB) \
+ $(top_builddir)/src/core/libgnunetcore.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/util/libgnunetutil.la 
 
-#check_PROGRAMS = \
-# test_testing
-#
-#TESTS = $(check_PROGRAMS)
-#
-#test_testing_SOURCES = \
-# test_testing.c
-#test_testing_LDADD = \
-# $(top_builddir)/src/testing/libgnunettesting.la \
-# $(top_builddir)/src/util/libgnunetutil.la  
+check_PROGRAMS = \
+ test_testing
 
+TESTS = $(check_PROGRAMS)
+
+test_testing_SOURCES = \
+ test_testing.c
+test_testing_LDADD = \
+ $(top_builddir)/src/testing/libgnunettesting.la \
+ $(top_builddir)/src/util/libgnunetutil.la  
+
+EXTRA_DIST = test_testing_data.conf

Added: gnunet/src/testing/test_testing.c
===================================================================
--- gnunet/src/testing/test_testing.c                           (rev 0)
+++ gnunet/src/testing/test_testing.c   2009-07-29 08:05:52 UTC (rev 8809)
@@ -0,0 +1,116 @@
+/*
+     This file is part of GNUnet.
+     (C) 2009 Christian Grothoff (and other contributing authors)
+
+     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
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     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.
+*/
+/**
+ * @file testing/test_testing.c
+ * @brief testcase for testing.c
+ */
+#include "platform.h"
+#include "gnunet_testing_lib.h"
+
+#define VERBOSE GNUNET_YES
+
+static int ok;
+
+static void end_cb(void *cls,
+                  const char *emsg)
+{
+  GNUNET_assert (emsg == NULL); 
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Daemon terminated, will now exit.\n");
+#endif
+ ok = 0;
+}
+
+static void my_cb(void *cls,
+                 const struct GNUNET_PeerIdentity *id,
+                 const struct GNUNET_CONFIGURATION_Handle *cfg,
+                 struct GNUNET_TESTING_Daemon *d,
+                 const char *emsg)
+{
+  GNUNET_assert (id != NULL);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Daemon started, will now stop it.\n");
+#endif
+  GNUNET_TESTING_daemon_stop (d, &end_cb, NULL);
+}
+
+
+static void
+run (void *cls,
+     struct GNUNET_SCHEDULER_Handle *sched,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_TESTING_Daemon *d;
+
+  ok = 1;
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Starting daemon.\n");
+#endif
+  d = GNUNET_TESTING_daemon_start (sched,
+                                  cfg,
+                                  NULL,
+                                  &my_cb,
+                                  NULL);
+  GNUNET_assert (d != NULL);
+}
+
+static int
+check ()
+{
+  char *const argv[] = { "test-testing",
+    "-c",
+    "test_testing_data.conf",
+#if VERBOSE
+    "-L", "DEBUG",
+#endif
+    NULL
+  };
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_END
+  };
+  GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+                      argv, "test-tesing", "nohelp",
+                      options, &run, &ok);
+  return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+
+  GNUNET_log_setup ("test-testing",
+#if VERBOSE
+                    "DEBUG",
+#else
+                    "WARNING",
+#endif
+                    NULL);
+  ret = check ();
+
+  return ret;
+}
+
+/* end of test_testing.c */

Added: gnunet/src/testing/test_testing_data.conf
===================================================================
--- gnunet/src/testing/test_testing_data.conf                           (rev 0)
+++ gnunet/src/testing/test_testing_data.conf   2009-07-29 08:05:52 UTC (rev 
8809)
@@ -0,0 +1,29 @@
+[PATHS]
+SERVICEHOME = /tmp/test-gnunet-testing/
+DEFAULTCONFIG = test_testing_data.conf
+
+[resolver]
+PORT = 2564
+
+[transport]
+PORT = 2565
+PLUGINS = tcp
+
+[arm]
+PORT = 2566
+DEFAULTSERVICES = transport core
+
+[statistics]
+PORT = 2567
+
+[tcp]
+PORT = 2568
+
+[peerinfo]
+PORT = 2569
+
+[core]
+PORT = 2570
+
+[testing]
+WEAKRANDOM = YES

Modified: gnunet/src/testing/testing.c
===================================================================
--- gnunet/src/testing/testing.c        2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/testing/testing.c        2009-07-29 08:05:52 UTC (rev 8809)
@@ -85,7 +85,7 @@
   /**
    * Our configuration.
    */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
    * Host to run GNUnet on.
@@ -202,10 +202,11 @@
   d->cb = NULL;
   if (server == NULL)
     {
-      cb (d->cb_cls, NULL, d->cfg, d,
-         _("Failed to connect to core service\n"));
       if (GNUNET_YES == d->dead)
        GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
+      else if (NULL != cb)
+       cb (d->cb_cls, NULL, d->cfg, d,
+           _("Failed to connect to core service\n"));
       return;
     }
 #if DEBUG_TESTING
@@ -216,7 +217,7 @@
   d->id = *my_identity;
   if (GNUNET_YES == d->dead)
     GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
-  else
+  else if (NULL != cb)
     cb (d->cb_cls, my_identity, d->cfg, d, NULL);
   d->server = server;
 }
@@ -240,6 +241,11 @@
   unsigned long code;
   char *dst;
  
+#if DEBUG_TESTING
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Peer FSM is in phase %u.\n",
+             d->phase);
+#endif
   d->task = GNUNET_SCHEDULER_NO_TASK;
   switch (d->phase)
     {
@@ -255,11 +261,12 @@
            {
              cb = d->cb;
              d->cb = NULL;
-             cb (d->cb_cls,
-                 NULL,
-                 d->cfg,
-                 d,
-                 _("`scp' does not seem to terminate.\n"));
+             if (NULL != cb)
+               cb (d->cb_cls,
+                   NULL,
+                   d->cfg,
+                   d,
+                   _("`scp' does not seem to terminate.\n"));
              return;
            }
          /* wait some more */
@@ -278,11 +285,12 @@
        {
          cb = d->cb;
          d->cb = NULL;
-         cb (d->cb_cls,
-             NULL,
-             d->cfg,
-             d,
-             _("`scp' did not complete cleanly.\n"));    
+         if (NULL != cb)
+           cb (d->cb_cls,
+               NULL,
+               d->cfg,
+               d,
+               _("`scp' did not complete cleanly.\n"));          
          return;
        }         
 #if DEBUG_TESTING
@@ -299,7 +307,11 @@
                                            "gnunet-service-arm",
                                            "-c",
                                            d->cfgfile,
+#if DEBUG_TESTING
+                                           "-L", "DEBUG",
+#else
                                            "-d",
+#endif
                                            NULL);
        }
       else
@@ -328,16 +340,31 @@
                      (NULL == d->hostname) ? "gnunet-service-arm" : "ssh");
          cb = d->cb;
          d->cb = NULL;
-         cb (d->cb_cls,
-             NULL,
-             d->cfg,
-             d,
-             (NULL == d->hostname) 
-             ? _("Failed to start `gnunet-service-arm' process.\n") 
-             : _("Failed to start `ssh' process.\n"));
+         if (NULL != cb)
+           cb (d->cb_cls,
+               NULL,
+               d->cfg,
+               d,
+               (NULL == d->hostname) 
+               ? _("Failed to start `gnunet-service-arm' process.\n") 
+               : _("Failed to start `ssh' process.\n"));
        }      
+#if DEBUG_TESTING
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Started `%s', waiting for `%s' to be up.\n",
+                 "gnunet-service-arm",
+                 "gnunet-service-core");
+#endif
       d->phase = SP_START_ARMING;
       d->wait_runs = 0;
+      d->task
+       = GNUNET_SCHEDULER_add_delayed (d->sched, 
+                                       GNUNET_NO,
+                                       GNUNET_SCHEDULER_PRIORITY_KEEP,
+                                       GNUNET_SCHEDULER_NO_TASK,
+                                       GNUNET_CONSTANTS_EXEC_WAIT,
+                                       &start_fsm,
+                                       d);
       break;     
     case SP_START_ARMING:
       if (GNUNET_OK != 
@@ -350,13 +377,14 @@
            {
              cb = d->cb;
              d->cb = NULL;
-             cb (d->cb_cls,
-                 NULL,
-                 d->cfg,
-                 d,
-                 (NULL == d->hostname) 
-                 ? _("`gnunet-service-arm' does not seem to terminate.\n") 
-                 : _("`ssh' does not seem to terminate.\n"));
+             if (NULL != cb)
+               cb (d->cb_cls,
+                   NULL,
+                   d->cfg,
+                   d,
+                   (NULL == d->hostname) 
+                   ? _("`gnunet-service-arm' does not seem to terminate.\n") 
+                   : _("`ssh' does not seem to terminate.\n"));
              return;
            }
          /* wait some more */
@@ -424,18 +452,24 @@
       if ( (type != GNUNET_OS_PROCESS_EXITED) ||
           (code != 0) )
        {
-         d->dead_cb (d->dead_cb_cls,
-                     _("`sshp' did not complete cleanly.\n"));   
+         if (NULL != d->dead_cb)
+           d->dead_cb (d->dead_cb_cls,
+                       _("`ssh' did not complete cleanly.\n"));          
          GNUNET_free (d->cfgfile);
          GNUNET_free_non_null (d->hostname);
          GNUNET_free_non_null (d->username);
          GNUNET_free (d);
          return;
        }        
+#if DEBUG_TESTING
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                 "Peer shutdown complete.\n");
+#endif
       GNUNET_free (d->cfgfile);
       GNUNET_free_non_null (d->hostname);
       GNUNET_free_non_null (d->username);
-      d->dead_cb (d->dead_cb_cls, NULL);
+      if (NULL != d->dead_cb)
+       d->dead_cb (d->dead_cb_cls, NULL);
       GNUNET_free (d);
       break;
     case SP_CONFIG_UPDATE:
@@ -450,11 +484,12 @@
            {
              cb = d->cb;
              d->cb = NULL;
-             cb (d->cb_cls,
-                 NULL,
-                 d->cfg,
-                 d,
-                 _("`scp' does not seem to terminate.\n"));
+             if (NULL != cb)
+               cb (d->cb_cls,
+                   NULL,
+                   d->cfg,
+                   d,
+                   _("`scp' does not seem to terminate.\n"));
              return;
            }
          /* wait some more */
@@ -471,15 +506,17 @@
       if ( (type != GNUNET_OS_PROCESS_EXITED) ||
           (code != 0) )
        {
-         d->update_cb (d->update_cb_cls,
-                       _("`scp' did not complete cleanly.\n"));          
+         if (NULL != d->update_cb)
+           d->update_cb (d->update_cb_cls,
+                         _("`scp' did not complete cleanly.\n"));        
          return;
        }         
 #if DEBUG_TESTING
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Successfully copied configuration file.\n");
 #endif
-      d->update_cb (d->update_cb_cls, NULL);
+      if  (NULL != d->update_cb)
+       d->update_cb (d->update_cb_cls, NULL);
       d->phase = SP_START_DONE;
       break;
     }
@@ -502,7 +539,7 @@
  */
 struct GNUNET_TESTING_Daemon *
 GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
-                            struct GNUNET_CONFIGURATION_Handle *cfg,
+                            const struct GNUNET_CONFIGURATION_Handle *cfg,
                             const char *hostname,
                             GNUNET_TESTING_NotifyDaemonRunning cb,
                             void *cb_cls)
@@ -513,9 +550,13 @@
 
   ret = GNUNET_malloc (sizeof(struct GNUNET_TESTING_Daemon));
   ret->sched = sched;
-  ret->cfg = cfg;
   ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
   ret->cfgfile = GNUNET_DISK_mktemp ("gnunet-testing-config");
+#if DEBUG_TESTING
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Setting up peer with configuration file `%s'.\n",
+             ret->cfgfile);
+#endif
   if (NULL == ret->cfgfile)
     {                                          
       GNUNET_free_non_null (ret->hostname);
@@ -524,15 +565,21 @@
     }
   ret->cb = cb;
   ret->cb_cls = cb_cls;
+  ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
+  GNUNET_CONFIGURATION_set_value_string (ret->cfg,
+                                        "PATHS",
+                                        "DEFAULTCONFIG",
+                                        ret->cfgfile);
   /* 1) write configuration to temporary file */
   if (GNUNET_OK != 
-      GNUNET_CONFIGURATION_write (cfg,
+      GNUNET_CONFIGURATION_write (ret->cfg,
                                  ret->cfgfile))
     {
       if (0 != UNLINK (ret->cfgfile))
          GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                    "unlink",
                                    ret->cfgfile);
+      GNUNET_CONFIGURATION_destroy (ret->cfg);
       GNUNET_free_non_null (ret->hostname);
       GNUNET_free (ret->cfgfile);
       GNUNET_free (ret);
@@ -581,6 +628,7 @@
            GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
                                      "unlink",
                                      ret->cfgfile);
+         GNUNET_CONFIGURATION_destroy (ret->cfg);
          GNUNET_free_non_null (ret->hostname);
          GNUNET_free_non_null (ret->username);
          GNUNET_free (ret->cfgfile);
@@ -589,7 +637,7 @@
        }
       ret->task
        = GNUNET_SCHEDULER_add_delayed (sched, 
-                                       GNUNET_NO,
+                                       GNUNET_YES,
                                        GNUNET_SCHEDULER_PRIORITY_KEEP,
                                        GNUNET_SCHEDULER_NO_TASK,
                                        GNUNET_CONSTANTS_EXEC_WAIT,
@@ -597,6 +645,10 @@
                                        ret);
       return ret;
     }
+#if DEBUG_TESTING
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "No need to copy configuration file since we are running 
locally.\n");
+#endif
   ret->phase = SP_COPIED;
   GNUNET_SCHEDULER_add_continuation (sched,
                                     GNUNET_NO,
@@ -687,7 +739,7 @@
       d->dead_cb_cls = cb_cls;
       d->task
        = GNUNET_SCHEDULER_add_delayed (d->sched, 
-                                       GNUNET_NO,
+                                       GNUNET_YES,
                                        GNUNET_SCHEDULER_PRIORITY_KEEP,
                                        GNUNET_SCHEDULER_NO_TASK,
                                        GNUNET_CONSTANTS_EXEC_WAIT,
@@ -695,11 +747,13 @@
                                        d);
       return;
     }
+  GNUNET_CONFIGURATION_destroy (d->cfg);
   GNUNET_free (d->cfgfile);
   GNUNET_free_non_null (d->hostname);
   GNUNET_free_non_null (d->username);
   GNUNET_free (d);
-  cb (cb_cls, NULL);
+  if (NULL != cb)
+    cb (cb_cls, NULL);
 }
 
 
@@ -720,8 +774,9 @@
 
   if (d->phase != SP_START_DONE)
     {
-      cb (cb_cls,
-         _("Peer not yet running, can not change configuration at this 
point."));
+      if (NULL != cb)
+       cb (cb_cls,
+           _("Peer not yet running, can not change configuration at this 
point."));
       return;      
     }
 
@@ -730,7 +785,8 @@
       GNUNET_CONFIGURATION_write (cfg,
                                  d->cfgfile))
     {
-      cb (cb_cls,
+      if (NULL != cb)
+       cb (cb_cls,
          _("Failed to write new configuration to disk."));
       return;
     }
@@ -739,7 +795,8 @@
   if (NULL == d->hostname)
     {
       /* signal success */
-      cb (cb_cls, NULL); 
+      if (NULL != cb)
+       cb (cb_cls, NULL); 
       return;
     }
   d->phase = SP_CONFIG_UPDATE;
@@ -765,8 +822,9 @@
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Could not start `%s' process to copy configuration 
file.\n"),
                  "scp");
-      cb (cb_cls,
-         _("Failed to copy new configuration to remote machine."));
+      if (NULL != cb)
+       cb (cb_cls,
+           _("Failed to copy new configuration to remote machine."));
       d->phase = SP_START_DONE;
       return;
     }
@@ -802,10 +860,14 @@
 transmit_ready (void *cls, size_t size, void *buf)
 {
   struct ConnectContext *ctx = cls;
-  if (buf == NULL)
-    ctx->cb (ctx->cb_cls, _("Peers failed to connect"));
-  else
-    ctx->cb (ctx->cb_cls, NULL);
+
+  if (NULL != ctx->cb)
+    {
+      if (buf == NULL)
+       ctx->cb (ctx->cb_cls, _("Peers failed to connect"));
+      else
+       ctx->cb (ctx->cb_cls, NULL);
+    }
   GNUNET_free (ctx);
   return 0;
 }
@@ -831,8 +893,9 @@
   if (peer == NULL)
     {
       /* signal error */
-      ctx->cb (ctx->cb_cls,
-              _("Failed to receive `HELLO' from peer\n"));
+      if (NULL != ctx->cb)
+       ctx->cb (ctx->cb_cls,
+                _("Failed to receive `HELLO' from peer\n"));
       GNUNET_TRANSPORT_disconnect (ctx->d1th);
       GNUNET_TRANSPORT_disconnect (ctx->d2th);
       GNUNET_free (ctx);
@@ -873,7 +936,8 @@
   if ( (d1->server == NULL) ||
        (d2->server == NULL) )
     {
-      cb (cb_cls, _("Peers are not fully running yet, can not connect!\n"));
+      if (NULL != cb)
+       cb (cb_cls, _("Peers are not fully running yet, can not connect!\n"));
       return;
     }
   ctx = GNUNET_malloc (sizeof(struct ConnectContext));
@@ -886,7 +950,8 @@
   if (ctx->d1th == NULL)
     {
       GNUNET_free (ctx);
-      cb (cb_cls, _("Failed to connect to transport service!\n"));
+      if (NULL != cb)
+       cb (cb_cls, _("Failed to connect to transport service!\n"));
       return;
     }
   ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched, d2->cfg, d2, NULL, NULL, 
NULL);
@@ -894,7 +959,8 @@
     {
       GNUNET_TRANSPORT_disconnect (ctx->d1th);
       GNUNET_free (ctx);
-      cb (cb_cls, _("Failed to connect to transport service!\n"));
+      if (NULL != cb)
+       cb (cb_cls, _("Failed to connect to transport service!\n"));
       return;
     }
   GNUNET_TRANSPORT_get_hello (ctx->d1th, 

Modified: gnunet/src/testing/testing_group.c
===================================================================
--- gnunet/src/testing/testing_group.c  2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/testing/testing_group.c  2009-07-29 08:05:52 UTC (rev 8809)
@@ -27,8 +27,60 @@
 #include "gnunet_arm_service.h"
 #include "gnunet_testing_lib.h"
 
+/**
+ * Lowest port used for GNUnet testing.  Should be high enough to not
+ * conflict with other applications running on the hosts but be low
+ * enough to not conflict with client-ports (typically starting around
+ * 32k).
+ */
+#define LOW_PORT 10000
 
 /**
+ * Highest port used for GNUnet testing.  Should be low enough to not
+ * conflict with the port range for "local" ports (client apps; see
+ * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
+ */
+#define HIGH_PORT 32000
+
+/**
+ * Data we keep per peer.
+ */
+struct PeerData
+{
+  /**
+   * (Initial) configuration of the host.
+   * (initial because clients could change
+   *  it and we would not know about those
+   *  updates).
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  
+  /**
+   * Handle for controlling the daemon.
+   */
+  struct GNUNET_TESTING_Daemon *daemon;
+};
+
+
+/**
+ * Data we keep per host.
+ */
+struct HostData
+{
+  /**
+   * Name of the host.
+   */
+  char *hostname;
+  
+  /**
+   * Lowest port that we have not yet used
+   * for GNUnet.
+   */
+  uint16_t minport;
+};
+
+
+/**
  * Handle to a group of GNUnet peers.
  */
 struct GNUNET_TESTING_PeerGroup
@@ -41,7 +93,7 @@
   /**
    * Configuration template.
    */
-  struct GNUNET_CONFIGURATION_Handle *cfg;
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
    * Function to call on each started daemon.
@@ -54,14 +106,15 @@
   void *cb_cls;
 
   /**
-   * NULL-terminated array of hostnames.
+   * NULL-terminated array of information about
+   * hosts.
    */
-  char **hostnames;
+  struct HostData *hosts;
 
   /**
    * Array of "total" peers.
    */
-  struct GNUNET_TESTING_Daemon **peers;
+  struct PeerData *peers;
 
   /**
    * Number of peers in this group.
@@ -71,81 +124,214 @@
 };
 
 
+struct UpdateContext 
+{
+  struct GNUNET_CONFIGURATION_Handle *ret;
+  unsigned int nport;
+};
+
 /**
- * Start count gnunetd processes with the same set of transports and
- * applications.  The port numbers (any option called "PORT") will be
- * adjusted to ensure that no two peers running on the same system
- * have the same port(s) in their respective configurations.
+ * Function to iterate over options.  Copies
+ * the options to the target configuration,
+ * updating PORT values as needed.
  *
- * @param sched scheduler to use 
- * @param cfg configuration template to use
- * @param total number of daemons to start
- * @param cb function to call on each daemon that was started
- * @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- *        everything on localhost).
- * @param va Additional hosts can be specified using a NULL-terminated list of
- *        varargs, hosts will then be used round-robin from that
- *        list; va only contains anything if hostname != NULL.
- * @return NULL on error, otherwise handle to control peer group
+ * @param cls closure
+ * @param section name of the section
+ * @param option name of the option
+ * @param value value of the option
  */
-struct GNUNET_TESTING_PeerGroup *
-GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched,
-                                const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                unsigned int total,
-                                GNUNET_TESTING_NotifyDaemonRunning cb,
-                                void *cb_cls,
-                                const char *hostname,
-                                va_list va)
+static void 
+update_config(void *cls,
+             const char *section,
+             const char *option,
+             const char *value)
 {
-  struct GNUNET_TESTING_PeerGroup *pg;
-  
-  pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
-  return pg;
+  struct UpdateContext *ctx = cls;
+  unsigned int ival;
+  char cval[12];
+
+  if ( (0 == strcmp (option, "PORT")) &&
+       (1 == sscanf (value, "%u", &ival)) )
+    {
+      GNUNET_snprintf (cval,
+                      sizeof(cval),
+                      "%u",
+                      ctx->nport++);
+      value = cval;
+    }             
+  GNUNET_CONFIGURATION_set_value_string (ctx->ret,
+                                        section,
+                                        option,
+                                        value);
 }
 
 
 /**
- * Start count gnunetd processes with the same set of
- * transports and applications.  The port numbers will
- * be computed by adding delta each time (zero
- * times for the first peer).
+ * Create a new configuration using the given configuration
+ * as a template; however, each PORT in the existing cfg
+ * must be renumbered by incrementing "*port".  If we run
+ * out of "*port" numbers, return NULL. 
+ * 
+ * @param cfg template configuration
+ * @param port port numbers to use, update to reflect
+ *             port numbers that were used
+ * @return new configuration, NULL on error
+ */
+static struct GNUNET_CONFIGURATION_Handle*
+make_config (const struct GNUNET_CONFIGURATION_Handle*cfg,
+            uint16_t *port)
+{
+  struct UpdateContext uc;
+  uint16_t orig;
+
+  orig = *port;
+  uc.nport = *port;
+  uc.ret = GNUNET_CONFIGURATION_create ();
+  GNUNET_CONFIGURATION_iterate (cfg,
+                               &update_config,
+                               &uc);
+  if (uc.nport >= HIGH_PORT)
+    {
+      *port = orig;
+      GNUNET_CONFIGURATION_destroy (uc.ret);
+      return NULL;
+    }
+  *port = (uint16_t) uc.nport;
+  return uc.ret;
+}
+
+
+/**
+ * Start count gnunetd processes with the same set of transports and
+ * applications.  The port numbers (any option called "PORT") will be
+ * adjusted to ensure that no two peers running on the same system
+ * have the same port(s) in their respective configurations.
  *
  * @param sched scheduler to use 
  * @param cfg configuration template to use
  * @param total number of daemons to start
- * @param timeout how long is this allowed to take?
  * @param cb function to call on each daemon that was started
  * @param cb_cls closure for cb
- * @param hostname where to run the peers; can be NULL (to run
- *        everything on localhost). Additional
- *        hosts can be specified using a NULL-terminated list of
- *        varargs, hosts will then be used round-robin from that
- *        list.
+ * @param hostnames space-separated list of hostnames to use; can be NULL (to 
run
+ *        everything on localhost).
  * @return NULL on error, otherwise handle to control peer group
  */
 struct GNUNET_TESTING_PeerGroup *
 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
-                             struct GNUNET_CONFIGURATION_Handle *cfg,
+                             const struct GNUNET_CONFIGURATION_Handle *cfg,
                              unsigned int total,
                              GNUNET_TESTING_NotifyDaemonRunning cb,
                              void *cb_cls,
-                             const char *hostname,
-                             ...)
+                             const char *hostnames)
 {
-  struct GNUNET_TESTING_PeerGroup * ret;
-  va_list va;
-  
-  va_start (va, hostname);
-  ret = GNUNET_TESTING_daemons_start_va (sched, cfg,
-                                        total, cb, cb_cls, hostname,
-                                        va);
-  va_end (va);
-  return ret;
+  struct GNUNET_TESTING_PeerGroup *pg;
+  const char *rpos;
+  char *pos;
+  char *start;
+  const char *hostname;
+  struct GNUNET_CONFIGURATION_Handle *pcfg;
+  unsigned int off;
+  unsigned int hostcnt;
+  uint16_t minport;
+
+  if (0 == total)
+    {
+      GNUNET_break (0);
+      return NULL;
+    }
+  pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
+  pg->sched = sched;
+  pg->cfg = cfg;
+  pg->cb = cb;
+  pg->cb_cls = cb_cls;
+  pg->total = total;
+  pg->peers = GNUNET_malloc (total * sizeof(struct PeerData));
+  if (NULL != hostnames)
+    {
+      off = 2;
+      /* skip leading spaces */
+      while ( (0 != *hostnames) &&
+             (isspace(*hostnames)))
+       hostnames++;
+      rpos = hostnames;
+      while ('\0' != *rpos)
+       {
+         if (isspace (*rpos))
+           off++;
+         rpos++;
+       }
+      pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
+      off = 0;
+      start = GNUNET_strdup (hostnames);
+      pos = start;
+      while ('\0' != *pos)
+       {
+         if (isspace (*pos))
+           {
+             *pos = '\0';
+             if (strlen(start) > 0)
+               {
+                 pg->hosts[off].minport = LOW_PORT;
+                 pg->hosts[off++].hostname = start;
+               }
+             start = pos+1;
+           }
+         pos++;
+       }
+      if (strlen(start) > 0)
+       {
+         pg->hosts[off].minport = LOW_PORT;
+         pg->hosts[off++].hostname = start;
+       }
+      if (off == 0)
+       {
+         GNUNET_free (start);
+         GNUNET_free (pg->hosts);
+         pg->hosts = NULL;
+       }
+      hostcnt = off;
+      minport = 0; /* make gcc happy */
+    }
+  else
+    {
+      hostcnt = 0;
+      minport = LOW_PORT;
+    }
+  for (off = 0; off < total; off++)
+    {
+      if (hostcnt > 0)
+       {
+         hostname = pg->hosts[off % hostcnt].hostname;
+         pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
+       }
+      else
+       {
+         hostname = NULL;
+         pcfg = make_config (cfg, &minport);
+       }
+      if (NULL == pcfg)
+       {
+         GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
+                     _("Could not create configuration for peer number %u on 
`%s'!\n"),
+                     off,
+                     hostname == NULL ? "localhost" : hostname);
+         continue;
+       }
+      pg->peers[off].cfg = pcfg;
+      pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
+                                                          pcfg,
+                                                          hostname,
+                                                          cb,
+                                                          cb_cls);
+      if (NULL == pg->peers[off].daemon)
+       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
+                   _("Could not start peer number %u!\n"),
+                   off);
+    }
+  return pg;
 }
 
 
-
 /**
  * Shutdown all peers started in the given group.
  * 
@@ -154,7 +340,26 @@
 void
 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
 {
-  
+  unsigned int off;
+
+  for (off = 0; off < pg->total; off++)
+    {
+      /* FIXME: should we wait for our
+        continuations to be called here? This
+        would require us to take a continuation
+        as well... */
+      if (NULL != pg->peers[off].daemon)
+       GNUNET_TESTING_daemon_stop (pg->peers[off].daemon,
+                                   NULL, NULL);
+      if (NULL != pg->peers[off].cfg)
+       GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
+    }
+  GNUNET_free (pg->peers);
+  if (NULL != pg->hosts)
+    {
+      GNUNET_free (pg->hosts[0].hostname);
+      GNUNET_free (pg->hosts);
+    }
   GNUNET_free (pg);
 }
 

Modified: gnunet/src/topology/gnunet-daemon-topology.c
===================================================================
--- gnunet/src/topology/gnunet-daemon-topology.c        2009-07-27 21:38:38 UTC 
(rev 8808)
+++ gnunet/src/topology/gnunet-daemon-topology.c        2009-07-29 08:05:52 UTC 
(rev 8809)
@@ -508,7 +508,7 @@
                                  &have_address);
   if (GNUNET_NO == have_address)
     return; /* no point in advertising this one... */
-  GNUNET_HELLO_get_id (hello, &pid);
+  GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
   pos = hellos;
   while (pos != NULL)
     {
@@ -736,11 +736,18 @@
   unsigned int entries_found;
   struct PeerList *fl;
 
-  fn = NULL;
-  GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                          "TOPOLOGY",
-                                          "FRIENDS",
-                                          &fn);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                              "TOPOLOGY",
+                                              "FRIENDS",
+                                              &fn))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                 _("Option `%s' in section `%s' not specified!\n"),
+                 "FRIENDS",
+                 "TOPOLOGY");
+      return;
+    }
   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
         | GNUNET_DISK_PERM_USER_WRITE);
@@ -920,7 +927,7 @@
       if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
        {
          /* time to discard... */
-         if (prev == NULL)
+         if (prev != NULL)
            prev->next = next;
          else
            hellos = next;
@@ -1015,17 +1022,19 @@
   friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
                                                       "TOPOLOGY",
                                                       "FRIENDS-ONLY");
-  opt = 0;
-  GNUNET_CONFIGURATION_get_value_number (cfg,
-                                        "TOPOLOGY",
-                                        "MINIMUM-FRIENDS",
-                                        &opt);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (cfg,
+                                            "TOPOLOGY",
+                                            "MINIMUM-FRIENDS",
+                                            &opt))
+    opt = 0;
   minimum_friend_count = (unsigned int) opt;
-  opt = 16;
-  GNUNET_CONFIGURATION_get_value_number (cfg,
-                                        "TOPOLOGY",
-                                        "TARGET-CONNECTION-COUNT",
-                                        &opt);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (cfg,
+                                            "TOPOLOGY",
+                                            "TARGET-CONNECTION-COUNT",
+                                            &opt))
+    opt = 16;
   target_connection_count = (unsigned int) opt;
 
   if ( (friends_only == GNUNET_YES) ||

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2009-07-27 21:38:38 UTC 
(rev 8808)
+++ gnunet/src/transport/gnunet-service-transport.c     2009-07-29 08:05:52 UTC 
(rev 8809)
@@ -2132,7 +2132,8 @@
                   _
                   ("Dropping incoming message due to repeated bandwidth quota 
violations.\n"));
       /* TODO: call stats */
-      GNUNET_assert (NULL != service_context->neighbour);
+      GNUNET_assert ( (service_context == NULL) ||
+                     (NULL != service_context->neighbour) );
       return service_context;
     }
   switch (ntohs (message->type))

Modified: gnunet/src/util/configuration.c
===================================================================
--- gnunet/src/util/configuration.c     2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/util/configuration.c     2009-07-29 08:05:52 UTC (rev 8809)
@@ -315,6 +315,49 @@
 }
 
 
+void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle 
*cfg,
+                                  GNUNET_CONFIGURATION_Iterator iter,
+                                  void *iter_cls)
+{
+  struct ConfigSection *spos;
+  struct ConfigEntry *epos;
+
+  spos = cfg->sections;
+  while (spos != NULL)
+    {
+      epos = spos->entries;
+      while (epos != NULL)
+       {
+         iter (iter_cls, spos->name, epos->key, epos->val);
+         epos = epos->next;
+       }
+      spos = spos->next;
+    }
+}
+
+
+static void
+copy_entry (void *cls,
+           const char *section,
+           const char *option,
+           const char *value)
+{
+  struct GNUNET_CONFIGURATION_Handle *dst = cls;
+  GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
+}
+
+
+struct GNUNET_CONFIGURATION_Handle *
+GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_CONFIGURATION_Handle *ret;
+
+  ret = GNUNET_CONFIGURATION_create ();
+  GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
+  return ret;
+}
+
+
 static struct ConfigSection *
 findSection (const struct GNUNET_CONFIGURATION_Handle *data, const char 
*section)
 {

Modified: gnunet/src/util/container_meta_data.c
===================================================================
--- gnunet/src/util/container_meta_data.c       2009-07-27 21:38:38 UTC (rev 
8808)
+++ gnunet/src/util/container_meta_data.c       2009-07-29 08:05:52 UTC (rev 
8809)
@@ -187,8 +187,9 @@
       if (!EXTRACTOR_isBinaryType (md->items[i].type))
         {
           if ((iterator != NULL) &&
-              (GNUNET_OK != iterator (md->items[i].type,
-                                      md->items[i].data, closure)))
+              (GNUNET_OK != iterator (closure,
+                                     md->items[i].type,
+                                      md->items[i].data)))
             return GNUNET_SYSERR;
         }
       else

Modified: gnunet/src/util/crypto_ksk.c
===================================================================
--- gnunet/src/util/crypto_ksk.c        2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/util/crypto_ksk.c        2009-07-29 08:05:52 UTC (rev 8809)
@@ -790,7 +790,9 @@
     {
       if (genproc != 0)
        {
-         PLIBC_KILL(genproc, SIGTERM);
+         if (0 != PLIBC_KILL(genproc, SIGTERM))
+           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                                "kill");
          GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
          genproc = 0;
        }
@@ -808,7 +810,9 @@
          GNUNET_break (0);
          return;
        }
-      PLIBC_KILL(genproc, SIGTERM);
+      if (0 != PLIBC_KILL(genproc, SIGTERM))
+       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                            "kill");
       GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
       genproc = 0;     
     }

Modified: gnunet/src/util/disk.c
===================================================================
--- gnunet/src/util/disk.c      2009-07-27 21:38:38 UTC (rev 8808)
+++ gnunet/src/util/disk.c      2009-07-29 08:05:52 UTC (rev 8809)
@@ -234,7 +234,10 @@
       GNUNET_free (fn);
       return NULL;
     }
-  CLOSE (fd);
+  if (0 != CLOSE (fd))
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                             "close",
+                             fn);
   return fn;
 }
 
@@ -1043,6 +1046,7 @@
   else
     {
       GNUNET_break (0);
+      GNUNET_free (expfn);
       return NULL;
     }
   if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]