psycstore: add option to perform membership test when retrieving fragment or message
[oweals/gnunet.git] / src / psycstore / gnunet-service-psycstore.c
1 /*
2  * This file is part of GNUnet
3  * (C) 2013 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 psycstore/gnunet-service-psycstore.c
23  * @brief PSYCstore service
24  * @author Gabor X Toth
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_psycstore_service.h"
34 #include "gnunet_psycstore_plugin.h"
35 #include "psycstore.h"
36
37
38 /**
39  * Handle to our current configuration.
40  */
41 static const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43 /**
44  * Handle to the statistics service.
45  */
46 static struct GNUNET_STATISTICS_Handle *stats;
47
48 /**
49  * Notification context, simplifies client broadcasts.
50  */
51 static struct GNUNET_SERVER_NotificationContext *nc;
52
53 /**
54  * Database handle
55  */
56 static struct GNUNET_PSYCSTORE_PluginFunctions *db;
57
58 /**
59  * Name of the database plugin
60  */
61 static char *db_lib_name;
62
63
64 /**
65  * Task run during shutdown.
66  *
67  * @param cls unused
68  * @param tc unused
69  */
70 static void
71 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
72 {
73   if (NULL != nc)
74   {
75     GNUNET_SERVER_notification_context_destroy (nc);
76     nc = NULL;
77   }
78   if (NULL != stats)
79   {
80     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
81     stats = NULL;
82   }
83   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db));
84   GNUNET_free (db_lib_name);
85   db_lib_name = NULL;
86 }
87
88
89 /**
90  * Send a result code back to the client.
91  *
92  * @param client Client that should receive the result code.
93  * @param result_code Code to transmit.
94  * @param op_id Operation ID.
95  * @param err_msg Error message to include (or NULL for none).
96  */
97 static void
98 send_result_code (struct GNUNET_SERVER_Client *client, uint32_t result_code,
99                   uint32_t op_id, const char *err_msg)
100 {
101   struct OperationResult *res;
102   size_t err_len;
103
104   if (NULL == err_msg)
105     err_len = 0;
106   else
107     err_len = strlen (err_msg) + 1;
108   res = GNUNET_malloc (sizeof (struct OperationResult) + err_len);
109   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE);
110   res->header.size = htons (sizeof (struct OperationResult) + err_len);
111   res->result_code = htonl (result_code);
112   res->op_id = op_id;
113   if (0 < err_len)
114     memcpy (&res[1], err_msg, err_len);
115   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
116               "Sending result %d (%s) to client\n",
117               (int) result_code,
118               err_msg);
119   GNUNET_SERVER_notification_context_add (nc, client);
120   GNUNET_SERVER_notification_context_unicast (nc, client, &res->header,
121                                               GNUNET_NO);
122   GNUNET_free (res);
123 }
124
125 enum
126 {
127   MEMBERSHIP_TEST_NOT_NEEDED = 0,
128   MEMBERSHIP_TEST_NEEDED = 1,
129   MEMBERSHIP_TEST_DONE = 2,
130 } MessageMembershipTest;
131
132 struct SendClosure
133 {
134   struct GNUNET_SERVER_Client *client;
135
136   /**
137    * Channel's public key.
138    */
139   struct GNUNET_CRYPTO_EddsaPublicKey channel_key;
140
141   /**
142    * Slave's public key.
143    */
144   struct GNUNET_CRYPTO_EcdsaPublicKey slave_key;
145
146   /**
147    * Operation ID.
148    */
149   uint64_t op_id;
150
151   /**
152    * Membership test result.
153    */
154   int membership_test_result;
155
156   /**
157    * Do membership test with @a slave_key before returning fragment?
158    * @see enum MessageMembershipTest
159    */
160   uint8_t membership_test;
161
162 };
163
164
165 static int
166 send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg,
167                enum GNUNET_PSYCSTORE_MessageFlags flags)
168 {
169   struct SendClosure *sc = cls;
170   struct FragmentResult *res;
171
172   if (MEMBERSHIP_TEST_NEEDED == sc->membership_test)
173   {
174     sc->membership_test = MEMBERSHIP_TEST_DONE;
175     sc->membership_test_result
176       = db->membership_test (db->cls, &sc->channel_key, &sc->slave_key,
177                              GNUNET_ntohll (msg->message_id));
178     switch (sc->membership_test_result)
179     {
180     case GNUNET_YES:
181       break;
182
183     case GNUNET_NO:
184     case GNUNET_SYSERR:
185       return GNUNET_NO;
186     }
187   }
188
189   size_t msg_size = ntohs (msg->header.size);
190
191   res = GNUNET_malloc (sizeof (struct FragmentResult) + msg_size);
192   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT);
193   res->header.size = htons (sizeof (struct FragmentResult) + msg_size);
194   res->op_id = sc->op_id;
195   res->psycstore_flags = htonl (flags);
196   memcpy (&res[1], msg, msg_size);
197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
198               "Sending fragment %ld to client\n",
199               GNUNET_ntohll (msg->fragment_id));
200   GNUNET_free (msg);
201   GNUNET_SERVER_notification_context_add (nc, sc->client);
202   GNUNET_SERVER_notification_context_unicast (nc, sc->client, &res->header,
203                                               GNUNET_NO);
204   GNUNET_free (res);
205   return GNUNET_YES;
206 }
207
208
209 static int
210 send_state_var (void *cls, const char *name,
211                 const void *value, size_t value_size)
212 {
213   struct SendClosure *sc = cls;
214   struct StateResult *res;
215   size_t name_size = strlen (name) + 1;
216
217   res = GNUNET_malloc (sizeof (struct StateResult) + name_size + value_size);
218   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE);
219   res->header.size = htons (sizeof (struct StateResult) + name_size + value_size);
220   res->op_id = sc->op_id;
221   res->name_size = htons (name_size);
222   memcpy (&res[1], name, name_size);
223   memcpy ((char *) &res[1] + name_size, value, value_size);
224   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225               "Sending state variable %s to client\n", name);
226   GNUNET_SERVER_notification_context_add (nc, sc->client);
227   GNUNET_SERVER_notification_context_unicast (nc, sc->client, &res->header,
228                                               GNUNET_NO);
229   GNUNET_free (res);
230   return GNUNET_OK;
231 }
232
233
234 static void
235 handle_membership_store (void *cls,
236                          struct GNUNET_SERVER_Client *client,
237                          const struct GNUNET_MessageHeader *msg)
238 {
239   const struct MembershipStoreRequest *req =
240     (const struct MembershipStoreRequest *) msg;
241
242   int ret = db->membership_store (db->cls, &req->channel_key, &req->slave_key,
243                                   ntohl (req->did_join),
244                                   GNUNET_ntohll (req->announced_at),
245                                   GNUNET_ntohll (req->effective_since),
246                                   GNUNET_ntohll (req->group_generation));
247
248   if (ret != GNUNET_OK)
249     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
250                 _("Failed to store membership information!\n"));
251
252   send_result_code (client, ret, req->op_id, NULL);
253   GNUNET_SERVER_receive_done (client, GNUNET_OK);
254 }
255
256
257 static void
258 handle_membership_test (void *cls,
259                         struct GNUNET_SERVER_Client *client,
260                         const struct GNUNET_MessageHeader *msg)
261 {
262   const struct MembershipTestRequest *req =
263     (const struct MembershipTestRequest *) msg;
264
265   int ret = db->membership_test (db->cls, &req->channel_key, &req->slave_key,
266                                  GNUNET_ntohll (req->message_id));
267   switch (ret)
268   {
269   case GNUNET_YES:
270   case GNUNET_NO:
271     break;
272   default:
273     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
274                 _("Failed to test membership!\n"));
275   }
276
277   send_result_code (client, ret, req->op_id, NULL);
278   GNUNET_SERVER_receive_done (client, GNUNET_OK);
279 }
280
281
282 static void
283 handle_fragment_store (void *cls,
284                        struct GNUNET_SERVER_Client *client,
285                        const struct GNUNET_MessageHeader *msg)
286 {
287   const struct FragmentStoreRequest *req =
288     (const struct FragmentStoreRequest *) msg;
289
290   int ret = db->fragment_store (db->cls, &req->channel_key,
291                                 (const struct GNUNET_MULTICAST_MessageHeader *)
292                                 &req[1], ntohl (req->psycstore_flags));
293
294   if (ret != GNUNET_OK)
295     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
296                 _("Failed to store fragment!\n"));
297
298   send_result_code (client, ret, req->op_id, NULL);
299   GNUNET_SERVER_receive_done (client, GNUNET_OK);
300 }
301
302
303 static void
304 handle_fragment_get (void *cls,
305                      struct GNUNET_SERVER_Client *client,
306                      const struct GNUNET_MessageHeader *msg)
307 {
308   const struct FragmentGetRequest *
309     req = (const struct FragmentGetRequest *) msg;
310   struct SendClosure
311     sc = { .op_id = req->op_id, .client = client,
312            .channel_key = req->channel_key, .slave_key = req->slave_key,
313            .membership_test = req->do_membership_test };
314
315   int ret = db->fragment_get (db->cls, &req->channel_key,
316                               GNUNET_ntohll (req->fragment_id),
317                               &send_fragment, &sc);
318   switch (ret)
319   {
320   case GNUNET_YES:
321   case GNUNET_NO:
322     if (MEMBERSHIP_TEST_DONE == sc.membership_test)
323     {
324       switch (sc.membership_test_result)
325       {
326       case GNUNET_YES:
327         break;
328
329       case GNUNET_NO:
330         ret = GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED;
331         break;
332
333       case GNUNET_SYSERR:
334         ret = GNUNET_SYSERR;
335         break;
336       }
337     }
338     break;
339   default:
340     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
341                 _("Failed to get fragment!\n"));
342   }
343
344   send_result_code (client, ret, req->op_id, NULL);
345   GNUNET_SERVER_receive_done (client, GNUNET_OK);
346 }
347
348
349 static void
350 handle_message_get (void *cls,
351                     struct GNUNET_SERVER_Client *client,
352                     const struct GNUNET_MessageHeader *msg)
353 {
354   const struct MessageGetRequest *
355     req = (const struct MessageGetRequest *) msg;
356   struct SendClosure
357     sc = { .op_id = req->op_id, .client = client,
358            .channel_key = req->channel_key, .slave_key = req->slave_key,
359            .membership_test = req->do_membership_test };
360
361   uint64_t ret_frags = 0;
362   int64_t ret = db->message_get (db->cls, &req->channel_key,
363                                  GNUNET_ntohll (req->message_id),
364                                  &ret_frags, &send_fragment, &sc);
365   switch (ret)
366   {
367   case GNUNET_YES:
368   case GNUNET_NO:
369     break;
370   default:
371     ret_frags = ret;
372     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373                 _("Failed to get message!\n"));
374   }
375
376   send_result_code (client, ret_frags, req->op_id, NULL);
377   GNUNET_SERVER_receive_done (client, GNUNET_OK);
378 }
379
380
381 static void
382 handle_message_get_fragment (void *cls,
383                              struct GNUNET_SERVER_Client *client,
384                              const struct GNUNET_MessageHeader *msg)
385 {
386   const struct MessageGetFragmentRequest *
387     req = (const struct MessageGetFragmentRequest *) msg;
388   struct SendClosure
389     sc = { .op_id = req->op_id, .client = client,
390            .channel_key = req->channel_key, .slave_key = req->slave_key,
391            .membership_test = req->do_membership_test };
392
393   int ret = db->message_get_fragment (db->cls, &req->channel_key,
394                                       GNUNET_ntohll (req->message_id),
395                                       GNUNET_ntohll (req->fragment_offset),
396                                       &send_fragment, &sc);
397   switch (ret)
398   {
399   case GNUNET_YES:
400   case GNUNET_NO:
401     break;
402   default:
403     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404                 _("Failed to get message fragment!\n"));
405   }
406
407   send_result_code (client, ret, req->op_id, NULL);
408   GNUNET_SERVER_receive_done (client, GNUNET_OK);
409 }
410
411
412 static void
413 handle_counters_get (void *cls,
414                      struct GNUNET_SERVER_Client *client,
415                      const struct GNUNET_MessageHeader *msg)
416 {
417   const struct OperationRequest *req = (const struct OperationRequest *) msg;
418   struct CountersResult res = { {0} };
419
420   int ret = db->counters_message_get (db->cls, &req->channel_key,
421                                       &res.max_fragment_id, &res.max_message_id,
422                                       &res.max_group_generation);
423   switch (ret)
424   {
425   case GNUNET_OK:
426     ret = db->counters_state_get (db->cls, &req->channel_key,
427                                   &res.max_state_message_id);
428   case GNUNET_NO:
429     break;
430   default:
431     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432                 _("Failed to get master counters!\n"));
433   }
434
435   res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS);
436   res.header.size = htons (sizeof (res));
437   res.result_code = htonl (ret);
438   res.op_id = req->op_id;
439   res.max_fragment_id = GNUNET_htonll (res.max_fragment_id);
440   res.max_message_id = GNUNET_htonll (res.max_message_id);
441   res.max_group_generation = GNUNET_htonll (res.max_group_generation);
442   res.max_state_message_id = GNUNET_htonll (res.max_state_message_id);
443
444   GNUNET_SERVER_notification_context_add (nc, client);
445   GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
446                                               GNUNET_NO);
447
448   GNUNET_SERVER_receive_done (client, GNUNET_OK);
449 }
450
451
452 /* FIXME: stop processing further state modify messages after an error */
453 static void
454 handle_state_modify (void *cls,
455                      struct GNUNET_SERVER_Client *client,
456                      const struct GNUNET_MessageHeader *msg)
457 {
458   const struct StateModifyRequest *req
459     = (const struct StateModifyRequest *) msg;
460
461   int ret = GNUNET_SYSERR;
462   const char *name = (const char *) &req[1];
463   uint16_t name_size = ntohs (req->name_size);
464
465   if (name_size <= 2 || '\0' != name[name_size - 1])
466   {
467     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
468                 _("Tried to set invalid state variable name!\n"));
469     GNUNET_break_op (0);
470   }
471   else
472   {
473     ret = GNUNET_OK;
474
475     if (req->flags & STATE_OP_FIRST)
476     {
477       ret = db->state_modify_begin (db->cls, &req->channel_key,
478                                     GNUNET_ntohll (req->message_id),
479                                     GNUNET_ntohll (req->state_delta));
480     }
481     if (ret != GNUNET_OK)
482     {
483       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
484                   _("Failed to begin modifying state!\n"));
485     }
486     else
487     {
488       switch (req->oper)
489       {
490       case GNUNET_ENV_OP_ASSIGN:
491         ret = db->state_modify_set (db->cls, &req->channel_key,
492                                     (const char *) &req[1],
493                                     name + ntohs (req->name_size),
494                                     ntohs (req->header.size) - sizeof (*req)
495                                     - ntohs (req->name_size));
496         break;
497       default:
498 #if TODO
499         ret = GNUNET_ENV_operation ((const char *) &req[1],
500                                     current_value, current_value_size,
501                                     req->oper, name + ntohs (req->name_size),
502                                     ntohs (req->header.size) - sizeof (*req)
503                                     - ntohs (req->name_size), &value, &value_size);
504 #endif
505         ret = GNUNET_SYSERR;
506         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
507                     _("Unknown operator: %c\n"), req->oper);
508       }
509     }
510
511     if (GNUNET_OK == ret && req->flags & STATE_OP_LAST)
512     {
513       ret = db->state_modify_end (db->cls, &req->channel_key,
514                                   GNUNET_ntohll (req->message_id));
515       if (ret != GNUNET_OK)
516         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
517                     _("Failed to end modifying state!\n"));
518     }
519   }
520   send_result_code (client, ret, req->op_id, NULL);
521   GNUNET_SERVER_receive_done (client, GNUNET_OK);
522 }
523
524
525 /* FIXME: stop processing further state sync messages after an error */
526 static void
527 handle_state_sync (void *cls,
528                    struct GNUNET_SERVER_Client *client,
529                    const struct GNUNET_MessageHeader *msg)
530 {
531   const struct StateSyncRequest *req
532     = (const struct StateSyncRequest *) msg;
533
534   int ret = GNUNET_SYSERR;
535   const char *name = (const char *) &req[1];
536   uint16_t name_size = ntohs (req->name_size);
537
538   if (name_size <= 2 || '\0' != name[name_size - 1])
539   {
540     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
541                 _("Tried to set invalid state variable name!\n"));
542     GNUNET_break_op (0);
543   }
544   else
545   {
546     ret = GNUNET_OK;
547
548     if (req->flags & STATE_OP_FIRST)
549     {
550       ret = db->state_sync_begin (db->cls, &req->channel_key);
551     }
552     if (ret != GNUNET_OK)
553     {
554       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555                   _("Failed to begin synchronizing state!\n"));
556     }
557     else
558     {
559       ret = db->state_sync_set (db->cls, &req->channel_key, name,
560                                 name + ntohs (req->name_size),
561                                 ntohs (req->header.size) - sizeof (*req)
562                                 - ntohs (req->name_size));
563     }
564
565     if (GNUNET_OK == ret && req->flags & STATE_OP_LAST)
566     {
567       ret = db->state_sync_end (db->cls, &req->channel_key,
568                                 GNUNET_ntohll (req->message_id));
569       if (ret != GNUNET_OK)
570         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
571                     _("Failed to end synchronizing state!\n"));
572     }
573   }
574   send_result_code (client, ret, req->op_id, NULL);
575   GNUNET_SERVER_receive_done (client, GNUNET_OK);
576 }
577
578
579 static void
580 handle_state_reset (void *cls,
581                     struct GNUNET_SERVER_Client *client,
582                     const struct GNUNET_MessageHeader *msg)
583 {
584   const struct OperationRequest *req =
585     (const struct OperationRequest *) msg;
586
587   int ret = db->state_reset (db->cls, &req->channel_key);
588
589   if (ret != GNUNET_OK)
590     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
591                 _("Failed to reset state!\n"));
592
593   send_result_code (client, ret, req->op_id, NULL);
594   GNUNET_SERVER_receive_done (client, GNUNET_OK);
595 }
596
597
598 static void
599 handle_state_hash_update (void *cls,
600                           struct GNUNET_SERVER_Client *client,
601                           const struct GNUNET_MessageHeader *msg)
602 {
603   const struct OperationRequest *req =
604     (const struct OperationRequest *) msg;
605
606   int ret = db->state_reset (db->cls, &req->channel_key);
607
608   if (ret != GNUNET_OK)
609     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
610                 _("Failed to reset state!\n"));
611
612   send_result_code (client, ret, req->op_id, NULL);
613   GNUNET_SERVER_receive_done (client, GNUNET_OK);
614 }
615
616
617 static void
618 handle_state_get (void *cls,
619                   struct GNUNET_SERVER_Client *client,
620                   const struct GNUNET_MessageHeader *msg)
621 {
622   const struct OperationRequest *req =
623     (const struct OperationRequest *) msg;
624
625   struct SendClosure sc = { .op_id = req->op_id, .client = client };
626   int64_t ret = GNUNET_SYSERR;
627   const char *name = (const char *) &req[1];
628   uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
629
630   if (name_size <= 2 || '\0' != name[name_size - 1])
631   {
632     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
633                 _("Tried to get invalid state variable name!\n"));
634     GNUNET_break (0);
635   }
636   else
637   {
638     ret = db->state_get (db->cls, &req->channel_key, name,
639                          &send_state_var, &sc);
640     if (GNUNET_NO == ret && name_size >= 5) /* min: _a_b\0 */
641     {
642       char *p, *n = GNUNET_malloc (name_size);
643       memcpy (n, name, name_size);
644       while (&n[1] < (p = strrchr (n, '_')) && GNUNET_NO == ret)
645       {
646         *p = '\0';
647         ret = db->state_get (db->cls, &req->channel_key, n,
648                              &send_state_var, &sc);
649       }
650       GNUNET_free (n);
651     }
652   }
653   switch (ret)
654   {
655   case GNUNET_OK:
656   case GNUNET_NO:
657     break;
658   default:
659     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
660                 _("Failed to get state variable!\n"));
661   }
662
663   send_result_code (client, ret, req->op_id, NULL);
664   GNUNET_SERVER_receive_done (client, GNUNET_OK);
665 }
666
667
668 static void
669 handle_state_get_prefix (void *cls,
670                          struct GNUNET_SERVER_Client *client,
671                          const struct GNUNET_MessageHeader *msg)
672 {
673   const struct OperationRequest *req =
674     (const struct OperationRequest *) msg;
675
676   struct SendClosure sc = { .op_id = req->op_id, .client = client };
677   int64_t ret = GNUNET_SYSERR;
678   const char *name = (const char *) &req[1];
679   uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
680
681   if (name_size <= 1 || '\0' != name[name_size - 1])
682   {
683     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
684                 _("Tried to get invalid state variable name!\n"));
685     GNUNET_break (0);
686   }
687   else
688   {
689     ret = db->state_get_prefix (db->cls, &req->channel_key, name,
690                                 &send_state_var, &sc);
691   }
692   switch (ret)
693   {
694   case GNUNET_OK:
695   case GNUNET_NO:
696     break;
697   default:
698     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
699                 _("Failed to get state variable!\n"));
700   }
701
702   send_result_code (client, ret, req->op_id, NULL);
703   GNUNET_SERVER_receive_done (client, GNUNET_OK);
704 }
705
706
707 /**
708  * Initialize the PSYCstore service.
709  *
710  * @param cls Closure.
711  * @param server The initialized server.
712  * @param c Configuration to use.
713  */
714 static void
715 run (void *cls, struct GNUNET_SERVER_Handle *server,
716      const struct GNUNET_CONFIGURATION_Handle *c)
717 {
718   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
719     { &handle_membership_store, NULL,
720       GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE,
721       sizeof (struct MembershipStoreRequest) },
722
723     { &handle_membership_test, NULL,
724       GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST,
725       sizeof (struct MembershipTestRequest) },
726
727     { &handle_fragment_store, NULL,
728       GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE, 0, },
729
730     { &handle_fragment_get, NULL,
731       GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET,
732       sizeof (struct FragmentGetRequest) },
733
734     { &handle_message_get, NULL,
735       GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET,
736       sizeof (struct MessageGetRequest) },
737
738     { &handle_message_get_fragment, NULL,
739       GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT,
740       sizeof (struct MessageGetFragmentRequest) },
741
742     { &handle_counters_get, NULL,
743       GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET,
744       sizeof (struct OperationRequest) },
745
746     { &handle_state_modify, NULL,
747       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY, 0 },
748
749     { &handle_state_sync, NULL,
750       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC, 0 },
751
752     { &handle_state_reset, NULL,
753       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET,
754       sizeof (struct OperationRequest) },
755
756     { &handle_state_hash_update, NULL,
757       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE,
758       sizeof (struct StateHashUpdateRequest) },
759
760     { &handle_state_get, NULL,
761       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET, 0 },
762
763     { &handle_state_get_prefix, NULL,
764       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX, 0 },
765
766     { NULL, NULL, 0, 0 }
767   };
768
769   cfg = c;
770
771   /* Loading database plugin */
772   char *database;
773   if (GNUNET_OK !=
774       GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database",
775                                              &database))
776   {
777     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
778   }
779   else
780   {
781     GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_psycstore_%s", database);
782     db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
783     GNUNET_free (database);
784   }
785   if (NULL == db)
786   {
787     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
788                 "Could not load database backend `%s'\n",
789                 db_lib_name);
790     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
791     return;
792   }
793
794   stats = GNUNET_STATISTICS_create ("psycstore", cfg);
795   GNUNET_SERVER_add_handlers (server, handlers);
796   nc = GNUNET_SERVER_notification_context_create (server, 1);
797   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
798                                 NULL);
799 }
800
801
802 /**
803  * The main function for the service.
804  *
805  * @param argc number of arguments from the command line
806  * @param argv command line arguments
807  * @return 0 ok, 1 on error
808  */
809 int
810 main (int argc, char *const *argv)
811 {
812   return (GNUNET_OK ==
813           GNUNET_SERVICE_run (argc, argv, "psycstore",
814                               GNUNET_SERVICE_OPTION_NONE,
815                               &run, NULL)) ? 0 : 1;
816 }
817
818
819 /* end of gnunet-service-psycstore.c */