2 * This file is part of GNUnet
3 * Copyright (C) 2013 GNUnet e.V.
5 * GNUnet is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Affero 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.
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.
17 * @author Gabor X Toth
26 #include "gnunet_util_lib.h"
27 #include "gnunet_psyc_util_lib.h"
29 #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__)
33 * Handle for a try-and-slice instance.
35 struct GNUNET_PSYC_Slicer
38 * Method handlers: H(method_name) -> SlicerMethodCallbacks
40 struct GNUNET_CONTAINER_MultiHashMap *method_handlers;
43 * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks
45 struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers;
48 * Receive handle for incoming messages.
50 struct GNUNET_PSYC_ReceiveHandle *recv;
53 * Currently being processed message.
55 const struct GNUNET_PSYC_MessageHeader *msg;
58 * Currently being processed message part.
60 const struct GNUNET_MessageHeader *pmsg;
63 * ID of currently being received message.
68 * Fragment offset of currently being received message.
70 uint64_t fragment_offset;
73 * Flags of currently being received message.
78 * Method name of currently being received message.
83 * Name of currently processed modifier.
88 * Value of currently processed modifier.
93 * Public key of the nym the current message originates from.
95 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
98 * Size of @a method_name (including terminating \0).
100 uint16_t method_name_size;
103 * Size of @a modifier_name (including terminating \0).
105 uint16_t mod_name_size;
108 * Size of modifier value fragment.
110 uint16_t mod_value_size;
113 * Full size of modifier value.
115 uint16_t mod_full_value_size;
118 * Remaining bytes from the value of the current modifier.
120 uint16_t mod_value_remaining;
123 * Operator of currently processed modifier.
130 * Callbacks for a slicer method handler.
132 struct SlicerMethodCallbacks
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;
143 struct SlicerMethodRemoveClosure
145 struct GNUNET_PSYC_Slicer *slicer;
146 struct SlicerMethodCallbacks rm_cbs;
151 * Callbacks for a slicer method handler.
153 struct SlicerModifierCallbacks
155 GNUNET_PSYC_ModifierCallback modifier_cb;
160 struct SlicerModifierRemoveClosure
162 struct GNUNET_PSYC_Slicer *slicer;
163 struct SlicerModifierCallbacks rm_cbs;
168 * Call a method handler for an incoming message part.
171 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
174 struct GNUNET_PSYC_Slicer *slicer = cls;
175 const struct GNUNET_MessageHeader *pmsg = slicer->pmsg;
176 struct SlicerMethodCallbacks *cbs = value;
178 uint16_t ptype = ntohs (pmsg->type);
181 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
183 if (NULL != cbs->msg_cb)
184 cbs->msg_cb (cbs->cls, slicer->msg);
185 if (NULL == cbs->method_cb)
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);
194 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
196 if (NULL == cbs->modifier_cb)
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));
208 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
210 if (NULL == cbs->modifier_cb)
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);
219 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
221 if (NULL == cbs->data_cb)
223 cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
224 &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg));
228 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
229 if (NULL == cbs->eom_cb)
231 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO);
234 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
235 if (NULL == cbs->eom_cb)
237 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES);
245 * Call a method handler for an incoming message part.
248 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
251 struct GNUNET_PSYC_Slicer *slicer = cls;
252 struct SlicerModifierCallbacks *cbs = value;
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);
262 * Process an incoming message and call matching handlers.
267 * The message as it arrived from the network.
270 GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
271 const struct GNUNET_PSYC_MessageHeader *msg)
273 GNUNET_PSYC_receive_message (slicer->recv, msg);
278 * Process an incoming message part and call matching handlers.
285 * Flags for the message.
286 * @see enum GNUNET_PSYC_MessageFlags
288 * The message part. as it arrived from the network.
291 GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
292 const struct GNUNET_PSYC_MessageHeader *msg,
293 const struct GNUNET_MessageHeader *pmsg)
298 uint64_t message_id = GNUNET_ntohll (msg->message_id);
300 uint16_t ptype = ntohs (pmsg->type);
301 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
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;
312 GNUNET_assert (message_id == slicer->message_id);
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);
322 /* try-and-slice modifier */
326 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
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;
341 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
342 if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
344 slicer->mod_value = (char *) &pmsg[1];
345 slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg);
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);
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,
358 char *p = strrchr (name, '_');
366 /* try-and-slice method */
368 char *name = GNUNET_malloc (slicer->method_name_size);
369 GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size);
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,
378 char *p = strrchr (name, '_');
385 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
386 GNUNET_free (slicer->method_name);
388 if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
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;
404 * Create a try-and-slice instance.
406 * A slicer processes incoming messages and notifies callbacks about matching
407 * methods or modifiers encountered.
409 * @return A new try-and-slice construct.
411 struct GNUNET_PSYC_Slicer *
412 GNUNET_PSYC_slicer_create (void)
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,
426 * Add a method to the try-and-slice instance.
428 * The callbacks are called for messages with a matching @a method_name prefix.
431 * The try-and-slice instance to extend.
433 * Name of the given method, use empty string to match all.
435 * Method handler invoked upon a matching message.
437 * Modifier handler, invoked after @a method_cb
438 * for each modifier in the message.
440 * Data handler, invoked after @a modifier_cb for each data fragment.
442 * Invoked upon reaching the end of a matching message.
444 * Closure for the callbacks.
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,
456 struct GNUNET_HashCode key;
457 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
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;
467 GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
468 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
473 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
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;
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))
486 GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
495 * Remove a registered method from the try-and-slice instance.
497 * Removes one matching handler registered with the given
498 * @a method_name and callbacks.
501 * The try-and-slice instance.
503 * Name of the method to remove.
511 * End of message handler.
513 * @return #GNUNET_OK if a method handler was removed,
514 * #GNUNET_NO if no handler matched the given method name and callbacks.
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)
525 struct GNUNET_HashCode key;
526 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
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;
539 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
540 slicer_method_remove,
548 * Watch a place for changed objects.
551 * The try-and-slice instance.
552 * @param object_filter
553 * Object prefix to match.
555 * Function to call when encountering a state modifier.
557 * Closure for callback.
560 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
561 const char *object_filter,
562 GNUNET_PSYC_ModifierCallback modifier_cb,
565 struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
566 cbs->modifier_cb = modifier_cb;
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);
577 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
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;
584 if (cbs->modifier_cb == rm_cbs->modifier_cb)
586 GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
595 * Remove a registered modifier from the try-and-slice instance.
597 * Removes one matching handler registered with the given
598 * @a object_filter and @a modifier_cb.
601 * The try-and-slice instance.
602 * @param object_filter
603 * Object prefix to match.
605 * Function to call when encountering a state modifier changes.
608 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
609 const char *object_filter,
610 GNUNET_PSYC_ModifierCallback modifier_cb)
612 struct GNUNET_HashCode key;
613 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
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;
622 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
623 slicer_modifier_remove,
631 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
633 struct SlicerMethodCallbacks *cbs = value;
640 slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
642 struct SlicerModifierCallbacks *cbs = value;
649 * Remove all registered method handlers.
655 GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
657 GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
658 slicer_method_free, NULL);
659 GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers);
664 * Remove all registered modifier handlers.
670 GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
672 GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
673 slicer_modifier_free, NULL);
674 GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers);
679 * Remove all registered method & modifier handlers.
685 GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
687 GNUNET_PSYC_slicer_method_clear (slicer);
688 GNUNET_PSYC_slicer_modifier_clear (slicer);
693 * Destroy a given try-and-slice instance.
699 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
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);