2 * This file is part of GNUnet
3 * Copyright (C) 2013 Christian Grothoff (and other contributing authors)
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 part.
60 const struct GNUNET_MessageHeader *msg;
63 * ID of currently being received message.
68 * Method name of currently being received message.
73 * Name of currently processed modifier.
78 * Value of currently processed modifier.
83 * Public key of the nym the current message originates from.
85 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
88 * Size of @a method_name (including terminating \0).
90 uint16_t method_name_size;
93 * Size of @a modifier_name (including terminating \0).
95 uint16_t mod_name_size;
98 * Size of modifier value fragment.
100 uint16_t mod_value_size;
103 * Full size of modifier value.
105 uint16_t mod_full_value_size;
108 * Remaining bytes from the value of the current modifier.
110 uint16_t mod_value_remaining;
113 * Operator of currently processed modifier.
120 * Callbacks for a slicer method handler.
122 struct SlicerMethodCallbacks
124 GNUNET_PSYC_MethodCallback method_cb;
125 GNUNET_PSYC_ModifierCallback modifier_cb;
126 GNUNET_PSYC_DataCallback data_cb;
127 GNUNET_PSYC_EndOfMessageCallback eom_cb;
132 struct SlicerMethodRemoveClosure
134 struct GNUNET_PSYC_Slicer *slicer;
135 struct SlicerMethodCallbacks rm_cbs;
140 * Callbacks for a slicer method handler.
142 struct SlicerModifierCallbacks
144 GNUNET_PSYC_ModifierCallback modifier_cb;
149 struct SlicerModifierRemoveClosure
151 struct GNUNET_PSYC_Slicer *slicer;
152 struct SlicerModifierCallbacks rm_cbs;
157 * Call a method handler for an incoming message part.
160 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
163 struct GNUNET_PSYC_Slicer *slicer = cls;
164 const struct GNUNET_MessageHeader *msg = slicer->msg;
165 struct SlicerMethodCallbacks *cbs = value;
166 uint16_t ptype = ntohs (msg->type);
170 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
172 if (NULL == cbs->method_cb)
174 struct GNUNET_PSYC_MessageMethod *
175 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
176 cbs->method_cb (cbs->cls, meth, slicer->message_id,
178 &slicer->nym_pub_key,
179 slicer->method_name);
183 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
185 if (NULL == cbs->modifier_cb)
187 struct GNUNET_PSYC_MessageModifier *
188 mod = (struct GNUNET_PSYC_MessageModifier *) msg;
189 cbs->modifier_cb (cbs->cls, &mod->header, slicer->message_id,
190 mod->oper, (const char *) &mod[1],
191 (const void *) &mod[1] + ntohs (mod->name_size),
192 ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size),
193 ntohs (mod->value_size));
197 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
199 if (NULL == cbs->modifier_cb)
201 cbs->modifier_cb (cbs->cls, msg, slicer->message_id,
202 slicer->mod_oper, slicer->mod_name, &msg[1],
203 ntohs (msg->size) - sizeof (*msg),
204 slicer->mod_full_value_size);
208 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
210 if (NULL == cbs->data_cb)
212 uint64_t data_offset = 0; // FIXME
213 cbs->data_cb (cbs->cls, msg, slicer->message_id,
214 data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg));
218 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
219 if (NULL == cbs->eom_cb)
221 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO);
224 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
225 if (NULL == cbs->eom_cb)
227 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES);
235 * Call a method handler for an incoming message part.
238 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
241 struct GNUNET_PSYC_Slicer *slicer = cls;
242 struct SlicerModifierCallbacks *cbs = value;
244 cbs->modifier_cb (cbs->cls, slicer->msg, slicer->message_id, slicer->mod_oper,
245 slicer->mod_name, slicer->mod_value,
246 slicer->mod_value_size, slicer->mod_full_value_size);
252 * Process an incoming message and call matching handlers.
257 * The message as it arrived from the network.
260 GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer,
261 const struct GNUNET_PSYC_MessageHeader *msg)
263 GNUNET_PSYC_receive_message (slicer->recv, msg);
268 * Process an incoming message part and call matching handlers.
275 * Flags for the message.
276 * @see enum GNUNET_PSYC_MessageFlags
278 * The message part. as it arrived from the network.
281 GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer,
282 const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
285 uint64_t fragment_offset,
286 const struct GNUNET_MessageHeader *msg)
288 slicer->nym_pub_key = *slave_pub_key;
290 uint16_t ptype = ntohs (msg->type);
291 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
293 struct GNUNET_PSYC_MessageMethod *
294 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
295 slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
296 slicer->method_name = GNUNET_malloc (slicer->method_name_size);
297 memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
298 slicer->message_id = message_id;
302 GNUNET_assert (message_id == slicer->message_id);
305 char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (slave_pub_key);
306 LOG (GNUNET_ERROR_TYPE_DEBUG,
307 "Slicer received message of type %u and size %u, "
308 "with ID %" PRIu64 " and method %s from %s\n",
309 ptype, ntohs (msg->size), message_id, slicer->method_name, nym_str);
310 GNUNET_free (nym_str);
314 /* try-and-slice modifier */
318 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
320 struct GNUNET_PSYC_MessageModifier *
321 mod = (struct GNUNET_PSYC_MessageModifier *) msg;
322 slicer->mod_oper = mod->oper;
323 slicer->mod_name_size = ntohs (mod->name_size);
324 slicer->mod_name = GNUNET_malloc (slicer->mod_name_size);
325 memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size);
326 slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size;
327 slicer->mod_full_value_size = ntohs (mod->value_size);
328 slicer->mod_value_remaining = slicer->mod_full_value_size;
329 slicer->mod_value_size
330 = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size;
332 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
333 if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
335 slicer->mod_value = (char *) &msg[1];
336 slicer->mod_value_size = ntohs (msg->size) - sizeof (*msg);
338 slicer->mod_value_remaining -= slicer->mod_value_size;
339 char *name = GNUNET_malloc (slicer->mod_name_size);
340 memcpy (name, slicer->mod_name, slicer->mod_name_size);
343 struct GNUNET_HashCode key;
344 uint16_t name_len = strlen (name);
345 GNUNET_CRYPTO_hash (name, name_len, &key);
346 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
347 slicer_modifier_handler_notify,
349 char *p = strrchr (name, '_');
357 /* try-and-slice method */
359 char *name = GNUNET_malloc (slicer->method_name_size);
360 memcpy (name, slicer->method_name, slicer->method_name_size);
363 struct GNUNET_HashCode key;
364 uint16_t name_len = strlen (name);
365 GNUNET_CRYPTO_hash (name, name_len, &key);
366 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
367 slicer_method_handler_notify,
369 char *p = strrchr (name, '_');
376 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
377 GNUNET_free (slicer->method_name);
379 if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
381 GNUNET_free (slicer->mod_name);
382 slicer->mod_name = NULL;
383 slicer->mod_name_size = 0;
384 slicer->mod_value_size = 0;
385 slicer->mod_full_value_size = 0;
386 slicer->mod_oper = 0;
394 * Create a try-and-slice instance.
396 * A slicer processes incoming messages and notifies callbacks about matching
397 * methods or modifiers encountered.
399 * @return A new try-and-slice construct.
401 struct GNUNET_PSYC_Slicer *
402 GNUNET_PSYC_slicer_create (void)
404 struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
405 slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
406 slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
407 slicer->recv = GNUNET_PSYC_receive_create (NULL,
408 (GNUNET_PSYC_MessagePartCallback)
409 GNUNET_PSYC_slicer_message_part,
416 * Add a method to the try-and-slice instance.
418 * The callbacks are called for messages with a matching @a method_name prefix.
421 * The try-and-slice instance to extend.
423 * Name of the given method, use empty string to match all.
425 * Method handler invoked upon a matching message.
427 * Modifier handler, invoked after @a method_cb
428 * for each modifier in the message.
430 * Data handler, invoked after @a modifier_cb for each data fragment.
432 * Invoked upon reaching the end of a matching message.
434 * Closure for the callbacks.
437 GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
438 const char *method_name,
439 GNUNET_PSYC_MethodCallback method_cb,
440 GNUNET_PSYC_ModifierCallback modifier_cb,
441 GNUNET_PSYC_DataCallback data_cb,
442 GNUNET_PSYC_EndOfMessageCallback eom_cb,
445 struct GNUNET_HashCode key;
446 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
448 struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
449 cbs->method_cb = method_cb;
450 cbs->modifier_cb = modifier_cb;
451 cbs->data_cb = data_cb;
452 cbs->eom_cb = eom_cb;
455 GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
456 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
461 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
463 struct SlicerMethodRemoveClosure *rm_cls = cls;
464 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
465 struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
466 struct SlicerMethodCallbacks *cbs = value;
468 if (cbs->method_cb == rm_cbs->method_cb
469 && cbs->modifier_cb == rm_cbs->modifier_cb
470 && cbs->data_cb == rm_cbs->data_cb
471 && cbs->eom_cb == rm_cbs->eom_cb)
473 GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
482 * Remove a registered method from the try-and-slice instance.
484 * Removes one matching handler registered with the given
485 * @a method_name and callbacks.
488 * The try-and-slice instance.
490 * Name of the method to remove.
498 * End of message handler.
500 * @return #GNUNET_OK if a method handler was removed,
501 * #GNUNET_NO if no handler matched the given method name and callbacks.
504 GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
505 const char *method_name,
506 GNUNET_PSYC_MethodCallback method_cb,
507 GNUNET_PSYC_ModifierCallback modifier_cb,
508 GNUNET_PSYC_DataCallback data_cb,
509 GNUNET_PSYC_EndOfMessageCallback eom_cb)
511 struct GNUNET_HashCode key;
512 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
514 struct SlicerMethodRemoveClosure rm_cls;
515 rm_cls.slicer = slicer;
516 struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
517 rm_cbs->method_cb = method_cb;
518 rm_cbs->modifier_cb = modifier_cb;
519 rm_cbs->data_cb = data_cb;
520 rm_cbs->eom_cb = eom_cb;
524 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
525 slicer_method_remove,
533 * Watch a place for changed objects.
536 * The try-and-slice instance.
537 * @param object_filter
538 * Object prefix to match.
540 * Function to call when encountering a state modifier.
542 * Closure for callback.
545 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
546 const char *object_filter,
547 GNUNET_PSYC_ModifierCallback modifier_cb,
550 struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
551 cbs->modifier_cb = modifier_cb;
554 struct GNUNET_HashCode key;
555 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
556 GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
557 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
562 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
564 struct SlicerModifierRemoveClosure *rm_cls = cls;
565 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
566 struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
567 struct SlicerModifierCallbacks *cbs = value;
569 if (cbs->modifier_cb == rm_cbs->modifier_cb)
571 GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
580 * Remove a registered modifier from the try-and-slice instance.
582 * Removes one matching handler registered with the given
583 * @a object_filter and @a modifier_cb.
586 * The try-and-slice instance.
587 * @param object_filter
588 * Object prefix to match.
590 * Function to call when encountering a state modifier changes.
593 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
594 const char *object_filter,
595 GNUNET_PSYC_ModifierCallback modifier_cb)
597 struct GNUNET_HashCode key;
598 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
600 struct SlicerModifierRemoveClosure rm_cls;
601 rm_cls.slicer = slicer;
602 struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
603 rm_cbs->modifier_cb = modifier_cb;
607 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
608 slicer_modifier_remove,
616 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
618 struct SlicerMethodCallbacks *cbs = value;
625 slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value)
627 struct SlicerModifierCallbacks *cbs = value;
634 * Remove all registered method handlers.
640 GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer)
642 GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
643 slicer_method_free, NULL);
648 * Remove all registered modifier handlers.
654 GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer)
656 GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers,
657 slicer_modifier_free, NULL);
662 * Remove all registered method & modifier handlers.
668 GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer)
670 GNUNET_PSYC_slicer_method_clear (slicer);
671 GNUNET_PSYC_slicer_modifier_clear (slicer);
676 * Destroy a given try-and-slice instance.
682 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
684 GNUNET_PSYC_slicer_clear (slicer);
685 GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
686 GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers);
687 GNUNET_PSYC_receive_destroy (slicer->recv);
688 GNUNET_free (slicer);