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 * Currently being processed message part.
55 const struct GNUNET_MessageHeader *msg;
58 * ID of currently being received message.
63 * Method name of currently being received message.
68 * Name of currently processed modifier.
73 * Value of currently processed modifier.
78 * Public key of the nym the current message originates from.
80 struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key;
83 * Size of @a method_name (including terminating \0).
85 uint16_t method_name_size;
88 * Size of @a modifier_name (including terminating \0).
90 uint16_t mod_name_size;
93 * Size of modifier value fragment.
95 uint16_t mod_value_size;
98 * Full size of modifier value.
100 uint16_t mod_full_value_size;
103 * Remaining bytes from the value of the current modifier.
105 uint16_t mod_value_remaining;
108 * Operator of currently processed modifier.
115 * Callbacks for a slicer method handler.
117 struct SlicerMethodCallbacks
119 GNUNET_PSYC_MethodCallback method_cb;
120 GNUNET_PSYC_ModifierCallback modifier_cb;
121 GNUNET_PSYC_DataCallback data_cb;
122 GNUNET_PSYC_EndOfMessageCallback eom_cb;
127 struct SlicerMethodRemoveClosure
129 struct GNUNET_PSYC_Slicer *slicer;
130 struct SlicerMethodCallbacks rm_cbs;
135 * Callbacks for a slicer method handler.
137 struct SlicerModifierCallbacks
139 GNUNET_PSYC_ModifierCallback modifier_cb;
144 struct SlicerModifierRemoveClosure
146 struct GNUNET_PSYC_Slicer *slicer;
147 struct SlicerModifierCallbacks rm_cbs;
152 * Call a method handler for an incoming message part.
155 slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key,
158 struct GNUNET_PSYC_Slicer *slicer = cls;
159 const struct GNUNET_MessageHeader *msg = slicer->msg;
160 struct SlicerMethodCallbacks *cbs = value;
161 uint16_t ptype = ntohs (msg->type);
165 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
167 if (NULL == cbs->method_cb)
169 struct GNUNET_PSYC_MessageMethod *
170 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
171 cbs->method_cb (cbs->cls, meth, slicer->message_id,
173 &slicer->nym_pub_key,
174 slicer->method_name);
178 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
180 if (NULL == cbs->modifier_cb)
182 struct GNUNET_PSYC_MessageModifier *
183 mod = (struct GNUNET_PSYC_MessageModifier *) msg;
184 cbs->modifier_cb (cbs->cls, &mod->header, slicer->message_id,
185 mod->oper, (const char *) &mod[1],
186 (const void *) &mod[1] + ntohs (mod->name_size),
187 ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size),
188 ntohs (mod->value_size));
192 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
194 if (NULL == cbs->modifier_cb)
196 cbs->modifier_cb (cbs->cls, msg, slicer->message_id,
197 slicer->mod_oper, slicer->mod_name, &msg[1],
198 ntohs (msg->size) - sizeof (*msg),
199 slicer->mod_full_value_size);
203 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
205 if (NULL == cbs->data_cb)
207 uint64_t data_offset = 0; // FIXME
208 cbs->data_cb (cbs->cls, msg, slicer->message_id,
209 data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg));
213 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
214 if (NULL == cbs->eom_cb)
216 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO);
219 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
220 if (NULL == cbs->eom_cb)
222 cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES);
230 * Call a method handler for an incoming message part.
233 slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key,
236 struct GNUNET_PSYC_Slicer *slicer = cls;
237 struct SlicerModifierCallbacks *cbs = value;
239 cbs->modifier_cb (cbs->cls, slicer->msg, slicer->message_id, slicer->mod_oper,
240 slicer->mod_name, slicer->mod_value,
241 slicer->mod_value_size, slicer->mod_full_value_size);
247 * Process an incoming message part and call matching handlers.
254 * Flags for the message.
255 * @see enum GNUNET_PSYC_MessageFlags
257 * The message part. as it arrived from the network.
260 GNUNET_PSYC_slicer_message (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key,
261 uint64_t message_id, uint32_t flags, uint64_t fragment_offset,
262 const struct GNUNET_MessageHeader *msg)
264 struct GNUNET_PSYC_Slicer *slicer = cls;
265 slicer->nym_pub_key = *slave_pub_key;
267 uint16_t ptype = ntohs (msg->type);
268 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype)
270 struct GNUNET_PSYC_MessageMethod *
271 meth = (struct GNUNET_PSYC_MessageMethod *) msg;
272 slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth);
273 slicer->method_name = GNUNET_malloc (slicer->method_name_size);
274 memcpy (slicer->method_name, &meth[1], slicer->method_name_size);
275 slicer->message_id = message_id;
279 GNUNET_assert (message_id == slicer->message_id);
282 char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (slave_pub_key);
283 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 "Slicer received message of type %u and size %u, "
285 "with ID %" PRIu64 " and method %s from %s\n",
286 ptype, ntohs (msg->size), message_id, slicer->method_name, nym_str);
287 GNUNET_free (nym_str);
291 /* try-and-slice modifier */
295 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
297 struct GNUNET_PSYC_MessageModifier *
298 mod = (struct GNUNET_PSYC_MessageModifier *) msg;
299 slicer->mod_oper = mod->oper;
300 slicer->mod_name_size = ntohs (mod->name_size);
301 slicer->mod_name = GNUNET_malloc (slicer->mod_name_size);
302 memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size);
303 slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size;
304 slicer->mod_full_value_size = ntohs (mod->value_size);
305 slicer->mod_value_remaining = slicer->mod_full_value_size;
306 slicer->mod_value_size
307 = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size;
309 case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
310 if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT)
312 slicer->mod_value = (char *) &msg[1];
313 slicer->mod_value_size = ntohs (msg->size) - sizeof (*msg);
315 slicer->mod_value_remaining -= slicer->mod_value_size;
316 char *name = GNUNET_malloc (slicer->mod_name_size);
317 memcpy (name, slicer->mod_name, slicer->mod_name_size);
320 struct GNUNET_HashCode key;
321 uint16_t name_len = strlen (name);
322 GNUNET_CRYPTO_hash (name, name_len, &key);
323 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
324 slicer_modifier_handler_notify,
326 char *p = strrchr (name, '_');
334 /* try-and-slice method */
336 char *name = GNUNET_malloc (slicer->method_name_size);
337 memcpy (name, slicer->method_name, slicer->method_name_size);
340 struct GNUNET_HashCode key;
341 uint16_t name_len = strlen (name);
342 GNUNET_CRYPTO_hash (name, name_len, &key);
343 GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
344 slicer_method_handler_notify,
346 char *p = strrchr (name, '_');
353 if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype)
354 GNUNET_free (slicer->method_name);
356 if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name)
358 GNUNET_free (slicer->mod_name);
359 slicer->mod_name = NULL;
360 slicer->mod_name_size = 0;
361 slicer->mod_value_size = 0;
362 slicer->mod_full_value_size = 0;
363 slicer->mod_oper = 0;
371 * Create a try-and-slice instance.
373 * A slicer processes incoming messages and notifies callbacks about matching
374 * methods or modifiers encountered.
376 * @return A new try-and-slice construct.
378 struct GNUNET_PSYC_Slicer *
379 GNUNET_PSYC_slicer_create (void)
381 struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer));
382 slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
383 slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
389 * Add a method to the try-and-slice instance.
391 * The callbacks are called for messages with a matching @a method_name prefix.
394 * The try-and-slice instance to extend.
396 * Name of the given method, use empty string to match all.
398 * Method handler invoked upon a matching message.
400 * Modifier handler, invoked after @a method_cb
401 * for each modifier in the message.
403 * Data handler, invoked after @a modifier_cb for each data fragment.
405 * Invoked upon reaching the end of a matching message.
407 * Closure for the callbacks.
410 GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer,
411 const char *method_name,
412 GNUNET_PSYC_MethodCallback method_cb,
413 GNUNET_PSYC_ModifierCallback modifier_cb,
414 GNUNET_PSYC_DataCallback data_cb,
415 GNUNET_PSYC_EndOfMessageCallback eom_cb,
418 struct GNUNET_HashCode key;
419 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
421 struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs));
422 cbs->method_cb = method_cb;
423 cbs->modifier_cb = modifier_cb;
424 cbs->data_cb = data_cb;
425 cbs->eom_cb = eom_cb;
428 GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs,
429 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
434 slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
436 struct SlicerMethodRemoveClosure *rm_cls = cls;
437 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
438 struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs;
439 struct SlicerMethodCallbacks *cbs = value;
441 if (cbs->method_cb == rm_cbs->method_cb
442 && cbs->modifier_cb == rm_cbs->modifier_cb
443 && cbs->data_cb == rm_cbs->data_cb
444 && cbs->eom_cb == rm_cbs->eom_cb)
446 GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs);
455 * Remove a registered method from the try-and-slice instance.
457 * Removes one matching handler registered with the given
458 * @a method_name and callbacks.
461 * The try-and-slice instance.
463 * Name of the method to remove.
471 * End of message handler.
473 * @return #GNUNET_OK if a method handler was removed,
474 * #GNUNET_NO if no handler matched the given method name and callbacks.
477 GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer,
478 const char *method_name,
479 GNUNET_PSYC_MethodCallback method_cb,
480 GNUNET_PSYC_ModifierCallback modifier_cb,
481 GNUNET_PSYC_DataCallback data_cb,
482 GNUNET_PSYC_EndOfMessageCallback eom_cb)
484 struct GNUNET_HashCode key;
485 GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key);
487 struct SlicerMethodRemoveClosure rm_cls;
488 rm_cls.slicer = slicer;
489 struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs;
490 rm_cbs->method_cb = method_cb;
491 rm_cbs->modifier_cb = modifier_cb;
492 rm_cbs->data_cb = data_cb;
493 rm_cbs->eom_cb = eom_cb;
497 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key,
498 slicer_method_remove,
506 * Watch a place for changed objects.
509 * The try-and-slice instance.
510 * @param object_filter
511 * Object prefix to match.
513 * Function to call when encountering a state modifier.
515 * Closure for callback.
518 GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer,
519 const char *object_filter,
520 GNUNET_PSYC_ModifierCallback modifier_cb,
523 struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs);
524 cbs->modifier_cb = modifier_cb;
527 struct GNUNET_HashCode key;
528 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
529 GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs,
530 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
535 slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value)
537 struct SlicerModifierRemoveClosure *rm_cls = cls;
538 struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer;
539 struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs;
540 struct SlicerModifierCallbacks *cbs = value;
542 if (cbs->modifier_cb == rm_cbs->modifier_cb)
544 GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs);
553 * Remove a registered modifier from the try-and-slice instance.
555 * Removes one matching handler registered with the given
556 * @a object_filter and @a modifier_cb.
559 * The try-and-slice instance.
560 * @param object_filter
561 * Object prefix to match.
563 * Function to call when encountering a state modifier changes.
566 GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer,
567 const char *object_filter,
568 GNUNET_PSYC_ModifierCallback modifier_cb)
570 struct GNUNET_HashCode key;
571 GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key);
573 struct SlicerModifierRemoveClosure rm_cls;
574 rm_cls.slicer = slicer;
575 struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs;
576 rm_cbs->modifier_cb = modifier_cb;
580 == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key,
581 slicer_modifier_remove,
589 slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value)
591 struct SlicerMethodCallbacks *cbs = value;
598 * Destroy a given try-and-slice instance.
604 GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer)
606 GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers,
607 slicer_method_free, NULL);
608 GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers);
609 GNUNET_free (slicer);