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