aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-07-29 08:05:52 +0000
committerChristian Grothoff <christian@grothoff.org>2009-07-29 08:05:52 +0000
commitb80e650bad570e01b5600aab2a667d177fc17770 (patch)
treeae5b933796c34f8c0e56f54448da98c4174f683c
parent673dda8cec9a607d77543abd697982fc1fe9e271 (diff)
downloadgnunet-b80e650bad570e01b5600aab2a667d177fc17770.tar.gz
gnunet-b80e650bad570e01b5600aab2a667d177fc17770.zip
travelhacking
-rw-r--r--TODO19
-rw-r--r--src/Makefile.am2
-rw-r--r--src/arm/arm.h2
-rw-r--r--src/arm/gnunet-service-arm.c5
-rw-r--r--src/datacache/plugin_datacache_sqlite.c5
-rw-r--r--src/datastore/gnunet-service-datastore.c3
-rw-r--r--src/fs/Makefile.am61
-rw-r--r--src/fs/fs.h128
-rw-r--r--src/fs/fs_getopt.c192
-rw-r--r--src/fs/fs_uri.c1317
-rw-r--r--src/fs/test_fs_getopt.c33
-rw-r--r--src/fs/test_fs_uri.c255
-rw-r--r--src/hostlist/hostlist-client.c11
-rw-r--r--src/hostlist/hostlist-server.c5
-rw-r--r--src/include/gnunet_configuration_lib.h46
-rw-r--r--src/include/gnunet_container_lib.h10
-rw-r--r--src/include/gnunet_testing_lib.h43
-rw-r--r--src/testing/Makefile.am29
-rw-r--r--src/testing/test_testing.c116
-rw-r--r--src/testing/test_testing_data.conf29
-rw-r--r--src/testing/testing.c186
-rw-r--r--src/testing/testing_group.c315
-rw-r--r--src/topology/gnunet-daemon-topology.c43
-rw-r--r--src/transport/gnunet-service-transport.c3
-rw-r--r--src/util/configuration.c43
-rw-r--r--src/util/container_meta_data.c5
-rw-r--r--src/util/crypto_ksk.c8
-rw-r--r--src/util/disk.c6
28 files changed, 2706 insertions, 214 deletions
diff --git a/TODO b/TODO
index 509c3cb91..ebccd0a39 100644
--- a/TODO
+++ b/TODO
@@ -16,20 +16,21 @@ away), in order in which they will likely be done:
16PHASE #2: (Goal: recover basic file-sharing functionality) 16PHASE #2: (Goal: recover basic file-sharing functionality)
17* TESTING (needed for DV, DHT, Topology) 17* TESTING (needed for DV, DHT, Topology)
18 - implement library for local testing 18 - implement library for local testing
19 + check API for hostname specification;
20 maybe use space-separated list instead?
21 + modify configuration to allow controlling 19 + modify configuration to allow controlling
22 connections for non-local starts 20 connections for non-local starts
23 + starting of groups of peers (and auto-setting 21 + CORE service does not start with valid peer ID (all zeross)
24 of PORT options) 22 -- testcase fails!
25 + testbed creation with topology 23 + consider changing API for peer-group termination
26 + testbed with churn 24 to call continuation when done
25 + testbed creation with topology (needs working F2F topology) [Nate]
26 + testbed with churn [Nate]
27 - implement testcases for library 27 - implement testcases for library
28 + test basic peer start 28 + get test for basic peer start to work!
29 + test basic peer connect 29 + test basic peer connect
30 + test group start 30 + test group start
31 + test topology creation 31 + test basic peer re-configure [Nate]
32 + test churn generation 32 + test topology creation [Nate]
33 + test churn generation [Nate]
33* TOPOLOGY: 34* TOPOLOGY:
34 - implement testcases (needs TESTING) 35 - implement testcases (needs TESTING)
35* HOSTLIST: 36* HOSTLIST:
diff --git a/src/Makefile.am b/src/Makefile.am
index 92be62974..9b3aa46ab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,10 +18,10 @@ SUBDIRS = \
18 statistics \ 18 statistics \
19 datacache \ 19 datacache \
20 datastore \ 20 datastore \
21 testing \
22 template \ 21 template \
23 transport \ 22 transport \
24 core \ 23 core \
24 testing \
25 $(HOSTLIST_DIR) \ 25 $(HOSTLIST_DIR) \
26 topology 26 topology
27 27
diff --git a/src/arm/arm.h b/src/arm/arm.h
index 2293ec036..a8f5d0706 100644
--- a/src/arm/arm.h
+++ b/src/arm/arm.h
@@ -27,6 +27,6 @@
27 27
28#include "gnunet_common.h" 28#include "gnunet_common.h"
29 29
30#define DEBUG_ARM GNUNET_NO 30#define DEBUG_ARM GNUNET_YES
31 31
32#endif 32#endif
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 32674117c..ac58904ed 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -167,6 +167,8 @@ signal_result (struct GNUNET_SERVER_Client *client,
167{ 167{
168 uint16_t *res; 168 uint16_t *res;
169 169
170 if (NULL == client)
171 return;
170#if DEBUG_ARM 172#if DEBUG_ARM
171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
172 "Telling client that service `%s' is now %s\n", 174 "Telling client that service `%s' is now %s\n",
@@ -387,7 +389,8 @@ start_service (struct GNUNET_SERVER_Client *client, const char *servicename)
387 sl->mtime = sbuf.st_mtime; 389 sl->mtime = sbuf.st_mtime;
388 running = sl; 390 running = sl;
389 start_process (sl); 391 start_process (sl);
390 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP); 392 if (NULL != client)
393 signal_result (client, servicename, GNUNET_MESSAGE_TYPE_ARM_IS_UP);
391} 394}
392 395
393 396
diff --git a/src/datacache/plugin_datacache_sqlite.c b/src/datacache/plugin_datacache_sqlite.c
index 63f8cbd67..e8ef5cd09 100644
--- a/src/datacache/plugin_datacache_sqlite.c
+++ b/src/datacache/plugin_datacache_sqlite.c
@@ -405,7 +405,10 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
405 struct GNUNET_DATACACHE_PluginFunctions *api = cls; 405 struct GNUNET_DATACACHE_PluginFunctions *api = cls;
406 struct Plugin *plugin = api->cls; 406 struct Plugin *plugin = api->cls;
407 407
408 UNLINK (plugin->fn); 408 if (0 != UNLINK (plugin->fn))
409 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
410 "unlink",
411 plugin->fn);
409 GNUNET_free (plugin->fn); 412 GNUNET_free (plugin->fn);
410 sqlite3_close (plugin->dbh); 413 sqlite3_close (plugin->dbh);
411 GNUNET_free (plugin); 414 GNUNET_free (plugin);
diff --git a/src/datastore/gnunet-service-datastore.c b/src/datastore/gnunet-service-datastore.c
index 26e894bf4..977f1398e 100644
--- a/src/datastore/gnunet-service-datastore.c
+++ b/src/datastore/gnunet-service-datastore.c
@@ -527,7 +527,8 @@ transmit_status (struct GNUNET_SERVER_Client *client,
527 sm->header.size = htons(sizeof(struct StatusMessage) + slen); 527 sm->header.size = htons(sizeof(struct StatusMessage) + slen);
528 sm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_STATUS); 528 sm->header.type = htons(GNUNET_MESSAGE_TYPE_DATASTORE_STATUS);
529 sm->status = htonl(code); 529 sm->status = htonl(code);
530 memcpy (&sm[1], msg, slen); 530 if (slen > 0)
531 memcpy (&sm[1], msg, slen);
531 transmit (client, &sm->header, NULL, NULL, GNUNET_YES); 532 transmit (client, &sm->header, NULL, NULL, GNUNET_YES);
532} 533}
533 534
diff --git a/src/fs/Makefile.am b/src/fs/Makefile.am
new file mode 100644
index 000000000..03c40a5da
--- /dev/null
+++ b/src/fs/Makefile.am
@@ -0,0 +1,61 @@
1INCLUDES = -I$(top_srcdir)/src/include
2
3if MINGW
4 WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols
5endif
6
7if USE_COVERAGE
8 AM_CFLAGS = --coverage -O0
9 XLIB = -lgcov
10endif
11
12
13lib_LTLIBRARIES = libgnunetfs.la
14
15libgnunetfs_la_SOURCES = \
16 fs_getopt.c \
17 fs_uri.c
18libgnunetfs_la_LIBADD = \
19 $(top_builddir)/src/util/libgnunetutil.la \
20 $(GN_LIBINTL) $(XLIB)
21libgnunetfs_la_LDFLAGS = \
22 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
23 -version-info 0:0:0
24
25
26#bin_PROGRAMS = \
27# gnunet-directory \
28# gnunet-download \
29# gnunet-pseudonym \
30# gnunet-search \
31# gnunet-share \
32# gnunet-unindex
33
34#gnunet_directory_SOURCES = \
35# gnunet-directory.c
36#gnunet_directory_LDADD = \
37# $(top_builddir)/src/fs/libgnunetfs.la \
38# $(top_builddir)/src/util/libgnunetutil.la \
39# $(GN_LIBINTL)
40
41
42check_PROGRAMS = \
43 test_fs_getopt \
44 test_fs_uri
45
46TESTS = $(check_PROGRAMS)
47
48test_fs_uri_SOURCES = \
49 test_fs_uri.c
50test_fs_LDADD = \
51 $(top_builddir)/src/fs/libgnunetfs.la \
52 $(top_builddir)/src/util/libgnunetutil.la
53
54test_fs_getopt_SOURCES = \
55 test_fs_getopt.c
56test_fs_LDADD = \
57 $(top_builddir)/src/fs/libgnunetfs.la \
58 $(top_builddir)/src/util/libgnunetutil.la
59
60#EXTRA_DIST = \
61# test_fs_data.conf
diff --git a/src/fs/fs.h b/src/fs/fs.h
new file mode 100644
index 000000000..c6d5d38cc
--- /dev/null
+++ b/src/fs/fs.h
@@ -0,0 +1,128 @@
1/*
2 This file is part of GNUnet.
3 (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file fs/fs.h
23 * @brief definitions for the entire fs module
24 * @author Igor Wronsky, Christian Grothoff
25 */
26#ifndef FS_H
27#define FS_H
28
29/**
30 * @brief content hash key
31 */
32struct ContentHashKey
33{
34 GNUNET_HashCode key;
35 GNUNET_HashCode query;
36};
37
38
39/**
40 * @brief complete information needed
41 * to download a file.
42 */
43struct FileIdentifier
44{
45
46 /**
47 * Total size of the file in bytes. (network byte order (!))
48 */
49 unsigned long long file_length;
50
51 /**
52 * Query and key of the top GNUNET_EC_IBlock.
53 */
54 struct ContentHashKey chk;
55
56};
57
58
59/**
60 * Information about a file and its location
61 * (peer claiming to share the file).
62 */
63struct Location
64{
65 /**
66 * Information about the shared file.
67 */
68 struct FileIdentifier fi;
69
70 /**
71 * Identity of the peer sharing the file.
72 */
73 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer;
74
75 /**
76 * Time when the HELLO *and* this location URI
77 * expire (they expire together!).
78 */
79 struct GNUNET_TIME_Absolute expirationTime;
80
81 /**
82 * RSA signature over the GNUNET_EC_FileIdentifier,
83 * GNUNET_hash of the peer and expiration time.
84 */
85 struct GNUNET_CRYPTO_RsaSignature contentSignature;
86
87};
88
89enum uri_types
90{ chk, sks, ksk, loc };
91
92/**
93 * A Universal Resource Identifier (URI), opaque.
94 */
95struct GNUNET_FS_Uri
96{
97 enum uri_types type;
98 union
99 {
100 struct
101 {
102 /**
103 * Keywords start with a '+' if they are
104 * mandatory (in which case the '+' is NOT
105 * part of the keyword) and with a
106 * simple space if they are optional
107 * (in which case the space is ALSO not
108 * part of the actual keyword).
109 *
110 * Double-quotes to protect spaces and
111 * %-encoding are NOT used internally
112 * (only in URI-strings).
113 */
114 char **keywords;
115 unsigned int keywordCount;
116 } ksk;
117 struct
118 {
119 GNUNET_HashCode namespace;
120 char *identifier;
121 } sks;
122 struct FileIdentifier chk;
123 struct Location loc;
124 } data;
125
126};
127
128#endif
diff --git a/src/fs/fs_getopt.c b/src/fs/fs_getopt.c
new file mode 100644
index 000000000..8afe49852
--- /dev/null
+++ b/src/fs/fs_getopt.c
@@ -0,0 +1,192 @@
1/*
2 This file is part of GNUnet.
3 (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file fs/fs_getopt.c
23 * @brief helper functions for command-line argument processing
24 * @author Igor Wronsky, Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_fs_lib.h"
28
29
30
31/* ******************** command-line option parsing API *********************** */
32
33/**
34 * Command-line option parser function that allows the user
35 * to specify one or more '-k' options with keywords. Each
36 * specified keyword will be added to the URI. A pointer to
37 * the URI must be passed as the "scls" argument.
38 *
39 * @param ctx command line processor context
40 * @param scls must be of type "struct GNUNET_FS_Uri **"
41 * @param option name of the option (typically 'k')
42 * @param value command line argument given
43 * @return GNUNET_OK on success
44 */
45int
46GNUNET_FS_getopt_configure_set_keywords (GNUNET_GETOPT_CommandLineProcessorContext* ctx,
47 void *scls,
48 const char *option,
49 const char *value)
50{
51 struct GNUNET_FS_Uri **uri = scls;
52 struct GNUNET_FS_Uri *u = *uri;
53 char *val;
54 size_t slen;
55
56 if (u == NULL)
57 {
58 u = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI));
59 *uri = u;
60 u->type = ksk;
61 u->data.ksk.keywordCount = 0;
62 u->data.ksk.keywords = NULL;
63 }
64 else
65 {
66 GNUNET_assert (u->type == ksk);
67 }
68 slen = strlen (value);
69 if (slen == 0)
70 return GNUNET_SYSERR; /* cannot be empty */
71 if (value[0] == '+')
72 {
73 /* simply preserve the "mandatory" flag */
74 if (slen < 2)
75 return GNUNET_SYSERR; /* empty keywords not allowed */
76 if ((value[1] == '"') && (slen > 3) && (value[slen - 1] == '"'))
77 {
78 /* remove the quotes, keep the '+' */
79 val = GNUNET_malloc (slen - 1);
80 val[0] = '+';
81 memcpy (&val[1], &value[2], slen - 3);
82 val[slen - 2] = '\0';
83 }
84 else
85 {
86 /* no quotes, just keep the '+' */
87 val = GNUNET_strdup (value);
88 }
89 }
90 else
91 {
92 if ((value[0] == '"') && (slen > 2) && (value[slen - 1] == '"'))
93 {
94 /* remove the quotes, add a space */
95 val = GNUNET_malloc (slen);
96 val[0] = ' ';
97 memcpy (&val[1], &value[1], slen - 2);
98 val[slen - 1] = '\0';
99 }
100 else
101 {
102 /* add a space to indicate "not mandatory" */
103 val = GNUNET_malloc (slen + 2);
104 strcpy (val, " ");
105 strcat (val, value);
106 }
107 }
108 GNUNET_array_grow (u->data.ksk.keywords,
109 u->data.ksk.keywordCount, u->data.ksk.keywordCount + 1);
110 u->data.ksk.keywords[u->data.ksk.keywordCount - 1] = val;
111 return GNUNET_OK;
112}
113
114
115/**
116 * Command-line option parser function that allows the user to specify
117 * one or more '-m' options with metadata. Each specified entry of
118 * the form "type=value" will be added to the metadata. A pointer to
119 * the metadata must be passed as the "scls" argument.
120 *
121 * @param ctx command line processor context
122 * @param scls must be of type "struct GNUNET_MetaData **"
123 * @param option name of the option (typically 'k')
124 * @param value command line argument given
125 * @return GNUNET_OK on success
126 */
127int
128GNUNET_FS_getopt_configure_set_metadata (GNUNET_GETOPT_CommandLineProcessorContext* ctx,
129 void *scls,
130 const char *option,
131 const char *value)
132
133{
134 struct GNUNET_CONTAINER_MetaData **mm = scls;
135 EXTRACTOR_KeywordType type;
136 const char *typename;
137 const char *typename_i18n;
138 struct GNUNET_CONTAINER_MetaData *meta;
139 char *tmp;
140
141 meta = *mm;
142 if (meta == NULL)
143 {
144 meta = GNUNET_CONTAINER_meta_data_create ();
145 *mm = meta;
146 }
147
148 tmp = GNUNET_STRINGS_to_utf8 (NULL, value, strlen (value),
149#if ENABLE_NLS
150 nl_langinfo (CODESET)
151#else
152 "utf-8"
153#endif
154 );
155 type = EXTRACTOR_getHighestKeywordTypeNumber ();
156 while (type > 0)
157 {
158 type--;
159 typename = EXTRACTOR_getKeywordTypeAsString (type);
160 typename_i18n = dgettext (LIBEXTRACTOR_GETTEXT_DOMAIN, typename);
161 if ((strlen (tmp) >= strlen (typename) + 1) &&
162 (tmp[strlen (typename)] == ':') &&
163 (0 == strncmp (typename, tmp, strlen (typename))))
164 {
165 GNUNET_CONTAINER_meta_data_insert (meta, type, &tmp[strlen (typename) + 1]);
166 GNUNET_free (tmp);
167 tmp = NULL;
168 break;
169 }
170 if ((strlen (tmp) >= strlen (typename_i18n) + 1) &&
171 (tmp[strlen (typename_i18n)] == ':') &&
172 (0 == strncmp (typename_i18n, tmp, strlen (typename_i18n))))
173 {
174 GNUNET_CONTAINER_meta_data_insert (meta, type,
175 &tmp[strlen (typename_i18n) + 1]);
176 GNUNET_free (tmp);
177 tmp = NULL;
178 break;
179 }
180 }
181 if (tmp != NULL)
182 {
183 GNUNET_CONTAINER_meta_data_insert (meta, EXTRACTOR_UNKNOWN, tmp);
184 GNUNET_free (tmp);
185 printf (_
186 ("Unknown metadata type in metadata option `%s'. Using metadata type `unknown' instead.\n"),
187 value);
188 }
189 return GNUNET_OK;
190}
191
192/* end of fs_getopt.c */
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c
new file mode 100644
index 000000000..863ab475d
--- /dev/null
+++ b/src/fs/fs_uri.c
@@ -0,0 +1,1317 @@
1/*
2 This file is part of GNUnet.
3 (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file fs/fs_uri.c
23 * @brief Parses and produces uri strings.
24 * @author Igor Wronsky, Christian Grothoff
25 *
26 * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
27 * The specific structure of "IDENTIFIER" depends on the module and
28 * maybe differenciated into additional subcategories if applicable.
29 * This module only deals with ecrs identifiers (MODULE = "ecrs").
30 * <p>
31 *
32 * This module only parses URIs for the AFS module. The ECRS URIs fall
33 * into four categories, "chk", "sks", "ksk" and "loc". The first three
34 * categories were named in analogy (!) to Freenet, but they do NOT
35 * work in exactly the same way. They are very similar from the user's
36 * point of view (unique file identifier, subspace, keyword), but the
37 * implementation is rather different in pretty much every detail.
38 * The concrete URI formats are:
39 *
40 * <ul><li>
41 *
42 * First, there are URIs that identify a file. They have the format
43 * "gnunet://ecrs/chk/HEX1.HEX2.SIZE". These URIs can be used to
44 * download the file. The description, filename, mime-type and other
45 * meta-data is NOT part of the file-URI since a URI uniquely
46 * identifies a resource (and the contents of the file would be the
47 * same even if it had a different description).
48 *
49 * </li><li>
50 *
51 * The second category identifies entries in a namespace. The format
52 * is "gnunet://ecrs/sks/NAMESPACE/IDENTIFIER" where the namespace
53 * should be given in HEX. Applications may allow using a nickname
54 * for the namespace if the nickname is not ambiguous. The identifier
55 * can be either an ASCII sequence or a HEX-encoding. If the
56 * identifier is in ASCII but the format is ambiguous and could denote
57 * a HEX-string a "/" is appended to indicate ASCII encoding.
58 *
59 * </li> <li>
60 *
61 * The third category identifies ordinary searches. The format is
62 * "gnunet://ecrs/ksk/KEYWORD[+KEYWORD]*". Using the "+" syntax
63 * it is possible to encode searches with the boolean "AND" operator.
64 * "+" is used since it indicates a commutative 'and' operation and
65 * is unlikely to be used in a keyword by itself.
66 *
67 * </li><li>
68 *
69 * The last category identifies a datum on a specific machine. The
70 * format is "gnunet://ecrs/loc/HEX1.HEX2.SIZE.PEER.SIG.EXPTIME". PEER is
71 * the BinName of the public key of the peer storing the datum. The
72 * signature (SIG) certifies that this peer has this content.
73 * HEX1, HEX2 and SIZE correspond to a 'chk' URI.
74 *
75 * </li></ul>
76 *
77 * The encoding for hexadecimal values is defined in the hashing.c
78 * module in the gnunetutil library and discussed there.
79 * <p>
80 */
81#include "platform.h"
82#include "gnunet_fs_lib.h"
83#include "fs.h"
84
85
86/**
87 * Get a unique key from a URI. This is for putting URIs
88 * into HashMaps. The key may change between FS implementations.
89 *
90 * @param uri uri to convert to a unique key
91 * @param key wherer to store the unique key
92 */
93void
94GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri,
95 GNUNET_HashCode * key)
96{
97 switch (uri->type)
98 {
99 case chk:
100 *key = uri->data.fi.chk.query;
101 return;
102 case sks:
103 GNUNET_hash (uri->data.sks.identifier,
104 strlen (uri->data.sks.identifier), key);
105 break;
106 case ksk:
107 if (uri->data.ksk.keywordCount > 0)
108 GNUNET_hash (uri->data.ksk.keywords[0],
109 strlen (uri->data.ksk.keywords[0]), key);
110 break;
111 case loc:
112 GNUNET_hash (&uri->data.loc.fi,
113 sizeof (GNUNET_EC_FileIdentifier) +
114 sizeof (GNUNET_RSA_PublicKey), key);
115 break;
116 default:
117 memset (key, 0, sizeof (GNUNET_HashCode));
118 break;
119 }
120}
121
122
123/**
124 * Convert a URI to a UTF-8 String.
125 *
126 * @param uri uri to convert to a string
127 * @return the UTF-8 string
128 */
129char *
130GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri);
131
132
133/**
134 * Convert keyword URI to a human readable format
135 * (i.e. the search query that was used in the first place)
136 *
137 * @param uri ksk uri to convert to a string
138 * @return string with the keywords
139 */
140char *
141GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri);
142
143/**
144 * Convert a UTF-8 String to a URI.
145 *
146 * @param uri string to parse
147 * @param emsg where to store the parser error message (if any)
148 * @return NULL on error
149 */
150struct GNUNET_FS_Uri *
151GNUNET_FS_uri_parse (const char *uri,
152 char **emsg);
153
154/**
155 * Free URI.
156 *
157 * @param uri uri to free
158 */
159void
160GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri)
161{
162 unsigned int i;
163
164 GNUNET_assert (uri != NULL);
165 switch (uri->type)
166 {
167 case ksk:
168 for (i = 0; i < uri->data.ksk.keywordCount; i++)
169 GNUNET_free (uri->data.ksk.keywords[i]);
170 GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount,
171 0);
172 break;
173 case sks:
174 GNUNET_free (uri->data.sks.identifier);
175 break;
176 case loc:
177 break;
178 default:
179 /* do nothing */
180 break;
181 }
182 GNUNET_free (uri);
183}
184
185/**
186 * How many keywords are ANDed in this keyword URI?
187 *
188 * @param uri ksk uri to get the number of keywords from
189 * @return 0 if this is not a keyword URI
190 */
191unsigned int
192GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri)
193{
194 if (uri->type != ksk)
195 return 0;
196 return uri->data.ksk.keywordCount;
197}
198
199
200/**
201 * Iterate over all keywords in this keyword URI.
202 *
203 * @param uri ksk uri to get the keywords from
204 * @param iterator function to call on each keyword
205 * @param iterator_cls closure for iterator
206 * @return -1 if this is not a keyword URI, otherwise number of
207 * keywords iterated over until iterator aborted
208 */
209int
210GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri,
211 GNUNET_FS_KeywordIterator iterator,
212 void *iterator_cls)
213{
214 unsigned int i;
215 char *keyword;
216
217 if (uri->type != ksk)
218 return -1;
219 if (iterator == NULL)
220 return uri->data.ksk.keywordCount;
221 for (i = 0; i < uri->data.ksk.keywordCount; i++)
222 {
223 keyword = uri->data.ksk.keywords[i];
224 /* first character of keyword indicates
225 if it is mandatory or not */
226 if (GNUNET_OK != iterator (&keyword[1], keyword[0] == '+', cls))
227 return i;
228 }
229 return i;
230}
231
232
233/**
234 * Obtain the identity of the peer offering the data
235 *
236 * @param uri the location URI to inspect
237 * @param peer where to store the identify of the peer (presumably) offering the content
238 * @return GNUNET_SYSERR if this is not a location URI, otherwise GNUNET_OK
239 */
240int
241GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri,
242 struct GNUNET_PeerIdentity * peer)
243{
244 if (uri->type != loc)
245 return GNUNET_SYSERR;
246 GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey),
247 &peer->hashPubKey);
248 return GNUNET_OK;
249}
250
251
252/**
253 * Obtain the URI of the content itself.
254 *
255 * @param uri location URI to get the content URI from
256 * @return NULL if argument is not a location URI
257 */
258struct GNUNET_FS_Uri *
259GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri)
260{
261 struct GNUNET_ECRS_Uri *ret;
262
263 if (uri->type != loc)
264 return NULL;
265 ret = GNUNET_malloc (sizeof (struct GNUNET_ECRS_Uri));
266 ret->type = chk;
267 ret->data.chk = uri->data.loc.fi;
268 return ret;
269}
270
271
272/**
273 * Construct a location URI (this peer will be used for the location).
274 *
275 * @param baseURI content offered by the sender
276 * @param cfg configuration information (used to find our hostkey)
277 * @param expiration_time how long will the content be offered?
278 * @return the location URI, NULL on error
279 */
280struct GNUNET_FS_Uri *
281GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri,
282 struct GNUNET_CONFIGURATION_Handle *cfg,
283 struct GNUNET_TIME_Absolute expiration_time);
284
285
286/**
287 * Canonicalize keyword URI. Performs operations such
288 * as decapitalization and removal of certain characters.
289 * (useful for search).
290 *
291 * @param uri the URI to canonicalize
292 * @return canonicalized version of the URI, NULL on error
293 */
294struct GNUNET_FS_Uri *
295GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri);
296
297
298/**
299 * Merge the sets of keywords from two KSK URIs.
300 * (useful for merging the canonicalized keywords with
301 * the original keywords for sharing).
302 *
303 * @param u1 first uri
304 * @param u2 second uri
305 * @return merged URI, NULL on error
306 */
307struct GNUNET_FS_Uri *
308GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1,
309 const struct GNUNET_FS_Uri *u2);
310
311
312/**
313 * Duplicate URI.
314 *
315 * @param uri the URI to duplicate
316 * @return copy of the URI
317 */
318struct GNUNET_FS_Uri *
319GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri)
320{
321 struct GNUNET_ECRS_URI *ret;
322 unsigned int i;
323
324 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
325 memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri));
326 switch (ret->type)
327 {
328 case ksk:
329 if (ret->data.ksk.keywordCount > 0)
330 {
331 ret->data.ksk.keywords
332 = GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *));
333 for (i = 0; i < ret->data.ksk.keywordCount; i++)
334 ret->data.ksk.keywords[i] =
335 GNUNET_strdup (uri->data.ksk.keywords[i]);
336 }
337 else
338 ret->data.ksk.keywords = NULL; /* just to be sure */
339 break;
340 case sks:
341 ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier);
342 break;
343 case loc:
344 break;
345 default:
346 break;
347 }
348 return ret;
349}
350
351
352/**
353 * Create an FS URI from a single user-supplied string of keywords.
354 * The string is broken up at spaces into individual keywords.
355 * Keywords that start with "+" are mandatory. Double-quotes can
356 * be used to prevent breaking up strings at spaces (and also
357 * to specify non-mandatory keywords starting with "+").
358 *
359 * Keywords must contain a balanced number of double quotes and
360 * double quotes can not be used in the actual keywords (for
361 * example, the string '""foo bar""' will be turned into two
362 * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'.
363 *
364 * @param keywords the keyword string
365 * @return an FS URI for the given keywords, NULL
366 * if keywords is not legal (i.e. empty).
367 */
368struct GNUNET_FS_Uri *
369GNUNET_FS_uri_ksk_create (const char *keywords);
370
371
372/**
373 * Create an FS URI from a user-supplied command line of keywords.
374 * Arguments should start with "+" to indicate mandatory
375 * keywords.
376 *
377 * @param argc number of keywords
378 * @param argv keywords (double quotes are not required for
379 * keywords containing spaces; however, double
380 * quotes are required for keywords starting with
381 * "+"); there is no mechanism for having double
382 * quotes in the actual keywords (if the user
383 * did specifically specify double quotes, the
384 * caller should convert each double quote
385 * into two single quotes).
386 * @return an FS URI for the given keywords, NULL
387 * if keywords is not legal (i.e. empty).
388 */
389struct GNUNET_FS_Uri *
390GNUNET_FS_uri_ksk_create_from_args (unsigned int argc,
391 const char **argv);
392
393
394/**
395 * Test if two URIs are equal.
396 *
397 * @param u1 one of the URIs
398 * @param u2 the other URI
399 * @return GNUNET_YES if the URIs are equal
400 */
401int
402GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1,
403 const struct GNUNET_FS_Uri *u2)
404{
405 int ret;
406 unsigned int i;
407 unsigned int j;
408
409 GNUNET_assert (uri1 != NULL);
410 GNUNET_assert (uri2 != NULL);
411 if (uri1->type != uri2->type)
412 return GNUNET_NO;
413 switch (uri1->type)
414 {
415 case chk:
416 if (0 == memcmp (&uri1->data.chk,
417 &uri2->data.chk,
418 sizeof (struct FileIdentifier)))
419 return GNUNET_YES;
420 return GNUNET_NO;
421 case sks:
422 if ((0 == memcmp (&uri1->data.sks.namespace,
423 &uri2->data.sks.namespace,
424 sizeof (GNUNET_HashCode))) &&
425 (0 == strcmp (uri1->data.sks.identifier,
426 uri2->data.sks.identifier)))
427
428 return GNUNET_YES;
429 return GNUNET_NO;
430 case ksk:
431 if (uri1->data.ksk.keywordCount != uri2->data.ksk.keywordCount)
432 return GNUNET_NO;
433 for (i = 0; i < uri1->data.ksk.keywordCount; i++)
434 {
435 ret = GNUNET_NO;
436 for (j = 0; j < uri2->data.ksk.keywordCount; j++)
437 {
438 if (0 == strcmp (uri1->data.ksk.keywords[i],
439 uri2->data.ksk.keywords[j]))
440 {
441 ret = GNUNET_YES;
442 break;
443 }
444 }
445 if (ret == GNUNET_NO)
446 return GNUNET_NO;
447 }
448 return GNUNET_YES;
449 case loc:
450 if (memcmp (&uri1->data.loc,
451 &uri2->data.loc,
452 sizeof (struct FileIdentifier) +
453 sizeof (GNUNET_RSA_PublicKey) +
454 sizeof (struct GNUNET_TIME_Absolute) +
455 sizeof (unsigned short) + sizeof (unsigned short)) != 0)
456 return GNUNET_NO;
457 return GNUNET_YES;
458 default:
459 return GNUNET_NO;
460 }
461}
462
463
464/**
465 * Is this a namespace URI?
466 *
467 * @param uri the uri to check
468 * @return GNUNET_YES if this is an SKS uri
469 */
470int
471GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri)
472{
473 return uri->type == sks;
474}
475
476
477/**
478 * Get the ID of a namespace from the given
479 * namespace URI.
480 *
481 * @param uri the uri to get the namespace ID from
482 * @param nsid where to store the ID of the namespace
483 * @return GNUNET_OK on success
484 */
485int
486GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri,
487 GNUNET_HashCode * nsid)
488{
489 if (! GNUNET_FS_uri_test_sks (uri))
490 {
491 GNUNET_break (0);
492 return GNUNET_SYSERR;
493 }
494 *id = uri->data.sks.namespace;
495 return GNUNET_OK;
496}
497
498
499/**
500 * Get the content identifier of an SKS URI.
501 *
502 * @param uri the sks uri
503 * @return NULL on error (not a valid SKS URI)
504 */
505char *
506GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri)
507{
508 if (!GNUNET_FS_uri_test_sks (uri))
509 {
510 GNUNET_break (0);
511 return NULL;
512 }
513 return GNUNET_strdup (uri->data.sks.identifier);
514}
515
516
517/**
518 * Convert namespace URI to a human readable format
519 * (using the namespace description, if available).
520 *
521 * @param cfg configuration to use
522 * @param uri SKS uri to convert
523 * @return NULL on error (not an SKS URI)
524 */
525char *
526GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg,
527 const struct GNUNET_FS_Uri *uri);
528
529
530/**
531 * Is this a keyword URI?
532 *
533 * @param uri the uri
534 * @return GNUNET_YES if this is a KSK uri
535 */
536int
537GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri)
538{
539#if EXTRA_CHECKS
540 unsigned int i;
541
542 if (uri->type == ksk)
543 {
544 for (i = uri->data.ksk.keywordCount - 1; i >= 0; i--)
545 GNUNET_assert (uri->data.ksk.keywords[i] != NULL);
546 }
547#endif
548 return uri->type == ksk;
549}
550
551
552/**
553 * Is this a file (or directory) URI?
554 *
555 * @param uri the uri to check
556 * @return GNUNET_YES if this is a CHK uri
557 */
558int
559GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri)
560{
561 return uri->type == chk;
562}
563
564
565/**
566 * What is the size of the file that this URI
567 * refers to?
568 *
569 * @param uri the CHK URI to inspect
570 * @return size of the file as specified in the CHK URI
571 */
572uint64_t
573GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri)
574{
575 switch (uri->type)
576 {
577 case chk:
578 return GNUNET_ntohll (uri->data.chk.file_length);
579 case loc:
580 return GNUNET_ntohll (uri->data.loc.fi.file_length);
581 default:
582 GNUNET_assert (0);
583 }
584 return 0; /* unreachable */
585}
586
587
588/**
589 * Is this a location URI?
590 *
591 * @param uri the uri to check
592 * @return GNUNET_YES if this is a LOC uri
593 */
594int
595GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri)
596{
597 return uri->type == loc;
598}
599
600
601/**
602 * Function called on each value in the meta data.
603 * Adds it to the URI.
604 *
605 * @param cls URI to update
606 * @param type type of the meta data
607 * @param data value of the meta data
608 * @return GNUNET_OK (always)
609 */
610static int
611gather_uri_data (void *cls,
612 EXTRACTOR_KeywordType type,
613 const char *data)
614{
615 struct GNUNET_FS_Uri *uri = cls;
616 char *nkword;
617 int j;
618
619 for (j = uri->data.ksk.keywordCount - 1; j >= 0; j--)
620 if (0 == strcmp (&uri->data.ksk.keywords[j][1], data))
621 return GNUNET_OK;
622 nkword = GNUNET_malloc (strlen (data) + 2);
623 strcpy (nkword, " "); /* not mandatory */
624 strcat (nkword, data);
625 uri->data.ksk.keywords[uri->data.ksk.keywordCount++] = nkword;
626 return GNUNET_OK;
627}
628
629
630/**
631 * Construct a keyword-URI from meta-data (take all entries
632 * in the meta-data and construct one large keyword URI
633 * that lists all keywords that can be found in the meta-data).
634 * @deprecated
635 */
636struct GNUNET_FS_Uri *
637GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_MetaData *md)
638{
639 struct GNUNET_FS_Uri *ret;
640
641 if (md == NULL)
642 return NULL;
643 ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
644 ret->type = ksk;
645 ret->data.ksk.keywordCount = 0;
646 ret->data.ksk.keywords = NULL;
647 ret->data.ksk.keywords
648 = GNUNET_malloc (sizeof (char *) *
649 GNUNET_meta_data_get_contents (md, NULL, NULL));
650 GNUNET_meta_data_get_contents (md, &gather_uri_data, ret);
651 return ret;
652
653}
654
655#if 0
656
657// old code...
658
659
660
661/**
662 * In URI-encoding, does the given character
663 * need to be encoded using %-encoding?
664 */
665static int
666needs_percent (char c)
667{
668 return (!((isalnum (c)) ||
669 (c == '-') || (c == '_') || (c == '.') || (c == '~')));
670}
671
672/**
673 * Generate a keyword URI.
674 * @return NULL on error (i.e. keywordCount == 0)
675 */
676static char *
677createKeywordURI (char **keywords, unsigned int keywordCount)
678{
679 size_t n;
680 char *ret;
681 unsigned int i;
682 unsigned int j;
683 unsigned int wpos;
684 size_t slen;
685 const char *keyword;
686
687 n =
688 keywordCount + strlen (GNUNET_ECRS_URI_PREFIX) +
689 strlen (GNUNET_ECRS_SEARCH_INFIX) + 1;
690 for (i = 0; i < keywordCount; i++)
691 {
692 keyword = keywords[i];
693 slen = strlen (keyword);
694 n += slen;
695 for (j = 0; j < slen; j++)
696 {
697 if ((j == 0) && (keyword[j] == ' '))
698 {
699 n--;
700 continue; /* skip leading space */
701 }
702 if (needs_percent (keyword[j]))
703 n += 2; /* will use %-encoding */
704 }
705 }
706 ret = GNUNET_malloc (n);
707 strcpy (ret, GNUNET_ECRS_URI_PREFIX);
708 strcat (ret, GNUNET_ECRS_SEARCH_INFIX);
709 wpos = strlen (ret);
710 for (i = 0; i < keywordCount; i++)
711 {
712 keyword = keywords[i];
713 slen = strlen (keyword);
714 for (j = 0; j < slen; j++)
715 {
716 if ((j == 0) && (keyword[j] == ' '))
717 continue; /* skip leading space */
718 if (needs_percent (keyword[j]))
719 {
720 sprintf (&ret[wpos], "%%%02X", keyword[j]);
721 wpos += 3;
722 }
723 else
724 {
725 ret[wpos++] = keyword[j];
726 }
727 }
728 if (i != keywordCount - 1)
729 ret[wpos++] = '+';
730 }
731 return ret;
732}
733
734/**
735 * Generate a subspace URI.
736 */
737static char *
738createSubspaceURI (const GNUNET_HashCode * namespace, const char *identifier)
739{
740 size_t n;
741 char *ret;
742 GNUNET_EncName ns;
743
744 n =
745 sizeof (GNUNET_EncName) + strlen (GNUNET_ECRS_URI_PREFIX) +
746 strlen (GNUNET_ECRS_SUBSPACE_INFIX) + 1 + strlen (identifier);
747 ret = GNUNET_malloc (n);
748 GNUNET_hash_to_enc (namespace, &ns);
749 GNUNET_snprintf (ret, n,
750 "%s%s%s/%s",
751 GNUNET_ECRS_URI_PREFIX, GNUNET_ECRS_SUBSPACE_INFIX,
752 (const char *) &ns, identifier);
753 return ret;
754}
755
756/**
757 * Generate a file URI.
758 */
759static char *
760createFileURI (const GNUNET_EC_FileIdentifier * fi)
761{
762 char *ret;
763 GNUNET_EncName keyhash;
764 GNUNET_EncName queryhash;
765 size_t n;
766
767 GNUNET_hash_to_enc (&fi->chk.key, &keyhash);
768 GNUNET_hash_to_enc (&fi->chk.query, &queryhash);
769
770 n =
771 strlen (GNUNET_ECRS_URI_PREFIX) + 2 * sizeof (GNUNET_EncName) + 8 + 16 +
772 32 + strlen (GNUNET_ECRS_FILE_INFIX);
773 ret = GNUNET_malloc (n);
774 GNUNET_snprintf (ret,
775 n,
776 "%s%s%s.%s.%llu",
777 GNUNET_ECRS_URI_PREFIX,
778 GNUNET_ECRS_FILE_INFIX,
779 (char *) &keyhash, (char *) &queryhash,
780 GNUNET_ntohll (fi->file_length));
781 return ret;
782}
783
784#include "bincoder.c"
785
786/**
787 * Create a (string) location URI from a Location.
788 */
789static char *
790createLocURI (const Location * loc)
791{
792 size_t n;
793 char *ret;
794 GNUNET_EncName keyhash;
795 GNUNET_EncName queryhash;
796 char *peerId;
797 char *peerSig;
798
799 GNUNET_hash_to_enc (&loc->fi.chk.key, &keyhash);
800 GNUNET_hash_to_enc (&loc->fi.chk.query, &queryhash);
801 n = 2148;
802 peerId = bin2enc (&loc->peer, sizeof (GNUNET_RSA_PublicKey));
803 peerSig = bin2enc (&loc->contentSignature, sizeof (GNUNET_RSA_Signature));
804 ret = GNUNET_malloc (n);
805 GNUNET_snprintf (ret,
806 n,
807 "%s%s%s.%s.%llu.%s.%s.%u",
808 GNUNET_ECRS_URI_PREFIX,
809 GNUNET_ECRS_LOCATION_INFIX,
810 (char *) &keyhash,
811 (char *) &queryhash,
812 GNUNET_ntohll (loc->fi.file_length),
813 peerId, peerSig, loc->expirationTime);
814 GNUNET_free (peerSig);
815 GNUNET_free (peerId);
816 return ret;
817}
818
819/**
820 * Convert a URI to a UTF-8 String.
821 */
822char *
823GNUNET_ECRS_uri_to_string (const struct GNUNET_ECRS_URI *uri)
824{
825 if (uri == NULL)
826 {
827 GNUNET_GE_BREAK (NULL, 0);
828 return NULL;
829 }
830 switch (uri->type)
831 {
832 case ksk:
833 return createKeywordURI (uri->data.ksk.keywords,
834 uri->data.ksk.keywordCount);
835 case sks:
836 return createSubspaceURI (&uri->data.sks.namespace,
837 uri->data.sks.identifier);
838 case chk:
839 return createFileURI (&uri->data.fi);
840 case loc:
841 return createLocURI (&uri->data.loc);
842 default:
843 GNUNET_GE_BREAK (NULL, 0);
844 return NULL;
845 }
846}
847
848/**
849 * Convert keyword URI to a human readable format
850 * (i.e. the search query that was used in the first place)
851 */
852char *
853GNUNET_ECRS_ksk_uri_to_human_readable_string (const struct GNUNET_ECRS_URI
854 *uri)
855{
856 size_t n;
857 char *ret;
858 unsigned int i;
859 const char *keyword;
860 char **keywords;
861 unsigned int keywordCount;
862
863 if ((uri == NULL) || (uri->type != ksk))
864 {
865 GNUNET_GE_BREAK (NULL, 0);
866 return NULL;
867 }
868 keywords = uri->data.ksk.keywords;
869 keywordCount = uri->data.ksk.keywordCount;
870 n = keywordCount + 1;
871 for (i = 0; i < keywordCount; i++)
872 {
873 keyword = keywords[i];
874 n += strlen (keyword) - 1;
875 if (NULL != strstr (&keyword[1], " "))
876 n += 2;
877 if (keyword[0] == '+')
878 n++;
879 }
880 ret = GNUNET_malloc (n);
881 strcpy (ret, "");
882 for (i = 0; i < keywordCount; i++)
883 {
884 keyword = keywords[i];
885 if (NULL != strstr (&keyword[1], " "))
886 {
887 strcat (ret, "\"");
888 if (keyword[0] == '+')
889 strcat (ret, keyword);
890 else
891 strcat (ret, &keyword[1]);
892 strcat (ret, "\"");
893 }
894 else
895 {
896 if (keyword[0] == '+')
897 strcat (ret, keyword);
898 else
899 strcat (ret, &keyword[1]);
900 }
901 strcat (ret, " ");
902 }
903 return ret;
904}
905
906/**
907 * Given a keyword with %-encoding (and possibly quotes to protect
908 * spaces), return a copy of the keyword without %-encoding and
909 * without double-quotes (%22). Also, add a space at the beginning
910 * if there is not a '+'.
911 */
912static char *
913percent_decode_keyword (const char *in)
914{
915 char *out;
916 char *ret;
917 unsigned int rpos;
918 unsigned int wpos;
919 unsigned int hx;
920
921 out = GNUNET_strdup (in);
922 rpos = 0;
923 wpos = 0;
924 while (out[rpos] != '\0')
925 {
926 if (out[rpos] == '%')
927 {
928 if (1 != sscanf (&out[rpos + 1], "%2X", &hx))
929 {
930 GNUNET_free (out);
931 return NULL;
932 }
933 rpos += 3;
934 if (hx == '"')
935 continue; /* skip double quote */
936 out[wpos++] = (char) hx;
937 }
938 else
939 {
940 out[wpos++] = out[rpos++];
941 }
942 }
943 out[wpos] = '\0';
944 if (out[0] == '+')
945 {
946 ret = GNUNET_strdup (out);
947 }
948 else
949 {
950 /* need to prefix with space */
951 ret = GNUNET_malloc (strlen (out) + 2);
952 strcpy (ret, " ");
953 strcat (ret, out);
954 }
955 GNUNET_free (out);
956 return ret;
957}
958
959/**
960 * Parses an ECRS search URI.
961 *
962 * @param uri an uri string
963 * @param keyword will be set to an array with the keywords
964 * @return GNUNET_SYSERR if this is not a search URI, otherwise
965 * the number of keywords placed in the array
966 */
967static int
968parseKeywordURI (struct GNUNET_GE_Context *ectx, const char *uri,
969 char ***keywords)
970{
971 unsigned int pos;
972 int ret;
973 int iret;
974 int i;
975 size_t slen;
976 char *dup;
977 int saw_quote;
978
979 GNUNET_GE_ASSERT (ectx, uri != NULL);
980
981 slen = strlen (uri);
982 pos = strlen (GNUNET_ECRS_URI_PREFIX);
983
984 if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
985 return GNUNET_SYSERR;
986 if (0 !=
987 strncmp (&uri[pos], GNUNET_ECRS_SEARCH_INFIX,
988 strlen (GNUNET_ECRS_SEARCH_INFIX)))
989 return GNUNET_SYSERR;
990 pos += strlen (GNUNET_ECRS_SEARCH_INFIX);
991 if (slen == pos)
992 {
993 /* no keywords */
994 (*keywords) = NULL;
995 return 0;
996 }
997 if ((uri[slen - 1] == '+') || (uri[pos] == '+'))
998 return GNUNET_SYSERR; /* no keywords / malformed */
999
1000 ret = 1;
1001 saw_quote = 0;
1002 for (i = pos; i < slen; i++)
1003 {
1004 if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22")))
1005 {
1006 saw_quote = (saw_quote + 1) % 2;
1007 i += 3;
1008 continue;
1009 }
1010 if ((uri[i] == '+') && (saw_quote == 0))
1011 {
1012 ret++;
1013 if (uri[i - 1] == '+')
1014 return GNUNET_SYSERR; /* "++" not allowed */
1015 }
1016 }
1017 if (saw_quote == 1)
1018 return GNUNET_SYSERR; /* quotes not balanced */
1019 iret = ret;
1020 dup = GNUNET_strdup (uri);
1021 (*keywords) = GNUNET_malloc (ret * sizeof (char *));
1022 for (i = 0; i < ret; i++)
1023 (*keywords)[i] = NULL;
1024 for (i = slen - 1; i >= pos; i--)
1025 {
1026 if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22")))
1027 {
1028 saw_quote = (saw_quote + 1) % 2;
1029 i += 3;
1030 continue;
1031 }
1032 if ((dup[i] == '+') && (saw_quote == 0))
1033 {
1034 (*keywords)[--ret] = percent_decode_keyword (&dup[i + 1]);
1035 if (NULL == (*keywords)[ret])
1036 goto CLEANUP;
1037 dup[i] = '\0';
1038 }
1039 }
1040 (*keywords)[--ret] = percent_decode_keyword (&dup[pos]);
1041 if (NULL == (*keywords)[ret])
1042 goto CLEANUP;
1043 GNUNET_GE_ASSERT (ectx, ret == 0);
1044 GNUNET_free (dup);
1045 return iret;
1046CLEANUP:
1047 for (i = 0; i < ret; i++)
1048 GNUNET_free_non_null ((*keywords)[i]);
1049 GNUNET_free (*keywords);
1050 *keywords = NULL;
1051 GNUNET_free (dup);
1052 return GNUNET_SYSERR;
1053}
1054
1055/**
1056 * Parses an AFS namespace / subspace identifier URI.
1057 *
1058 * @param uri an uri string
1059 * @param namespace set to the namespace ID
1060 * @param identifier set to the ID in the namespace
1061 * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a namespace URI
1062 */
1063static int
1064parseSubspaceURI (struct GNUNET_GE_Context *ectx,
1065 const char *uri,
1066 GNUNET_HashCode * namespace, char **identifier)
1067{
1068 unsigned int pos;
1069 size_t slen;
1070 char *up;
1071
1072 GNUNET_GE_ASSERT (ectx, uri != NULL);
1073
1074 slen = strlen (uri);
1075 pos = strlen (GNUNET_ECRS_URI_PREFIX);
1076
1077 if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
1078 return GNUNET_SYSERR;
1079 if (0 != strncmp (&uri[pos],
1080 GNUNET_ECRS_SUBSPACE_INFIX,
1081 strlen (GNUNET_ECRS_SUBSPACE_INFIX)))
1082 return GNUNET_SYSERR;
1083 pos += strlen (GNUNET_ECRS_SUBSPACE_INFIX);
1084 if ((slen < pos + sizeof (GNUNET_EncName) + 1) ||
1085 (!((uri[pos + sizeof (GNUNET_EncName) - 1] == '/') ||
1086 (uri[pos + sizeof (GNUNET_EncName) - 1] == '\\'))))
1087 return GNUNET_SYSERR;
1088
1089 up = GNUNET_strdup (uri);
1090 up[pos + sizeof (GNUNET_EncName) - 1] = '\0';
1091 if ((GNUNET_OK != GNUNET_enc_to_hash (&up[pos], namespace)))
1092 {
1093 GNUNET_free (up);
1094 return GNUNET_SYSERR;
1095 }
1096 *identifier = GNUNET_strdup (&up[pos + sizeof (GNUNET_EncName)]);
1097 GNUNET_free (up);
1098 return GNUNET_OK;
1099}
1100
1101/**
1102 * Parses an URI that identifies a file
1103 *
1104 * @param uri an uri string
1105 * @param fi the file identifier
1106 * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI
1107 */
1108static int
1109parseFileURI (struct GNUNET_GE_Context *ectx, const char *uri,
1110 GNUNET_EC_FileIdentifier * fi)
1111{
1112 unsigned int pos;
1113 size_t slen;
1114 char *dup;
1115
1116 GNUNET_GE_ASSERT (ectx, uri != NULL);
1117
1118 slen = strlen (uri);
1119 pos = strlen (GNUNET_ECRS_URI_PREFIX);
1120
1121 if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
1122 return GNUNET_SYSERR;
1123 if (0 !=
1124 strncmp (&uri[pos], GNUNET_ECRS_FILE_INFIX,
1125 strlen (GNUNET_ECRS_FILE_INFIX)))
1126 return GNUNET_SYSERR;
1127 pos += strlen (GNUNET_ECRS_FILE_INFIX);
1128 if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) ||
1129 (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') ||
1130 (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.'))
1131 return GNUNET_SYSERR;
1132
1133 dup = GNUNET_strdup (uri);
1134 dup[pos + sizeof (GNUNET_EncName) - 1] = '\0';
1135 dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0';
1136 if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos],
1137 &fi->chk.key)) ||
1138 (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)],
1139 &fi->chk.query)) ||
1140 (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2],
1141 "%llu", &fi->file_length)))
1142 {
1143 GNUNET_free (dup);
1144 return GNUNET_SYSERR;
1145 }
1146 GNUNET_free (dup);
1147 fi->file_length = GNUNET_htonll (fi->file_length);
1148 return GNUNET_OK;
1149}
1150
1151/**
1152 * Parses an URI that identifies a location (and file).
1153 * Also verifies validity of the location URI.
1154 *
1155 * @param uri an uri string
1156 * @param loc where to store the location
1157 * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI
1158 */
1159static int
1160parseLocationURI (struct GNUNET_GE_Context *ectx, const char *uri,
1161 Location * loc)
1162{
1163 unsigned int pos;
1164 unsigned int npos;
1165 int ret;
1166 size_t slen;
1167 char *dup;
1168 char *addr;
1169
1170
1171 GNUNET_GE_ASSERT (ectx, uri != NULL);
1172 addr = NULL;
1173 slen = strlen (uri);
1174 pos = strlen (GNUNET_ECRS_URI_PREFIX);
1175
1176 if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos))
1177 return GNUNET_SYSERR;
1178 if (0 != strncmp (&uri[pos],
1179 GNUNET_ECRS_LOCATION_INFIX,
1180 strlen (GNUNET_ECRS_LOCATION_INFIX)))
1181 return GNUNET_SYSERR;
1182 pos += strlen (GNUNET_ECRS_LOCATION_INFIX);
1183 if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) ||
1184 (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') ||
1185 (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.'))
1186 return GNUNET_SYSERR;
1187
1188 dup = GNUNET_strdup (uri);
1189 dup[pos + sizeof (GNUNET_EncName) - 1] = '\0';
1190 dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0';
1191 npos = pos + sizeof (GNUNET_EncName) * 2;
1192 while ((uri[npos] != '\0') && (uri[npos] != '.'))
1193 npos++;
1194 if (dup[npos] == '\0')
1195 goto ERR;
1196 dup[npos++] = '\0';
1197 if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos],
1198 &loc->fi.chk.key)) ||
1199 (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)],
1200 &loc->fi.chk.query)) ||
1201 (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2],
1202 "%llu", &loc->fi.file_length)))
1203 goto ERR;
1204 loc->fi.file_length = GNUNET_htonll (loc->fi.file_length);
1205 ret = enc2bin (&dup[npos], &loc->peer, sizeof (GNUNET_RSA_PublicKey));
1206 if (ret == -1)
1207 goto ERR;
1208 npos += ret;
1209 if (dup[npos++] != '.')
1210 goto ERR;
1211 ret =
1212 enc2bin (&dup[npos], &loc->contentSignature,
1213 sizeof (GNUNET_RSA_Signature));
1214 if (ret == -1)
1215 goto ERR;
1216 npos += ret;
1217 if (dup[npos++] != '.')
1218 goto ERR;
1219 if (1 != SSCANF (&dup[npos], "%u", &loc->expirationTime))
1220 goto ERR;
1221 /* Finally: verify sigs! */
1222 if (GNUNET_OK != GNUNET_RSA_verify (&loc->fi,
1223 sizeof (GNUNET_EC_FileIdentifier) +
1224 sizeof (GNUNET_PeerIdentity) +
1225 sizeof (GNUNET_Int32Time),
1226 &loc->contentSignature, &loc->peer))
1227 goto ERR;
1228 GNUNET_free (dup);
1229 return GNUNET_OK;
1230ERR:
1231 GNUNET_free (dup);
1232 GNUNET_free_non_null (addr);
1233 return GNUNET_SYSERR;
1234}
1235
1236/**
1237 * Convert a UTF-8 String to a URI.
1238 */
1239URI *
1240GNUNET_ECRS_string_to_uri (struct GNUNET_GE_Context * ectx, const char *uri)
1241{
1242 URI *ret;
1243 int len;
1244
1245 ret = GNUNET_malloc (sizeof (URI));
1246 if (GNUNET_OK == parseFileURI (ectx, uri, &ret->data.fi))
1247 {
1248 ret->type = chk;
1249 return ret;
1250 }
1251 if (GNUNET_OK == parseSubspaceURI (ectx,
1252 uri,
1253 &ret->data.sks.namespace,
1254 &ret->data.sks.identifier))
1255 {
1256 ret->type = sks;
1257 return ret;
1258 }
1259 if (GNUNET_OK == parseLocationURI (ectx, uri, &ret->data.loc))
1260 {
1261 ret->type = loc;
1262 return ret;
1263 }
1264 len = parseKeywordURI (ectx, uri, &ret->data.ksk.keywords);
1265 if (len < 0)
1266 {
1267 GNUNET_free (ret);
1268 return NULL;
1269 }
1270 ret->type = ksk;
1271 ret->data.ksk.keywordCount = len;
1272 return ret;
1273}
1274
1275
1276
1277/**
1278 * Construct a location URI.
1279 *
1280 * @param baseURI content offered by the sender
1281 * @param sender identity of the peer with the content
1282 * @param expiration_time how long will the content be offered?
1283 * @param proto transport protocol to reach the peer
1284 * @param sas sender address size (for HELLO)
1285 * @param address sas bytes of address information
1286 * @param signer function to call for obtaining
1287 * RSA signatures for "sender".
1288 * @return the location URI
1289 */
1290struct GNUNET_ECRS_URI *
1291GNUNET_ECRS_location_to_uri (const struct GNUNET_ECRS_URI *baseUri,
1292 const GNUNET_RSA_PublicKey * sender,
1293 GNUNET_Int32Time expirationTime,
1294 GNUNET_ECRS_SignFunction signer,
1295 void *signer_cls)
1296{
1297 struct GNUNET_ECRS_URI *uri;
1298
1299 if (baseUri->type != chk)
1300 return NULL;
1301
1302 uri = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI));
1303 uri->type = loc;
1304 uri->data.loc.fi = baseUri->data.fi;
1305 uri->data.loc.peer = *sender;
1306 uri->data.loc.expirationTime = expirationTime;
1307 signer (signer_cls,
1308 sizeof (GNUNET_EC_FileIdentifier) +
1309 sizeof (GNUNET_PeerIdentity) +
1310 sizeof (GNUNET_Int32Time),
1311 &uri->data.loc.fi, &uri->data.loc.contentSignature);
1312 return uri;
1313}
1314
1315#endif
1316
1317/* end of uri.c */
diff --git a/src/fs/test_fs_getopt.c b/src/fs/test_fs_getopt.c
new file mode 100644
index 000000000..2c0a0eba4
--- /dev/null
+++ b/src/fs/test_fs_getopt.c
@@ -0,0 +1,33 @@
1/*
2 This file is part of GNUnet
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file fs/test_fs_getopt.c
22 * @brief test for fs_getopt.c
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_fs_lib.h"
27
28int
29main (int argc, char *argv[])
30{
31 fprintf (stderr, "WARNING: testcase not yet written.\n");
32 return 0; /* testcase passed */
33}
diff --git a/src/fs/test_fs_uri.c b/src/fs/test_fs_uri.c
new file mode 100644
index 000000000..f24f4fe27
--- /dev/null
+++ b/src/fs/test_fs_uri.c
@@ -0,0 +1,255 @@
1/*
2 This file is part of GNUnet.
3 (C) 2003, 2004, 2006, 2007 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file applications/fs/ecrs/uritest.c
23 * @brief Test for uri.c
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util.h"
29#include "gnunet_ecrs_lib.h"
30#include "ecrs.h"
31
32#define ABORT() { fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); return 1; }
33
34static int
35testKeyword ()
36{
37 char *uri;
38 struct GNUNET_ECRS_URI *ret;
39
40 if (NULL != GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/ksk/++"))
41 ABORT ();
42 ret = GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/ksk/foo+bar");
43 if (ret == NULL)
44 ABORT ();
45 if (!GNUNET_ECRS_uri_test_ksk (ret))
46 {
47 GNUNET_ECRS_uri_destroy (ret);
48 ABORT ();
49 }
50 if ((2 != ret->data.ksk.keywordCount) ||
51 (0 != strcmp (" foo", ret->data.ksk.keywords[0])) ||
52 (0 != strcmp (" bar", ret->data.ksk.keywords[1])))
53 {
54 GNUNET_ECRS_uri_destroy (ret);
55 ABORT ();
56 }
57
58 uri = GNUNET_ECRS_uri_to_string (ret);
59 if (0 != strcmp (uri, "gnunet://ecrs/ksk/foo+bar"))
60 {
61 GNUNET_free (uri);
62 GNUNET_ECRS_uri_destroy (ret);
63 ABORT ();
64 }
65 GNUNET_free (uri);
66 GNUNET_ECRS_uri_destroy (ret);
67 return 0;
68}
69
70static int
71testLocation ()
72{
73 struct GNUNET_ECRS_URI *uri;
74 char *uric;
75 struct GNUNET_ECRS_URI *uri2;
76 GNUNET_RSA_PublicKey pk;
77 struct GNUNET_RSA_PrivateKey *hk;
78 struct GNUNET_ECRS_URI *baseURI;
79
80 baseURI =
81 GNUNET_ECRS_string_to_uri (NULL,
82 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42");
83 hk = GNUNET_RSA_create_key ();
84 GNUNET_RSA_get_public_key (hk, &pk);
85 uri = GNUNET_ECRS_location_to_uri (baseURI,
86 &pk, 43,
87 (GNUNET_ECRS_SignFunction) &
88 GNUNET_RSA_sign, hk);
89 GNUNET_RSA_free_key (hk);
90 if (uri == NULL)
91 {
92 GNUNET_GE_BREAK (NULL, 0);
93 GNUNET_ECRS_uri_destroy (baseURI);
94 return 1;
95 }
96 if (!GNUNET_ECRS_uri_test_loc (uri))
97 {
98 GNUNET_GE_BREAK (NULL, 0);
99 GNUNET_ECRS_uri_destroy (uri);
100 GNUNET_ECRS_uri_destroy (baseURI);
101 return 1;
102 }
103 uri2 = GNUNET_ECRS_uri_get_content_uri_from_loc (uri);
104 if (!GNUNET_ECRS_uri_test_equal (baseURI, uri2))
105 {
106 GNUNET_GE_BREAK (NULL, 0);
107 GNUNET_ECRS_uri_destroy (uri);
108 GNUNET_ECRS_uri_destroy (uri2);
109 GNUNET_ECRS_uri_destroy (baseURI);
110 return 1;
111 }
112 GNUNET_ECRS_uri_destroy (uri2);
113 GNUNET_ECRS_uri_destroy (baseURI);
114 uric = GNUNET_ECRS_uri_to_string (uri);
115#if 0
116 /* not for the faint of heart: */
117 printf ("URI: `%s'\n", uric);
118#endif
119 uri2 = GNUNET_ECRS_string_to_uri (NULL, uric);
120 GNUNET_free (uric);
121 if (uri2 == NULL)
122 {
123 GNUNET_GE_BREAK (NULL, 0);
124 GNUNET_ECRS_uri_destroy (uri);
125 return 1;
126 }
127 if (GNUNET_YES != GNUNET_ECRS_uri_test_equal (uri, uri2))
128 {
129 GNUNET_GE_BREAK (NULL, 0);
130 GNUNET_ECRS_uri_destroy (uri);
131 GNUNET_ECRS_uri_destroy (uri2);
132 return 1;
133 }
134 GNUNET_ECRS_uri_destroy (uri2);
135 GNUNET_ECRS_uri_destroy (uri);
136 return 0;
137}
138
139static int
140testNamespace (int i)
141{
142 char *uri;
143 struct GNUNET_ECRS_URI *ret;
144
145 if (NULL !=
146 GNUNET_ECRS_string_to_uri (NULL,
147 "gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK"))
148 ABORT ();
149 if (NULL !=
150 GNUNET_ECRS_string_to_uri (NULL,
151 "gnunet://ecrs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3V/test"))
152 ABORT ();
153 if (NULL != GNUNET_ECRS_string_to_uri (NULL, "gnunet://ecrs/sks/test"))
154 ABORT ();
155 ret =
156 GNUNET_ECRS_string_to_uri (NULL,
157 "gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test");
158 if (ret == NULL)
159 ABORT ();
160 if (GNUNET_ECRS_uri_test_ksk (ret))
161 {
162 GNUNET_ECRS_uri_destroy (ret);
163 ABORT ();
164 }
165 if (!GNUNET_ECRS_uri_test_sks (ret))
166 {
167 GNUNET_ECRS_uri_destroy (ret);
168 ABORT ();
169 }
170
171 uri = GNUNET_ECRS_uri_to_string (ret);
172 if (0 != strcmp (uri,
173 "gnunet://ecrs/sks/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820/test"))
174 {
175 GNUNET_ECRS_uri_destroy (ret);
176 GNUNET_free (uri);
177 ABORT ();
178 }
179 GNUNET_free (uri);
180 GNUNET_ECRS_uri_destroy (ret);
181 return 0;
182}
183
184static int
185testFile (int i)
186{
187 char *uri;
188 struct GNUNET_ECRS_URI *ret;
189
190 if (NULL !=
191 GNUNET_ECRS_string_to_uri (NULL,
192 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H00000440000.42"))
193 ABORT ();
194 if (NULL !=
195 GNUNET_ECRS_string_to_uri (NULL,
196 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000"))
197 ABORT ();
198 if (NULL !=
199 GNUNET_ECRS_string_to_uri (NULL,
200 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.FGH"))
201 ABORT ();
202 ret =
203 GNUNET_ECRS_string_to_uri (NULL,
204 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42");
205 if (ret == NULL)
206 ABORT ();
207 if (GNUNET_ECRS_uri_test_ksk (ret))
208 {
209 GNUNET_ECRS_uri_destroy (ret);
210 ABORT ();
211 }
212 if (GNUNET_ECRS_uri_test_sks (ret))
213 {
214 GNUNET_ECRS_uri_destroy (ret);
215 ABORT ();
216 }
217 if (GNUNET_ntohll (ret->data.fi.file_length) != 42)
218 {
219 GNUNET_ECRS_uri_destroy (ret);
220 ABORT ();
221 }
222
223 uri = GNUNET_ECRS_uri_to_string (ret);
224 if (0 != strcmp (uri,
225 "gnunet://ecrs/chk/C282GG70GKK41O4551011DO413KFBVTVMQG1OG30I0K4045N0G41HAPB82G680A02JRVVFO8URVRU2F159011DO41000000022RG820.RNVVVVOOLCLK065B5D04HTNVNSIB2AI022RG8200HSLK1CO1000ATQ98824DMA2032LIMG50CG0K057NVUVG200000H000004400000.42"))
226 {
227 GNUNET_free (uri);
228 GNUNET_ECRS_uri_destroy (ret);
229 ABORT ();
230 }
231 GNUNET_free (uri);
232 GNUNET_ECRS_uri_destroy (ret);
233 return 0;
234}
235
236int
237main (int argc, char *argv[])
238{
239 int failureCount = 0;
240 int i;
241
242 GNUNET_disable_entropy_gathering ();
243 failureCount += testKeyword ();
244 failureCount += testLocation ();
245 for (i = 0; i < 255; i++)
246 {
247 failureCount += testNamespace (i);
248 failureCount += testFile (i);
249 }
250 if (failureCount != 0)
251 return 1;
252 return 0;
253}
254
255/* end of uritest.c */
diff --git a/src/hostlist/hostlist-client.c b/src/hostlist/hostlist-client.c
index bc98a2bcf..468c6b64c 100644
--- a/src/hostlist/hostlist-client.c
+++ b/src/hostlist/hostlist-client.c
@@ -625,11 +625,12 @@ GNUNET_HOSTLIST_client_start (const struct GNUNET_CONFIGURATION_Handle *c,
625 cfg = c; 625 cfg = c;
626 sched = s; 626 sched = s;
627 stats = st; 627 stats = st;
628 proxy = NULL; 628 if (GNUNET_OK !=
629 GNUNET_CONFIGURATION_get_value_string (cfg, 629 GNUNET_CONFIGURATION_get_value_string (cfg,
630 "HOSTLIST", 630 "HOSTLIST",
631 "HTTP-PROXY", 631 "HTTP-PROXY",
632 &proxy); 632 &proxy))
633 proxy = NULL;
633 *ch = &connect_handler; 634 *ch = &connect_handler;
634 *dh = &disconnect_handler; 635 *dh = &disconnect_handler;
635 GNUNET_STATISTICS_get (stats, 636 GNUNET_STATISTICS_get (stats,
diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c
index 34e9310e4..5cc26c409 100644
--- a/src/hostlist/hostlist-server.c
+++ b/src/hostlist/hostlist-server.c
@@ -116,7 +116,10 @@ host_processor (void *cls,
116 size_t s; 116 size_t s;
117 117
118 if (peer == NULL) 118 if (peer == NULL)
119 finish_response (results); 119 {
120 finish_response (results);
121 return;
122 }
120 old = results->size; 123 old = results->size;
121 s = GNUNET_HELLO_size(hello); 124 s = GNUNET_HELLO_size(hello);
122 if (old + s >= GNUNET_MAX_MALLOC_CHECKED) 125 if (old + s >= GNUNET_MAX_MALLOC_CHECKED)
diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h
index abbfe2eec..c5ea21ed8 100644
--- a/src/include/gnunet_configuration_lib.h
+++ b/src/include/gnunet_configuration_lib.h
@@ -47,16 +47,27 @@ struct GNUNET_CONFIGURATION_Handle;
47 47
48/** 48/**
49 * Create a new configuration object. 49 * Create a new configuration object.
50 * 50 * @return fresh configuration object
51 * @param component name of responsible component
52 */ 51 */
53struct GNUNET_CONFIGURATION_Handle *GNUNET_CONFIGURATION_create (void); 52struct GNUNET_CONFIGURATION_Handle *GNUNET_CONFIGURATION_create (void);
54 53
54
55/**
56 * Duplicate an existing configuration object.
57 *
58 * @param c configuration to duplicate
59 * @return duplicate configuration
60 */
61struct GNUNET_CONFIGURATION_Handle *
62GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *c);
63
64
55/** 65/**
56 * Destroy configuration object. 66 * Destroy configuration object.
57 */ 67 */
58void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg); 68void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg);
59 69
70
60/** 71/**
61 * Load configuration. This function will first parse the 72 * Load configuration. This function will first parse the
62 * defaults and then parse the specific configuration file 73 * defaults and then parse the specific configuration file
@@ -68,6 +79,7 @@ void GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg);
68int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, 79int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
69 const char *filename); 80 const char *filename);
70 81
82
71/** 83/**
72 * Parse a configuration file, add all of the options in the 84 * Parse a configuration file, add all of the options in the
73 * file to the configuration environment. 85 * file to the configuration environment.
@@ -76,6 +88,7 @@ int GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
76int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg, 88int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
77 const char *filename); 89 const char *filename);
78 90
91
79/** 92/**
80 * Write configuration file. 93 * Write configuration file.
81 * @return GNUNET_OK on success, GNUNET_SYSERR on error 94 * @return GNUNET_OK on success, GNUNET_SYSERR on error
@@ -83,6 +96,7 @@ int GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
83int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg, 96int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
84 const char *filename); 97 const char *filename);
85 98
99
86/** 100/**
87 * Test if there are configuration options that were 101 * Test if there are configuration options that were
88 * changed since the last save. 102 * changed since the last save.
@@ -90,6 +104,33 @@ int GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
90 */ 104 */
91int GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg); 105int GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg);
92 106
107
108/**
109 * Function to iterate over options.
110 *
111 * @param cls closure
112 * @param section name of the section
113 * @param option name of the option
114 * @param value value of the option
115 */
116typedef void (*GNUNET_CONFIGURATION_Iterator)(void *cls,
117 const char *section,
118 const char *option,
119 const char *value);
120
121
122/**
123 * Iterate over all options in the configuration.
124 *
125 * @param cfg configuration to inspect
126 * @param iter function to call on each option
127 * @param iter_cls closure for iter
128 */
129void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
130 GNUNET_CONFIGURATION_Iterator iter,
131 void *iter_cls);
132
133
93/** 134/**
94 * Get a configuration value that should be a number. 135 * Get a configuration value that should be a number.
95 * @return GNUNET_OK on success, GNUNET_SYSERR on error 136 * @return GNUNET_OK on success, GNUNET_SYSERR on error
@@ -240,6 +281,7 @@ int GNUNET_CONFIGURATION_append_value_filename (struct
240 const char *option, 281 const char *option,
241 const char *value); 282 const char *value);
242 283
284
243#if 0 /* keep Emacsens' auto-indent happy */ 285#if 0 /* keep Emacsens' auto-indent happy */
244{ 286{
245#endif 287#endif
diff --git a/src/include/gnunet_container_lib.h b/src/include/gnunet_container_lib.h
index 255f68a89..c3a9a79ba 100644
--- a/src/include/gnunet_container_lib.h
+++ b/src/include/gnunet_container_lib.h
@@ -189,11 +189,15 @@ struct GNUNET_CONTAINER_MetaData;
189 189
190/** 190/**
191 * Iterator over meta data. 191 * Iterator over meta data.
192 *
193 * @param cls closure
194 * @param type type of the meta data
195 * @param data value of the meta data
192 * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort 196 * @return GNUNET_OK to continue to iterate, GNUNET_SYSERR to abort
193 */ 197 */
194typedef int (*GNUNET_CONTAINER_MetaDataProcessor) (EXTRACTOR_KeywordType type, 198typedef int (*GNUNET_CONTAINER_MetaDataProcessor) (void *cls,
195 const char *data, 199 EXTRACTOR_KeywordType type,
196 void *closure); 200 const char *data);
197 201
198/** 202/**
199 * Create a fresh MetaData token. 203 * Create a fresh MetaData token.
diff --git a/src/include/gnunet_testing_lib.h b/src/include/gnunet_testing_lib.h
index dbd8a3d3f..8de354853 100644
--- a/src/include/gnunet_testing_lib.h
+++ b/src/include/gnunet_testing_lib.h
@@ -85,7 +85,7 @@ typedef void (*GNUNET_TESTING_NotifyDaemonRunning)(void *cls,
85 */ 85 */
86struct GNUNET_TESTING_Daemon * 86struct GNUNET_TESTING_Daemon *
87GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched, 87GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
88 struct GNUNET_CONFIGURATION_Handle *cfg, 88 const struct GNUNET_CONFIGURATION_Handle *cfg,
89 const char *hostname, 89 const char *hostname,
90 GNUNET_TESTING_NotifyDaemonRunning cb, 90 GNUNET_TESTING_NotifyDaemonRunning cb,
91 void *cb_cls); 91 void *cb_cls);
@@ -163,50 +163,17 @@ struct GNUNET_TESTING_PeerGroup;
163 * @param total number of daemons to start 163 * @param total number of daemons to start
164 * @param cb function to call on each daemon that was started 164 * @param cb function to call on each daemon that was started
165 * @param cb_cls closure for cb 165 * @param cb_cls closure for cb
166 * @param hostname where to run the peers; can be NULL (to run 166 * @param hostnames space-separated list of hostnames to use,
167 * everything on localhost). 167 * NULL to use localhost only
168 * @param va Additional hosts can be specified using a NULL-terminated list of
169 * varargs, hosts will then be used round-robin from that
170 * list; va only contains anything if hostname != NULL.
171 * @return NULL on error, otherwise handle to control peer group
172 */
173struct GNUNET_TESTING_PeerGroup *
174GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched,
175 const struct GNUNET_CONFIGURATION_Handle *cfg,
176 unsigned int total,
177 GNUNET_TESTING_NotifyDaemonRunning cb,
178 void *cb_cls,
179 const char *hostname,
180 va_list va);
181
182
183/**
184 * Start count gnunetd processes with the same set of
185 * transports and applications. The port numbers will
186 * be computed by adding delta each time (zero
187 * times for the first peer).
188 *
189 * @param sched scheduler to use
190 * @param cfg configuration template to use
191 * @param total number of daemons to start
192 * @param timeout how long is this allowed to take?
193 * @param cb function to call on each daemon that was started
194 * @param cb_cls closure for cb
195 * @param hostname where to run the peers; can be NULL (to run
196 * everything on localhost). Additional
197 * hosts can be specified using a NULL-terminated list of
198 * varargs, hosts will then be used round-robin from that
199 * list.
200 * @return NULL on error, otherwise handle to control peer group 168 * @return NULL on error, otherwise handle to control peer group
201 */ 169 */
202struct GNUNET_TESTING_PeerGroup * 170struct GNUNET_TESTING_PeerGroup *
203GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, 171GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
204 struct GNUNET_CONFIGURATION_Handle *cfg, 172 const struct GNUNET_CONFIGURATION_Handle *cfg,
205 unsigned int total, 173 unsigned int total,
206 GNUNET_TESTING_NotifyDaemonRunning cb, 174 GNUNET_TESTING_NotifyDaemonRunning cb,
207 void *cb_cls, 175 void *cb_cls,
208 const char *hostname, 176 const char *hostnames);
209 ...);
210 177
211 178
212/** 179/**
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 635570482..9ac831a88 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -15,17 +15,20 @@ libgnunettesting_la_SOURCES = \
15 testing.c \ 15 testing.c \
16 testing_group.c \ 16 testing_group.c \
17 testing_testbed.c 17 testing_testbed.c
18libgnunettesting_la_LIBADD = \ 18libgnunettesting_la_LIBADD = $(XLIB) \
19 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) 19 $(top_builddir)/src/core/libgnunetcore.la \
20 20 $(top_builddir)/src/transport/libgnunettransport.la \
21#check_PROGRAMS = \ 21 $(top_builddir)/src/util/libgnunetutil.la
22# test_testing
23#
24#TESTS = $(check_PROGRAMS)
25#
26#test_testing_SOURCES = \
27# test_testing.c
28#test_testing_LDADD = \
29# $(top_builddir)/src/testing/libgnunettesting.la \
30# $(top_builddir)/src/util/libgnunetutil.la
31 22
23check_PROGRAMS = \
24 test_testing
25
26TESTS = $(check_PROGRAMS)
27
28test_testing_SOURCES = \
29 test_testing.c
30test_testing_LDADD = \
31 $(top_builddir)/src/testing/libgnunettesting.la \
32 $(top_builddir)/src/util/libgnunetutil.la
33
34EXTRA_DIST = test_testing_data.conf
diff --git a/src/testing/test_testing.c b/src/testing/test_testing.c
new file mode 100644
index 000000000..cbedf60fb
--- /dev/null
+++ b/src/testing/test_testing.c
@@ -0,0 +1,116 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file testing/test_testing.c
22 * @brief testcase for testing.c
23 */
24#include "platform.h"
25#include "gnunet_testing_lib.h"
26
27#define VERBOSE GNUNET_YES
28
29static int ok;
30
31static void end_cb(void *cls,
32 const char *emsg)
33{
34 GNUNET_assert (emsg == NULL);
35#if VERBOSE
36 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
37 "Daemon terminated, will now exit.\n");
38#endif
39 ok = 0;
40}
41
42static void my_cb(void *cls,
43 const struct GNUNET_PeerIdentity *id,
44 const struct GNUNET_CONFIGURATION_Handle *cfg,
45 struct GNUNET_TESTING_Daemon *d,
46 const char *emsg)
47{
48 GNUNET_assert (id != NULL);
49#if VERBOSE
50 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
51 "Daemon started, will now stop it.\n");
52#endif
53 GNUNET_TESTING_daemon_stop (d, &end_cb, NULL);
54}
55
56
57static void
58run (void *cls,
59 struct GNUNET_SCHEDULER_Handle *sched,
60 char *const *args,
61 const char *cfgfile,
62 const struct GNUNET_CONFIGURATION_Handle *cfg)
63{
64 struct GNUNET_TESTING_Daemon *d;
65
66 ok = 1;
67#if VERBOSE
68 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
69 "Starting daemon.\n");
70#endif
71 d = GNUNET_TESTING_daemon_start (sched,
72 cfg,
73 NULL,
74 &my_cb,
75 NULL);
76 GNUNET_assert (d != NULL);
77}
78
79static int
80check ()
81{
82 char *const argv[] = { "test-testing",
83 "-c",
84 "test_testing_data.conf",
85#if VERBOSE
86 "-L", "DEBUG",
87#endif
88 NULL
89 };
90 struct GNUNET_GETOPT_CommandLineOption options[] = {
91 GNUNET_GETOPT_OPTION_END
92 };
93 GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
94 argv, "test-tesing", "nohelp",
95 options, &run, &ok);
96 return ok;
97}
98
99int
100main (int argc, char *argv[])
101{
102 int ret;
103
104 GNUNET_log_setup ("test-testing",
105#if VERBOSE
106 "DEBUG",
107#else
108 "WARNING",
109#endif
110 NULL);
111 ret = check ();
112
113 return ret;
114}
115
116/* end of test_testing.c */
diff --git a/src/testing/test_testing_data.conf b/src/testing/test_testing_data.conf
new file mode 100644
index 000000000..7c46fdf34
--- /dev/null
+++ b/src/testing/test_testing_data.conf
@@ -0,0 +1,29 @@
1[PATHS]
2SERVICEHOME = /tmp/test-gnunet-testing/
3DEFAULTCONFIG = test_testing_data.conf
4
5[resolver]
6PORT = 2564
7
8[transport]
9PORT = 2565
10PLUGINS = tcp
11
12[arm]
13PORT = 2566
14DEFAULTSERVICES = transport core
15
16[statistics]
17PORT = 2567
18
19[tcp]
20PORT = 2568
21
22[peerinfo]
23PORT = 2569
24
25[core]
26PORT = 2570
27
28[testing]
29WEAKRANDOM = YES
diff --git a/src/testing/testing.c b/src/testing/testing.c
index 3406355c5..5d465e05f 100644
--- a/src/testing/testing.c
+++ b/src/testing/testing.c
@@ -85,7 +85,7 @@ struct GNUNET_TESTING_Daemon
85 /** 85 /**
86 * Our configuration. 86 * Our configuration.
87 */ 87 */
88 const struct GNUNET_CONFIGURATION_Handle *cfg; 88 struct GNUNET_CONFIGURATION_Handle *cfg;
89 89
90 /** 90 /**
91 * Host to run GNUnet on. 91 * Host to run GNUnet on.
@@ -202,10 +202,11 @@ testing_init (void *cls,
202 d->cb = NULL; 202 d->cb = NULL;
203 if (server == NULL) 203 if (server == NULL)
204 { 204 {
205 cb (d->cb_cls, NULL, d->cfg, d,
206 _("Failed to connect to core service\n"));
207 if (GNUNET_YES == d->dead) 205 if (GNUNET_YES == d->dead)
208 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls); 206 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
207 else if (NULL != cb)
208 cb (d->cb_cls, NULL, d->cfg, d,
209 _("Failed to connect to core service\n"));
209 return; 210 return;
210 } 211 }
211#if DEBUG_TESTING 212#if DEBUG_TESTING
@@ -216,7 +217,7 @@ testing_init (void *cls,
216 d->id = *my_identity; 217 d->id = *my_identity;
217 if (GNUNET_YES == d->dead) 218 if (GNUNET_YES == d->dead)
218 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls); 219 GNUNET_TESTING_daemon_stop (d, d->dead_cb, d->dead_cb_cls);
219 else 220 else if (NULL != cb)
220 cb (d->cb_cls, my_identity, d->cfg, d, NULL); 221 cb (d->cb_cls, my_identity, d->cfg, d, NULL);
221 d->server = server; 222 d->server = server;
222} 223}
@@ -240,6 +241,11 @@ start_fsm (void *cls,
240 unsigned long code; 241 unsigned long code;
241 char *dst; 242 char *dst;
242 243
244#if DEBUG_TESTING
245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
246 "Peer FSM is in phase %u.\n",
247 d->phase);
248#endif
243 d->task = GNUNET_SCHEDULER_NO_TASK; 249 d->task = GNUNET_SCHEDULER_NO_TASK;
244 switch (d->phase) 250 switch (d->phase)
245 { 251 {
@@ -255,11 +261,12 @@ start_fsm (void *cls,
255 { 261 {
256 cb = d->cb; 262 cb = d->cb;
257 d->cb = NULL; 263 d->cb = NULL;
258 cb (d->cb_cls, 264 if (NULL != cb)
259 NULL, 265 cb (d->cb_cls,
260 d->cfg, 266 NULL,
261 d, 267 d->cfg,
262 _("`scp' does not seem to terminate.\n")); 268 d,
269 _("`scp' does not seem to terminate.\n"));
263 return; 270 return;
264 } 271 }
265 /* wait some more */ 272 /* wait some more */
@@ -278,11 +285,12 @@ start_fsm (void *cls,
278 { 285 {
279 cb = d->cb; 286 cb = d->cb;
280 d->cb = NULL; 287 d->cb = NULL;
281 cb (d->cb_cls, 288 if (NULL != cb)
282 NULL, 289 cb (d->cb_cls,
283 d->cfg, 290 NULL,
284 d, 291 d->cfg,
285 _("`scp' did not complete cleanly.\n")); 292 d,
293 _("`scp' did not complete cleanly.\n"));
286 return; 294 return;
287 } 295 }
288#if DEBUG_TESTING 296#if DEBUG_TESTING
@@ -299,7 +307,11 @@ start_fsm (void *cls,
299 "gnunet-service-arm", 307 "gnunet-service-arm",
300 "-c", 308 "-c",
301 d->cfgfile, 309 d->cfgfile,
310#if DEBUG_TESTING
311 "-L", "DEBUG",
312#else
302 "-d", 313 "-d",
314#endif
303 NULL); 315 NULL);
304 } 316 }
305 else 317 else
@@ -328,16 +340,31 @@ start_fsm (void *cls,
328 (NULL == d->hostname) ? "gnunet-service-arm" : "ssh"); 340 (NULL == d->hostname) ? "gnunet-service-arm" : "ssh");
329 cb = d->cb; 341 cb = d->cb;
330 d->cb = NULL; 342 d->cb = NULL;
331 cb (d->cb_cls, 343 if (NULL != cb)
332 NULL, 344 cb (d->cb_cls,
333 d->cfg, 345 NULL,
334 d, 346 d->cfg,
335 (NULL == d->hostname) 347 d,
336 ? _("Failed to start `gnunet-service-arm' process.\n") 348 (NULL == d->hostname)
337 : _("Failed to start `ssh' process.\n")); 349 ? _("Failed to start `gnunet-service-arm' process.\n")
350 : _("Failed to start `ssh' process.\n"));
338 } 351 }
352#if DEBUG_TESTING
353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
354 "Started `%s', waiting for `%s' to be up.\n",
355 "gnunet-service-arm",
356 "gnunet-service-core");
357#endif
339 d->phase = SP_START_ARMING; 358 d->phase = SP_START_ARMING;
340 d->wait_runs = 0; 359 d->wait_runs = 0;
360 d->task
361 = GNUNET_SCHEDULER_add_delayed (d->sched,
362 GNUNET_NO,
363 GNUNET_SCHEDULER_PRIORITY_KEEP,
364 GNUNET_SCHEDULER_NO_TASK,
365 GNUNET_CONSTANTS_EXEC_WAIT,
366 &start_fsm,
367 d);
341 break; 368 break;
342 case SP_START_ARMING: 369 case SP_START_ARMING:
343 if (GNUNET_OK != 370 if (GNUNET_OK !=
@@ -350,13 +377,14 @@ start_fsm (void *cls,
350 { 377 {
351 cb = d->cb; 378 cb = d->cb;
352 d->cb = NULL; 379 d->cb = NULL;
353 cb (d->cb_cls, 380 if (NULL != cb)
354 NULL, 381 cb (d->cb_cls,
355 d->cfg, 382 NULL,
356 d, 383 d->cfg,
357 (NULL == d->hostname) 384 d,
358 ? _("`gnunet-service-arm' does not seem to terminate.\n") 385 (NULL == d->hostname)
359 : _("`ssh' does not seem to terminate.\n")); 386 ? _("`gnunet-service-arm' does not seem to terminate.\n")
387 : _("`ssh' does not seem to terminate.\n"));
360 return; 388 return;
361 } 389 }
362 /* wait some more */ 390 /* wait some more */
@@ -424,18 +452,24 @@ start_fsm (void *cls,
424 if ( (type != GNUNET_OS_PROCESS_EXITED) || 452 if ( (type != GNUNET_OS_PROCESS_EXITED) ||
425 (code != 0) ) 453 (code != 0) )
426 { 454 {
427 d->dead_cb (d->dead_cb_cls, 455 if (NULL != d->dead_cb)
428 _("`sshp' did not complete cleanly.\n")); 456 d->dead_cb (d->dead_cb_cls,
457 _("`ssh' did not complete cleanly.\n"));
429 GNUNET_free (d->cfgfile); 458 GNUNET_free (d->cfgfile);
430 GNUNET_free_non_null (d->hostname); 459 GNUNET_free_non_null (d->hostname);
431 GNUNET_free_non_null (d->username); 460 GNUNET_free_non_null (d->username);
432 GNUNET_free (d); 461 GNUNET_free (d);
433 return; 462 return;
434 } 463 }
464#if DEBUG_TESTING
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466 "Peer shutdown complete.\n");
467#endif
435 GNUNET_free (d->cfgfile); 468 GNUNET_free (d->cfgfile);
436 GNUNET_free_non_null (d->hostname); 469 GNUNET_free_non_null (d->hostname);
437 GNUNET_free_non_null (d->username); 470 GNUNET_free_non_null (d->username);
438 d->dead_cb (d->dead_cb_cls, NULL); 471 if (NULL != d->dead_cb)
472 d->dead_cb (d->dead_cb_cls, NULL);
439 GNUNET_free (d); 473 GNUNET_free (d);
440 break; 474 break;
441 case SP_CONFIG_UPDATE: 475 case SP_CONFIG_UPDATE:
@@ -450,11 +484,12 @@ start_fsm (void *cls,
450 { 484 {
451 cb = d->cb; 485 cb = d->cb;
452 d->cb = NULL; 486 d->cb = NULL;
453 cb (d->cb_cls, 487 if (NULL != cb)
454 NULL, 488 cb (d->cb_cls,
455 d->cfg, 489 NULL,
456 d, 490 d->cfg,
457 _("`scp' does not seem to terminate.\n")); 491 d,
492 _("`scp' does not seem to terminate.\n"));
458 return; 493 return;
459 } 494 }
460 /* wait some more */ 495 /* wait some more */
@@ -471,15 +506,17 @@ start_fsm (void *cls,
471 if ( (type != GNUNET_OS_PROCESS_EXITED) || 506 if ( (type != GNUNET_OS_PROCESS_EXITED) ||
472 (code != 0) ) 507 (code != 0) )
473 { 508 {
474 d->update_cb (d->update_cb_cls, 509 if (NULL != d->update_cb)
475 _("`scp' did not complete cleanly.\n")); 510 d->update_cb (d->update_cb_cls,
511 _("`scp' did not complete cleanly.\n"));
476 return; 512 return;
477 } 513 }
478#if DEBUG_TESTING 514#if DEBUG_TESTING
479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
480 "Successfully copied configuration file.\n"); 516 "Successfully copied configuration file.\n");
481#endif 517#endif
482 d->update_cb (d->update_cb_cls, NULL); 518 if (NULL != d->update_cb)
519 d->update_cb (d->update_cb_cls, NULL);
483 d->phase = SP_START_DONE; 520 d->phase = SP_START_DONE;
484 break; 521 break;
485 } 522 }
@@ -502,7 +539,7 @@ start_fsm (void *cls,
502 */ 539 */
503struct GNUNET_TESTING_Daemon * 540struct GNUNET_TESTING_Daemon *
504GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched, 541GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
505 struct GNUNET_CONFIGURATION_Handle *cfg, 542 const struct GNUNET_CONFIGURATION_Handle *cfg,
506 const char *hostname, 543 const char *hostname,
507 GNUNET_TESTING_NotifyDaemonRunning cb, 544 GNUNET_TESTING_NotifyDaemonRunning cb,
508 void *cb_cls) 545 void *cb_cls)
@@ -513,9 +550,13 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
513 550
514 ret = GNUNET_malloc (sizeof(struct GNUNET_TESTING_Daemon)); 551 ret = GNUNET_malloc (sizeof(struct GNUNET_TESTING_Daemon));
515 ret->sched = sched; 552 ret->sched = sched;
516 ret->cfg = cfg;
517 ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname); 553 ret->hostname = (hostname == NULL) ? NULL : GNUNET_strdup (hostname);
518 ret->cfgfile = GNUNET_DISK_mktemp ("gnunet-testing-config"); 554 ret->cfgfile = GNUNET_DISK_mktemp ("gnunet-testing-config");
555#if DEBUG_TESTING
556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557 "Setting up peer with configuration file `%s'.\n",
558 ret->cfgfile);
559#endif
519 if (NULL == ret->cfgfile) 560 if (NULL == ret->cfgfile)
520 { 561 {
521 GNUNET_free_non_null (ret->hostname); 562 GNUNET_free_non_null (ret->hostname);
@@ -524,15 +565,21 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
524 } 565 }
525 ret->cb = cb; 566 ret->cb = cb;
526 ret->cb_cls = cb_cls; 567 ret->cb_cls = cb_cls;
568 ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
569 GNUNET_CONFIGURATION_set_value_string (ret->cfg,
570 "PATHS",
571 "DEFAULTCONFIG",
572 ret->cfgfile);
527 /* 1) write configuration to temporary file */ 573 /* 1) write configuration to temporary file */
528 if (GNUNET_OK != 574 if (GNUNET_OK !=
529 GNUNET_CONFIGURATION_write (cfg, 575 GNUNET_CONFIGURATION_write (ret->cfg,
530 ret->cfgfile)) 576 ret->cfgfile))
531 { 577 {
532 if (0 != UNLINK (ret->cfgfile)) 578 if (0 != UNLINK (ret->cfgfile))
533 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 579 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
534 "unlink", 580 "unlink",
535 ret->cfgfile); 581 ret->cfgfile);
582 GNUNET_CONFIGURATION_destroy (ret->cfg);
536 GNUNET_free_non_null (ret->hostname); 583 GNUNET_free_non_null (ret->hostname);
537 GNUNET_free (ret->cfgfile); 584 GNUNET_free (ret->cfgfile);
538 GNUNET_free (ret); 585 GNUNET_free (ret);
@@ -581,6 +628,7 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
581 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 628 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
582 "unlink", 629 "unlink",
583 ret->cfgfile); 630 ret->cfgfile);
631 GNUNET_CONFIGURATION_destroy (ret->cfg);
584 GNUNET_free_non_null (ret->hostname); 632 GNUNET_free_non_null (ret->hostname);
585 GNUNET_free_non_null (ret->username); 633 GNUNET_free_non_null (ret->username);
586 GNUNET_free (ret->cfgfile); 634 GNUNET_free (ret->cfgfile);
@@ -589,7 +637,7 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
589 } 637 }
590 ret->task 638 ret->task
591 = GNUNET_SCHEDULER_add_delayed (sched, 639 = GNUNET_SCHEDULER_add_delayed (sched,
592 GNUNET_NO, 640 GNUNET_YES,
593 GNUNET_SCHEDULER_PRIORITY_KEEP, 641 GNUNET_SCHEDULER_PRIORITY_KEEP,
594 GNUNET_SCHEDULER_NO_TASK, 642 GNUNET_SCHEDULER_NO_TASK,
595 GNUNET_CONSTANTS_EXEC_WAIT, 643 GNUNET_CONSTANTS_EXEC_WAIT,
@@ -597,6 +645,10 @@ GNUNET_TESTING_daemon_start (struct GNUNET_SCHEDULER_Handle *sched,
597 ret); 645 ret);
598 return ret; 646 return ret;
599 } 647 }
648#if DEBUG_TESTING
649 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650 "No need to copy configuration file since we are running locally.\n");
651#endif
600 ret->phase = SP_COPIED; 652 ret->phase = SP_COPIED;
601 GNUNET_SCHEDULER_add_continuation (sched, 653 GNUNET_SCHEDULER_add_continuation (sched,
602 GNUNET_NO, 654 GNUNET_NO,
@@ -687,7 +739,7 @@ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
687 d->dead_cb_cls = cb_cls; 739 d->dead_cb_cls = cb_cls;
688 d->task 740 d->task
689 = GNUNET_SCHEDULER_add_delayed (d->sched, 741 = GNUNET_SCHEDULER_add_delayed (d->sched,
690 GNUNET_NO, 742 GNUNET_YES,
691 GNUNET_SCHEDULER_PRIORITY_KEEP, 743 GNUNET_SCHEDULER_PRIORITY_KEEP,
692 GNUNET_SCHEDULER_NO_TASK, 744 GNUNET_SCHEDULER_NO_TASK,
693 GNUNET_CONSTANTS_EXEC_WAIT, 745 GNUNET_CONSTANTS_EXEC_WAIT,
@@ -695,11 +747,13 @@ void GNUNET_TESTING_daemon_stop (struct GNUNET_TESTING_Daemon *d,
695 d); 747 d);
696 return; 748 return;
697 } 749 }
750 GNUNET_CONFIGURATION_destroy (d->cfg);
698 GNUNET_free (d->cfgfile); 751 GNUNET_free (d->cfgfile);
699 GNUNET_free_non_null (d->hostname); 752 GNUNET_free_non_null (d->hostname);
700 GNUNET_free_non_null (d->username); 753 GNUNET_free_non_null (d->username);
701 GNUNET_free (d); 754 GNUNET_free (d);
702 cb (cb_cls, NULL); 755 if (NULL != cb)
756 cb (cb_cls, NULL);
703} 757}
704 758
705 759
@@ -720,8 +774,9 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
720 774
721 if (d->phase != SP_START_DONE) 775 if (d->phase != SP_START_DONE)
722 { 776 {
723 cb (cb_cls, 777 if (NULL != cb)
724 _("Peer not yet running, can not change configuration at this point.")); 778 cb (cb_cls,
779 _("Peer not yet running, can not change configuration at this point."));
725 return; 780 return;
726 } 781 }
727 782
@@ -730,7 +785,8 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
730 GNUNET_CONFIGURATION_write (cfg, 785 GNUNET_CONFIGURATION_write (cfg,
731 d->cfgfile)) 786 d->cfgfile))
732 { 787 {
733 cb (cb_cls, 788 if (NULL != cb)
789 cb (cb_cls,
734 _("Failed to write new configuration to disk.")); 790 _("Failed to write new configuration to disk."));
735 return; 791 return;
736 } 792 }
@@ -739,7 +795,8 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
739 if (NULL == d->hostname) 795 if (NULL == d->hostname)
740 { 796 {
741 /* signal success */ 797 /* signal success */
742 cb (cb_cls, NULL); 798 if (NULL != cb)
799 cb (cb_cls, NULL);
743 return; 800 return;
744 } 801 }
745 d->phase = SP_CONFIG_UPDATE; 802 d->phase = SP_CONFIG_UPDATE;
@@ -765,8 +822,9 @@ void GNUNET_TESTING_daemon_reconfigure (struct GNUNET_TESTING_Daemon *d,
765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 822 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
766 _("Could not start `%s' process to copy configuration file.\n"), 823 _("Could not start `%s' process to copy configuration file.\n"),
767 "scp"); 824 "scp");
768 cb (cb_cls, 825 if (NULL != cb)
769 _("Failed to copy new configuration to remote machine.")); 826 cb (cb_cls,
827 _("Failed to copy new configuration to remote machine."));
770 d->phase = SP_START_DONE; 828 d->phase = SP_START_DONE;
771 return; 829 return;
772 } 830 }
@@ -802,10 +860,14 @@ static size_t
802transmit_ready (void *cls, size_t size, void *buf) 860transmit_ready (void *cls, size_t size, void *buf)
803{ 861{
804 struct ConnectContext *ctx = cls; 862 struct ConnectContext *ctx = cls;
805 if (buf == NULL) 863
806 ctx->cb (ctx->cb_cls, _("Peers failed to connect")); 864 if (NULL != ctx->cb)
807 else 865 {
808 ctx->cb (ctx->cb_cls, NULL); 866 if (buf == NULL)
867 ctx->cb (ctx->cb_cls, _("Peers failed to connect"));
868 else
869 ctx->cb (ctx->cb_cls, NULL);
870 }
809 GNUNET_free (ctx); 871 GNUNET_free (ctx);
810 return 0; 872 return 0;
811} 873}
@@ -831,8 +893,9 @@ process_hello (void *cls,
831 if (peer == NULL) 893 if (peer == NULL)
832 { 894 {
833 /* signal error */ 895 /* signal error */
834 ctx->cb (ctx->cb_cls, 896 if (NULL != ctx->cb)
835 _("Failed to receive `HELLO' from peer\n")); 897 ctx->cb (ctx->cb_cls,
898 _("Failed to receive `HELLO' from peer\n"));
836 GNUNET_TRANSPORT_disconnect (ctx->d1th); 899 GNUNET_TRANSPORT_disconnect (ctx->d1th);
837 GNUNET_TRANSPORT_disconnect (ctx->d2th); 900 GNUNET_TRANSPORT_disconnect (ctx->d2th);
838 GNUNET_free (ctx); 901 GNUNET_free (ctx);
@@ -873,7 +936,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
873 if ( (d1->server == NULL) || 936 if ( (d1->server == NULL) ||
874 (d2->server == NULL) ) 937 (d2->server == NULL) )
875 { 938 {
876 cb (cb_cls, _("Peers are not fully running yet, can not connect!\n")); 939 if (NULL != cb)
940 cb (cb_cls, _("Peers are not fully running yet, can not connect!\n"));
877 return; 941 return;
878 } 942 }
879 ctx = GNUNET_malloc (sizeof(struct ConnectContext)); 943 ctx = GNUNET_malloc (sizeof(struct ConnectContext));
@@ -886,7 +950,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
886 if (ctx->d1th == NULL) 950 if (ctx->d1th == NULL)
887 { 951 {
888 GNUNET_free (ctx); 952 GNUNET_free (ctx);
889 cb (cb_cls, _("Failed to connect to transport service!\n")); 953 if (NULL != cb)
954 cb (cb_cls, _("Failed to connect to transport service!\n"));
890 return; 955 return;
891 } 956 }
892 ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched, d2->cfg, d2, NULL, NULL, NULL); 957 ctx->d2th = GNUNET_TRANSPORT_connect (d2->sched, d2->cfg, d2, NULL, NULL, NULL);
@@ -894,7 +959,8 @@ void GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1,
894 { 959 {
895 GNUNET_TRANSPORT_disconnect (ctx->d1th); 960 GNUNET_TRANSPORT_disconnect (ctx->d1th);
896 GNUNET_free (ctx); 961 GNUNET_free (ctx);
897 cb (cb_cls, _("Failed to connect to transport service!\n")); 962 if (NULL != cb)
963 cb (cb_cls, _("Failed to connect to transport service!\n"));
898 return; 964 return;
899 } 965 }
900 GNUNET_TRANSPORT_get_hello (ctx->d1th, 966 GNUNET_TRANSPORT_get_hello (ctx->d1th,
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c
index 917a524de..b87507364 100644
--- a/src/testing/testing_group.c
+++ b/src/testing/testing_group.c
@@ -27,6 +27,58 @@
27#include "gnunet_arm_service.h" 27#include "gnunet_arm_service.h"
28#include "gnunet_testing_lib.h" 28#include "gnunet_testing_lib.h"
29 29
30/**
31 * Lowest port used for GNUnet testing. Should be high enough to not
32 * conflict with other applications running on the hosts but be low
33 * enough to not conflict with client-ports (typically starting around
34 * 32k).
35 */
36#define LOW_PORT 10000
37
38/**
39 * Highest port used for GNUnet testing. Should be low enough to not
40 * conflict with the port range for "local" ports (client apps; see
41 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
42 */
43#define HIGH_PORT 32000
44
45/**
46 * Data we keep per peer.
47 */
48struct PeerData
49{
50 /**
51 * (Initial) configuration of the host.
52 * (initial because clients could change
53 * it and we would not know about those
54 * updates).
55 */
56 struct GNUNET_CONFIGURATION_Handle *cfg;
57
58 /**
59 * Handle for controlling the daemon.
60 */
61 struct GNUNET_TESTING_Daemon *daemon;
62};
63
64
65/**
66 * Data we keep per host.
67 */
68struct HostData
69{
70 /**
71 * Name of the host.
72 */
73 char *hostname;
74
75 /**
76 * Lowest port that we have not yet used
77 * for GNUnet.
78 */
79 uint16_t minport;
80};
81
30 82
31/** 83/**
32 * Handle to a group of GNUnet peers. 84 * Handle to a group of GNUnet peers.
@@ -41,7 +93,7 @@ struct GNUNET_TESTING_PeerGroup
41 /** 93 /**
42 * Configuration template. 94 * Configuration template.
43 */ 95 */
44 struct GNUNET_CONFIGURATION_Handle *cfg; 96 const struct GNUNET_CONFIGURATION_Handle *cfg;
45 97
46 /** 98 /**
47 * Function to call on each started daemon. 99 * Function to call on each started daemon.
@@ -54,14 +106,15 @@ struct GNUNET_TESTING_PeerGroup
54 void *cb_cls; 106 void *cb_cls;
55 107
56 /** 108 /**
57 * NULL-terminated array of hostnames. 109 * NULL-terminated array of information about
110 * hosts.
58 */ 111 */
59 char **hostnames; 112 struct HostData *hosts;
60 113
61 /** 114 /**
62 * Array of "total" peers. 115 * Array of "total" peers.
63 */ 116 */
64 struct GNUNET_TESTING_Daemon **peers; 117 struct PeerData *peers;
65 118
66 /** 119 /**
67 * Number of peers in this group. 120 * Number of peers in this group.
@@ -71,79 +124,212 @@ struct GNUNET_TESTING_PeerGroup
71}; 124};
72 125
73 126
127struct UpdateContext
128{
129 struct GNUNET_CONFIGURATION_Handle *ret;
130 unsigned int nport;
131};
132
74/** 133/**
75 * Start count gnunetd processes with the same set of transports and 134 * Function to iterate over options. Copies
76 * applications. The port numbers (any option called "PORT") will be 135 * the options to the target configuration,
77 * adjusted to ensure that no two peers running on the same system 136 * updating PORT values as needed.
78 * have the same port(s) in their respective configurations.
79 * 137 *
80 * @param sched scheduler to use 138 * @param cls closure
81 * @param cfg configuration template to use 139 * @param section name of the section
82 * @param total number of daemons to start 140 * @param option name of the option
83 * @param cb function to call on each daemon that was started 141 * @param value value of the option
84 * @param cb_cls closure for cb
85 * @param hostname where to run the peers; can be NULL (to run
86 * everything on localhost).
87 * @param va Additional hosts can be specified using a NULL-terminated list of
88 * varargs, hosts will then be used round-robin from that
89 * list; va only contains anything if hostname != NULL.
90 * @return NULL on error, otherwise handle to control peer group
91 */ 142 */
92struct GNUNET_TESTING_PeerGroup * 143static void
93GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched, 144update_config(void *cls,
94 const struct GNUNET_CONFIGURATION_Handle *cfg, 145 const char *section,
95 unsigned int total, 146 const char *option,
96 GNUNET_TESTING_NotifyDaemonRunning cb, 147 const char *value)
97 void *cb_cls,
98 const char *hostname,
99 va_list va)
100{ 148{
101 struct GNUNET_TESTING_PeerGroup *pg; 149 struct UpdateContext *ctx = cls;
102 150 unsigned int ival;
103 pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup)); 151 char cval[12];
104 return pg; 152
153 if ( (0 == strcmp (option, "PORT")) &&
154 (1 == sscanf (value, "%u", &ival)) )
155 {
156 GNUNET_snprintf (cval,
157 sizeof(cval),
158 "%u",
159 ctx->nport++);
160 value = cval;
161 }
162 GNUNET_CONFIGURATION_set_value_string (ctx->ret,
163 section,
164 option,
165 value);
105} 166}
106 167
107 168
108/** 169/**
109 * Start count gnunetd processes with the same set of 170 * Create a new configuration using the given configuration
110 * transports and applications. The port numbers will 171 * as a template; however, each PORT in the existing cfg
111 * be computed by adding delta each time (zero 172 * must be renumbered by incrementing "*port". If we run
112 * times for the first peer). 173 * out of "*port" numbers, return NULL.
174 *
175 * @param cfg template configuration
176 * @param port port numbers to use, update to reflect
177 * port numbers that were used
178 * @return new configuration, NULL on error
179 */
180static struct GNUNET_CONFIGURATION_Handle*
181make_config (const struct GNUNET_CONFIGURATION_Handle*cfg,
182 uint16_t *port)
183{
184 struct UpdateContext uc;
185 uint16_t orig;
186
187 orig = *port;
188 uc.nport = *port;
189 uc.ret = GNUNET_CONFIGURATION_create ();
190 GNUNET_CONFIGURATION_iterate (cfg,
191 &update_config,
192 &uc);
193 if (uc.nport >= HIGH_PORT)
194 {
195 *port = orig;
196 GNUNET_CONFIGURATION_destroy (uc.ret);
197 return NULL;
198 }
199 *port = (uint16_t) uc.nport;
200 return uc.ret;
201}
202
203
204/**
205 * Start count gnunetd processes with the same set of transports and
206 * applications. The port numbers (any option called "PORT") will be
207 * adjusted to ensure that no two peers running on the same system
208 * have the same port(s) in their respective configurations.
113 * 209 *
114 * @param sched scheduler to use 210 * @param sched scheduler to use
115 * @param cfg configuration template to use 211 * @param cfg configuration template to use
116 * @param total number of daemons to start 212 * @param total number of daemons to start
117 * @param timeout how long is this allowed to take?
118 * @param cb function to call on each daemon that was started 213 * @param cb function to call on each daemon that was started
119 * @param cb_cls closure for cb 214 * @param cb_cls closure for cb
120 * @param hostname where to run the peers; can be NULL (to run 215 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
121 * everything on localhost). Additional 216 * everything on localhost).
122 * hosts can be specified using a NULL-terminated list of
123 * varargs, hosts will then be used round-robin from that
124 * list.
125 * @return NULL on error, otherwise handle to control peer group 217 * @return NULL on error, otherwise handle to control peer group
126 */ 218 */
127struct GNUNET_TESTING_PeerGroup * 219struct GNUNET_TESTING_PeerGroup *
128GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, 220GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
129 struct GNUNET_CONFIGURATION_Handle *cfg, 221 const struct GNUNET_CONFIGURATION_Handle *cfg,
130 unsigned int total, 222 unsigned int total,
131 GNUNET_TESTING_NotifyDaemonRunning cb, 223 GNUNET_TESTING_NotifyDaemonRunning cb,
132 void *cb_cls, 224 void *cb_cls,
133 const char *hostname, 225 const char *hostnames)
134 ...)
135{ 226{
136 struct GNUNET_TESTING_PeerGroup * ret; 227 struct GNUNET_TESTING_PeerGroup *pg;
137 va_list va; 228 const char *rpos;
138 229 char *pos;
139 va_start (va, hostname); 230 char *start;
140 ret = GNUNET_TESTING_daemons_start_va (sched, cfg, 231 const char *hostname;
141 total, cb, cb_cls, hostname, 232 struct GNUNET_CONFIGURATION_Handle *pcfg;
142 va); 233 unsigned int off;
143 va_end (va); 234 unsigned int hostcnt;
144 return ret; 235 uint16_t minport;
145}
146 236
237 if (0 == total)
238 {
239 GNUNET_break (0);
240 return NULL;
241 }
242 pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
243 pg->sched = sched;
244 pg->cfg = cfg;
245 pg->cb = cb;
246 pg->cb_cls = cb_cls;
247 pg->total = total;
248 pg->peers = GNUNET_malloc (total * sizeof(struct PeerData));
249 if (NULL != hostnames)
250 {
251 off = 2;
252 /* skip leading spaces */
253 while ( (0 != *hostnames) &&
254 (isspace(*hostnames)))
255 hostnames++;
256 rpos = hostnames;
257 while ('\0' != *rpos)
258 {
259 if (isspace (*rpos))
260 off++;
261 rpos++;
262 }
263 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
264 off = 0;
265 start = GNUNET_strdup (hostnames);
266 pos = start;
267 while ('\0' != *pos)
268 {
269 if (isspace (*pos))
270 {
271 *pos = '\0';
272 if (strlen(start) > 0)
273 {
274 pg->hosts[off].minport = LOW_PORT;
275 pg->hosts[off++].hostname = start;
276 }
277 start = pos+1;
278 }
279 pos++;
280 }
281 if (strlen(start) > 0)
282 {
283 pg->hosts[off].minport = LOW_PORT;
284 pg->hosts[off++].hostname = start;
285 }
286 if (off == 0)
287 {
288 GNUNET_free (start);
289 GNUNET_free (pg->hosts);
290 pg->hosts = NULL;
291 }
292 hostcnt = off;
293 minport = 0; /* make gcc happy */
294 }
295 else
296 {
297 hostcnt = 0;
298 minport = LOW_PORT;
299 }
300 for (off = 0; off < total; off++)
301 {
302 if (hostcnt > 0)
303 {
304 hostname = pg->hosts[off % hostcnt].hostname;
305 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
306 }
307 else
308 {
309 hostname = NULL;
310 pcfg = make_config (cfg, &minport);
311 }
312 if (NULL == pcfg)
313 {
314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315 _("Could not create configuration for peer number %u on `%s'!\n"),
316 off,
317 hostname == NULL ? "localhost" : hostname);
318 continue;
319 }
320 pg->peers[off].cfg = pcfg;
321 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
322 pcfg,
323 hostname,
324 cb,
325 cb_cls);
326 if (NULL == pg->peers[off].daemon)
327 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
328 _("Could not start peer number %u!\n"),
329 off);
330 }
331 return pg;
332}
147 333
148 334
149/** 335/**
@@ -154,7 +340,26 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
154void 340void
155GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg) 341GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
156{ 342{
157 343 unsigned int off;
344
345 for (off = 0; off < pg->total; off++)
346 {
347 /* FIXME: should we wait for our
348 continuations to be called here? This
349 would require us to take a continuation
350 as well... */
351 if (NULL != pg->peers[off].daemon)
352 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon,
353 NULL, NULL);
354 if (NULL != pg->peers[off].cfg)
355 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
356 }
357 GNUNET_free (pg->peers);
358 if (NULL != pg->hosts)
359 {
360 GNUNET_free (pg->hosts[0].hostname);
361 GNUNET_free (pg->hosts);
362 }
158 GNUNET_free (pg); 363 GNUNET_free (pg);
159} 364}
160 365
diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c
index a67023542..12171139e 100644
--- a/src/topology/gnunet-daemon-topology.c
+++ b/src/topology/gnunet-daemon-topology.c
@@ -508,7 +508,7 @@ consider_for_advertising (const struct GNUNET_HELLO_Message *hello)
508 &have_address); 508 &have_address);
509 if (GNUNET_NO == have_address) 509 if (GNUNET_NO == have_address)
510 return; /* no point in advertising this one... */ 510 return; /* no point in advertising this one... */
511 GNUNET_HELLO_get_id (hello, &pid); 511 GNUNET_break (GNUNET_OK == GNUNET_HELLO_get_id (hello, &pid));
512 pos = hellos; 512 pos = hellos;
513 while (pos != NULL) 513 while (pos != NULL)
514 { 514 {
@@ -736,11 +736,18 @@ read_friends_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
736 unsigned int entries_found; 736 unsigned int entries_found;
737 struct PeerList *fl; 737 struct PeerList *fl;
738 738
739 fn = NULL; 739 if (GNUNET_OK !=
740 GNUNET_CONFIGURATION_get_value_filename (cfg, 740 GNUNET_CONFIGURATION_get_value_filename (cfg,
741 "TOPOLOGY", 741 "TOPOLOGY",
742 "FRIENDS", 742 "FRIENDS",
743 &fn); 743 &fn))
744 {
745 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
746 _("Option `%s' in section `%s' not specified!\n"),
747 "FRIENDS",
748 "TOPOLOGY");
749 return;
750 }
744 if (GNUNET_OK != GNUNET_DISK_file_test (fn)) 751 if (GNUNET_OK != GNUNET_DISK_file_test (fn))
745 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ 752 GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
746 | GNUNET_DISK_PERM_USER_WRITE); 753 | GNUNET_DISK_PERM_USER_WRITE);
@@ -920,7 +927,7 @@ hello_advertising (void *cls,
920 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value) 927 if (0 == GNUNET_TIME_absolute_get_remaining (pos->expiration).value)
921 { 928 {
922 /* time to discard... */ 929 /* time to discard... */
923 if (prev == NULL) 930 if (prev != NULL)
924 prev->next = next; 931 prev->next = next;
925 else 932 else
926 hellos = next; 933 hellos = next;
@@ -1015,17 +1022,19 @@ run (void *cls,
1015 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg, 1022 friends_only = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1016 "TOPOLOGY", 1023 "TOPOLOGY",
1017 "FRIENDS-ONLY"); 1024 "FRIENDS-ONLY");
1018 opt = 0; 1025 if (GNUNET_OK !=
1019 GNUNET_CONFIGURATION_get_value_number (cfg, 1026 GNUNET_CONFIGURATION_get_value_number (cfg,
1020 "TOPOLOGY", 1027 "TOPOLOGY",
1021 "MINIMUM-FRIENDS", 1028 "MINIMUM-FRIENDS",
1022 &opt); 1029 &opt))
1030 opt = 0;
1023 minimum_friend_count = (unsigned int) opt; 1031 minimum_friend_count = (unsigned int) opt;
1024 opt = 16; 1032 if (GNUNET_OK !=
1025 GNUNET_CONFIGURATION_get_value_number (cfg, 1033 GNUNET_CONFIGURATION_get_value_number (cfg,
1026 "TOPOLOGY", 1034 "TOPOLOGY",
1027 "TARGET-CONNECTION-COUNT", 1035 "TARGET-CONNECTION-COUNT",
1028 &opt); 1036 &opt))
1037 opt = 16;
1029 target_connection_count = (unsigned int) opt; 1038 target_connection_count = (unsigned int) opt;
1030 1039
1031 if ( (friends_only == GNUNET_YES) || 1040 if ( (friends_only == GNUNET_YES) ||
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
index d97cb15eb..2b1e82d21 100644
--- a/src/transport/gnunet-service-transport.c
+++ b/src/transport/gnunet-service-transport.c
@@ -2132,7 +2132,8 @@ plugin_env_receive (void *cls,
2132 _ 2132 _
2133 ("Dropping incoming message due to repeated bandwidth quota violations.\n")); 2133 ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2134 /* TODO: call stats */ 2134 /* TODO: call stats */
2135 GNUNET_assert (NULL != service_context->neighbour); 2135 GNUNET_assert ( (service_context == NULL) ||
2136 (NULL != service_context->neighbour) );
2136 return service_context; 2137 return service_context;
2137 } 2138 }
2138 switch (ntohs (message->type)) 2139 switch (ntohs (message->type))
diff --git a/src/util/configuration.c b/src/util/configuration.c
index 769d2aadc..ff177d966 100644
--- a/src/util/configuration.c
+++ b/src/util/configuration.c
@@ -315,6 +315,49 @@ GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data,
315} 315}
316 316
317 317
318void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
319 GNUNET_CONFIGURATION_Iterator iter,
320 void *iter_cls)
321{
322 struct ConfigSection *spos;
323 struct ConfigEntry *epos;
324
325 spos = cfg->sections;
326 while (spos != NULL)
327 {
328 epos = spos->entries;
329 while (epos != NULL)
330 {
331 iter (iter_cls, spos->name, epos->key, epos->val);
332 epos = epos->next;
333 }
334 spos = spos->next;
335 }
336}
337
338
339static void
340copy_entry (void *cls,
341 const char *section,
342 const char *option,
343 const char *value)
344{
345 struct GNUNET_CONFIGURATION_Handle *dst = cls;
346 GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
347}
348
349
350struct GNUNET_CONFIGURATION_Handle *
351GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
352{
353 struct GNUNET_CONFIGURATION_Handle *ret;
354
355 ret = GNUNET_CONFIGURATION_create ();
356 GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
357 return ret;
358}
359
360
318static struct ConfigSection * 361static struct ConfigSection *
319findSection (const struct GNUNET_CONFIGURATION_Handle *data, const char *section) 362findSection (const struct GNUNET_CONFIGURATION_Handle *data, const char *section)
320{ 363{
diff --git a/src/util/container_meta_data.c b/src/util/container_meta_data.c
index b79de57d2..6265fc142 100644
--- a/src/util/container_meta_data.c
+++ b/src/util/container_meta_data.c
@@ -187,8 +187,9 @@ GNUNET_CONTAINER_meta_data_get_contents (const struct
187 if (!EXTRACTOR_isBinaryType (md->items[i].type)) 187 if (!EXTRACTOR_isBinaryType (md->items[i].type))
188 { 188 {
189 if ((iterator != NULL) && 189 if ((iterator != NULL) &&
190 (GNUNET_OK != iterator (md->items[i].type, 190 (GNUNET_OK != iterator (closure,
191 md->items[i].data, closure))) 191 md->items[i].type,
192 md->items[i].data)))
192 return GNUNET_SYSERR; 193 return GNUNET_SYSERR;
193 } 194 }
194 else 195 else
diff --git a/src/util/crypto_ksk.c b/src/util/crypto_ksk.c
index 45f11f8fe..170974b2f 100644
--- a/src/util/crypto_ksk.c
+++ b/src/util/crypto_ksk.c
@@ -790,7 +790,9 @@ entropy_generator (void *cls,
790 { 790 {
791 if (genproc != 0) 791 if (genproc != 0)
792 { 792 {
793 PLIBC_KILL(genproc, SIGTERM); 793 if (0 != PLIBC_KILL(genproc, SIGTERM))
794 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
795 "kill");
794 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); 796 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
795 genproc = 0; 797 genproc = 0;
796 } 798 }
@@ -808,7 +810,9 @@ entropy_generator (void *cls,
808 GNUNET_break (0); 810 GNUNET_break (0);
809 return; 811 return;
810 } 812 }
811 PLIBC_KILL(genproc, SIGTERM); 813 if (0 != PLIBC_KILL(genproc, SIGTERM))
814 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
815 "kill");
812 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc)); 816 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (genproc));
813 genproc = 0; 817 genproc = 0;
814 } 818 }
diff --git a/src/util/disk.c b/src/util/disk.c
index 738839807..08f14caf6 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -234,7 +234,10 @@ GNUNET_DISK_mktemp (const char *template)
234 GNUNET_free (fn); 234 GNUNET_free (fn);
235 return NULL; 235 return NULL;
236 } 236 }
237 CLOSE (fd); 237 if (0 != CLOSE (fd))
238 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
239 "close",
240 fn);
238 return fn; 241 return fn;
239} 242}
240 243
@@ -1043,6 +1046,7 @@ GNUNET_DISK_file_open (const char *fn, int flags, ...)
1043 else 1046 else
1044 { 1047 {
1045 GNUNET_break (0); 1048 GNUNET_break (0);
1049 GNUNET_free (expfn);
1046 return NULL; 1050 return NULL;
1047 } 1051 }
1048 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS) 1052 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)