docu
[oweals/gnunet.git] / src / experimentation / gnunet-daemon-experimentation_experiments.c
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 3, 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 experimentation/gnunet-daemon-experimentation_experiments.c
23  * @brief experimentation daemon: experiment management
24  * @author Christian Grothoff
25  * @author Matthias Wachs
26  */
27 #include "platform.h"
28 #include "gnunet_getopt_lib.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_core_service.h"
31 #include "gnunet_statistics_service.h"
32 #include "gnunet-daemon-experimentation.h"
33
34
35 /**
36  * Struct to store information about a specific experiment
37  */
38 struct Experiment
39 {
40         /* Header */
41         char *name;
42
43         /* Experiment issuer */
44         struct GNUNET_PeerIdentity issuer;
45
46         /* Experiment version as timestamp of creation */
47         struct GNUNET_TIME_Absolute version;
48
49         /* Description */
50         char *description;
51
52         /* Required capabilities  */
53         uint32_t required_capabilities;
54
55         /* Experiment itself */
56
57         /* TBD */
58 };
59
60
61 /**
62  * Struct to store information about an experiment issuer
63  */
64 struct Issuer
65 {
66         struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
67 };
68
69
70 /**
71  * Hashmap containing valid experiment issuer
72  */
73 static struct GNUNET_CONTAINER_MultiHashMap *valid_issuers;
74
75
76 /**
77  * Hashmap containing valid experiments
78  */
79 static struct GNUNET_CONTAINER_MultiHashMap *experiments;
80
81
82 /**
83  * Verify experiment signature
84  *
85  * @param i issuer
86  * @param e experiment
87  * @return GNUNET_OK or GNUNET_SYSERR
88  */
89 int
90 experiment_verify (struct Issuer *i, struct Experiment *e)
91 {
92         GNUNET_assert (NULL != i);
93         GNUNET_assert (NULL != e);
94
95         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Verification: to be implemented\n");
96         return GNUNET_OK;
97 }
98
99 int free_experiment (void *cls,
100                                                                                  const struct GNUNET_HashCode * key,
101                                                                                  void *value)
102 {
103         struct Experiment *e = value;
104         GNUNET_CONTAINER_multihashmap_remove (experiments, key, value);
105         GNUNET_free_non_null (e->description);
106         GNUNET_free_non_null (e->name);
107         GNUNET_free (e);
108         return GNUNET_OK;
109 }
110
111
112 /**
113  * Free issuer element
114  *
115  * @param cls unused
116  * @param key the key
117  * @param value the issuer element to free
118  * @return GNUNET_OK to continue
119  */
120 int free_issuer (void *cls,
121                                                                  const struct GNUNET_HashCode * key,
122                                                                  void *value)
123 {
124         struct Issuer *i = value;
125         GNUNET_CONTAINER_multihashmap_remove (valid_issuers, key, value);
126         GNUNET_free (i);
127         return GNUNET_OK;
128 }
129
130
131 /**
132  * Is peer a valid issuer
133  *
134  * @return GNUNET_YES or GNUNET_NO
135  */
136 int
137 GNUNET_EXPERIMENTATION_experiments_issuer_accepted (struct GNUNET_PeerIdentity *issuer_ID)
138 {
139         if (GNUNET_CONTAINER_multihashmap_contains (valid_issuers, &issuer_ID->hashPubKey))
140                 return GNUNET_YES;
141         else
142                 return GNUNET_NO;
143 }
144
145
146 /**
147  * Parse a configuration section containing experiments
148  *
149  * @param cls configuration handle
150  * @param section section name
151  */
152 void exp_file_iterator (void *cls,
153                                                                                                 const char *section)
154 {
155         struct GNUNET_CONFIGURATION_Handle *exp = cls;
156         struct Experiment *e;
157         struct Issuer *i;
158
159         char *val;
160         unsigned long long number;
161
162         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Parsing section `%s'\n", section);
163
164         e = GNUNET_malloc (sizeof (struct Experiment));
165         /* Mandatory fields */
166
167         /* Issuer */
168         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (exp, section, "ISSUER", &val))
169         {
170                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Issuer missing\n"), section);
171                         GNUNET_free (e);
172                         return;
173         }
174         if (GNUNET_SYSERR == GNUNET_CRYPTO_hash_from_string (val, &e->issuer.hashPubKey))
175         {
176                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Issuer invalid\n"), section);
177                         GNUNET_free (val);
178                         GNUNET_free (e);
179                         return;
180         }
181         if (NULL == (i = GNUNET_CONTAINER_multihashmap_get (valid_issuers, &e->issuer.hashPubKey)))
182         {
183                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Issuer not accepted!\n"), section);
184                 GNUNET_free (val);
185                 GNUNET_free (e);
186                 return;
187         }
188         GNUNET_free (val);
189
190         /* Version */
191         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, section, "VERSION", &number))
192         {
193                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Version missing or invalid \n"), section);
194                         GNUNET_free (e);
195                         return;
196         }
197         e->version.abs_value = number;
198
199         /* Required capabilities */
200         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (exp, section, "CAPABILITIES", &number))
201         {
202                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Required capabilities missing \n"), section);
203                         GNUNET_free (e);
204                         return;
205         }
206         if (number > UINT32_MAX)
207         {
208                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Required capabilities invalid \n"), section);
209                 GNUNET_free (e);
210                 return;
211         }
212         e->required_capabilities = number;
213         e->name = GNUNET_strdup (section);
214
215         /* Optional fields */
216         /* Description */
217         GNUNET_CONFIGURATION_get_value_string (exp, section, "DESCRIPTION", &e->description);
218
219         /* verify experiment */
220         if (GNUNET_SYSERR == experiment_verify (i, e))
221         {
222                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Experiment `%s': Experiment signature is invalid\n"), section);
223                         GNUNET_free (e);
224                         GNUNET_free_non_null (e->name);
225                         GNUNET_free_non_null (e->description);
226                         return;
227         }
228         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Adding experiment `%s'\n"), e->name);
229         GNUNET_CONTAINER_multihashmap_put (experiments, &e->issuer.hashPubKey, e, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
230   GNUNET_STATISTICS_set (GSE_stats, "# experiments", GNUNET_CONTAINER_multihashmap_size (experiments), GNUNET_NO);
231 }
232
233
234 /**
235  * Load experiments from file
236  *
237  * @param file source file
238  */
239 static void
240 load_file (const char * file)
241 {
242         struct GNUNET_CONFIGURATION_Handle *exp = GNUNET_CONFIGURATION_create();
243         if (NULL == exp)
244                 return;
245
246         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_parse (exp, file))
247         {
248                 GNUNET_CONFIGURATION_destroy (exp);
249                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to parse file `%s'\n"), file);
250                 return;
251         }
252         GNUNET_CONFIGURATION_iterate_sections (exp, &exp_file_iterator, exp);
253         GNUNET_CONFIGURATION_destroy (exp);
254 }
255
256
257 /**
258  * Start experiments management
259  */
260 int
261 GNUNET_EXPERIMENTATION_experiments_start ()
262 {
263         struct Issuer *i;
264         char *issuers;
265         char *file;
266         char *pubkey;
267         char *pos;
268         struct GNUNET_PeerIdentity issuer_ID;
269         struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
270         struct GNUNET_HashCode hash;
271
272         /* Load valid issuer */
273         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (GSE_cfg, "EXPERIMENTATION", "ISSUERS", &issuers))
274         {
275                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No valid experiment issuers configured! Set value to peer id of issuer! Exit...\n"));
276                         return GNUNET_SYSERR;
277         }
278
279         valid_issuers = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
280   for (pos = strtok (issuers, " "); pos != NULL; pos = strtok (NULL, " "))
281   {
282
283                 if (GNUNET_SYSERR == GNUNET_CRYPTO_hash_from_string (pos, &issuer_ID.hashPubKey))
284                 {
285                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid value `%s'\n"), pos);
286                 }
287                 else
288                 {
289                                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "`%s' is a valid issuer \n", GNUNET_i2s (&issuer_ID));
290                                 i = GNUNET_malloc (sizeof (struct Issuer));
291                                 GNUNET_CONTAINER_multihashmap_put (valid_issuers, &issuer_ID.hashPubKey,
292                                                 i, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
293                                 i = NULL;
294                 }
295   }
296   GNUNET_free (issuers);
297
298   if (0 == GNUNET_CONTAINER_multihashmap_size (valid_issuers))
299   {
300                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No valid experiment issuers configured! Set value to peer id of issuer! Exit...\n"));
301                 GNUNET_EXPERIMENTATION_experiments_stop ();
302                 return GNUNET_SYSERR;
303   }
304   GNUNET_STATISTICS_set (GSE_stats, "# issuer", GNUNET_CONTAINER_multihashmap_size (valid_issuers), GNUNET_NO);
305
306         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (GSE_cfg, "EXPERIMENTATION", "PUBKEY", &pubkey))
307         {
308                         if (GNUNET_OK != GNUNET_CRYPTO_ecc_public_key_from_string(pubkey, strlen (pubkey), &pub))
309                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Invalid public key `%s'\n"), pubkey);
310                         else
311                         {
312                                 GNUNET_CRYPTO_hash( &pub, sizeof (pub), &hash);
313                                 if (NULL != (i = GNUNET_CONTAINER_multihashmap_get (valid_issuers, &hash)))
314                                 {
315                                                 i->pubkey = pub;
316                                                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Found issuer for public key `%s'\n"), pubkey);
317                                 }
318                                 else
319                                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No issuer for public key `%s'\n"), pubkey);
320                         }
321                         GNUNET_free (pubkey);
322         }
323
324   experiments = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
325   /* Load experiments from file */
326         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (GSE_cfg, "EXPERIMENTATION", "EXPERIMENTS", &file))
327                 return GNUNET_OK;
328
329         if (GNUNET_YES != GNUNET_DISK_file_test (file))
330         {
331                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Cannot read experiments file `%s'\n"), file);
332                 GNUNET_free (file);
333                         return GNUNET_OK;
334         }
335         load_file (file);
336         GNUNET_free (file);
337         return GNUNET_OK;
338 }
339
340
341 /**
342  * Stop experiments management
343  */
344 void
345 GNUNET_EXPERIMENTATION_experiments_stop ()
346 {
347         if (NULL != valid_issuers)
348         {
349                 GNUNET_CONTAINER_multihashmap_iterate (valid_issuers, &free_issuer, NULL);
350                 GNUNET_CONTAINER_multihashmap_destroy (valid_issuers);
351         }
352         valid_issuers = NULL;
353         if (NULL != experiments)
354         {
355                 GNUNET_CONTAINER_multihashmap_iterate (experiments, &free_experiment, NULL);
356                 GNUNET_CONTAINER_multihashmap_destroy (experiments);
357         }
358         experiments = NULL;
359 }
360
361 /* end of gnunet-daemon-experimentation_experiments.c */