-first thoughs on a PSYC API, not finished
[oweals/gnunet.git] / src / include / gnunet_psyc_service.h
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file include/gnunet_psyc_service.h
23  * @brief psyc service; high-level access to the PSYC protocol
24  *        note that clients of this API are NOT expected to
25  *        understand the PSYC message format, only the semantics!
26  * @author Christian Grothoff
27  *
28  * TODO:
29  * - how to deal with very large channel state (i.e. channel
30  *   containing a movie); this might relate to the question
31  *   of how (when/etc.) we replay method calls; is only the
32  *   channel state persistent? What about a 'bounded' 
33  *   channel history, how would we enable that?
34  * - how to deal with seeking in large channel state (i.e. 
35  *   skip to minute 45 in movie)
36  * - need to change send operations to 'notify_transmit_ready'-style;
37  *   deal better with 'streaming' arguments while we're at it
38  */
39
40 #ifndef GNUNET_PSYC_SERVICE_H
41 #define GNUNET_PSYC_SERVICE_H
42
43 #ifdef __cplusplus
44 extern "C"
45 {
46 #if 0                           /* keep Emacsens' auto-indent happy */
47 }
48 #endif
49 #endif
50
51 #include "gnunet_util_lib.h"
52 #include "gnunet_multicast_service.h"
53
54
55 /**
56  * Version number of GNUnet-PSYC API.
57  */
58 #define GNUNET_PSYC_VERSION 0x00000000
59
60
61 /**
62  * Bits describing special properties of arguments.
63  */
64 enum GNUNET_PSYC_ArgumentFlags
65 {
66   /**
67    * Argument is fixed size.
68    */
69   GNUNET_PSYC_AF_FIXED_SIZE = 0,
70
71   /**
72    * Argument is variable-length
73    */
74   GNUNET_PSYC_AF_VARIABLE_SIZE = 1,
75
76   /**
77    * Argument may be supplied incrementally to the callback 
78    */
79   GNUNET_PSYC_AF_STREAMABLE = 2,
80
81   /**
82    * Argument is variable-length, incrementally supplied
83    * data stream.
84    */
85   GNUNET_PSYC_AF_STREAM = 3,
86
87   /**
88    * Argument is zero-terminated character array.
89    */
90   GNUNET_PSYC_AF_ZERO_TERMINATED_CHARARRAY = 4,
91
92   /**
93    * Argument is variable-length UTF-8 encoded, zero-terminated string.
94    */
95   GNUNET_PSYC_AF_UTF8 = 5,
96
97   /**
98    * Payload is an unsigned integer and might thus be encoded as an
99    * integer when generating PSYC stream (useful if we want to
100    * generate human-readable PSYC streams, instead of just always
101    * using length-prefixed binary encodings).  Note that it
102    * is not sufficient to just test for this bit, as it is
103    * also set for 'REAL' numbers!
104    */
105   GNUNET_PSYC_AF_UNSIGNED_INTEGER = 8,
106
107   /**
108    * Payload is an unsigned integer and might thus be encoded as an
109    * integer when generating PSYC stream (useful if we want to
110    * generate human-readable PSYC streams, instead of just always
111    * using length-prefixed binary encodings).  Note that it
112    * is not sufficient to just test for this bit, as it is
113    * also set for 'REAL' numbers!
114    */
115   GNUNET_PSYC_AF_SIGNED_INTEGER = 16,
116
117   /**
118    * Payload is a 'real' number (float or double).  We save a bit here
119    * as a number cannot be both SIGNED and UNSIGNED, so setting both
120    * bits is fine to use for REALs.
121    */
122   GNUNET_PSYC_AF_REAL_NUMBER = 24
123
124 };
125
126
127 /**
128  * Argument descriptors are used to describe types that can be
129  * embedded in a PSYC stream.  For example, a "uint32_t" is 
130  * described as 4-byte, fixed-length data, whereas a movie 
131  * would be a variable-size, streaming argument.
132  */
133 struct GNUNET_PSYC_ArgumentDescriptor
134 {
135
136   /**
137    * Required length of the argument in bytes, zero for
138    * variable-size arguments.
139    */
140   size_t arg_len;
141
142   /**
143    * Flags describing additional properties of the argument,
144    * such as variable-size, streaming or 0-termination.  This
145    * argument is a bitfield.
146    */
147   enum GNUNET_PSYC_ArgumentFlags flags;
148
149 };
150
151
152 /**
153  * Convenience macro to define an argument descriptor for
154  * some fixed-size C data type.
155  *
156  * @param pt C data type (i.e. 'uint32_t')
157  */
158 #define GNUNET_PSYC_AD_C_TYPE(pt) { sizeof (pt), GNUNET_PSYC_AF_FIXED_SIZE }
159
160 /**
161  * Convenience macro to define an argument descriptor for
162  * some fixed-size unsigned integer type.
163  *
164  * @param it C integer data type (i.e. 'uint32_t')
165  */
166 #define GNUNET_PSYC_AD_C_UINT_TYPE(it) { sizeof (it), GNUNET_PSYC_AF_FIXED_SIZE | GNUNET_PSYC_AF_UNSIGNED_INTEGER }
167
168 /**
169  * Argument descriptor for a 'uint8_t' argument.
170  */
171 #define GNUNET_PSYC_AD_UINT8 GNUNET_PSYC_AD_C_UINT_TYPE(uint8_t)
172
173 /**
174  * Argument descriptor for a 'uint16_t' argument.
175  */
176 #define GNUNET_PSYC_AD_UINT16 GNUNET_PSYC_AD_C_UINT_TYPE(uint16_t)
177
178 /**
179  * Argument descriptor for a 'uint32_t' argument.
180  */
181 #define GNUNET_PSYC_AD_UINT32 GNUNET_PSYC_AD_C_UINT_TYPE(uint32_t)
182
183 /**
184  * Argument descriptor for a 'uint64_t' argument.
185  */
186 #define GNUNET_PSYC_AD_UINT64 GNUNET_PSYC_AD_C_UINT_TYPE(uint64_t)
187
188 /**
189  * Convenience macro to define an argument descriptor for
190  * a 0-terminated, variable-length UTF-8 string.
191  */
192 #define GNUNET_PSYC_AD_UTF8 { 0, GNUNET_PSYC_AF_UTF8 }
193
194
195 /* TODO: add more convenience macros for argument types later as needed */
196
197
198 /**
199  * Abstract argument passed to a GNUNET_PSYC_Method.  
200  */
201 struct GNUNET_PSYC_Argument
202 {
203
204   /**
205    * Data of the argument.
206    */
207   const void *data;
208
209   /**
210    * Number of bytes in 'data', guaranteed to be the argument
211    * descriptor 'arg_len' MINUS 'data_off' unless
212    * GNUNET_PSYC_AF_VARIABLE_SIZE was set.
213    */
214   size_t data_size;
215
216   /**
217    * Offset of 'data' in the overall argument,
218    * always zero unless GNUNET_PSYC_AF_STREAMABLE was
219    * set for the argument.
220    */
221   uint64_t data_off;
222
223   /**
224    * Total number of bytes to be expected in 'data',
225    * UINT64_MAX for 'unknown' (i.e. for "infinite" 
226    * streams).
227    */
228   uint64_t value_size;
229 };
230
231
232 /**
233  * Method called from PSYC upon receiving a message indicating a call
234  * to a 'method'.  The arguments given will match those of the
235  * respective argument descriptor.  If some arguments were marked
236  * as 'streaming', the function can return a value other than -1
237  * to request "more" of the data for that argument.  Note that all
238  * non-streaming arguments will be replayed in full for each additional
239  * invocation of the method.  Using more than one streaming argument 
240  * is possible, in which case PSYC will ONLY advance the stream of the
241  * argument for which the index was returned; the values of other
242  * streaming arguments will be replayed at the current offset.
243  *
244  * Returning a value other than -1 or that of a streaming argument is
245  * not allowed.  Returning -1 does not indicate an error; it simply
246  * indicates that the client wants to proceed with the next method
247  * (and not see the rest of the data from any of the streaming
248  * arguments).
249  *
250  * TODO: note that this API currently doesn't allow for seeking
251  *       in streaming data (very advanced feature)
252  *
253  * @param cls closure
254  * @param full_method_name original method name from PSYC (may be more
255  *        specific than the registered method name due to try&slice matching)
256  * @param sender who transmitted the message (origin, except for messages
257  *        from one of the members to the origin)
258  * @param message_id unique message counter for this message
259  * @param group_generation group generation counter for this message
260  * @param argc number of arguments in argv
261  * @param argv array of argc arguments to the method
262  * @return -1 if we're finished with this method, index
263  *            of a streaming argument for which more data is
264  *            requested otherwise
265  */
266 typedef int (*GNUNET_PSYC_Method)(void *cls,
267                                   const char *full_method_name,
268                                   const struct GNUNET_PeerIdentity *sender,
269                                   unsigned int argc,
270                                   const struct GNUNET_PSYC_Argument *argv);
271
272
273 /**
274  * Descriptor for a PSYC method and its arguments.  Here is how this
275  * is expected to be used.  Imagine we have a method with the
276  * following signature:
277  * <pre>
278  * static void 
279  * logger (void *cls, uint32_t log_level, const char *log_message);
280  * </pre>
281  * where 'cls' is supposed to be a 'FILE *'.
282  * Then for PSYC to call this method with 'stderr' for 'cls',
283  * we would provide the following method descriptor:
284  * <pre>
285  * .method_name = "log";
286  * .method = &wrap_logger;
287  * .method_cls = stderr;
288  * .argc = 2;
289  * .argv = { GNUNET_PSYC_AD_UINT32, GNUNET_PSYC_AD_UTF8 };
290  * </pre>
291  * and define <tt>wrap_logger</tt> as follows:
292  * <pre>
293  * static void
294  * wrap_logger (void *cls, const char full_method_name, 
295  *              const struct GNUNET_PeerIdentity *sender,
296  *              unsigned int argc, const struct GNUNET_PSYC_Argument *argv)
297  * {
298  *    uint32_t *log_level = argv[0].data;
299  *    const char *log_message = argv[1].data;
300  *    logger (cls, *log_level, log_message);
301  * }
302  * </pre> 
303  * Note that the PSYC library will take care of making sure
304  * that 'argv[0].data_size == 4' and that the log message
305  * is 0-terminated, as those requirements were specified
306  * in the method descriptor for those arguments.  Finally,
307  * it is conceivable to generate the wrappers and method
308  * descriptors automatically, as they are trivial.
309  * <p>
310  * Note that due to try & slice, the given full method name
311  * might be more specific; for example, the given method
312  * might be called for a request to "log_warning" instead
313  * of just a request to "log".
314  */
315 struct GNUNET_PSYC_MethodDescriptor
316 {
317
318   /**
319    * Name of the method to be used in try-and-slice matching.
320    */
321   const char *method_name;
322
323   /**
324    * Function to call.  Note that if a more specific handler exists
325    * as well, the more generic handler will not be invoked.
326    */
327   GNUNET_PSYC_Method method;
328
329   /**
330    * Closure for the method (this argument and the 'sender' argument
331    * are both not included in 'argc').
332    */
333   void *method_cls;
334
335   /**
336    * Number of arguments to pass to the method (length of the 'ads'
337    * array).
338    */
339   unsigned int argc;
340
341   /**
342    * Array of 'argc' argument descriptors describing the arguments to
343    * be passed to the method.  Non-matching method calls will be
344    * ignored (but logged).  Note that the 'ads' of all methods with
345    * the same method name prefix should be identical.
346    */
347   const struct GNUNET_PSYC_ArgumentDescriptor *ads;
348
349 };
350
351
352 /**
353  * Handle for the origin of a psyc group.
354  */
355 struct GNUNET_PSYC_Origin;
356
357
358 /**
359  * Start a psyc group.  Will create a multicast group identified by
360  * the given public key.  Messages recevied from group members will be
361  * given to the respective handler methods.  If a new member wants to
362  * join a group, the "join" method handler will be invoked; the join
363  * handler must then generate a "join" message to approve the joining
364  * of the new member.  The origin can also change group membership
365  * without explicit requests.  Note that PSYC doesn't itself "understand"
366  * join or leave messages, the respective methods must call other
367  * PSYC functions to inform PSYC about the meaning of the respective
368  * events.
369  *
370  * @param cfg configuration to use (to connect to PSYC service)
371  * @param method_count number of methods in 'methods' array
372  * @param methods functions to invoke on messages received from members,
373  *                typcially at least contains functions for 'join' and 'leave'.
374  * @param priv_key ECC key that will be used to sign messages for this
375  *                 psyc session; public key is used to identify the
376  *                 psyc group; FIXME: we'll likely want to use
377  *                 NOT the p521 curve here, but a cheaper one in the future
378  * @param join_policy what is the membership policy of the group?
379  * @return handle for the origin, NULL on error 
380  */
381 struct GNUNET_PSYC_Origin *
382 GNUNET_PSYC_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, 
383                           unsigned int method_count,
384                           const struct GNUNET_PSYC_MethodDescriptor *methods,
385                           const struct GNUNET_CRYPTO_EccPrivateKey *priv_key,
386                           enum GNUNET_MULTICAST_JoinPolicy join_policy);
387
388
389 /**
390  * Update channel state.  The state of a channel must fit into the
391  * memory of each member (and the origin); large values that require
392  * streaming must only be passed as streaming arguments to methods.
393  * State updates might not be transmitted to group members until
394  * the next call to 'GNUNET_PSYC_origin_broadcast_call_method'.
395  *
396  * @param origin handle to the psyc group / channel
397  * @param full_state_name name of the field in the channel state to change
398  * @param data_size number of bytes in data
399  * @param data new state value
400  */
401 void
402 GNUNET_PSYC_origin_update_state (struct GNUNET_PSYC_Origin *origin,
403                                  const char *full_state_name,
404                                  size_t data_size,
405                                  const void *data);
406
407
408 /**
409  * Data needed to construct a PSYC message to call a method.
410  */
411 struct GNUNET_PSYC_CallData
412 {
413
414   /**
415    * Name of the function to call.  This name may be more specific
416    * than the registered method name due to try&slice matching.
417    */
418   const char *full_method_name;
419
420   /**
421    * Number of arguments to pass (other than closure and sender),
422    * length of the 'argv' array.
423    */
424   unsigned int argc;
425
426   /**
427    * Arguments to pass to the function.
428    */
429   const struct GNUNET_PSYC_Argument *argv;
430
431 };
432
433
434 /**
435  * Send a message to call a method to all members in the psyc group.
436  *
437  * @param origin handle to the psyc group
438  * @param increment_group_generation GNUNET_YES if we need to increment
439  *        the group generation counter after transmitting this message
440  * @param call_data data needed to determine how to call which method 
441  * @param message_id set to the unique message ID that was generated for
442  *        this message
443  * @param group_generation set to the group generation used for this
444  *        message
445  * FIXME: change to notify_transmit_ready-style to wait for ACKs?
446  *        that'd also help with streaming arguments!
447  *        => need to change multicast API first as well!
448  */
449 void
450 GNUNET_PSYC_origin_broadcast_call_method (struct GNUNET_PSYC_Origin *origin,
451                                           int increment_group_generation,
452                                           const struct GNUNET_PSYC_CallData *call_data,
453                                           uint64_t *message_id,
454                                           uint64_t *group_generation);
455
456
457 /**
458  * End a psyc group.
459  *
460  * @param origin psyc group to terminate
461  */
462 void
463 GNUNET_PSYC_origin_end (struct GNUNET_PSYC_Origin *origin);
464
465
466 /**
467  * Handle to access PSYC group operations for all members.
468  */
469 struct GNUNET_PSYC_Group;
470
471
472 /**
473  * Convert 'origin' to a 'group' handle to access the 'group' APIs.
474  * 
475  * @param origin origin handle
476  * @return group handle, valid for as long as 'origin' is valid
477  */ 
478 struct GNUNET_PSYC_Group *
479 GNUNET_PSYC_origin_get_group (struct GNUNET_PSYC_Origin *origin);
480
481
482 /**
483  * Add a member to the group.    Note that this will NOT generate any
484  * PSYC traffic, it will merely update the local data base to modify
485  * how we react to 'membership test' queries.  The origin still needs to
486  * explicitly transmit a 'leave' message to notify other group members
487  * and they then also must still call this function in their respective
488  * methods handling the 'leave' message.  This way, how 'join' and 'leave'
489  * operations are exactly implemented is still up to the application;
490  * for example, there might be a 'leave_all' message to kick out everyone.
491  *
492  * Note that group members are explicitly trusted to perform these
493  * operations correctly; not doing so correctly will result in either
494  * denying members access or offering access to group data to
495  * non-members.
496  *
497  * @param group group handle
498  * @param member which peer to add
499  * @param message_id message ID for the message that changed the membership
500  * @param group_generation the generation ID where the change went into effect
501  */
502 void
503 GNUNET_PSYC_group_member_admit (struct GNUNET_PSYC_Group *group,
504                                 const struct GNUNET_PeerIdentity *member,
505                                 uint64_t message_id,
506                                 uint64_t group_generation);
507
508
509 /**
510  * Remove a member from the group.  Note that this will NOT generate any
511  * PSYC traffic, it will merely update the local data base to modify
512  * how we react to 'membership test' queries.  The origin still needs to
513  * explicitly transmit a 'leave' message to notify other group members
514  * and they then also must still call this function in their respective
515  * methods handling the 'leave' message.  This way, how 'join' and 'leave'
516  * operations are exactly implemented is still up to the application;
517  * for example, there might be a 'leave_all' message to kick out everyone.
518  *
519  * Note that group members are explicitly trusted to perform these
520  * operations correctly; not doing so correctly will result in either
521  * denying members access or offering access to group data to
522  * non-members.
523  *
524  * @param group group handle
525  * @param member which peer to remove
526  * @param message_id message ID for the message that changed the membership
527  * @param group_generation the generation ID where the change went into effect
528  */
529 void
530 GNUNET_PSYC_group_member_kick (struct GNUNET_PSYC_Group *group,
531                                const struct GNUNET_PeerIdentity *member,
532                                uint64_t message_id,
533                                uint64_t group_generation);
534
535
536 /**
537  * Function called to inform a member about state values for a channel.
538  *
539  * @param cls closure
540  * @param full_state_name full name of the state
541  * @param data_size number of bytes in 'data'
542  * @param data raw data of the state
543  */
544 typedef void (*GNUNET_PSYC_StateCallback)(void *cls,
545                                           const char *full_state_name,
546                                           size_t data_size,
547                                           const void *data);
548
549
550 /**
551  * Descriptor for an event handler handling PSYC state updates.
552  */
553 struct GNUNET_PSYC_StateHandler
554 {
555
556   /**
557    * Name of the state this handler calls about, used in try-and-slice matching.
558    */
559   const char *state_name;
560
561   /**
562    * Function to call whenever the respective state changes.
563    */
564   GNUNET_PSYC_StateCallback event_handler;
565
566   /**
567    * Closure for the 'event_handler' function.
568    */
569   void *event_handler_cls;
570
571   /**
572    * Description of the kind of state that the handler expects to see.
573    * Non-matching state updates will be ignored (but logged).  Note
574    * that the state_types of all states with the same state name prefix
575    * should be identical.
576    */
577   struct GNUNET_PSYC_ArgumentDescriptor state_type;
578
579 };
580
581
582 /**
583  * Join a psyc group.  The entity joining is always the local peer.
584  * This will send a 'join_msg' to the origin; if it succeeds, the
585  * channel state will be replayed to the joining member and the 'join'
586  * method will be invoked to show that we joined successfully.  There
587  * is no explicit notification on failure (as the origin may simply
588  * take days to approve, and disapproval is simply being ignored).
589  *
590  * Note that we also specify the message to transmit to origin on
591  * 'leave' here, as a sudden crash might otherwise not permit sending
592  * a 'nice' leave message.   TODO: we might want an API to change
593  * the 'leave' message later during the session.
594  * 
595  * @param cfg configuration to use
596  * @param pub_key ECC key that identifies the group
597  * @param method_count number of methods in 'methods' array
598  * @param methods functions to invoke on messages received from the origin,
599  *                typcially at least contains functions for 'join' and 'leave'.
600  * @param state_count number of state handlers
601  * @param state_handlers array of state event handlers
602  * @param join_data method to invoke on origin to trigger joining;
603  *        use NULL to send nothing (useful for anonymous groups that permit anyone);
604           arguments to give to join method, must not include streaming args
605  * @param leave_data method to invoke on origin on leaving;
606  *        use NULL to send nothing (useful for anonymous groups that permit anyone);
607           arguments to give to leave method, must not include streaming args
608  * @return handle for the member, NULL on error 
609  */
610 struct GNUNET_PSYC_Member *
611 GNUNET_PSYC_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, 
612                          const struct GNUNET_CRYPTO_EccPublicKey *pub_key,
613                          unsigned int method_count,
614                          const struct GNUNET_PSYC_MethodDescriptor *methods,
615                          unsigned int state_count,
616                          struct GNUNET_PSYC_StateHandler *state_handlers,
617                          const struct GNUNET_PSYC_CallData *join_data,
618                          const struct GNUNET_PSYC_CallData *leave_data);
619
620
621 /**
622  * Request a message to be send to the origin.
623  *
624  * @param member membership handle
625  * @param request_data which method should be invoked on origin (and how)
626  *
627  * FIXME: change to notify_transmit_ready-style to wait for ACKs
628  * and to enable streaming arguments!
629  */
630 void
631 GNUNET_PSYC_member_send_to_origin (struct GNUNET_PSYC_Member *member,
632                                    const struct GNUNET_PSYC_CallData *request_data);
633
634
635 /**
636  * Call the given state callback on all matching states in the channel
637  * state.  The callback is invoked synchronously on all matching
638  * states (as the state is fully replicated in the library in this
639  * process; channel states should be small, large data is to be passed
640  * as streaming data to methods).
641  *
642  * @param member membership handle
643  * @param state_name name of the state to query (full name 
644  *        might be longer, this is only the prefix that must match)
645  * @param cb function to call on the matching state values
646  * @param cb_cls closure for 'cb'
647  */
648 int
649 GNUNET_PSYC_member_state_get (struct GNUNET_PSYC_Member *member,
650                               const char *state_name,
651                               GNUNET_PSYC_StateCallback cb,
652                               void *cb_cls);
653
654
655 /**
656  * Leave a mutlicast group.  Will terminate the connection to the PSYC
657  * service, which will send the 'leave' method that was prepared
658  * earlier to the origin.  This function must not be called on a
659  * 'member' that was obtained from GNUNET_PSYC_origin_get_group.
660  *
661  * @param member membership handle
662  */
663 void
664 GNUNET_PSYC_member_leave (struct GNUNET_PSYC_Member *member);
665
666
667
668 #if 0                           /* keep Emacsens' auto-indent happy */
669 {
670 #endif
671 #ifdef __cplusplus
672 }
673 #endif
674
675 /* ifndef GNUNET_PSYC_SERVICE_H */
676 #endif
677 /* end of gnunet_psyc_service.h */