51902dd1a09110908e7de18c898f11ab996c0be8
[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
793   req->header.size = htons (sizeof (*req)
794                             + sizeof (*channel_key) + sizeof (*slave_key)
795                             + relay_count * sizeof (*relays));
796   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
797   req->channel_key = *channel_key;
798   req->slave_key = *slave_key;
799   req->origin = *origin;
800   req->relay_count = relay_count;
801   memcpy (&req[1], relays, relay_count * sizeof (*relays));
802
803   ch->cfg = cfg;
804   ch->is_master = GNUNET_NO;
805   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
806   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
807   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, slv);
808
809   return slv;
810 }
811
812
813 /**
814  * Part a PSYC channel.
815  *
816  * Will terminate the connection to the PSYC service.  Polite clients should
817  * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
818  *
819  * @param slave Slave handle.
820  */
821 void
822 GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave)
823 {
824   disconnect (slave);
825   GNUNET_free (slave);
826 }
827
828
829 /**
830  * Request a message to be sent to the channel master.
831  *
832  * @param slave Slave handle.
833  * @param method_name Which (PSYC) method should be invoked (on host).
834  * @param env Environment containing transient variables for the message, or
835  *            NULL.
836  * @param notify Function to call when we are allowed to transmit (to get data).
837  * @param notify_cls Closure for @a notify.
838  * @param flags Flags for the message being transmitted.
839  * @return Transmission handle, NULL on error (i.e. more than one request
840  *         queued).
841  */
842 struct GNUNET_PSYC_SlaveTransmitHandle *
843 GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave,
844                             const char *method_name,
845                             const struct GNUNET_ENV_Environment *env,
846                             GNUNET_PSYC_SlaveTransmitNotify notify,
847                             void *notify_cls,
848                             enum GNUNET_PSYC_SlaveTransmitFlags flags)
849 {
850   return NULL;
851 }
852
853
854 /**
855  * Resume transmission to the master.
856  *
857  * @param th Handle of the request that is being resumed.
858  */
859 void
860 GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
861 {
862
863 }
864
865
866 /**
867  * Abort transmission request to master.
868  *
869  * @param th Handle of the request that is being aborted.
870  */
871 void
872 GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th)
873 {
874
875 }
876
877
878 /**
879  * Convert a channel @a master to a @e channel handle to access the @e channel
880  * APIs.
881  *
882  * @param master Channel master handle.
883  * @return Channel handle, valid for as long as @a master is valid.
884  */
885 struct GNUNET_PSYC_Channel *
886 GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master)
887 {
888   return (struct GNUNET_PSYC_Channel *) master;
889 }
890
891
892 /**
893  * Convert @a slave to a @e channel handle to access the @e channel APIs.
894  *
895  * @param slave Slave handle.
896  * @return Channel handle, valid for as long as @a slave is valid.
897  */
898 struct GNUNET_PSYC_Channel *
899 GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave)
900 {
901   return (struct GNUNET_PSYC_Channel *) slave;
902 }
903
904
905 /**
906  * Add a slave to the channel's membership list.
907  *
908  * Note that this will NOT generate any PSYC traffic, it will merely update the
909  * local database to modify how we react to <em>membership test</em> queries.
910  * The channel master still needs to explicitly transmit a @e join message to
911  * notify other channel members and they then also must still call this function
912  * in their respective methods handling the @e join message.  This way, how @e
913  * join and @e part operations are exactly implemented is still up to the
914  * application; for example, there might be a @e part_all method to kick out
915  * everyone.
916  *
917  * Note that channel slaves are explicitly trusted to execute such methods
918  * correctly; not doing so correctly will result in either denying other slaves
919  * access or offering access to channel data to non-members.
920  *
921  * @param channel Channel handle.
922  * @param slave_key Identity of channel slave to add.
923  * @param announced_at ID of the message that announced the membership change.
924  * @param effective_since Addition of slave is in effect since this message ID.
925  */
926 void
927 GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel,
928                                const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
929                                uint64_t announced_at,
930                                uint64_t effective_since)
931 {
932   struct ChannelSlaveAdd *slvadd;
933   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvadd));
934
935   slvadd = (struct ChannelSlaveAdd *) &op[1];
936   op->msg = (struct GNUNET_MessageHeader *) slvadd;
937
938   slvadd->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_ADD;
939   slvadd->header.size = htons (sizeof (*slvadd));
940   slvadd->announced_at = GNUNET_htonll (announced_at);
941   slvadd->effective_since = GNUNET_htonll (effective_since);
942   GNUNET_CONTAINER_DLL_insert_tail (channel->transmit_head,
943                                     channel->transmit_tail,
944                                     op);
945   transmit_next (channel);
946 }
947
948
949 /**
950  * Remove a slave from the channel's membership list.
951  *
952  * Note that this will NOT generate any PSYC traffic, it will merely update the
953  * local database to modify how we react to <em>membership test</em> queries.
954  * The channel master still needs to explicitly transmit a @e part message to
955  * notify other channel members and they then also must still call this function
956  * in their respective methods handling the @e part message.  This way, how
957  * @e join and @e part operations are exactly implemented is still up to the
958  * application; for example, there might be a @e part_all message to kick out
959  * everyone.
960  *
961  * Note that channel members are explicitly trusted to perform these
962  * operations correctly; not doing so correctly will result in either
963  * denying members access or offering access to channel data to
964  * non-members.
965  *
966  * @param channel Channel handle.
967  * @param slave_key Identity of channel slave to remove.
968  * @param announced_at ID of the message that announced the membership change.
969  */
970 void
971 GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel,
972                                   const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
973                                   uint64_t announced_at)
974 {
975   struct ChannelSlaveRemove *slvrm;
976   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvrm));
977
978   slvrm = (struct ChannelSlaveRemove *) &op[1];
979   op->msg = (struct GNUNET_MessageHeader *) slvrm;
980   slvrm->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM;
981   slvrm->header.size = htons (sizeof (*slvrm));
982   slvrm->announced_at = GNUNET_htonll (announced_at);
983   GNUNET_CONTAINER_DLL_insert_tail (channel->transmit_head,
984                                     channel->transmit_tail,
985                                     op);
986   transmit_next (channel);
987 }
988
989
990 /**
991  * Request to be told the message history of the channel.
992  *
993  * Historic messages (but NOT the state at the time) will be replayed (given to
994  * the normal method handlers) if available and if access is permitted.
995  *
996  * To get the latest message, use 0 for both the start and end message ID.
997  *
998  * @param channel Which channel should be replayed?
999  * @param start_message_id Earliest interesting point in history.
1000  * @param end_message_id Last (exclusive) interesting point in history.
1001  * @param method Function to invoke on messages received from the story.
1002  * @param finish_cb Function to call when the requested story has been fully
1003  *        told (counting message IDs might not suffice, as some messages
1004  *        might be secret and thus the listener would not know the story is
1005  *        finished without being told explicitly) once this function
1006  *        has been called, the client must not call
1007  *        GNUNET_PSYC_channel_story_tell_cancel() anymore.
1008  * @param cls Closure for the callbacks.
1009  * @return Handle to cancel story telling operation.
1010  */
1011 struct GNUNET_PSYC_Story *
1012 GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *channel,
1013                                 uint64_t start_message_id,
1014                                 uint64_t end_message_id,
1015                                 GNUNET_PSYC_Method method,
1016                                 GNUNET_PSYC_FinishCallback *finish_cb,
1017                                 void *cls)
1018 {
1019   return NULL;
1020 }
1021
1022
1023 /**
1024  * Abort story telling.
1025  *
1026  * This function must not be called from within method handlers (as given to
1027  * GNUNET_PSYC_slave_join()) of the slave.
1028  *
1029  * @param story Story telling operation to stop.
1030  */
1031 void
1032 GNUNET_PSYC_channel_story_tell_cancel (struct GNUNET_PSYC_Story *story)
1033 {
1034
1035 }
1036
1037
1038 /**
1039  * Retrieve the best matching channel state variable.
1040  *
1041  * If the requested variable name is not present in the state, the nearest
1042  * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1043  * if "_a_b" does not exist.
1044  *
1045  * @param channel Channel handle.
1046  * @param full_name Full name of the requested variable, the actual variable
1047  *        returned might have a shorter name..
1048  * @param cb Function called once when a matching state variable is found.
1049  *        Not called if there's no matching state variable.
1050  * @param cb_cls Closure for the callbacks.
1051  * @return Handle that can be used to cancel the query operation.
1052  */
1053 struct GNUNET_PSYC_StateQuery *
1054 GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel,
1055                                const char *full_name,
1056                                GNUNET_PSYC_StateCallback cb,
1057                                void *cb_cls)
1058 {
1059   return NULL;
1060 }
1061
1062
1063 /**
1064  * Return all channel state variables whose name matches a given prefix.
1065  *
1066  * A name matches if it starts with the given @a name_prefix, thus requesting
1067  * the empty prefix ("") will match all values; requesting "_a_b" will also
1068  * return values stored under "_a_b_c".
1069  *
1070  * The @a state_cb is invoked on all matching state variables asynchronously, as
1071  * the state is stored in and retrieved from the PSYCstore,
1072  *
1073  * @param channel Channel handle.
1074  * @param name_prefix Prefix of the state variable name to match.
1075  * @param cb Function to call with the matching state variables.
1076  * @param cb_cls Closure for the callbacks.
1077  * @return Handle that can be used to cancel the query operation.
1078  */
1079 struct GNUNET_PSYC_StateQuery *
1080 GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel,
1081                                       const char *name_prefix,
1082                                       GNUNET_PSYC_StateCallback cb,
1083                                       void *cb_cls)
1084 {
1085   return NULL;
1086 }
1087
1088
1089 /**
1090  * Cancel a state query operation.
1091  *
1092  * @param query Handle for the operation to cancel.
1093  */
1094 void
1095 GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateQuery *query)
1096 {
1097
1098 }
1099
1100
1101 /* end of psyc_api.c */