first batch of license fixes (boring)
[oweals/gnunet.git] / src / psycutil / psyc_slicer.c
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2013 GNUnet e.V.
4  *
5  * GNUnet is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published
7  * by the Free Software Foundation, either version 3 of the License,
8  * or (at your 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  * Affero General Public License for more details.
14  */
15
16 /**
17  * @author Gabor X Toth
18  *
19  * @file
20  * PSYC Slicer API
21  */
22
23 #include <inttypes.h>
24
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_psyc_util_lib.h"
28
29 #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__)
30
31
32 /**
33  * Handle for a try-and-slice instance.
34  */
35 struct GNUNET_PSYC_Slicer
36 {
37   /**
38    * Method handlers: H(method_name) -> SlicerMethodCallbacks
39    */
40   struct GNUNET_CONTAINER_MultiHashMap *method_handlers;
41
42   /**
43    * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks
44    */
45   struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers;
46
47   /**
48    * Receive handle for incoming messages.
49    */
50   struct GNUNET_PSYC_ReceiveHandle *recv;
51
52   /**
53    * Currently being processed message.
54    */
55   const struct GNUNET_PSYC_MessageHeader *msg;
56
57   /**
58    * Currently being processed message part.
59    */
60   const struct GNUNET_MessageHeader *pmsg;
61
62   /**
63    * ID of currently being received message.
64    */
65   uint64_t message_id;
66
67   /**
68    * Fragment offset of currently being received message.
69    */
70   uint64_t fragment_offset;
71
72   /**
73    * Flags of currently being received message.
74    */
75   uint32_t flags;
76
77   /**
78    * Method name of currently being received message.
79    */
80   char *method_name;
81
82   /**
83    * Name of currently processed modifier.
84    */
85   char *mod_name;
86
87   /**
88    * Value of currently processed modifier.
89    */
90   char *mod_value;
91
92   /**
93    * Public key of the nym the current message originates from.
94    */
95   struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
96
97   /**
98    * Size of @a method_name (including terminating \0).
99    */
100   uint16_t method_name_size;
101
102   /**
103    * Size of @a modifier_name (including terminating \0).
104    */
105   uint16_t mod_name_size;
106
107   /**
108    * Size of modifier value fragment.
109    */
110   uint16_t mod_value_size;
111
112   /**
113    * Full size of modifier value.
114    */
115   uint16_t mod_full_value_size;
116
117   /**
118    * Remaining bytes from the value of the current modifier.
119    */
120   uint16_t mod_value_remaining;
121
122   /**
123    * Operator of currently processed modifier.
124    */
125   uint8_t mod_oper;
126 };
127
128
129 /**
130  * Callbacks for a slicer method handler.
131  */
132 struct SlicerMethodCallbacks
133 {
134   GNUNET_PSYC_MessageCallback msg_cb;
135   GNUNET_PSYC_MethodCallback method_cb;
136   GNUNET_PSYC_ModifierCallback modifier_cb;
137   GNUNET_PSYC_DataCallback data_cb;
138   GNUNET_PSYC_EndOfMessageCallback eom_cb;
139   void *cls;
140 };
141
142
143 struct SlicerMethodRemoveClosure
144 {
145   struct GNUNET_PSYC_Slicer *slicer;
146   struct SlicerMethodCallbacks rm_cbs;
147 };
148
149
150 /**
151  * Callbacks for a slicer method handler.
152  */
153 struct SlicerModifierCallbacks
154 {
155   GNUNET_PSYC_ModifierCallback modifier_cb;
156   void *cls;
157 };
158
159
160 struct SlicerModifierRemoveClosure
161 {
162   struct GNUNET_PSYC_Slicer *slicer;
163   struct SlicerModifierCallbacks rm_cbs;
164 };
165
166
167 /**
168  * Call a method handler for an incoming message part.
169  */
170 static int
171 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
172                               void *value)
173 {
174   struct GNUNET_PSYC_Slicer *slicer = cls;
175   const struct GNUNET_MessageHeader *pmsg = slicer->pmsg;
176   struct SlicerMethodCallbacks *cbs = value;
177
178   uint16_t ptype = ntohs (pmsg->type);
179   switch (ptype)
180   {
181   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
182   {
183     if (NULL != cbs->msg_cb)
184       cbs->msg_cb (cbs->cls, slicer->msg);
185     if (NULL == cbs->method_cb)
186       break;
187     struct GNUNET_PSYC_MessageMethod *
188       meth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
189     cbs->method_cb (cbs->cls, slicer->msg, meth, slicer->message_id,
190                     slicer->method_name);
191     break;
192   }
193
194   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
195   {
196     if (NULL == cbs->modifier_cb)
197       break;
198     struct GNUNET_PSYC_MessageModifier *
199       mod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
200     cbs->modifier_cb (cbs->cls, slicer->msg, &mod->header, slicer->message_id,
201                       mod->oper, (const char *) &mod[1],
202                       (const void *) &mod[1] + ntohs (mod->name_size),
203                       ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size),
204                       ntohs (mod->value_size));
205     break;
206   }
207
208   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
209   {
210     if (NULL == cbs->modifier_cb)
211       break;
212     cbs->modifier_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
213                       slicer->mod_oper, slicer->mod_name, &pmsg[1],
214                       ntohs (pmsg->size) - sizeof (*pmsg),
215                       slicer->mod_full_value_size);
216     break;
217   }
218
219   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
220   {
221     if (NULL == cbs->data_cb)
222       break;
223     cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
224                   &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg));
225     break;
226   }
227
228   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
229     if (NULL == cbs->eom_cb)
230       break;
231     cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO);
232     break;
233
234   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
235     if (NULL == cbs->eom_cb)
236       break;
237     cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES);
238     break;
239   }
240   return GNUNET_YES;
241 }
242
243
244 /**
245  * Call a method handler for an incoming message part.
246  */
247 static int
248 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
249                                 void *value)
250 {
251   struct GNUNET_PSYC_Slicer *slicer = cls;
252   struct SlicerModifierCallbacks *cbs = value;
253
254   cbs->modifier_cb (cbs->cls, slicer->msg, slicer->pmsg, slicer->message_id,
255                     slicer->mod_oper, slicer->mod_name, slicer->mod_value,
256                     slicer->mod_value_size, slicer->mod_full_value_size);
257   return GNUNET_YES;
258 }
259
260
261 /**
262  * Process an incoming message and call matching handlers.
263  *
264  * @param slicer
265  *        The slicer to use.
266  * @param msg
267  *        The message as it arrived from the network.
268  */
269 void
270 GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
271                             const struct GNUNET_PSYC_MessageHeader *msg)
272 {
273   GNUNET_PSYC_receive_message (slicer->recv, msg);
274 }
275
276
277 /**
278  * Process an incoming message part and call matching handlers.
279  *
280  * @param cls
281  *        Closure.
282  * @param message_id
283  *        ID of the message.
284  * @param flags
285  *        Flags for the message.
286  *        @see enum GNUNET_PSYC_MessageFlags
287  * @param msg
288  *        The message part. as it arrived from the network.
289  */
290 void
291 GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
292                                  const struct GNUNET_PSYC_MessageHeader *msg,
293                                  const struct GNUNET_MessageHeader *pmsg)
294 {
295   slicer->msg = msg;
296   slicer->pmsg = pmsg;
297
298   uint64_t message_id = GNUNET_ntohll (msg->message_id);
299
300   uint16_t ptype = ntohs (pmsg->type);
301   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
302   {
303     struct GNUNET_PSYC_MessageMethod *
304       meth = (struct GNUNET_PSYC_MessageMethod *) pmsg;
305     slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
306     slicer->method_name = GNUNET_malloc (slicer->method_name_size);
307     GNUNET_memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
308      slicer->message_id = message_id;
309   }
310   else
311   {
312     GNUNET_assert (message_id == slicer->message_id);
313   }
314
315   char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key);
316   LOG (GNUNET_ERROR_TYPE_DEBUG,
317        "Slicer received message of type %u and size %u, "
318        "with ID %" PRIu64 " and method %s from %s\n",
319        ptype, ntohs (pmsg->size), message_id, slicer->method_name, nym_str);
320   GNUNET_free (nym_str);
321
322   /* try-and-slice modifier */
323
324   switch (ptype)
325   {
326   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
327   {
328     struct GNUNET_PSYC_MessageModifier *
329       mod = (struct GNUNET_PSYC_MessageModifier *) pmsg;
330     slicer->mod_oper = mod->oper;
331     slicer->mod_name_size = ntohs (mod->name_size);
332     slicer->mod_name = GNUNET_malloc (slicer->mod_name_size);
333     GNUNET_memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size);
334     slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size;
335     slicer->mod_full_value_size = ntohs (mod->value_size);
336     slicer->mod_value_remaining = slicer->mod_full_value_size;
337     slicer->mod_value_size
338       = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size;
339     // fall through
340   }
341   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
342     if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
343     {
344       slicer->mod_value = (char *) &pmsg[1];
345       slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg);
346     }
347     slicer->mod_value_remaining -= slicer->mod_value_size;
348     char *name = GNUNET_malloc (slicer->mod_name_size);
349     GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size);
350     do
351     {
352       struct GNUNET_HashCode key;
353       uint16_t name_len = strlen (name);
354       GNUNET_CRYPTO_hash (name, name_len, &key);
355       GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
356                                                   slicer_modifier_handler_notify,
357                                                   slicer);
358       char *p = strrchr (name, '_');
359       if (NULL == p)
360         break;
361       *p = '\0';
362     } while (1);
363     GNUNET_free (name);
364   }
365
366   /* try-and-slice method */
367
368   char *name = GNUNET_malloc (slicer->method_name_size);
369   GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size);
370   do
371   {
372     struct GNUNET_HashCode key;
373     uint16_t name_len = strlen (name);
374     GNUNET_CRYPTO_hash (name, name_len, &key);
375     GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
376                                                 slicer_method_handler_notify,
377                                                 slicer);
378     char *p = strrchr (name, '_');
379     if (NULL == p)
380       break;
381     *p = '\0';
382   } while (1);
383   GNUNET_free (name);
384
385   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
386     GNUNET_free (slicer->method_name);
387
388   if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
389   {
390     GNUNET_free (slicer->mod_name);
391     slicer->mod_name = NULL;
392     slicer->mod_name_size = 0;
393     slicer->mod_value_size = 0;
394     slicer->mod_full_value_size = 0;
395     slicer->mod_oper = 0;
396   }
397
398   slicer->msg = NULL;
399   slicer->pmsg = NULL;
400 }
401
402
403 /**
404  * Create a try-and-slice instance.
405  *
406  * A slicer processes incoming messages and notifies callbacks about matching
407  * methods or modifiers encountered.
408  *
409  * @return A new try-and-slice construct.
410  */
411 struct GNUNET_PSYC_Slicer *
412 GNUNET_PSYC_slicer_create (void)
413 {
414   struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
415   slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
416   slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
417   slicer->recv = GNUNET_PSYC_receive_create (NULL,
418                                              (GNUNET_PSYC_MessagePartCallback)
419                                              GNUNET_PSYC_slicer_message_part,
420                                              slicer);
421   return slicer;
422 }
423
424
425 /**
426  * Add a method to the try-and-slice instance.
427  *
428  * The callbacks are called for messages with a matching @a method_name prefix.
429  *
430  * @param slicer
431  *        The try-and-slice instance to extend.
432  * @param method_name
433  *        Name of the given method, use empty string to match all.
434  * @param method_cb
435  *        Method handler invoked upon a matching message.
436  * @param modifier_cb
437  *        Modifier handler, invoked after @a method_cb
438  *        for each modifier in the message.
439  * @param data_cb
440  *        Data handler, invoked after @a modifier_cb for each data fragment.
441  * @param eom_cb
442  *        Invoked upon reaching the end of a matching message.
443  * @param cls
444  *        Closure for the callbacks.
445  */
446 void
447 GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
448                                const char *method_name,
449                                GNUNET_PSYC_MessageCallback msg_cb,
450                                GNUNET_PSYC_MethodCallback method_cb,
451                                GNUNET_PSYC_ModifierCallback modifier_cb,
452                                GNUNET_PSYC_DataCallback data_cb,
453                                GNUNET_PSYC_EndOfMessageCallback eom_cb,
454                                void *cls)
455 {
456   struct GNUNET_HashCode key;
457   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
458
459   struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
460   cbs->msg_cb = msg_cb,
461   cbs->method_cb = method_cb;
462   cbs->modifier_cb = modifier_cb;
463   cbs->data_cb = data_cb;
464   cbs->eom_cb = eom_cb;
465   cbs->cls = cls;
466
467   GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
468                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
469 }
470
471
472 static int
473 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
474 {
475   struct SlicerMethodRemoveClosure *rm_cls = cls;
476   struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
477   struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
478   struct SlicerMethodCallbacks *cbs = value;
479
480   if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb)
481       && (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb)
482       && (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb)
483       && (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb)
484       && (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb))
485   {
486     GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
487     GNUNET_free (cbs);
488     return GNUNET_NO;
489   }
490   return GNUNET_YES;
491 }
492
493
494 /**
495  * Remove a registered method from the try-and-slice instance.
496  *
497  * Removes one matching handler registered with the given
498  * @a method_name and  callbacks.
499  *
500  * @param slicer
501  *        The try-and-slice instance.
502  * @param method_name
503  *        Name of the method to remove.
504  * @param method_cb
505  *        Method handler.
506  * @param modifier_cb
507  *        Modifier handler.
508  * @param data_cb
509  *        Data handler.
510  * @param eom_cb
511  *        End of message handler.
512  *
513  * @return #GNUNET_OK if a method handler was removed,
514  *         #GNUNET_NO if no handler matched the given method name and callbacks.
515  */
516 int
517 GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
518                                   const char *method_name,
519                                   GNUNET_PSYC_MessageCallback msg_cb,
520                                   GNUNET_PSYC_MethodCallback method_cb,
521                                   GNUNET_PSYC_ModifierCallback modifier_cb,
522                                   GNUNET_PSYC_DataCallback data_cb,
523                                   GNUNET_PSYC_EndOfMessageCallback eom_cb)
524 {
525   struct GNUNET_HashCode key;
526   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
527
528   struct SlicerMethodRemoveClosure rm_cls;
529   rm_cls.slicer = slicer;
530   struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
531   rm_cbs->msg_cb = msg_cb;
532   rm_cbs->method_cb = method_cb;
533   rm_cbs->modifier_cb = modifier_cb;
534   rm_cbs->data_cb = data_cb;
535   rm_cbs->eom_cb = eom_cb;
536
537   return
538     (GNUNET_SYSERR
539      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
540                                                     slicer_method_remove,
541                                                     &rm_cls))
542     ? GNUNET_NO
543     : GNUNET_OK;
544 }
545
546
547 /**
548  * Watch a place for changed objects.
549  *
550  * @param slicer
551  *        The try-and-slice instance.
552  * @param object_filter
553  *        Object prefix to match.
554  * @param modifier_cb
555  *        Function to call when encountering a state modifier.
556  * @param cls
557  *        Closure for callback.
558  */
559 void
560 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
561                                  const char *object_filter,
562                                  GNUNET_PSYC_ModifierCallback modifier_cb,
563                                  void *cls)
564 {
565   struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
566   cbs->modifier_cb = modifier_cb;
567   cbs->cls = cls;
568
569   struct GNUNET_HashCode key;
570   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
571   GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
572                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
573 }
574
575
576 static int
577 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
578 {
579   struct SlicerModifierRemoveClosure *rm_cls = cls;
580   struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
581   struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
582   struct SlicerModifierCallbacks *cbs = value;
583
584   if (cbs->modifier_cb == rm_cbs->modifier_cb)
585   {
586     GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
587     GNUNET_free (cbs);
588     return GNUNET_NO;
589   }
590   return GNUNET_YES;
591 }
592
593
594 /**
595  * Remove a registered modifier from the try-and-slice instance.
596  *
597  * Removes one matching handler registered with the given
598  * @a object_filter and @a modifier_cb.
599  *
600  * @param slicer
601  *        The try-and-slice instance.
602  * @param object_filter
603  *        Object prefix to match.
604  * @param modifier_cb
605  *        Function to call when encountering a state modifier changes.
606  */
607 int
608 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
609                                     const char *object_filter,
610                                     GNUNET_PSYC_ModifierCallback modifier_cb)
611 {
612   struct GNUNET_HashCode key;
613   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
614
615   struct SlicerModifierRemoveClosure rm_cls;
616   rm_cls.slicer = slicer;
617   struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
618   rm_cbs->modifier_cb = modifier_cb;
619
620   return
621     (GNUNET_SYSERR
622      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
623                                                     slicer_modifier_remove,
624                                                     &rm_cls))
625     ? GNUNET_NO
626     : GNUNET_OK;
627  }
628
629
630 static int
631 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
632 {
633   struct SlicerMethodCallbacks *cbs = value;
634   GNUNET_free (cbs);
635   return GNUNET_YES;
636 }
637
638
639 static int
640 slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
641 {
642   struct SlicerModifierCallbacks *cbs = value;
643   GNUNET_free (cbs);
644   return GNUNET_YES;
645 }
646
647
648 /**
649  * Remove all registered method handlers.
650  *
651  * @param slicer
652  *        Slicer to clear.
653  */
654 void
655 GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
656 {
657   GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
658                                          slicer_method_free, NULL);
659   GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers);
660 }
661
662
663 /**
664  * Remove all registered modifier handlers.
665  *
666  * @param slicer
667  *        Slicer to clear.
668  */
669 void
670 GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
671 {
672   GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
673                                          slicer_modifier_free, NULL);
674   GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers);
675 }
676
677
678 /**
679  * Remove all registered method & modifier handlers.
680  *
681  * @param slicer
682  *        Slicer to clear.
683  */
684 void
685 GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
686 {
687   GNUNET_PSYC_slicer_method_clear (slicer);
688   GNUNET_PSYC_slicer_modifier_clear (slicer);
689 }
690
691
692 /**
693  * Destroy a given try-and-slice instance.
694  *
695  * @param slicer
696  *        Slicer to destroy
697  */
698 void
699 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
700 {
701   GNUNET_PSYC_slicer_clear (slicer);
702   GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
703   GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers);
704   GNUNET_PSYC_receive_destroy (slicer->recv);
705   GNUNET_free (slicer);
706 }