psyc, social: switch to MQ
[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     GNUNET_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     GNUNET_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     // fall through
345   }
346   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
347     if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
348     {
349       slicer->mod_value = (char *) &pmsg[1];
350       slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg);
351     }
352     slicer->mod_value_remaining -= slicer->mod_value_size;
353     char *name = GNUNET_malloc (slicer->mod_name_size);
354     GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size);
355     do
356     {
357       struct GNUNET_HashCode key;
358       uint16_t name_len = strlen (name);
359       GNUNET_CRYPTO_hash (name, name_len, &key);
360       GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
361                                                   slicer_modifier_handler_notify,
362                                                   slicer);
363       char *p = strrchr (name, '_');
364       if (NULL == p)
365         break;
366       *p = '\0';
367     } while (1);
368     GNUNET_free (name);
369   }
370
371   /* try-and-slice method */
372
373   char *name = GNUNET_malloc (slicer->method_name_size);
374   GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size);
375   do
376   {
377     struct GNUNET_HashCode key;
378     uint16_t name_len = strlen (name);
379     GNUNET_CRYPTO_hash (name, name_len, &key);
380     GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
381                                                 slicer_method_handler_notify,
382                                                 slicer);
383     char *p = strrchr (name, '_');
384     if (NULL == p)
385       break;
386     *p = '\0';
387   } while (1);
388   GNUNET_free (name);
389
390   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
391     GNUNET_free (slicer->method_name);
392
393   if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
394   {
395     GNUNET_free (slicer->mod_name);
396     slicer->mod_name = NULL;
397     slicer->mod_name_size = 0;
398     slicer->mod_value_size = 0;
399     slicer->mod_full_value_size = 0;
400     slicer->mod_oper = 0;
401   }
402
403   slicer->msg = NULL;
404   slicer->pmsg = NULL;
405 }
406
407
408 /**
409  * Create a try-and-slice instance.
410  *
411  * A slicer processes incoming messages and notifies callbacks about matching
412  * methods or modifiers encountered.
413  *
414  * @return A new try-and-slice construct.
415  */
416 struct GNUNET_PSYC_Slicer *
417 GNUNET_PSYC_slicer_create (void)
418 {
419   struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
420   slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
421   slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
422   slicer->recv = GNUNET_PSYC_receive_create (NULL,
423                                              (GNUNET_PSYC_MessagePartCallback)
424                                              GNUNET_PSYC_slicer_message_part,
425                                              slicer);
426   return slicer;
427 }
428
429
430 /**
431  * Add a method to the try-and-slice instance.
432  *
433  * The callbacks are called for messages with a matching @a method_name prefix.
434  *
435  * @param slicer
436  *        The try-and-slice instance to extend.
437  * @param method_name
438  *        Name of the given method, use empty string to match all.
439  * @param method_cb
440  *        Method handler invoked upon a matching message.
441  * @param modifier_cb
442  *        Modifier handler, invoked after @a method_cb
443  *        for each modifier in the message.
444  * @param data_cb
445  *        Data handler, invoked after @a modifier_cb for each data fragment.
446  * @param eom_cb
447  *        Invoked upon reaching the end of a matching message.
448  * @param cls
449  *        Closure for the callbacks.
450  */
451 void
452 GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
453                                const char *method_name,
454                                GNUNET_PSYC_MessageCallback msg_cb,
455                                GNUNET_PSYC_MethodCallback method_cb,
456                                GNUNET_PSYC_ModifierCallback modifier_cb,
457                                GNUNET_PSYC_DataCallback data_cb,
458                                GNUNET_PSYC_EndOfMessageCallback eom_cb,
459                                void *cls)
460 {
461   struct GNUNET_HashCode key;
462   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
463
464   struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
465   cbs->msg_cb = msg_cb,
466   cbs->method_cb = method_cb;
467   cbs->modifier_cb = modifier_cb;
468   cbs->data_cb = data_cb;
469   cbs->eom_cb = eom_cb;
470   cbs->cls = cls;
471
472   GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
473                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
474 }
475
476
477 static int
478 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
479 {
480   struct SlicerMethodRemoveClosure *rm_cls = cls;
481   struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
482   struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
483   struct SlicerMethodCallbacks *cbs = value;
484
485   if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb)
486       && (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb)
487       && (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb)
488       && (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb)
489       && (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb))
490   {
491     GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
492     GNUNET_free (cbs);
493     return GNUNET_NO;
494   }
495   return GNUNET_YES;
496 }
497
498
499 /**
500  * Remove a registered method from the try-and-slice instance.
501  *
502  * Removes one matching handler registered with the given
503  * @a method_name and  callbacks.
504  *
505  * @param slicer
506  *        The try-and-slice instance.
507  * @param method_name
508  *        Name of the method to remove.
509  * @param method_cb
510  *        Method handler.
511  * @param modifier_cb
512  *        Modifier handler.
513  * @param data_cb
514  *        Data handler.
515  * @param eom_cb
516  *        End of message handler.
517  *
518  * @return #GNUNET_OK if a method handler was removed,
519  *         #GNUNET_NO if no handler matched the given method name and callbacks.
520  */
521 int
522 GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
523                                   const char *method_name,
524                                   GNUNET_PSYC_MessageCallback msg_cb,
525                                   GNUNET_PSYC_MethodCallback method_cb,
526                                   GNUNET_PSYC_ModifierCallback modifier_cb,
527                                   GNUNET_PSYC_DataCallback data_cb,
528                                   GNUNET_PSYC_EndOfMessageCallback eom_cb)
529 {
530   struct GNUNET_HashCode key;
531   GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
532
533   struct SlicerMethodRemoveClosure rm_cls;
534   rm_cls.slicer = slicer;
535   struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
536   rm_cbs->msg_cb = msg_cb;
537   rm_cbs->method_cb = method_cb;
538   rm_cbs->modifier_cb = modifier_cb;
539   rm_cbs->data_cb = data_cb;
540   rm_cbs->eom_cb = eom_cb;
541
542   return
543     (GNUNET_SYSERR
544      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
545                                                     slicer_method_remove,
546                                                     &rm_cls))
547     ? GNUNET_NO
548     : GNUNET_OK;
549 }
550
551
552 /**
553  * Watch a place for changed objects.
554  *
555  * @param slicer
556  *        The try-and-slice instance.
557  * @param object_filter
558  *        Object prefix to match.
559  * @param modifier_cb
560  *        Function to call when encountering a state modifier.
561  * @param cls
562  *        Closure for callback.
563  */
564 void
565 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
566                                  const char *object_filter,
567                                  GNUNET_PSYC_ModifierCallback modifier_cb,
568                                  void *cls)
569 {
570   struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
571   cbs->modifier_cb = modifier_cb;
572   cbs->cls = cls;
573
574   struct GNUNET_HashCode key;
575   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
576   GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
577                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
578 }
579
580
581 static int
582 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
583 {
584   struct SlicerModifierRemoveClosure *rm_cls = cls;
585   struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
586   struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
587   struct SlicerModifierCallbacks *cbs = value;
588
589   if (cbs->modifier_cb == rm_cbs->modifier_cb)
590   {
591     GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
592     GNUNET_free (cbs);
593     return GNUNET_NO;
594   }
595   return GNUNET_YES;
596 }
597
598
599 /**
600  * Remove a registered modifier from the try-and-slice instance.
601  *
602  * Removes one matching handler registered with the given
603  * @a object_filter and @a modifier_cb.
604  *
605  * @param slicer
606  *        The try-and-slice instance.
607  * @param object_filter
608  *        Object prefix to match.
609  * @param modifier_cb
610  *        Function to call when encountering a state modifier changes.
611  */
612 int
613 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
614                                     const char *object_filter,
615                                     GNUNET_PSYC_ModifierCallback modifier_cb)
616 {
617   struct GNUNET_HashCode key;
618   GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
619
620   struct SlicerModifierRemoveClosure rm_cls;
621   rm_cls.slicer = slicer;
622   struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
623   rm_cbs->modifier_cb = modifier_cb;
624
625   return
626     (GNUNET_SYSERR
627      == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
628                                                     slicer_modifier_remove,
629                                                     &rm_cls))
630     ? GNUNET_NO
631     : GNUNET_OK;
632  }
633
634
635 static int
636 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
637 {
638   struct SlicerMethodCallbacks *cbs = value;
639   GNUNET_free (cbs);
640   return GNUNET_YES;
641 }
642
643
644 static int
645 slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
646 {
647   struct SlicerModifierCallbacks *cbs = value;
648   GNUNET_free (cbs);
649   return GNUNET_YES;
650 }
651
652
653 /**
654  * Remove all registered method handlers.
655  *
656  * @param slicer
657  *        Slicer to clear.
658  */
659 void
660 GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
661 {
662   GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
663                                          slicer_method_free, NULL);
664   GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers);
665 }
666
667
668 /**
669  * Remove all registered modifier handlers.
670  *
671  * @param slicer
672  *        Slicer to clear.
673  */
674 void
675 GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
676 {
677   GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
678                                          slicer_modifier_free, NULL);
679   GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers);
680 }
681
682
683 /**
684  * Remove all registered method & modifier handlers.
685  *
686  * @param slicer
687  *        Slicer to clear.
688  */
689 void
690 GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
691 {
692   GNUNET_PSYC_slicer_method_clear (slicer);
693   GNUNET_PSYC_slicer_modifier_clear (slicer);
694 }
695
696
697 /**
698  * Destroy a given try-and-slice instance.
699  *
700  * @param slicer
701  *        Slicer to destroy
702  */
703 void
704 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
705 {
706   GNUNET_PSYC_slicer_clear (slicer);
707   GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
708   GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers);
709   GNUNET_PSYC_receive_destroy (slicer->recv);
710   GNUNET_free (slicer);
711 }