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
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.
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.
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.
22 * @author Gabor X Toth
31 #include "gnunet_util_lib.h"
32 #include "gnunet_psyc_util_lib.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__)
38 * Handle for a try-and-slice instance.
40 struct GNUNET_PSYC_Slicer
43 * Method handlers: H(method_name) -> SlicerMethodCallbacks
45 struct GNUNET_CONTAINER_MultiHashMap *method_handlers;
48 * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks
50 struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers;
53 * Receive handle for incoming messages.
55 struct GNUNET_PSYC_ReceiveHandle *recv;
58 * Currently being processed message.
60 const struct GNUNET_PSYC_MessageHeader *msg;
63 * Currently being processed message part.
65 const struct GNUNET_MessageHeader *pmsg;
68 * ID of currently being received message.
73 * Fragment offset of currently being received message.
75 uint64_t fragment_offset;
78 * Flags of currently being received message.
83 * Method name of currently being received message.
88 * Name of currently processed modifier.
93 * Value of currently processed modifier.
98 * Public key of the nym the current message originates from.
100 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
103 * Size of @a method_name (including terminating \0).
105 uint16_t method_name_size;
108 * Size of @a modifier_name (including terminating \0).
110 uint16_t mod_name_size;
113 * Size of modifier value fragment.
115 uint16_t mod_value_size;
118 * Full size of modifier value.
120 uint16_t mod_full_value_size;
123 * Remaining bytes from the value of the current modifier.
125 uint16_t mod_value_remaining;
128 * Operator of currently processed modifier.
135 * Callbacks for a slicer method handler.
137 struct SlicerMethodCallbacks
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;
148 struct SlicerMethodRemoveClosure
150 struct GNUNET_PSYC_Slicer *slicer;
151 struct SlicerMethodCallbacks rm_cbs;
156 * Callbacks for a slicer method handler.
158 struct SlicerModifierCallbacks
160 GNUNET_PSYC_ModifierCallback modifier_cb;
165 struct SlicerModifierRemoveClosure
167 struct GNUNET_PSYC_Slicer *slicer;
168 struct SlicerModifierCallbacks rm_cbs;
173 * Call a method handler for an incoming message part.
176 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
179 struct GNUNET_PSYC_Slicer *slicer = cls;
180 const struct GNUNET_MessageHeader *pmsg = slicer->pmsg;
181 struct SlicerMethodCallbacks *cbs = value;
183 uint16_t ptype = ntohs (pmsg->type);
186 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
188 if (NULL != cbs->msg_cb)
189 cbs->msg_cb (cbs->cls, slicer->msg);
190 if (NULL == cbs->method_cb)
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);
199 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
201 if (NULL == cbs->modifier_cb)
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));
213 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
215 if (NULL == cbs->modifier_cb)
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);
224 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
226 if (NULL == cbs->data_cb)
228 cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id,
229 &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg));
233 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
234 if (NULL == cbs->eom_cb)
236 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO);
239 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
240 if (NULL == cbs->eom_cb)
242 cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES);
250 * Call a method handler for an incoming message part.
253 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
256 struct GNUNET_PSYC_Slicer *slicer = cls;
257 struct SlicerModifierCallbacks *cbs = value;
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);
267 * Process an incoming message and call matching handlers.
272 * The message as it arrived from the network.
275 GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
276 const struct GNUNET_PSYC_MessageHeader *msg)
278 GNUNET_PSYC_receive_message (slicer->recv, msg);
283 * Process an incoming message part and call matching handlers.
290 * Flags for the message.
291 * @see enum GNUNET_PSYC_MessageFlags
293 * The message part. as it arrived from the network.
296 GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
297 const struct GNUNET_PSYC_MessageHeader *msg,
298 const struct GNUNET_MessageHeader *pmsg)
303 uint64_t message_id = GNUNET_ntohll (msg->message_id);
305 uint16_t ptype = ntohs (pmsg->type);
306 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
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;
317 GNUNET_assert (message_id == slicer->message_id);
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);
327 /* try-and-slice modifier */
331 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
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;
345 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
346 if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
348 slicer->mod_value = (char *) &pmsg[1];
349 slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg);
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);
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,
362 char *p = strrchr (name, '_');
370 /* try-and-slice method */
372 char *name = GNUNET_malloc (slicer->method_name_size);
373 memcpy (name, slicer->method_name, slicer->method_name_size);
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,
382 char *p = strrchr (name, '_');
389 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
390 GNUNET_free (slicer->method_name);
392 if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
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;
408 * Create a try-and-slice instance.
410 * A slicer processes incoming messages and notifies callbacks about matching
411 * methods or modifiers encountered.
413 * @return A new try-and-slice construct.
415 struct GNUNET_PSYC_Slicer *
416 GNUNET_PSYC_slicer_create (void)
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,
430 * Add a method to the try-and-slice instance.
432 * The callbacks are called for messages with a matching @a method_name prefix.
435 * The try-and-slice instance to extend.
437 * Name of the given method, use empty string to match all.
439 * Method handler invoked upon a matching message.
441 * Modifier handler, invoked after @a method_cb
442 * for each modifier in the message.
444 * Data handler, invoked after @a modifier_cb for each data fragment.
446 * Invoked upon reaching the end of a matching message.
448 * Closure for the callbacks.
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,
460 struct GNUNET_HashCode key;
461 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
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;
471 GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
472 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
477 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
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;
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))
490 GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
499 * Remove a registered method from the try-and-slice instance.
501 * Removes one matching handler registered with the given
502 * @a method_name and callbacks.
505 * The try-and-slice instance.
507 * Name of the method to remove.
515 * End of message handler.
517 * @return #GNUNET_OK if a method handler was removed,
518 * #GNUNET_NO if no handler matched the given method name and callbacks.
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)
529 struct GNUNET_HashCode key;
530 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
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;
543 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
544 slicer_method_remove,
552 * Watch a place for changed objects.
555 * The try-and-slice instance.
556 * @param object_filter
557 * Object prefix to match.
559 * Function to call when encountering a state modifier.
561 * Closure for callback.
564 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
565 const char *object_filter,
566 GNUNET_PSYC_ModifierCallback modifier_cb,
569 struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
570 cbs->modifier_cb = modifier_cb;
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);
581 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
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;
588 if (cbs->modifier_cb == rm_cbs->modifier_cb)
590 GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
599 * Remove a registered modifier from the try-and-slice instance.
601 * Removes one matching handler registered with the given
602 * @a object_filter and @a modifier_cb.
605 * The try-and-slice instance.
606 * @param object_filter
607 * Object prefix to match.
609 * Function to call when encountering a state modifier changes.
612 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
613 const char *object_filter,
614 GNUNET_PSYC_ModifierCallback modifier_cb)
616 struct GNUNET_HashCode key;
617 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
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;
626 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
627 slicer_modifier_remove,
635 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
637 struct SlicerMethodCallbacks *cbs = value;
644 slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
646 struct SlicerModifierCallbacks *cbs = value;
653 * Remove all registered method handlers.
659 GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
661 GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
662 slicer_method_free, NULL);
663 GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers);
668 * Remove all registered modifier handlers.
674 GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
676 GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
677 slicer_modifier_free, NULL);
678 GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers);
683 * Remove all registered method & modifier handlers.
689 GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
691 GNUNET_PSYC_slicer_method_clear (slicer);
692 GNUNET_PSYC_slicer_modifier_clear (slicer);
697 * Destroy a given try-and-slice instance.
703 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
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);