added adaptive step-intervals
[oweals/gnunet.git] / src / psyc / psyc_api.c
1 /*
2  * This file is part of GNUnet
3  * (C) 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 psyc/psyc_api.c
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  *        Parsing (and serializing) the PSYC stream format is done
27  *        within the implementation of the libgnunetpsyc library,
28  *        and this API deliberately exposes as little as possible
29  *        of the actual data stream format to the application!
30  * @author Gabor X Toth
31  */
32
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_env_lib.h"
36 #include "gnunet_psyc_service.h"
37 #include "psyc.h"
38
39 #define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__)
40
41
42 struct OperationHandle
43 {
44   struct OperationHandle *prev;
45   struct OperationHandle *next;
46   const struct GNUNET_MessageHeader *msg;
47 };
48
49 /**
50  * Handle to access PSYC channel operations for both the master and slaves.
51  */
52 struct GNUNET_PSYC_Channel
53 {
54   /**
55    * Configuration to use.
56    */
57   const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59   /**
60    * Socket (if available).
61    */
62   struct GNUNET_CLIENT_Connection *client;
63
64   /**
65    * Currently pending transmission request, or NULL for none.
66    */
67   struct GNUNET_CLIENT_TransmitHandle *th;
68
69   /**
70    * Head of operations to transmit.
71    */
72   struct OperationHandle *transmit_head;
73
74   /**
75    * Tail of operations to transmit.
76    */
77   struct OperationHandle *transmit_tail;
78
79   /**
80    * Message to send on reconnect.
81    */
82   struct GNUNET_MessageHeader *reconnect_msg;
83
84   /**
85    * Task doing exponential back-off trying to reconnect.
86    */
87   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
88
89   /**
90    * Time for next connect retry.
91    */
92   struct GNUNET_TIME_Relative reconnect_delay;
93
94   GNUNET_PSYC_Method method_cb;
95
96   GNUNET_PSYC_JoinCallback join_cb;
97
98   void *cb_cls;
99
100   /**
101    * Are we polling for incoming messages right now?
102    */
103   int in_receive;
104
105   /**
106    * Are we currently transmitting a message?
107    */
108   int in_transmit;
109
110   /**
111    * Is this a master or slave channel?
112    */
113   int is_master;
114
115   /**
116    * Buffer space available for transmitting the next data fragment.
117    */
118   uint16_t tmit_buf_avail;
119 };
120
121
122 /**
123  * Handle for a pending PSYC transmission operation.
124  */
125 struct GNUNET_PSYC_MasterTransmitHandle
126 {
127   struct GNUNET_PSYC_Master *master;
128   GNUNET_PSYC_MasterTransmitNotify notify;
129   void *notify_cls;
130   enum GNUNET_PSYC_DataStatus status;
131 };
132
133
134 /**
135  * Handle for the master of a PSYC channel.
136  */
137 struct GNUNET_PSYC_Master
138 {
139   struct GNUNET_PSYC_Channel ch;
140
141   struct GNUNET_PSYC_MasterTransmitHandle *tmit;
142
143   GNUNET_PSYC_MasterStartCallback start_cb;
144
145   uint64_t max_message_id;
146 };
147
148
149 /**
150  * Handle for a PSYC channel slave.
151  */
152 struct GNUNET_PSYC_Slave
153 {
154   struct GNUNET_PSYC_Channel ch;
155 };
156
157
158 /**
159  * Handle that identifies a join request.
160  *
161  * Used to match calls to #GNUNET_PSYC_JoinCallback to the
162  * corresponding calls to GNUNET_PSYC_join_decision().
163  */
164 struct GNUNET_PSYC_JoinHandle
165 {
166
167 };
168
169
170 /**
171  * Handle for a pending PSYC transmission operation.
172  */
173 struct GNUNET_PSYC_SlaveTransmitHandle
174 {
175
176 };
177
178
179 /**
180  * Handle to a story telling operation.
181  */
182 struct GNUNET_PSYC_Story
183 {
184
185 };
186
187
188 /**
189  * Handle for a state query operation.
190  */
191 struct GNUNET_PSYC_StateQuery
192 {
193
194 };
195
196
197 /**
198  * Try again to connect to the PSYC service.
199  *
200  * @param cls Handle to the PSYC service.
201  * @param tc Scheduler context
202  */
203 static void
204 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
205
206
207 /**
208  * Reschedule a connect attempt to the service.
209  *
210  * @param c channel to reconnect
211  */
212 static void
213 reschedule_connect (struct GNUNET_PSYC_Channel *c)
214 {
215   GNUNET_assert (c->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
216
217   if (NULL != c->th)
218   {
219     GNUNET_CLIENT_notify_transmit_ready_cancel (c->th);
220     c->th = NULL;
221   }
222   if (NULL != c->client)
223   {
224     GNUNET_CLIENT_disconnect (c->client);
225     c->client = NULL;
226   }
227   c->in_receive = GNUNET_NO;
228   LOG (GNUNET_ERROR_TYPE_DEBUG,
229        "Scheduling task to reconnect to PSYC service in %s.\n",
230        GNUNET_STRINGS_relative_time_to_string (c->reconnect_delay, GNUNET_YES));
231   c->reconnect_task =
232       GNUNET_SCHEDULER_add_delayed (c->reconnect_delay, &reconnect, c);
233   c->reconnect_delay = GNUNET_TIME_STD_BACKOFF (c->reconnect_delay);
234 }
235
236
237 /**
238  * Schedule transmission of the next message from our queue.
239  *
240  * @param ch PSYC channel handle
241  */
242 static void
243 transmit_next (struct GNUNET_PSYC_Channel *ch);
244
245
246 static void
247 master_transmit_data (struct GNUNET_PSYC_Master *mst)
248 {
249   struct GNUNET_PSYC_Channel *ch = &mst->ch;
250   size_t data_size = ch->tmit_buf_avail;
251   struct GNUNET_PSYC_MessageData *pdata;
252   struct OperationHandle *op
253     = GNUNET_malloc (sizeof (*op) + sizeof (*pdata) + data_size);
254   pdata = (struct GNUNET_PSYC_MessageData *) &op[1];
255   op->msg = (struct GNUNET_MessageHeader *) pdata;
256   pdata->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
257
258   switch (mst->tmit->notify (mst->tmit->notify_cls, &data_size, &pdata[1]))
259   {
260   case GNUNET_NO:
261     mst->tmit->status = GNUNET_PSYC_DATA_CONT;
262     break;
263
264   case GNUNET_YES:
265     mst->tmit->status = GNUNET_PSYC_DATA_END;
266     break;
267
268   default:
269     mst->tmit->status = GNUNET_PSYC_DATA_CANCEL;
270     data_size = 0;
271     LOG (GNUNET_ERROR_TYPE_ERROR, "MasterTransmitNotify returned error\n");
272   }
273
274   if ((GNUNET_PSYC_DATA_CONT == mst->tmit->status && 0 == data_size))
275   {
276     /* Transmission paused, nothing to send. */
277     GNUNET_free (op);
278   }
279   else
280   {
281     GNUNET_assert (data_size <= ch->tmit_buf_avail);
282     pdata->header.size = htons (sizeof (*pdata) + data_size);
283     pdata->status = htons (mst->tmit->status);
284     GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
285     transmit_next (ch);
286   }
287 }
288
289
290 /**
291  * Type of a function to call when we receive a message
292  * from the service.
293  *
294  * @param cls closure
295  * @param msg message received, NULL on timeout or fatal error
296  */
297 static void
298 message_handler (void *cls,
299                  const struct GNUNET_MessageHeader *msg)
300 {
301   // YUCK! => please have disjoint message handlers...
302   struct GNUNET_PSYC_Channel *ch = cls;
303   struct GNUNET_PSYC_Master *mst = cls;
304   struct GNUNET_PSYC_Slave *slv = cls;
305   struct CountersResult *cres;
306   struct TransmitAck *tack;
307
308
309   if (NULL == msg)
310   {
311     reschedule_connect (ch);
312     return;
313   }
314   uint16_t size_eq = 0;
315   uint16_t size_min = 0;
316   uint16_t size = ntohs (msg->size);
317   uint16_t type = ntohs (msg->type);
318
319   LOG (GNUNET_ERROR_TYPE_DEBUG,
320        "Received message of type %d from PSYC service\n", type);
321
322   switch (type)
323   {
324   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
325   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
326     size_eq = sizeof (struct CountersResult);
327     break;
328   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
329     size_eq = sizeof (struct TransmitAck);
330     break;
331   }
332
333   if (! ((0 < size_eq && size == size_eq)
334          || (0 < size_min && size >= size_min)))
335   {
336     GNUNET_break (0);
337     reschedule_connect (ch);
338     return;
339   }
340
341   switch (type)
342   {
343   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
344     cres = (struct CountersResult *) msg;
345     mst->max_message_id = GNUNET_ntohll (cres->max_message_id);
346     if (NULL != mst->start_cb)
347       mst->start_cb (ch->cb_cls, mst->max_message_id);
348     break;
349
350   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
351     cres = (struct CountersResult *) msg;
352 #if TODO
353     slv->max_message_id = GNUNET_ntohll (cres->max_message_id);
354     if (NULL != slv->join_ack_cb)
355       mst->join_ack_cb (ch->cb_cls, mst->max_message_id);
356 #endif
357     break;
358
359   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
360     tack = (struct TransmitAck *) msg;
361     if (ch->is_master)
362     {
363       GNUNET_assert (NULL != mst->tmit);
364       if (GNUNET_PSYC_DATA_CONT != mst->tmit->status
365           || NULL == mst->tmit->notify)
366       {
367         GNUNET_free (mst->tmit);
368         mst->tmit = NULL;
369       }
370       else
371       {
372         ch->tmit_buf_avail = ntohs (tack->buf_avail);
373         master_transmit_data (mst);
374       }
375     }
376     else
377     {
378       /* TODO: slave */
379     }
380     break;
381   }
382
383   GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
384                          GNUNET_TIME_UNIT_FOREVER_REL);
385 }
386
387
388 /**
389  * Transmit next message to service.
390  *
391  * @param cls The 'struct GNUNET_PSYC_Channel'.
392  * @param size Number of bytes available in buf.
393  * @param buf Where to copy the message.
394  * @return Number of bytes copied to buf.
395  */
396 static size_t
397 send_next_message (void *cls, size_t size, void *buf)
398 {
399   struct GNUNET_PSYC_Channel *ch = cls;
400   struct OperationHandle *op = ch->transmit_head;
401   size_t ret;
402
403   ch->th = NULL;
404   if (NULL == op->msg)
405     return 0;
406   ret = ntohs (op->msg->size);
407   if (ret > size)
408   {
409     reschedule_connect (ch);
410     return 0;
411   }
412   LOG (GNUNET_ERROR_TYPE_DEBUG,
413        "Sending message of type %d to PSYC service\n",
414        ntohs (op->msg->type));
415   memcpy (buf, op->msg, ret);
416
417   GNUNET_CONTAINER_DLL_remove (ch->transmit_head, ch->transmit_tail, op);
418   GNUNET_free (op);
419
420   if (NULL != ch->transmit_head)
421     transmit_next (ch);
422
423   if (GNUNET_NO == ch->in_receive)
424   {
425     ch->in_receive = GNUNET_YES;
426     GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
427                            GNUNET_TIME_UNIT_FOREVER_REL);
428   }
429   return ret;
430 }
431
432
433 /**
434  * Schedule transmission of the next message from our queue.
435  *
436  * @param ch PSYC handle.
437  */
438 static void
439 transmit_next (struct GNUNET_PSYC_Channel *ch)
440 {
441   if (NULL != ch->th || NULL == ch->client)
442     return;
443
444   struct OperationHandle *op = ch->transmit_head;
445   if (NULL == op)
446     return;
447
448   ch->th = GNUNET_CLIENT_notify_transmit_ready (ch->client,
449                                                 ntohs (op->msg->size),
450                                                 GNUNET_TIME_UNIT_FOREVER_REL,
451                                                 GNUNET_NO,
452                                                 &send_next_message,
453                                                 ch);
454 }
455
456
457 /**
458  * Try again to connect to the PSYC service.
459  *
460  * @param cls Channel handle.
461  * @param tc Scheduler context.
462  */
463 static void
464 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
465 {
466   struct GNUNET_PSYC_Channel *ch = cls;
467
468   ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
469   LOG (GNUNET_ERROR_TYPE_DEBUG,
470        "Connecting to PSYC service.\n");
471   GNUNET_assert (NULL == ch->client);
472   ch->client = GNUNET_CLIENT_connect ("psyc", ch->cfg);
473   GNUNET_assert (NULL != ch->client);
474
475   if (NULL == ch->transmit_head ||
476       ch->transmit_head->msg->type != ch->reconnect_msg->type)
477   {
478     uint16_t reconn_size = ntohs (ch->reconnect_msg->size);
479     struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + reconn_size);
480     memcpy (&op[1], ch->reconnect_msg, reconn_size);
481     op->msg = (struct GNUNET_MessageHeader *) &op[1];
482     GNUNET_CONTAINER_DLL_insert (ch->transmit_head, ch->transmit_tail, op);
483   }
484   transmit_next (ch);
485 }
486
487
488 /**
489  * Disconnect from the PSYC service.
490  *
491  * @param c Channel handle to disconnect
492  */
493 static void
494 disconnect (void *c)
495 {
496   struct GNUNET_PSYC_Channel *ch = c;
497
498   GNUNET_assert (NULL != ch);
499   if (ch->transmit_head != ch->transmit_tail)
500   {
501     LOG (GNUNET_ERROR_TYPE_ERROR,
502          "Disconnecting while there are still outstanding messages!\n");
503     GNUNET_break (0);
504   }
505   if (ch->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
506   {
507     GNUNET_SCHEDULER_cancel (ch->reconnect_task);
508     ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
509   }
510   if (NULL != ch->th)
511   {
512     GNUNET_CLIENT_notify_transmit_ready_cancel (ch->th);
513     ch->th = NULL;
514   }
515   if (NULL != ch->client)
516   {
517     GNUNET_CLIENT_disconnect (ch->client);
518     ch->client = NULL;
519   }
520   if (NULL != ch->reconnect_msg)
521   {
522     GNUNET_free (ch->reconnect_msg);
523     ch->reconnect_msg = NULL;
524   }
525 }
526
527
528 /**
529  * Start a PSYC master channel.
530  *
531  * Will start a multicast group identified by the given ECC key.  Messages
532  * received from group members will be given to the respective handler methods.
533  * If a new member wants to join a group, the "join" method handler will be
534  * invoked; the join handler must then generate a "join" message to approve the
535  * joining of the new member.  The channel can also change group membership
536  * without explicit requests.  Note that PSYC doesn't itself "understand" join
537  * or part messages, the respective methods must call other PSYC functions to
538  * inform PSYC about the meaning of the respective events.
539  *
540  * @param cfg Configuration to use (to connect to PSYC service).
541  * @param channel_key ECC key that will be used to sign messages for this
542  *        PSYC session. The public key is used to identify the PSYC channel.
543  *        Note that end-users will usually not use the private key directly, but
544  *        rather look it up in GNS for places managed by other users, or select
545  *        a file with the private key(s) when setting up their own channels
546  *        FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper
547  *        one in the future.
548  * @param policy Channel policy specifying join and history restrictions.
549  *        Used to automate join decisions.
550  * @param method Function to invoke on messages received from slaves.
551  * @param join_cb Function to invoke when a peer wants to join.
552  * @param master_started_cb Function to invoke after the channel master started.
553  * @param cls Closure for @a master_started_cb and @a join_cb.
554  * @return Handle for the channel master, NULL on error.
555  */
556 struct GNUNET_PSYC_Master *
557 GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
558                           const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key,
559                           enum GNUNET_PSYC_Policy policy,
560                           GNUNET_PSYC_Method method,
561                           GNUNET_PSYC_JoinCallback join_cb,
562                           GNUNET_PSYC_MasterStartCallback master_started_cb,
563                           void *cls)
564 {
565   struct GNUNET_PSYC_Master *mst = GNUNET_malloc (sizeof (*mst));
566   struct GNUNET_PSYC_Channel *ch = &mst->ch;
567   struct MasterStartRequest *req = GNUNET_malloc (sizeof (*req));
568
569   req->header.size = htons (sizeof (*req));
570   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START);
571   req->channel_key = *channel_key;
572   req->policy = policy;
573
574   ch->cfg = cfg;
575   ch->is_master = GNUNET_YES;
576   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
577   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
578   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, mst);
579
580   ch->method_cb = method;
581   ch->join_cb = join_cb;
582   ch->cb_cls = cls;
583   mst->start_cb = master_started_cb;
584
585   return mst;
586 }
587
588
589 /**
590  * Stop a PSYC master channel.
591  *
592  * @param master PSYC channel master to stop.
593  */
594 void
595 GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master)
596 {
597   disconnect (master);
598   GNUNET_free (master);
599 }
600
601
602 /**
603  * Function to call with the decision made for a join request.
604  *
605  * Must be called once and only once in response to an invocation of the
606  * #GNUNET_PSYC_JoinCallback.
607  *
608  * @param jh Join request handle.
609  * @param is_admitted #GNUNET_YES if joining is approved,
610  *        #GNUNET_NO if it is disapproved.
611  * @param relay_count Number of relays given.
612  * @param relays Array of suggested peers that might be useful relays to use
613  *        when joining the multicast group (essentially a list of peers that
614  *        are already part of the multicast group and might thus be willing
615  *        to help with routing).  If empty, only this local peer (which must
616  *        be the multicast origin) is a good candidate for building the
617  *        multicast tree.  Note that it is unnecessary to specify our own
618  *        peer identity in this array.
619  * @param method_name Method name for the message transmitted with the response.
620  * @param env Environment containing transient variables for the message, or NULL.
621  * @param data Data of the message.
622  * @param data_size Size of @a data.
623  */
624 void
625 GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
626                            int is_admitted,
627                            uint32_t relay_count,
628                            const struct GNUNET_PeerIdentity *relays,
629                            const char *method_name,
630                            const struct GNUNET_ENV_Environment *env,
631                            const void *data,
632                            size_t data_size)
633 {
634
635 }
636
637
638 /* FIXME: split up value into <64K chunks and transmit the continuations in
639  *        MOD_CONT msgs */
640 static int
641 send_modifier (void *cls, struct GNUNET_ENV_Modifier *mod)
642 {
643   struct GNUNET_PSYC_Channel *ch = cls;
644   size_t name_size = strlen (mod->name) + 1;
645   struct GNUNET_PSYC_MessageModifier *pmod;
646   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*pmod)
647                                               + name_size + mod->value_size);
648   pmod = (struct GNUNET_PSYC_MessageModifier *) &op[1];
649   op->msg = (struct GNUNET_MessageHeader *) pmod;
650
651   pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
652   pmod->header.size = htons (sizeof (*pmod) + name_size + mod->value_size);
653   pmod->name_size = htons (name_size);
654   memcpy (&pmod[1], mod->name, name_size);
655   memcpy ((char *) &pmod[1] + name_size, mod->value, mod->value_size);
656
657   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
658   return GNUNET_YES;
659 }
660
661
662 /**
663  * Send a message to call a method to all members in the PSYC channel.
664  *
665  * @param master Handle to the PSYC channel.
666  * @param method_name Which method should be invoked.
667  * @param env Environment containing state operations and transient variables
668  *            for the message, or NULL.
669  * @param notify Function to call to obtain the arguments.
670  * @param notify_cls Closure for @a notify.
671  * @param flags Flags for the message being transmitted.
672  * @return Transmission handle, NULL on error (i.e. more than one request
673  *         queued).
674  */
675 struct GNUNET_PSYC_MasterTransmitHandle *
676 GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *master,
677                              const char *method_name,
678                              const struct GNUNET_ENV_Environment *env,
679                              GNUNET_PSYC_MasterTransmitNotify notify,
680                              void *notify_cls,
681                              enum GNUNET_PSYC_MasterTransmitFlags flags)
682 {
683   GNUNET_assert (NULL != master);
684   struct GNUNET_PSYC_Channel *ch = &master->ch;
685   if (GNUNET_NO != ch->in_transmit)
686     return NULL;
687   ch->in_transmit = GNUNET_YES;
688
689   size_t size = strlen (method_name) + 1;
690   struct GNUNET_PSYC_MessageMethod *pmeth;
691   struct OperationHandle *op
692     = GNUNET_malloc (sizeof (*op) + sizeof (*pmeth) + size);
693   pmeth = (struct GNUNET_PSYC_MessageMethod *) &op[1];
694   op->msg = (struct GNUNET_MessageHeader *) pmeth;
695
696   pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
697   pmeth->header.size = htons (sizeof (*pmeth) + size);
698   pmeth->flags = htonl (flags);
699   pmeth->mod_count = GNUNET_ntohll (GNUNET_ENV_environment_get_mod_count (env));
700   memcpy (&pmeth[1], method_name, size);
701
702   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
703   GNUNET_ENV_environment_iterate (env, send_modifier, master);
704   transmit_next (ch);
705
706   master->tmit = GNUNET_malloc (sizeof (*master->tmit));
707   master->tmit->master = master;
708   master->tmit->notify = notify;
709   master->tmit->notify_cls = notify_cls;
710   master->tmit->status = GNUNET_PSYC_DATA_CONT;
711   return master->tmit;
712 }
713
714
715 /**
716  * Resume transmission to the channel.
717  *
718  * @param th Handle of the request that is being resumed.
719  */
720 void
721 GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
722 {
723   master_transmit_data (th->master);
724 }
725
726
727 /**
728  * Abort transmission request to the channel.
729  *
730  * @param th Handle of the request that is being aborted.
731  */
732 void
733 GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th)
734 {
735   struct GNUNET_PSYC_Master *master = th->master;
736   struct GNUNET_PSYC_Channel *ch = &master->ch;
737   if (GNUNET_NO != ch->in_transmit)
738     return;
739 }
740
741
742 /**
743  * Join a PSYC channel.
744  *
745  * The entity joining is always the local peer.  The user must immediately use
746  * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the
747  * channel; if the join request succeeds, the channel state (and @e recent
748  * method calls) will be replayed to the joining member.  There is no explicit
749  * notification on failure (as the channel may simply take days to approve,
750  * and disapproval is simply being ignored).
751  *
752  * @param cfg Configuration to use.
753  * @param channel_key ECC public key that identifies the channel we wish to join.
754  * @param slave_key ECC private-public key pair that identifies the slave, and
755  *        used by multicast to sign the join request and subsequent unicast
756  *        requests sent to the master.
757  * @param origin Peer identity of the origin.
758  * @param relay_count Number of peers in the @a relays array.
759  * @param relays Peer identities of members of the multicast group, which serve
760  *        as relays and used to join the group at.
761  * @param method Function to invoke on messages received from the channel,
762  *        typically at least contains functions for @e join and @e part.
763  * @param join_cb function invoked once we have joined with the current
764  *        message ID of the channel
765  * @param slave_joined_cb Function to invoke when a peer wants to join.
766  * @param cls Closure for @a method_cb and @a slave_joined_cb.
767  * @param method_name Method name for the join request.
768  * @param env Environment containing transient variables for the request, or NULL.
769  * @param data Payload for the join message.
770  * @param data_size Number of bytes in @a data.
771  * @return Handle for the slave, NULL on error.
772  */
773 struct GNUNET_PSYC_Slave *
774 GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
775                         const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
776                         const struct GNUNET_CRYPTO_EddsaPrivateKey *slave_key,
777                         const struct GNUNET_PeerIdentity *origin,
778                         uint32_t relay_count,
779                         const struct GNUNET_PeerIdentity *relays,
780                         GNUNET_PSYC_Method method,
781                         GNUNET_PSYC_JoinCallback join_cb,
782                         GNUNET_PSYC_SlaveJoinCallback slave_joined_cb,
783                         void *cls,
784                         const char *method_name,
785                         const struct GNUNET_ENV_Environment *env,
786                         const void *data,
787                         uint16_t data_size)
788 {
789   struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv));
790   struct GNUNET_PSYC_Channel *ch = &slv->ch;
791   struct SlaveJoinRequest *req = GNUNET_malloc (sizeof (*req)
792                                                 + relay_count * sizeof (*relays));
793   req->header.size = htons (sizeof (*req)
794                             + relay_count * sizeof (*relays));
795   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
796   req->channel_key = *channel_key;
797   req->slave_key = *slave_key;
798   req->origin = *origin;
799   req->relay_count = relay_count;
800   memcpy (&req[1], relays, relay_count * sizeof (*relays));
801
802   ch->cfg = cfg;
803   ch->is_master = GNUNET_NO;
804   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
805   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
806   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, slv);
807
808   return slv;
809 }
810
811
812 /**
813  * Part a PSYC channel.
814  *
815  * Will terminate the connection to the PSYC service.  Polite clients should
816  * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
817  *
818  * @param slave Slave handle.
819  */
820 void
821 GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave)
822 {
823   disconnect (slave);
824   GNUNET_free (slave);
825 }
826
827
828 /**
829  * Request a message to be sent to the channel master.
830  *
831  * @param slave Slave handle.
832  * @param method_name Which (PSYC) method should be invoked (on host).
833  * @param env Environment containing transient variables for the message, or
834  *            NULL.
835  * @param notify Function to call when we are allowed to transmit (to get data).
836  * @param notify_cls Closure for @a notify.
837  * @param flags Flags for the message being transmitted.
838  * @return Transmission handle, NULL on error (i.e. more than one request
839  *         queued).
840  */
841 struct GNUNET_PSYC_SlaveTransmitHandle *
842 GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave,
843                             const char *method_name,
844                             const struct GNUNET_ENV_Environment *env,
845                             GNUNET_PSYC_SlaveTransmitNotify notify,
846                             void *notify_cls,
847                             enum GNUNET_PSYC_SlaveTransmitFlags flags)
848 {
849   return NULL;
850 }
851
852
853 /**
854  * Resume transmission to the master.
855  *
856  * @param th Handle of the request that is being resumed.
857  */
858 void
859 GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
860 {
861
862 }
863
864
865 /**
866  * Abort transmission request to master.
867  *
868  * @param th Handle of the request that is being aborted.
869  */
870 void
871 GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th)
872 {
873
874 }
875
876
877 /**
878  * Convert a channel @a master to a @e channel handle to access the @e channel
879  * APIs.
880  *
881  * @param master Channel master handle.
882  * @return Channel handle, valid for as long as @a master is valid.
883  */
884 struct GNUNET_PSYC_Channel *
885 GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master)
886 {
887   return (struct GNUNET_PSYC_Channel *) master;
888 }
889
890
891 /**
892  * Convert @a slave to a @e channel handle to access the @e channel APIs.
893  *
894  * @param slave Slave handle.
895  * @return Channel handle, valid for as long as @a slave is valid.
896  */
897 struct GNUNET_PSYC_Channel *
898 GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave)
899 {
900   return (struct GNUNET_PSYC_Channel *) slave;
901 }
902
903
904 /**
905  * Add a slave to the channel's membership list.
906  *
907  * Note that this will NOT generate any PSYC traffic, it will merely update the
908  * local database to modify how we react to <em>membership test</em> queries.
909  * The channel master still needs to explicitly transmit a @e join message to
910  * notify other channel members and they then also must still call this function
911  * in their respective methods handling the @e join message.  This way, how @e
912  * join and @e part operations are exactly implemented is still up to the
913  * application; for example, there might be a @e part_all method to kick out
914  * everyone.
915  *
916  * Note that channel slaves are explicitly trusted to execute such methods
917  * correctly; not doing so correctly will result in either denying other slaves
918  * access or offering access to channel data to non-members.
919  *
920  * @param channel Channel handle.
921  * @param slave_key Identity of channel slave to add.
922  * @param announced_at ID of the message that announced the membership change.
923  * @param effective_since Addition of slave is in effect since this message ID.
924  */
925 void
926 GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel,
927                                const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
928                                uint64_t announced_at,
929                                uint64_t effective_since)
930 {
931   struct ChannelSlaveAdd *slvadd;
932   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvadd));
933
934   slvadd = (struct ChannelSlaveAdd *) &op[1];
935   op->msg = (struct GNUNET_MessageHeader *) slvadd;
936
937   slvadd->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_ADD;
938   slvadd->header.size = htons (sizeof (*slvadd));
939   slvadd->announced_at = GNUNET_htonll (announced_at);
940   slvadd->effective_since = GNUNET_htonll (effective_since);
941   GNUNET_CONTAINER_DLL_insert_tail (channel->transmit_head,
942                                     channel->transmit_tail,
943                                     op);
944   transmit_next (channel);
945 }
946
947
948 /**
949  * Remove a slave from the channel's membership list.
950  *
951  * Note that this will NOT generate any PSYC traffic, it will merely update the
952  * local database to modify how we react to <em>membership test</em> queries.
953  * The channel master still needs to explicitly transmit a @e part message to
954  * notify other channel members and they then also must still call this function
955  * in their respective methods handling the @e part message.  This way, how
956  * @e join and @e part operations are exactly implemented is still up to the
957  * application; for example, there might be a @e part_all message to kick out
958  * everyone.
959  *
960  * Note that channel members are explicitly trusted to perform these
961  * operations correctly; not doing so correctly will result in either
962  * denying members access or offering access to channel data to
963  * non-members.
964  *
965  * @param channel Channel handle.
966  * @param slave_key Identity of channel slave to remove.
967  * @param announced_at ID of the message that announced the membership change.
968  */
969 void
970 GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel,
971                                   const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
972                                   uint64_t announced_at)
973 {
974   struct ChannelSlaveRemove *slvrm;
975   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvrm));
976
977   slvrm = (struct ChannelSlaveRemove *) &op[1];
978   op->msg = (struct GNUNET_MessageHeader *) slvrm;
979   slvrm->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM;
980   slvrm->header.size = htons (sizeof (*slvrm));
981   slvrm->announced_at = GNUNET_htonll (announced_at);
982   GNUNET_CONTAINER_DLL_insert_tail (channel->transmit_head,
983                                     channel->transmit_tail,
984                                     op);
985   transmit_next (channel);
986 }
987
988
989 /**
990  * Request to be told the message history of the channel.
991  *
992  * Historic messages (but NOT the state at the time) will be replayed (given to
993  * the normal method handlers) if available and if access is permitted.
994  *
995  * To get the latest message, use 0 for both the start and end message ID.
996  *
997  * @param channel Which channel should be replayed?
998  * @param start_message_id Earliest interesting point in history.
999  * @param end_message_id Last (exclusive) interesting point in history.
1000  * @param method Function to invoke on messages received from the story.
1001  * @param finish_cb Function to call when the requested story has been fully
1002  *        told (counting message IDs might not suffice, as some messages
1003  *        might be secret and thus the listener would not know the story is
1004  *        finished without being told explicitly) once this function
1005  *        has been called, the client must not call
1006  *        GNUNET_PSYC_channel_story_tell_cancel() anymore.
1007  * @param cls Closure for the callbacks.
1008  * @return Handle to cancel story telling operation.
1009  */
1010 struct GNUNET_PSYC_Story *
1011 GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *channel,
1012                                 uint64_t start_message_id,
1013                                 uint64_t end_message_id,
1014                                 GNUNET_PSYC_Method method,
1015                                 GNUNET_PSYC_FinishCallback *finish_cb,
1016                                 void *cls)
1017 {
1018   return NULL;
1019 }
1020
1021
1022 /**
1023  * Abort story telling.
1024  *
1025  * This function must not be called from within method handlers (as given to
1026  * GNUNET_PSYC_slave_join()) of the slave.
1027  *
1028  * @param story Story telling operation to stop.
1029  */
1030 void
1031 GNUNET_PSYC_channel_story_tell_cancel (struct GNUNET_PSYC_Story *story)
1032 {
1033
1034 }
1035
1036
1037 /**
1038  * Retrieve the best matching channel state variable.
1039  *
1040  * If the requested variable name is not present in the state, the nearest
1041  * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1042  * if "_a_b" does not exist.
1043  *
1044  * @param channel Channel handle.
1045  * @param full_name Full name of the requested variable, the actual variable
1046  *        returned might have a shorter name..
1047  * @param cb Function called once when a matching state variable is found.
1048  *        Not called if there's no matching state variable.
1049  * @param cb_cls Closure for the callbacks.
1050  * @return Handle that can be used to cancel the query operation.
1051  */
1052 struct GNUNET_PSYC_StateQuery *
1053 GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel,
1054                                const char *full_name,
1055                                GNUNET_PSYC_StateCallback cb,
1056                                void *cb_cls)
1057 {
1058   return NULL;
1059 }
1060
1061
1062 /**
1063  * Return all channel state variables whose name matches a given prefix.
1064  *
1065  * A name matches if it starts with the given @a name_prefix, thus requesting
1066  * the empty prefix ("") will match all values; requesting "_a_b" will also
1067  * return values stored under "_a_b_c".
1068  *
1069  * The @a state_cb is invoked on all matching state variables asynchronously, as
1070  * the state is stored in and retrieved from the PSYCstore,
1071  *
1072  * @param channel Channel handle.
1073  * @param name_prefix Prefix of the state variable name to match.
1074  * @param cb Function to call with the matching state variables.
1075  * @param cb_cls Closure for the callbacks.
1076  * @return Handle that can be used to cancel the query operation.
1077  */
1078 struct GNUNET_PSYC_StateQuery *
1079 GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel,
1080                                       const char *name_prefix,
1081                                       GNUNET_PSYC_StateCallback cb,
1082                                       void *cb_cls)
1083 {
1084   return NULL;
1085 }
1086
1087
1088 /**
1089  * Cancel a state query operation.
1090  *
1091  * @param query Handle for the operation to cancel.
1092  */
1093 void
1094 GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateQuery *query)
1095 {
1096
1097 }
1098
1099
1100 /* end of psyc_api.c */