- fix "broken connection" notifications
[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 h transport service 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 h PSYC handle
241  */
242 static void
243 transmit_next (struct GNUNET_PSYC_Channel *c);
244
245
246 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, const struct GNUNET_MessageHeader *msg)
299 {
300   struct GNUNET_PSYC_Channel *ch = cls;
301   struct GNUNET_PSYC_Master *mst = cls;
302   struct GNUNET_PSYC_Slave *slv = cls;
303
304   if (NULL == msg)
305   {
306     reschedule_connect (ch);
307     return;
308   }
309   uint16_t size_eq = 0;
310   uint16_t size_min = 0;
311   uint16_t size = ntohs (msg->size);
312   uint16_t type = ntohs (msg->type);
313
314   LOG (GNUNET_ERROR_TYPE_DEBUG,
315        "Received message of type %d from PSYC service\n", type);
316
317   switch (type)
318   {
319   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
320   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
321     size_eq = sizeof (struct CountersResult);
322     break;
323   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
324     size_eq = sizeof (struct TransmitAck);
325     break;
326   }
327
328   if (! ((0 < size_eq && size == size_eq)
329          || (0 < size_min && size >= size_min)))
330   {
331     GNUNET_break (0);
332     reschedule_connect (ch);
333     return;
334   }
335
336   struct CountersResult *cres;
337   struct TransmitAck *tack;
338
339   switch (type)
340   {
341   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
342     cres = (struct CountersResult *) msg;
343     mst->max_message_id = GNUNET_ntohll (cres->max_message_id);
344     if (NULL != mst->start_cb)
345       mst->start_cb (ch->cb_cls, mst->max_message_id);
346     break;
347
348   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
349     cres = (struct CountersResult *) msg;
350 #if TODO
351     slv->max_message_id = GNUNET_ntohll (cres->max_message_id);
352     if (NULL != slv->join_ack_cb)
353       mst->join_ack_cb (ch->cb_cls, mst->max_message_id);
354 #endif
355     break;
356
357   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
358     tack = (struct TransmitAck *) msg;
359     if (ch->is_master)
360     {
361       GNUNET_assert (NULL != mst->tmit);
362       if (GNUNET_PSYC_DATA_CONT != mst->tmit->status
363           || NULL == mst->tmit->notify)
364       {
365         GNUNET_free (mst->tmit);
366         mst->tmit = NULL;
367       }
368       else
369       {
370         ch->tmit_buf_avail = ntohs (tack->buf_avail);
371         master_transmit_data (mst);
372       }
373     }
374     else
375     {
376       /* TODO: slave */
377     }
378     break;
379   }
380
381   GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
382                          GNUNET_TIME_UNIT_FOREVER_REL);
383 }
384
385 /**
386  * Transmit next message to service.
387  *
388  * @param cls The 'struct GNUNET_PSYC_Channel'.
389  * @param size Number of bytes available in buf.
390  * @param buf Where to copy the message.
391  * @return Number of bytes copied to buf.
392  */
393 static size_t
394 send_next_message (void *cls, size_t size, void *buf)
395 {
396   struct GNUNET_PSYC_Channel *ch = cls;
397   struct OperationHandle *op = ch->transmit_head;
398   size_t ret;
399
400   ch->th = NULL;
401   if (NULL == op->msg)
402     return 0;
403   ret = ntohs (op->msg->size);
404   if (ret > size)
405   {
406     reschedule_connect (ch);
407     return 0;
408   }
409   LOG (GNUNET_ERROR_TYPE_DEBUG,
410        "Sending message of type %d to PSYC service\n",
411        ntohs (op->msg->type));
412   memcpy (buf, op->msg, ret);
413
414   GNUNET_CONTAINER_DLL_remove (ch->transmit_head, ch->transmit_tail, op);
415   GNUNET_free (op);
416
417   if (NULL != ch->transmit_head)
418     transmit_next (ch);
419
420   if (GNUNET_NO == ch->in_receive)
421   {
422     ch->in_receive = GNUNET_YES;
423     GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
424                            GNUNET_TIME_UNIT_FOREVER_REL);
425   }
426   return ret;
427 }
428
429
430 /**
431  * Schedule transmission of the next message from our queue.
432  *
433  * @param h PSYC handle.
434  */
435 static void
436 transmit_next (struct GNUNET_PSYC_Channel *ch)
437 {
438   if (NULL != ch->th || NULL == ch->client)
439     return;
440
441   struct OperationHandle *op = ch->transmit_head;
442   if (NULL == op)
443     return;
444
445   ch->th = GNUNET_CLIENT_notify_transmit_ready (ch->client,
446                                                 ntohs (op->msg->size),
447                                                 GNUNET_TIME_UNIT_FOREVER_REL,
448                                                 GNUNET_NO,
449                                                 &send_next_message,
450                                                 ch);
451 }
452
453
454 /**
455  * Try again to connect to the PSYC service.
456  *
457  * @param cls Channel handle.
458  * @param tc Scheduler context.
459  */
460 static void
461 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
462 {
463   struct GNUNET_PSYC_Channel *ch = cls;
464
465   ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
466   LOG (GNUNET_ERROR_TYPE_DEBUG,
467        "Connecting to PSYC service.\n");
468   GNUNET_assert (NULL == ch->client);
469   ch->client = GNUNET_CLIENT_connect ("psyc", ch->cfg);
470   GNUNET_assert (NULL != ch->client);
471
472   if (NULL == ch->transmit_head ||
473       ch->transmit_head->msg->type != ch->reconnect_msg->type)
474   {
475     uint16_t reconn_size = ntohs (ch->reconnect_msg->size);
476     struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + reconn_size);
477     memcpy (&op[1], ch->reconnect_msg, reconn_size);
478     op->msg = (struct GNUNET_MessageHeader *) &op[1];
479     GNUNET_CONTAINER_DLL_insert (ch->transmit_head, ch->transmit_tail, op);
480   }
481   transmit_next (ch);
482 }
483
484
485 /**
486  * Disconnect from the PSYC service.
487  *
488  * @param cls Channel handle.
489  * @param tc Scheduler context.
490  */
491 static void
492 disconnect (void *c)
493 {
494   struct GNUNET_PSYC_Channel *ch = c;
495   GNUNET_assert (NULL != ch);
496   if (ch->transmit_head != ch->transmit_tail)
497   {
498     LOG (GNUNET_ERROR_TYPE_ERROR,
499          "Disconnecting while there are still outstanding messages!\n");
500     GNUNET_break (0);
501   }
502   if (ch->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
503   {
504     GNUNET_SCHEDULER_cancel (ch->reconnect_task);
505     ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
506   }
507   if (NULL != ch->th)
508   {
509     GNUNET_CLIENT_notify_transmit_ready_cancel (ch->th);
510     ch->th = NULL;
511   }
512   if (NULL != ch->client)
513   {
514     GNUNET_CLIENT_disconnect (ch->client);
515     ch->client = NULL;
516   }
517   if (NULL != ch->reconnect_msg)
518   {
519     GNUNET_free (ch->reconnect_msg);
520     ch->reconnect_msg = NULL;
521   }
522 }
523
524
525 /**
526  * Start a PSYC master channel.
527  *
528  * Will start a multicast group identified by the given ECC key.  Messages
529  * received from group members will be given to the respective handler methods.
530  * If a new member wants to join a group, the "join" method handler will be
531  * invoked; the join handler must then generate a "join" message to approve the
532  * joining of the new member.  The channel can also change group membership
533  * without explicit requests.  Note that PSYC doesn't itself "understand" join
534  * or part messages, the respective methods must call other PSYC functions to
535  * inform PSYC about the meaning of the respective events.
536  *
537  * @param cfg Configuration to use (to connect to PSYC service).
538  * @param channel_key ECC key that will be used to sign messages for this
539  *        PSYC session. The public key is used to identify the PSYC channel.
540  *        Note that end-users will usually not use the private key directly, but
541  *        rather look it up in GNS for places managed by other users, or select
542  *        a file with the private key(s) when setting up their own channels
543  *        FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper
544  *        one in the future.
545  * @param policy Channel policy specifying join and history restrictions.
546  *        Used to automate join decisions.
547  * @param method Function to invoke on messages received from slaves.
548  * @param join_cb Function to invoke when a peer wants to join.
549  * @param cls Closure for @a method and @a join_cb.
550  * @return Handle for the channel master, NULL on error.
551  */
552 struct GNUNET_PSYC_Master *
553 GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
554                           const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key,
555                           enum GNUNET_PSYC_Policy policy,
556                           GNUNET_PSYC_Method method,
557                           GNUNET_PSYC_JoinCallback join_cb,
558                           GNUNET_PSYC_MasterStartCallback master_started_cb,
559                           void *cls)
560 {
561   struct GNUNET_PSYC_Master *mst = GNUNET_malloc (sizeof (*mst));
562   struct GNUNET_PSYC_Channel *ch = &mst->ch;
563   struct MasterStartRequest *req = GNUNET_malloc (sizeof (*req));
564
565   req->header.size = htons (sizeof (*req));
566   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START);
567   req->channel_key = *channel_key;
568   req->policy = policy;
569
570   ch->cfg = cfg;
571   ch->is_master = GNUNET_YES;
572   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
573   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
574   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, mst);
575
576   ch->method_cb = method;
577   ch->join_cb = join_cb;
578   ch->cb_cls = cls;
579   mst->start_cb = master_started_cb;
580
581   return mst;
582 }
583
584
585 /**
586  * Stop a PSYC master channel.
587  *
588  * @param master PSYC channel master to stop.
589  */
590 void
591 GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst)
592 {
593   disconnect (mst);
594   GNUNET_free (mst);
595 }
596
597
598 /**
599  * Function to call with the decision made for a join request.
600  *
601  * Must be called once and only once in response to an invocation of the
602  * #GNUNET_PSYC_JoinCallback.
603  *
604  * @param jh Join request handle.
605  * @param is_admitted #GNUNET_YES if joining is approved,
606  *        #GNUNET_NO if it is disapproved.
607  * @param relay_count Number of relays given.
608  * @param relays Array of suggested peers that might be useful relays to use
609  *        when joining the multicast group (essentially a list of peers that
610  *        are already part of the multicast group and might thus be willing
611  *        to help with routing).  If empty, only this local peer (which must
612  *        be the multicast origin) is a good candidate for building the
613  *        multicast tree.  Note that it is unnecessary to specify our own
614  *        peer identity in this array.
615  * @param method_name Method name for the message transmitted with the response.
616  * @param env Environment containing transient variables for the message, or NULL.
617  * @param data Data of the message.
618  * @param data_size Size of @a data.
619  */
620 void
621 GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
622                            int is_admitted,
623                            uint32_t relay_count,
624                            const struct GNUNET_PeerIdentity *relays,
625                            const char *method_name,
626                            const struct GNUNET_ENV_Environment *env,
627                            const void *data,
628                            size_t data_size)
629 {
630
631 }
632
633
634 /* FIXME: split up value into <64K chunks and transmit the continuations in
635  *        MOD_CONT msgs */
636 int
637 send_modifier (void *cls, struct GNUNET_ENV_Modifier *mod)
638 {
639   struct GNUNET_PSYC_Channel *ch = cls;
640   size_t name_size = strlen (mod->name) + 1;
641   struct GNUNET_PSYC_MessageModifier *pmod;
642   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*pmod)
643                                               + name_size + mod->value_size);
644   pmod = (struct GNUNET_PSYC_MessageModifier *) &op[1];
645   op->msg = (struct GNUNET_MessageHeader *) pmod;
646
647   pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
648   pmod->header.size = htons (sizeof (*pmod) + name_size + mod->value_size);
649   pmod->name_size = htons (name_size);
650   memcpy (&pmod[1], mod->name, name_size);
651   memcpy ((char *) &pmod[1] + name_size, mod->value, mod->value_size);
652
653   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
654   return GNUNET_YES;
655 }
656
657
658 /**
659  * Send a message to call a method to all members in the PSYC channel.
660  *
661  * @param mst Handle to the PSYC channel.
662  * @param method_name Which method should be invoked.
663  * @param env Environment containing state operations and transient variables
664  *            for the message, or NULL.
665  * @param notify Function to call to obtain the arguments.
666  * @param notify_cls Closure for @a notify.
667  * @param flags Flags for the message being transmitted.
668  * @return Transmission handle, NULL on error (i.e. more than one request
669  *         queued).
670  */
671 struct GNUNET_PSYC_MasterTransmitHandle *
672 GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *mst,
673                              const char *method_name,
674                              const struct GNUNET_ENV_Environment *env,
675                              GNUNET_PSYC_MasterTransmitNotify notify,
676                              void *notify_cls,
677                              enum GNUNET_PSYC_MasterTransmitFlags flags)
678 {
679   GNUNET_assert (NULL != mst);
680   struct GNUNET_PSYC_Channel *ch = &mst->ch;
681   if (GNUNET_NO != ch->in_transmit)
682     return NULL;
683   ch->in_transmit = GNUNET_YES;
684
685   size_t size = strlen (method_name) + 1;
686   struct GNUNET_PSYC_MessageMethod *pmeth;
687   struct OperationHandle *op
688     = GNUNET_malloc (sizeof (*op) + sizeof (*pmeth) + size);
689   pmeth = (struct GNUNET_PSYC_MessageMethod *) &op[1];
690   op->msg = (struct GNUNET_MessageHeader *) pmeth;
691
692   pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
693   pmeth->header.size = htons (sizeof (*pmeth) + size);
694   pmeth->flags = htonl (flags);
695   pmeth->mod_count = GNUNET_ntohll (GNUNET_ENV_environment_get_mod_count (env));
696   memcpy (&pmeth[1], method_name, size);
697
698   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
699   GNUNET_ENV_environment_iterate (env, send_modifier, mst);
700   transmit_next (ch);
701
702   mst->tmit = GNUNET_malloc (sizeof (*mst->tmit));
703   mst->tmit->master = mst;
704   mst->tmit->notify = notify;
705   mst->tmit->notify_cls = notify_cls;
706   mst->tmit->status = GNUNET_PSYC_DATA_CONT;
707   return mst->tmit;
708 }
709
710
711 /**
712  * Resume transmission to the channel.
713  *
714  * @param th Handle of the request that is being resumed.
715  */
716 void
717 GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
718 {
719   master_transmit_data (th->master);
720 }
721
722
723 /**
724  * Abort transmission request to the channel.
725  *
726  * @param th Handle of the request that is being aborted.
727  */
728 void
729 GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th)
730 {
731   struct GNUNET_PSYC_Master *mst = th->master;
732   struct GNUNET_PSYC_Channel *ch = &mst->ch;
733   if (GNUNET_NO != ch->in_transmit)
734     return;
735
736
737 }
738
739
740 /**
741  * Join a PSYC channel.
742  *
743  * The entity joining is always the local peer.  The user must immediately use
744  * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the
745  * channel; if the join request succeeds, the channel state (and @e recent
746  * method calls) will be replayed to the joining member.  There is no explicit
747  * notification on failure (as the channel may simply take days to approve,
748  * and disapproval is simply being ignored).
749  *
750  * @param cfg Configuration to use.
751  * @param channel_key ECC public key that identifies the channel we wish to join.
752  * @param slave_key ECC private-public key pair that identifies the slave, and
753  *        used by multicast to sign the join request and subsequent unicast
754  *        requests sent to the master.
755  * @param origin Peer identity of the origin.
756  * @param relay_count Number of peers in the @a relays array.
757  * @param relays Peer identities of members of the multicast group, which serve
758  *        as relays and used to join the group at.
759  * @param method Function to invoke on messages received from the channel,
760  *        typically at least contains functions for @e join and @e part.
761  * @param join_cb Function to invoke when a peer wants to join.
762  * @param cls Closure for @a method_cb and @a join_cb.
763  * @param method_name Method name for the join request.
764  * @param env Environment containing transient variables for the request, or NULL.
765  * @param data Payload for the join message.
766  * @param data_size Number of bytes in @a data.
767  * @return Handle for the slave, NULL on error.
768  */
769 struct GNUNET_PSYC_Slave *
770 GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
771                         const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
772                         const struct GNUNET_CRYPTO_EddsaPrivateKey *slave_key,
773                         const struct GNUNET_PeerIdentity *origin,
774                         uint32_t relay_count,
775                         const struct GNUNET_PeerIdentity *relays,
776                         GNUNET_PSYC_Method method,
777                         GNUNET_PSYC_JoinCallback join_cb,
778                         GNUNET_PSYC_SlaveJoinCallback slave_joined_cb,
779                         void *cls,
780                         const char *method_name,
781                         const struct GNUNET_ENV_Environment *env,
782                         const void *data,
783                         uint16_t data_size)
784 {
785   struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv));
786   struct GNUNET_PSYC_Channel *ch = &slv->ch;
787   struct SlaveJoinRequest *req = GNUNET_malloc (sizeof (*req));
788
789   req->header.size = htons (sizeof (*req)
790                             + sizeof (*channel_key) + sizeof (*slave_key)
791                             + relay_count * sizeof (*relays));
792   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
793   req->channel_key = *channel_key;
794   req->slave_key = *slave_key;
795   req->origin = *origin;
796   req->relay_count = relay_count;
797   memcpy (&req[1], relays, relay_count * sizeof (*relays));
798
799   ch->cfg = cfg;
800   ch->is_master = GNUNET_NO;
801   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
802   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
803   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, slv);
804
805   return slv;
806 }
807
808
809 /**
810  * Part a PSYC channel.
811  *
812  * Will terminate the connection to the PSYC service.  Polite clients should
813  * first explicitly send a @e part request (via GNUNET_PSYC_slave_transmit()).
814  *
815  * @param slv Slave handle.
816  */
817 void
818 GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv)
819 {
820   disconnect (slv);
821   GNUNET_free (slv);
822 }
823
824
825 /**
826  * Request a message to be sent to the channel master.
827  *
828  * @param slave Slave handle.
829  * @param method_name Which (PSYC) method should be invoked (on host).
830  * @param env Environment containing transient variables for the message, or
831  *            NULL.
832  * @param notify Function to call when we are allowed to transmit (to get data).
833  * @param notify_cls Closure for @a notify.
834  * @param flags Flags for the message being transmitted.
835  * @return Transmission handle, NULL on error (i.e. more than one request
836  *         queued).
837  */
838 struct GNUNET_PSYC_SlaveTransmitHandle *
839 GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave,
840                             const char *method_name,
841                             const struct GNUNET_ENV_Environment *env,
842                             GNUNET_PSYC_SlaveTransmitNotify notify,
843                             void *notify_cls,
844                             enum GNUNET_PSYC_SlaveTransmitFlags flags)
845 {
846   return NULL;
847 }
848
849
850 /**
851  * Resume transmission to the master.
852  *
853  * @param th Handle of the request that is being resumed.
854  */
855 void
856 GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
857 {
858
859 }
860
861
862 /**
863  * Abort transmission request to master.
864  *
865  * @param th Handle of the request that is being aborted.
866  */
867 void
868 GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th)
869 {
870
871 }
872
873
874 /**
875  * Convert a channel @a master to a @e channel handle to access the @e channel
876  * APIs.
877  *
878  * @param master Channel master handle.
879  * @return Channel handle, valid for as long as @a master is valid.
880  */
881 struct GNUNET_PSYC_Channel *
882 GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master)
883 {
884   return (struct GNUNET_PSYC_Channel *) master;
885 }
886
887
888 /**
889  * Convert @a slave to a @e channel handle to access the @e channel APIs.
890  *
891  * @param slave Slave handle.
892  * @return Channel handle, valid for as long as @a slave is valid.
893  */
894 struct GNUNET_PSYC_Channel *
895 GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave)
896 {
897   return (struct GNUNET_PSYC_Channel *) slave;
898 }
899
900
901 /**
902  * Add a slave to the channel's membership list.
903  *
904  * Note that this will NOT generate any PSYC traffic, it will merely update the
905  * local database to modify how we react to <em>membership test</em> queries.
906  * The channel master still needs to explicitly transmit a @e join message to
907  * notify other channel members and they then also must still call this function
908  * in their respective methods handling the @e join message.  This way, how @e
909  * join and @e part operations are exactly implemented is still up to the
910  * application; for example, there might be a @e part_all method to kick out
911  * everyone.
912  *
913  * Note that channel slaves are explicitly trusted to execute such methods
914  * correctly; not doing so correctly will result in either denying other slaves
915  * access or offering access to channel data to non-members.
916  *
917  * @param ch Channel handle.
918  * @param slave_key Identity of channel slave to add.
919  * @param announced_at ID of the message that announced the membership change.
920  * @param effective_since Addition of slave is in effect since this message ID.
921  */
922 void
923 GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *ch,
924                                const struct GNUNET_CRYPTO_EddsaPublicKey
925                                *slave_key,
926                                uint64_t announced_at,
927                                uint64_t effective_since)
928 {
929   struct ChannelSlaveAdd *slvadd;
930   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvadd));
931   slvadd = (struct ChannelSlaveAdd *) &op[1];
932   op->msg = (struct GNUNET_MessageHeader *) slvadd;
933
934   slvadd->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_ADD;
935   slvadd->header.size = htons (sizeof (*slvadd));
936   slvadd->announced_at = GNUNET_htonll (announced_at);
937   slvadd->effective_since = GNUNET_htonll (effective_since);
938
939   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
940   transmit_next (ch);
941 }
942
943
944 /**
945  * Remove a slave from the channel's membership list.
946  *
947  * Note that this will NOT generate any PSYC traffic, it will merely update the
948  * local database to modify how we react to <em>membership test</em> queries.
949  * The channel master still needs to explicitly transmit a @e part message to
950  * notify other channel members and they then also must still call this function
951  * in their respective methods handling the @e part message.  This way, how
952  * @e join and @e part operations are exactly implemented is still up to the
953  * application; for example, there might be a @e part_all message to kick out
954  * everyone.
955  *
956  * Note that channel members are explicitly trusted to perform these
957  * operations correctly; not doing so correctly will result in either
958  * denying members access or offering access to channel data to
959  * non-members.
960  *
961  * @param ch Channel handle.
962  * @param slave_key Identity of channel slave to remove.
963  * @param announced_at ID of the message that announced the membership change.
964  */
965 void
966 GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *ch,
967                                   const struct GNUNET_CRYPTO_EddsaPublicKey
968                                   *slave_key,
969                                   uint64_t announced_at)
970 {
971   struct ChannelSlaveRemove *slvrm;
972   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvrm));
973   slvrm = (struct ChannelSlaveRemove *) &op[1];
974   op->msg = (struct GNUNET_MessageHeader *) slvrm;
975
976   slvrm->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM;
977   slvrm->header.size = htons (sizeof (*slvrm));
978   slvrm->announced_at = GNUNET_htonll (announced_at);
979
980   GNUNET_CONTAINER_DLL_insert_tail (ch->transmit_head, ch->transmit_tail, op);
981   transmit_next (ch);
982 }
983
984
985 /**
986  * Request to be told the message history of the channel.
987  *
988  * Historic messages (but NOT the state at the time) will be replayed (given to
989  * the normal method handlers) if available and if access is permitted.
990  *
991  * To get the latest message, use 0 for both the start and end message ID.
992  *
993  * @param ch Which channel should be replayed?
994  * @param start_message_id Earliest interesting point in history.
995  * @param end_message_id Last (exclusive) interesting point in history.
996  * @param method Function to invoke on messages received from the story.
997  * @param finish_cb Function to call when the requested story has been fully
998  *        told (counting message IDs might not suffice, as some messages
999  *        might be secret and thus the listener would not know the story is
1000  *        finished without being told explicitly)
1001 {
1002   return NULL;
1003 } once this function
1004  *        has been called, the client must not call
1005  *        GNUNET_PSYC_channel_story_tell_cancel() anymore.
1006  * @param cls Closure for the callbacks.
1007  * @return Handle to cancel story telling operation.
1008  */
1009 struct GNUNET_PSYC_Story *
1010 GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *ch,
1011                                 uint64_t start_message_id,
1012                                 uint64_t end_message_id,
1013                                 GNUNET_PSYC_Method method,
1014                                 GNUNET_PSYC_FinishCallback *finish_cb,
1015                                 void *cls)
1016 {
1017   return NULL;
1018 }
1019
1020
1021 /**
1022  * Abort story telling.
1023  *
1024  * This function must not be called from within method handlers (as given to
1025  * GNUNET_PSYC_slave_join()) of the slave.
1026  *
1027  * @param story Story telling operation to stop.
1028  */
1029 void
1030 GNUNET_PSYC_channel_story_tell_cancel (struct GNUNET_PSYC_Story *story)
1031 {
1032
1033 }
1034
1035
1036 /**
1037  * Retrieve the best matching channel state variable.
1038  *
1039  * If the requested variable name is not present in the state, the nearest
1040  * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1041  * if "_a_b" does not exist.
1042  *
1043  * @param channel Channel handle.
1044  * @param full_name Full name of the requested variable, the actual variable
1045  *        returned might have a shorter name..
1046  * @param cb Function called once when a matching state variable is found.
1047  *        Not called if there's no matching state variable.
1048  * @param cb_cls Closure for the callbacks.
1049  * @return Handle that can be used to cancel the query operation.
1050  */
1051 struct GNUNET_PSYC_StateQuery *
1052 GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel,
1053                                const char *full_name,
1054                                GNUNET_PSYC_StateCallback cb,
1055                                void *cb_cls)
1056 {
1057   return NULL;
1058 }
1059
1060
1061 /**
1062  * Return all channel state variables whose name matches a given prefix.
1063  *
1064  * A name matches if it starts with the given @a name_prefix, thus requesting
1065  * the empty prefix ("") will match all values; requesting "_a_b" will also
1066  * return values stored under "_a_b_c".
1067  *
1068  * The @a state_cb is invoked on all matching state variables asynchronously, as
1069  * the state is stored in and retrieved from the PSYCstore,
1070  *
1071  * @param channel Channel handle.
1072  * @param name_prefix Prefix of the state variable name to match.
1073  * @param cb Function to call with the matching state variables.
1074  * @param cb_cls Closure for the callbacks.
1075  * @return Handle that can be used to cancel the query operation.
1076  */
1077 struct GNUNET_PSYC_StateQuery *
1078 GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel,
1079                                       const char *name_prefix,
1080                                       GNUNET_PSYC_StateCallback cb,
1081                                       void *cb_cls)
1082 {
1083   return NULL;
1084 }
1085
1086
1087 /**
1088  * Cancel a state query operation.
1089  *
1090  * @param query Handle for the operation to cancel.
1091  */
1092 void
1093 GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateQuery *query)
1094 {
1095
1096 }
1097
1098
1099 /* end of psyc_api.c */