- document string termination
[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
126 struct SendClosure
127 {
128   struct GNUNET_SERVER_Client *client;
129   uint64_t op_id;
130 };
131
132
133 static int
134 send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg,
135                enum GNUNET_PSYCSTORE_MessageFlags flags)
136 {
137   struct SendClosure *sc = cls;
138   struct FragmentResult *res;
139   size_t msg_size = ntohs (msg->header.size);
140
141   res = GNUNET_malloc (sizeof (struct FragmentResult) + msg_size);
142   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT);
143   res->header.size = htons (sizeof (struct FragmentResult) + msg_size);
144   res->op_id = sc->op_id;
145   res->psycstore_flags = htonl (flags);
146   memcpy (&res[1], msg, msg_size);
147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148               "Sending fragment %ld to client\n",
149               GNUNET_ntohll (msg->fragment_id));
150   GNUNET_free (msg);
151   GNUNET_SERVER_notification_context_add (nc, sc->client);
152   GNUNET_SERVER_notification_context_unicast (nc, sc->client, &res->header,
153                                               GNUNET_NO);
154   GNUNET_free (res);
155   return GNUNET_OK;
156 }
157
158
159 static int
160 send_state_var (void *cls, const char *name,
161                 const void *value, size_t value_size)
162 {
163   struct SendClosure *sc = cls;
164   struct StateResult *res;
165   size_t name_size = strlen (name) + 1;
166
167   res = GNUNET_malloc (sizeof (struct StateResult) + name_size + value_size);
168   res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE);
169   res->header.size = htons (sizeof (struct StateResult) + name_size + value_size);
170   res->op_id = sc->op_id;
171   res->name_size = htons (name_size);
172   memcpy (&res[1], name, name_size);
173   memcpy ((char *) &res[1] + name_size, value, value_size);
174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
175               "Sending state variable %s to client\n", name);
176   GNUNET_SERVER_notification_context_add (nc, sc->client);
177   GNUNET_SERVER_notification_context_unicast (nc, sc->client, &res->header,
178                                               GNUNET_NO);
179   GNUNET_free (res);
180   return GNUNET_OK;
181 }
182
183
184 static void
185 handle_membership_store (void *cls,
186                          struct GNUNET_SERVER_Client *client,
187                          const struct GNUNET_MessageHeader *msg)
188 {
189   const struct MembershipStoreRequest *req =
190     (const struct MembershipStoreRequest *) msg;
191
192   int ret = db->membership_store (db->cls, &req->channel_key, &req->slave_key,
193                                   ntohl (req->did_join),
194                                   GNUNET_ntohll (req->announced_at),
195                                   GNUNET_ntohll (req->effective_since),
196                                   GNUNET_ntohll (req->group_generation));
197
198   if (ret != GNUNET_OK)
199     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
200                 _("Failed to store membership information!\n"));
201
202   send_result_code (client, ret, req->op_id, NULL);
203   GNUNET_SERVER_receive_done (client, GNUNET_OK);
204 }
205
206
207 static void
208 handle_membership_test (void *cls,
209                         struct GNUNET_SERVER_Client *client,
210                         const struct GNUNET_MessageHeader *msg)
211 {
212   const struct MembershipTestRequest *req =
213     (const struct MembershipTestRequest *) msg;
214
215   int ret = db->membership_test (db->cls, &req->channel_key, &req->slave_key,
216                                  GNUNET_ntohll (req->message_id));
217   switch (ret)
218   {
219   case GNUNET_YES:
220   case GNUNET_NO:
221     break;
222   default:
223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
224                 _("Failed to test membership!\n"));
225   }
226
227   send_result_code (client, ret, req->op_id, NULL);
228   GNUNET_SERVER_receive_done (client, GNUNET_OK);
229 }
230
231
232 static void
233 handle_fragment_store (void *cls,
234                        struct GNUNET_SERVER_Client *client,
235                        const struct GNUNET_MessageHeader *msg)
236 {
237   const struct FragmentStoreRequest *req =
238     (const struct FragmentStoreRequest *) msg;
239
240   int ret = db->fragment_store (db->cls, &req->channel_key,
241                                 (const struct GNUNET_MULTICAST_MessageHeader *)
242                                 &req[1], ntohl (req->psycstore_flags));
243
244   if (ret != GNUNET_OK)
245     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
246                 _("Failed to store fragment!\n"));
247
248   send_result_code (client, ret, req->op_id, NULL);
249   GNUNET_SERVER_receive_done (client, GNUNET_OK);
250 }
251
252
253 static void
254 handle_fragment_get (void *cls,
255                      struct GNUNET_SERVER_Client *client,
256                      const struct GNUNET_MessageHeader *msg)
257 {
258   const struct FragmentGetRequest *req
259     = (const struct FragmentGetRequest *) msg;
260   struct SendClosure sc = { .op_id = req->op_id, .client = client };
261
262   int ret = db->fragment_get (db->cls, &req->channel_key,
263                               GNUNET_ntohll (req->fragment_id),
264                               &send_fragment, &sc);
265   switch (ret)
266   {
267   case GNUNET_YES:
268   case GNUNET_NO:
269     break;
270   default:
271     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
272                 _("Failed to get fragment!\n"));
273   }
274
275   send_result_code (client, ret, req->op_id, NULL);
276   GNUNET_SERVER_receive_done (client, GNUNET_OK);
277 }
278
279
280 static void
281 handle_message_get (void *cls,
282                     struct GNUNET_SERVER_Client *client,
283                     const struct GNUNET_MessageHeader *msg)
284 {
285   const struct MessageGetRequest *req = (const struct MessageGetRequest *) msg;
286   struct SendClosure sc = { .op_id = req->op_id, .client = client };
287   uint64_t ret_frags = 0;
288   int64_t ret = db->message_get (db->cls, &req->channel_key,
289                                  GNUNET_ntohll (req->message_id),
290                                  &ret_frags, &send_fragment, &sc);
291   switch (ret)
292   {
293   case GNUNET_YES:
294   case GNUNET_NO:
295     break;
296   default:
297     ret_frags = ret;
298     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
299                 _("Failed to get message!\n"));
300   }
301
302   send_result_code (client, ret_frags, req->op_id, NULL);
303   GNUNET_SERVER_receive_done (client, GNUNET_OK);
304 }
305
306
307 static void
308 handle_message_get_fragment (void *cls,
309                              struct GNUNET_SERVER_Client *client,
310                              const struct GNUNET_MessageHeader *msg)
311 {
312   const struct MessageGetFragmentRequest *req =
313     (const struct MessageGetFragmentRequest *) msg;
314
315   struct SendClosure sc = { .op_id = req->op_id, .client = client };
316
317   int ret = db->message_get_fragment (db->cls, &req->channel_key,
318                                       GNUNET_ntohll (req->message_id),
319                                       GNUNET_ntohll (req->fragment_offset),
320                                       &send_fragment, &sc);
321   switch (ret)
322   {
323   case GNUNET_YES:
324   case GNUNET_NO:
325     break;
326   default:
327     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328                 _("Failed to get message fragment!\n"));
329   }
330
331   send_result_code (client, ret, req->op_id, NULL);
332   GNUNET_SERVER_receive_done (client, GNUNET_OK);
333 }
334
335
336 static void
337 handle_counters_get (void *cls,
338                      struct GNUNET_SERVER_Client *client,
339                      const struct GNUNET_MessageHeader *msg)
340 {
341   const struct OperationRequest *req = (const struct OperationRequest *) msg;
342   struct CountersResult res = { {0} };
343
344   int ret = db->counters_message_get (db->cls, &req->channel_key,
345                                       &res.max_fragment_id, &res.max_message_id,
346                                       &res.max_group_generation);
347   switch (ret)
348   {
349   case GNUNET_OK:
350     ret = db->counters_state_get (db->cls, &req->channel_key,
351                                   &res.max_state_message_id);
352   case GNUNET_NO:
353     break;
354   default:
355     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
356                 _("Failed to get master counters!\n"));
357   }
358
359   res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS);
360   res.header.size = htons (sizeof (res));
361   res.result_code = htonl (ret);
362   res.op_id = req->op_id;
363   res.max_fragment_id = GNUNET_htonll (res.max_fragment_id);
364   res.max_message_id = GNUNET_htonll (res.max_message_id);
365   res.max_group_generation = GNUNET_htonll (res.max_group_generation);
366   res.max_state_message_id = GNUNET_htonll (res.max_state_message_id);
367
368   GNUNET_SERVER_notification_context_add (nc, client);
369   GNUNET_SERVER_notification_context_unicast (nc, client, &res.header,
370                                               GNUNET_NO);
371
372   GNUNET_SERVER_receive_done (client, GNUNET_OK);
373 }
374
375
376 /* FIXME: stop processing further state modify messages after an error */
377 static void
378 handle_state_modify (void *cls,
379                      struct GNUNET_SERVER_Client *client,
380                      const struct GNUNET_MessageHeader *msg)
381 {
382   const struct StateModifyRequest *req
383     = (const struct StateModifyRequest *) msg;
384
385   int ret = GNUNET_SYSERR;
386   const char *name = (const char *) &req[1];
387   uint16_t name_size = ntohs (req->name_size);
388
389   if (name_size <= 2 || '\0' != name[name_size - 1])
390   {
391     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392                 _("Tried to set invalid state variable name!\n"));
393     GNUNET_break_op (0);
394   }
395   else
396   {
397     ret = GNUNET_OK;
398
399     if (req->flags & STATE_OP_FIRST)
400     {
401       ret = db->state_modify_begin (db->cls, &req->channel_key,
402                                     GNUNET_ntohll (req->message_id),
403                                     GNUNET_ntohll (req->state_delta));
404     }
405     if (ret != GNUNET_OK)
406     {
407       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
408                   _("Failed to begin modifying state!\n"));
409     }
410     else
411     {
412       switch (req->oper)
413       {
414       case GNUNET_ENV_OP_ASSIGN:
415         ret = db->state_modify_set (db->cls, &req->channel_key,
416                                     (const char *) &req[1],
417                                     name + ntohs (req->name_size),
418                                     ntohs (req->header.size) - sizeof (*req)
419                                     - ntohs (req->name_size));
420         break;
421       default:
422 #if TODO
423         ret = GNUNET_ENV_operation ((const char *) &req[1],
424                                     current_value, current_value_size,
425                                     req->oper, name + ntohs (req->name_size),
426                                     ntohs (req->header.size) - sizeof (*req)
427                                     - ntohs (req->name_size), &value, &value_size);
428 #endif
429         ret = GNUNET_SYSERR;
430         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
431                     _("Unknown operator: %c\n"), req->oper);
432       }
433     }
434
435     if (GNUNET_OK == ret && req->flags & STATE_OP_LAST)
436     {
437       ret = db->state_modify_end (db->cls, &req->channel_key,
438                                   GNUNET_ntohll (req->message_id));
439       if (ret != GNUNET_OK)
440         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
441                     _("Failed to end modifying state!\n"));
442     }
443   }
444   send_result_code (client, ret, req->op_id, NULL);
445   GNUNET_SERVER_receive_done (client, GNUNET_OK);
446 }
447
448
449 /* FIXME: stop processing further state sync messages after an error */
450 static void
451 handle_state_sync (void *cls,
452                    struct GNUNET_SERVER_Client *client,
453                    const struct GNUNET_MessageHeader *msg)
454 {
455   const struct StateSyncRequest *req
456     = (const struct StateSyncRequest *) msg;
457
458   int ret = GNUNET_SYSERR;
459   const char *name = (const char *) &req[1];
460   uint16_t name_size = ntohs (req->name_size);
461
462   if (name_size <= 2 || '\0' != name[name_size - 1])
463   {
464     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
465                 _("Tried to set invalid state variable name!\n"));
466     GNUNET_break_op (0);
467   }
468   else
469   {
470     ret = GNUNET_OK;
471
472     if (req->flags & STATE_OP_FIRST)
473     {
474       ret = db->state_sync_begin (db->cls, &req->channel_key);
475     }
476     if (ret != GNUNET_OK)
477     {
478       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
479                   _("Failed to begin synchronizing state!\n"));
480     }
481     else
482     {
483       ret = db->state_sync_set (db->cls, &req->channel_key, name,
484                                 name + ntohs (req->name_size),
485                                 ntohs (req->header.size) - sizeof (*req)
486                                 - ntohs (req->name_size));
487     }
488
489     if (GNUNET_OK == ret && req->flags & STATE_OP_LAST)
490     {
491       ret = db->state_sync_end (db->cls, &req->channel_key,
492                                 GNUNET_ntohll (req->message_id));
493       if (ret != GNUNET_OK)
494         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
495                     _("Failed to end synchronizing state!\n"));
496     }
497   }
498   send_result_code (client, ret, req->op_id, NULL);
499   GNUNET_SERVER_receive_done (client, GNUNET_OK);
500 }
501
502
503 static void
504 handle_state_reset (void *cls,
505                     struct GNUNET_SERVER_Client *client,
506                     const struct GNUNET_MessageHeader *msg)
507 {
508   const struct OperationRequest *req =
509     (const struct OperationRequest *) msg;
510
511   int ret = db->state_reset (db->cls, &req->channel_key);
512
513   if (ret != GNUNET_OK)
514     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
515                 _("Failed to reset state!\n"));
516
517   send_result_code (client, ret, req->op_id, NULL);
518   GNUNET_SERVER_receive_done (client, GNUNET_OK);
519 }
520
521
522 static void
523 handle_state_hash_update (void *cls,
524                           struct GNUNET_SERVER_Client *client,
525                           const struct GNUNET_MessageHeader *msg)
526 {
527   const struct OperationRequest *req =
528     (const struct OperationRequest *) msg;
529
530   int ret = db->state_reset (db->cls, &req->channel_key);
531
532   if (ret != GNUNET_OK)
533     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
534                 _("Failed to reset state!\n"));
535
536   send_result_code (client, ret, req->op_id, NULL);
537   GNUNET_SERVER_receive_done (client, GNUNET_OK);
538 }
539
540
541 static void
542 handle_state_get (void *cls,
543                   struct GNUNET_SERVER_Client *client,
544                   const struct GNUNET_MessageHeader *msg)
545 {
546   const struct OperationRequest *req =
547     (const struct OperationRequest *) msg;
548
549   struct SendClosure sc = { .op_id = req->op_id, .client = client };
550   int64_t ret = GNUNET_SYSERR;
551   const char *name = (const char *) &req[1];
552   uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
553
554   if (name_size <= 2 || '\0' != name[name_size - 1])
555   {
556     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
557                 _("Tried to get invalid state variable name!\n"));
558     GNUNET_break (0);
559   }
560   else
561   {
562     ret = db->state_get (db->cls, &req->channel_key, name,
563                          &send_state_var, &sc);
564     if (GNUNET_NO == ret && name_size >= 5) /* min: _a_b\0 */
565     {
566       char *p, *n = GNUNET_malloc (name_size);
567       memcpy (n, name, name_size);
568       while (&n[1] < (p = strrchr (n, '_')) && GNUNET_NO == ret)
569       {
570         *p = '\0';
571         ret = db->state_get (db->cls, &req->channel_key, n,
572                              &send_state_var, &sc);
573       }
574       GNUNET_free (n);
575     }
576   }
577   switch (ret)
578   {
579   case GNUNET_OK:
580   case GNUNET_NO:
581     break;
582   default:
583     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
584                 _("Failed to get state variable!\n"));
585   }
586
587   send_result_code (client, ret, req->op_id, NULL);
588   GNUNET_SERVER_receive_done (client, GNUNET_OK);
589 }
590
591
592 static void
593 handle_state_get_prefix (void *cls,
594                          struct GNUNET_SERVER_Client *client,
595                          const struct GNUNET_MessageHeader *msg)
596 {
597   const struct OperationRequest *req =
598     (const struct OperationRequest *) msg;
599
600   struct SendClosure sc = { .op_id = req->op_id, .client = client };
601   int64_t ret = GNUNET_SYSERR;
602   const char *name = (const char *) &req[1];
603   uint16_t name_size = ntohs (req->header.size) - sizeof (*req);
604
605   if (name_size <= 1 || '\0' != name[name_size - 1])
606   {
607     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608                 _("Tried to get invalid state variable name!\n"));
609     GNUNET_break (0);
610   }
611   else
612   {
613     ret = db->state_get_prefix (db->cls, &req->channel_key, name,
614                                 &send_state_var, &sc);
615   }
616   switch (ret)
617   {
618   case GNUNET_OK:
619   case GNUNET_NO:
620     break;
621   default:
622     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
623                 _("Failed to get state variable!\n"));
624   }
625
626   send_result_code (client, ret, req->op_id, NULL);
627   GNUNET_SERVER_receive_done (client, GNUNET_OK);
628 }
629
630
631 /**
632  * Initialize the PSYCstore service.
633  *
634  * @param cls Closure.
635  * @param server The initialized server.
636  * @param c Configuration to use.
637  */
638 static void
639 run (void *cls, struct GNUNET_SERVER_Handle *server,
640      const struct GNUNET_CONFIGURATION_Handle *c)
641 {
642   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
643     { &handle_membership_store, NULL,
644       GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE,
645       sizeof (struct MembershipStoreRequest) },
646
647     { &handle_membership_test, NULL,
648       GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST,
649       sizeof (struct MembershipTestRequest) },
650
651     { &handle_fragment_store, NULL,
652       GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE, 0, },
653
654     { &handle_fragment_get, NULL,
655       GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET,
656       sizeof (struct FragmentGetRequest) },
657
658     { &handle_message_get, NULL,
659       GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET,
660       sizeof (struct MessageGetRequest) },
661
662     { &handle_message_get_fragment, NULL,
663       GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT,
664       sizeof (struct MessageGetFragmentRequest) },
665
666     { &handle_counters_get, NULL,
667       GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET,
668       sizeof (struct OperationRequest) },
669
670     { &handle_state_modify, NULL,
671       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY, 0 },
672
673     { &handle_state_sync, NULL,
674       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC, 0 },
675
676     { &handle_state_reset, NULL,
677       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET,
678       sizeof (struct OperationRequest) },
679
680     { &handle_state_hash_update, NULL,
681       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE,
682       sizeof (struct StateHashUpdateRequest) },
683
684     { &handle_state_get, NULL,
685       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET, 0 },
686
687     { &handle_state_get_prefix, NULL,
688       GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX, 0 },
689
690     { NULL, NULL, 0, 0 }
691   };
692
693   cfg = c;
694
695   /* Loading database plugin */
696   char *database;
697   if (GNUNET_OK !=
698       GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database",
699                                              &database))
700   {
701     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
702   }
703   else
704   {
705     GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_psycstore_%s", database);
706     db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg);
707     GNUNET_free (database);
708   }
709   if (NULL == db)
710   {
711     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
712                 "Could not load database backend `%s'\n",
713                 db_lib_name);
714     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
715     return;
716   }
717
718   stats = GNUNET_STATISTICS_create ("psycstore", cfg);
719   GNUNET_SERVER_add_handlers (server, handlers);
720   nc = GNUNET_SERVER_notification_context_create (server, 1);
721   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
722                                 NULL);
723 }
724
725
726 /**
727  * The main function for the service.
728  *
729  * @param argc number of arguments from the command line
730  * @param argv command line arguments
731  * @return 0 ok, 1 on error
732  */
733 int
734 main (int argc, char *const *argv)
735 {
736   return (GNUNET_OK ==
737           GNUNET_SERVICE_run (argc, argv, "psycstore",
738                               GNUNET_SERVICE_OPTION_NONE,
739                               &run, NULL)) ? 0 : 1;
740 }
741
742
743 /* end of gnunet-service-psycstore.c */