psyc: ipc messages
[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 <inttypes.h>
34
35 #include "platform.h"
36 #include "gnunet_util_lib.h"
37 #include "gnunet_env_lib.h"
38 #include "gnunet_multicast_service.h"
39 #include "gnunet_psyc_service.h"
40 #include "psyc.h"
41
42 #define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__)
43
44 struct OperationHandle
45 {
46   struct OperationHandle *prev;
47   struct OperationHandle *next;
48   const struct GNUNET_MessageHeader *msg;
49 };
50
51 /**
52  * Handle to access PSYC channel operations for both the master and slaves.
53  */
54 struct GNUNET_PSYC_Channel
55 {
56   /**
57    * Configuration to use.
58    */
59   const struct GNUNET_CONFIGURATION_Handle *cfg;
60
61   /**
62    * Socket (if available).
63    */
64   struct GNUNET_CLIENT_Connection *client;
65
66   /**
67    * Currently pending transmission request, or NULL for none.
68    */
69   struct GNUNET_CLIENT_TransmitHandle *th;
70
71   /**
72    * Head of operations to transmit.
73    */
74   struct OperationHandle *tmit_head;
75
76   /**
77    * Tail of operations to transmit.
78    */
79   struct OperationHandle *tmit_tail;
80
81   /**
82    * Message to send on reconnect.
83    */
84   struct GNUNET_MessageHeader *reconnect_msg;
85
86   /**
87    * Task doing exponential back-off trying to reconnect.
88    */
89   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
90
91   /**
92    * Time for next connect retry.
93    */
94   struct GNUNET_TIME_Relative reconnect_delay;
95
96   /**
97    * Message part callback.
98    */
99   GNUNET_PSYC_MessageCallback message_cb;
100
101   /**
102    * Message part callback for historic message.
103    */
104   GNUNET_PSYC_MessageCallback hist_message_cb;
105
106   /**
107    * Join handler callback.
108    */
109   GNUNET_PSYC_JoinCallback join_cb;
110
111   /**
112    * Closure for @a message_cb and @a join_cb.
113    */
114   void *cb_cls;
115
116   /**
117    * ID of the message being received from the PSYC service.
118    */
119   uint64_t recv_message_id;
120
121   /**
122    * State of the currently being received message from the PSYC service.
123    */
124   enum MessageState recv_state;
125
126   /**
127    * Flags for the currently being received message from the PSYC service.
128    */
129   enum GNUNET_PSYC_MessageFlags recv_flags;
130
131   /**
132    * Expected value size for the modifier being received from the PSYC service.
133    */
134   uint32_t recv_mod_value_size_expected;
135
136   /**
137    * Actual value size for the modifier being received from the PSYC service.
138    */
139   uint32_t recv_mod_value_size;
140
141   /**
142    * Buffer space available for transmitting the next data fragment.
143    */
144   uint16_t tmit_size; // FIXME
145
146   /**
147    * Is transmission paused?
148    */
149   uint8_t tmit_paused;
150
151   /**
152    * Are we still waiting for a PSYC_TRANSMIT_ACK?
153    */
154   uint8_t tmit_ack_pending; // FIXME
155
156   /**
157    * Are we polling for incoming messages right now?
158    */
159   uint8_t in_receive;
160
161   /**
162    * Are we currently transmitting a message?
163    */
164   uint8_t in_transmit;
165
166   /**
167    * Is this a master or slave channel?
168    */
169   uint8_t is_master;
170 };
171
172
173 /**
174  * Handle for a pending PSYC transmission operation.
175  */
176 struct GNUNET_PSYC_MasterTransmitHandle
177 {
178   struct GNUNET_PSYC_Master *master;
179   GNUNET_PSYC_MasterTransmitNotify notify_mod;
180   GNUNET_PSYC_MasterTransmitNotify notify_data;
181   void *notify_cls;
182   enum MessageState state;
183 };
184
185
186 /**
187  * Handle for the master of a PSYC channel.
188  */
189 struct GNUNET_PSYC_Master
190 {
191   struct GNUNET_PSYC_Channel ch;
192
193   struct GNUNET_PSYC_MasterTransmitHandle *tmit;
194
195   GNUNET_PSYC_MasterStartCallback start_cb;
196
197   uint64_t max_message_id;
198 };
199
200
201 /**
202  * Handle for a PSYC channel slave.
203  */
204 struct GNUNET_PSYC_Slave
205 {
206   struct GNUNET_PSYC_Channel ch;
207 };
208
209
210 /**
211  * Handle that identifies a join request.
212  *
213  * Used to match calls to #GNUNET_PSYC_JoinCallback to the
214  * corresponding calls to GNUNET_PSYC_join_decision().
215  */
216 struct GNUNET_PSYC_JoinHandle
217 {
218
219 };
220
221
222 /**
223  * Handle for a pending PSYC transmission operation.
224  */
225 struct GNUNET_PSYC_SlaveTransmitHandle
226 {
227
228 };
229
230
231 /**
232  * Handle to a story telling operation.
233  */
234 struct GNUNET_PSYC_Story
235 {
236
237 };
238
239
240 /**
241  * Handle for a state query operation.
242  */
243 struct GNUNET_PSYC_StateQuery
244 {
245
246 };
247
248
249 /**
250  * Try again to connect to the PSYC service.
251  *
252  * @param cls Handle to the PSYC service.
253  * @param tc Scheduler context
254  */
255 static void
256 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
257
258
259 /**
260  * Reschedule a connect attempt to the service.
261  *
262  * @param c channel to reconnect
263  */
264 static void
265 reschedule_connect (struct GNUNET_PSYC_Channel *c)
266 {
267   GNUNET_assert (c->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
268
269   if (NULL != c->th)
270   {
271     GNUNET_CLIENT_notify_transmit_ready_cancel (c->th);
272     c->th = NULL;
273   }
274   if (NULL != c->client)
275   {
276     GNUNET_CLIENT_disconnect (c->client);
277     c->client = NULL;
278   }
279   c->in_receive = GNUNET_NO;
280   LOG (GNUNET_ERROR_TYPE_DEBUG,
281        "Scheduling task to reconnect to PSYC service in %s.\n",
282        GNUNET_STRINGS_relative_time_to_string (c->reconnect_delay, GNUNET_YES));
283   c->reconnect_task =
284       GNUNET_SCHEDULER_add_delayed (c->reconnect_delay, &reconnect, c);
285   c->reconnect_delay = GNUNET_TIME_STD_BACKOFF (c->reconnect_delay);
286 }
287
288
289 /**
290  * Schedule transmission of the next message from our queue.
291  *
292  * @param ch PSYC channel handle
293  */
294 static void
295 transmit_next (struct GNUNET_PSYC_Channel *ch);
296
297
298 /**
299  * Reset data stored related to the last received message.
300  */
301 static void
302 recv_reset (struct GNUNET_PSYC_Channel *ch)
303 {
304   ch->recv_state = MSG_STATE_START;
305   ch->recv_flags = 0;
306   ch->recv_message_id = 0;
307   ch->recv_mod_value_size =0;
308   ch->recv_mod_value_size_expected = 0;
309 }
310
311
312 static void
313 recv_error (struct GNUNET_PSYC_Channel *ch)
314 {
315   recv_reset (ch);
316
317   GNUNET_PSYC_MessageCallback message_cb
318     = ch->recv_flags & GNUNET_PSYC_MESSAGE_HISTORIC
319     ? ch->hist_message_cb
320     : ch->message_cb;
321
322   if (NULL != message_cb)
323     message_cb (ch->cb_cls, ch->recv_message_id, ch->recv_flags, NULL);
324 }
325
326 /**
327  * Request a modifier from a client to transmit.
328  *
329  * @param mst Master handle.
330  */
331 static void
332 master_transmit_mod (struct GNUNET_PSYC_Master *mst)
333 {
334   struct GNUNET_PSYC_Channel *ch = &mst->ch;
335   uint16_t max_data_size
336     = ch->tmit_size > sizeof (struct GNUNET_MessageHeader)
337     ? GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - ch->tmit_size
338     : GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD - ch->tmit_size;
339   uint16_t data_size = max_data_size;
340
341   struct GNUNET_MessageHeader *msg;
342   struct OperationHandle *op
343     = GNUNET_malloc (sizeof (*op) + sizeof (*msg) + data_size);
344   op->msg = msg = (struct GNUNET_MessageHeader *) &op[1];
345   msg->type
346     = MSG_STATE_MODIFIER == mst->tmit->state
347     ? htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER)
348     : htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT);
349
350   int notify_ret = mst->tmit->notify_data (mst->tmit->notify_cls,
351                                            &data_size, &msg[1]);
352   switch (notify_ret)
353   {
354   case GNUNET_NO:
355     if (0 != data_size)
356       mst->tmit->state = MSG_STATE_MOD_CONT;
357     break;
358
359   case GNUNET_YES:
360     mst->tmit->state = (0 == data_size) ? MSG_STATE_DATA : MSG_STATE_MODIFIER;
361     break;
362
363   default:
364     LOG (GNUNET_ERROR_TYPE_ERROR,
365          "MasterTransmitNotify returned error when requesting a modifier.\n");
366
367     mst->tmit->state = MSG_STATE_START;
368     msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
369     msg->size = htons (sizeof (*msg));
370
371     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
372     transmit_next (ch);
373     return;
374   }
375
376   if ((GNUNET_NO == notify_ret && 0 == data_size))
377   {
378     /* Transmission paused, nothing to send. */
379     ch->tmit_paused = GNUNET_YES;
380     GNUNET_free (op);
381   }
382
383   if (0 < data_size)
384   {
385     GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD);
386     msg->size = htons (sizeof (*msg) + data_size);
387     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
388   }
389
390   /* End of message. */
391   if (GNUNET_YES == notify_ret)
392   {
393     op = GNUNET_malloc (sizeof *(op) + sizeof (*msg));
394     op->msg = msg = (struct GNUNET_MessageHeader *) &op[1];
395     msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
396     msg->size = htons (sizeof (*msg));
397     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
398   }
399
400   transmit_next (ch);
401 }
402
403
404 /**
405  * Request data from a client to transmit.
406  *
407  * @param mst Master handle.
408  */
409 static void
410 master_transmit_data (struct GNUNET_PSYC_Master *mst)
411 {
412   struct GNUNET_PSYC_Channel *ch = &mst->ch;
413   struct GNUNET_MessageHeader *msg;
414   uint16_t data_size = GNUNET_PSYC_DATA_MAX_PAYLOAD;
415   struct OperationHandle *op
416     = GNUNET_malloc (sizeof (*op) + sizeof (*msg) + data_size);
417   op->msg = msg = (struct GNUNET_MessageHeader *) &op[1];
418   msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA);
419
420   int notify_ret = mst->tmit->notify_data (mst->tmit->notify_cls,
421                                            &data_size, &msg[1]);
422   switch (notify_ret)
423   {
424   case GNUNET_NO:
425     if (0 == data_size)
426     {
427       /* Transmission paused, nothing to send. */
428       ch->tmit_paused = GNUNET_YES;
429       GNUNET_free (op);
430     }
431     break;
432
433   case GNUNET_YES:
434     mst->tmit->state = MSG_STATE_START;
435     break;
436
437   default:
438     LOG (GNUNET_ERROR_TYPE_ERROR,
439          "MasterTransmitNotify returned error when requesting data.\n");
440
441     mst->tmit->state = MSG_STATE_START;
442     msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL);
443     msg->size = htons (sizeof (*msg));
444
445     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
446     transmit_next (ch);
447     return;
448   }
449
450   if (0 < data_size)
451   {
452     GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD);
453     msg->size = htons (sizeof (*msg) + data_size);
454     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
455   }
456
457   /* End of message. */
458   if (GNUNET_YES == notify_ret)
459   {
460     op = GNUNET_malloc (sizeof *(op) + sizeof (*msg));
461     op->msg = msg = (struct GNUNET_MessageHeader *) &op[1];
462     msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END);
463     msg->size = htons (sizeof (*msg));
464     GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
465   }
466
467   transmit_next (ch);
468 }
469
470
471 /**
472  * Handle incoming message from the PSYC service.
473  *
474  * @param ch The channel the message is sent to.
475  * @param pmsg The message.
476  */
477 static void
478 handle_psyc_message (struct GNUNET_PSYC_Channel *ch,
479                      const struct GNUNET_PSYC_MessageHeader *pmsg)
480 {
481   const struct GNUNET_MessageHeader *msg;
482   uint16_t msize = ntohs (pmsg->header.size);
483   uint16_t pos = 0;
484   uint16_t size = 0;
485   uint16_t type, size_eq, size_min;
486
487   if (MSG_STATE_START == ch->recv_state)
488   {
489     ch->recv_message_id = GNUNET_ntohll (pmsg->message_id);
490     ch->recv_flags = ntohl (pmsg->flags);
491   }
492   else if (GNUNET_ntohll (pmsg->message_id) != ch->recv_message_id)
493   {
494     LOG (GNUNET_ERROR_TYPE_WARNING,
495          "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n",
496          GNUNET_ntohll (pmsg->message_id), ch->recv_message_id);
497     GNUNET_break_op (0);
498     recv_error (ch);
499   }
500   else if (ntohl (pmsg->flags) != ch->recv_flags)
501   {
502     LOG (GNUNET_ERROR_TYPE_WARNING,
503          "Unexpected message flags. Got: %lu, expected: %lu\n",
504          ntohl (pmsg->flags), ch->recv_flags);
505     GNUNET_break_op (0);
506     recv_error (ch);
507   }
508
509   for (pos = 0; sizeof (*pmsg) + pos < msize; pos += size)
510   {
511     msg = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos);
512     size = ntohs (msg->size);
513     type = ntohs (msg->type);
514     size_eq = size_min = 0;
515
516     if (msize < sizeof (*pmsg) + pos + size)
517     {
518       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
519                   "Discarding message of type %u with invalid size. "
520                   "(%u < %u + %u + %u)\n", ntohs (msg->type),
521                   msize, sizeof (*msg), pos, size);
522       break;
523     }
524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
525                 "Received message part of type %u and size %u from PSYC.\n",
526                 ntohs (msg->type), size);
527
528
529     switch (type)
530     {
531     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
532       size_min = sizeof (struct GNUNET_PSYC_MessageMethod);
533       break;
534     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
535       size_min = sizeof (struct GNUNET_PSYC_MessageModifier);
536       break;
537     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
538       size_min = sizeof (struct GNUNET_MessageHeader);
539       break;
540     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
541     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
542       size_eq = sizeof (struct GNUNET_MessageHeader);
543       break;
544     }
545
546     if (! ((0 < size_eq && size == size_eq)
547            || (0 < size_min && size_min <= size)))
548     {
549       GNUNET_break (0);
550       reschedule_connect (ch);
551       return;
552     }
553
554     switch (type)
555     {
556     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
557     {
558       struct GNUNET_PSYC_MessageMethod *meth
559         = (struct GNUNET_PSYC_MessageMethod *) msg;
560
561       if (MSG_STATE_HEADER != ch->recv_state)
562       {
563         LOG (GNUNET_ERROR_TYPE_WARNING,
564              "Discarding out of order message method.\n");
565         /* It is normal to receive an incomplete message right after connecting,
566          * but should not happen later.
567          * FIXME: add a check for this condition.
568          */
569         GNUNET_break_op (0);
570         recv_error (ch);
571         break;
572       }
573
574       if ('\0' != (char *) meth + msg->size - 1)
575       {
576         LOG (GNUNET_ERROR_TYPE_WARNING,
577              "Discarding message with malformed method. "
578              "Message ID: %" PRIu64 "\n", ch->recv_message_id);
579         GNUNET_break_op (0);
580         recv_error (ch);
581         break;
582       }
583       GNUNET_PSYC_MessageCallback message_cb
584         = ch->recv_flags & GNUNET_PSYC_MESSAGE_HISTORIC
585         ? ch->hist_message_cb
586         : ch->message_cb;
587
588       if (NULL != message_cb)
589         message_cb (ch->cb_cls, ch->recv_message_id, ch->recv_flags, msg);
590
591       ch->recv_state = MSG_STATE_METHOD;
592       break;
593     }
594     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
595     {
596       if (MSG_STATE_MODIFIER != ch->recv_state)
597       {
598         LOG (GNUNET_ERROR_TYPE_WARNING,
599              "Discarding out of order message modifier.\n");
600         GNUNET_break_op (0);
601         recv_error (ch);
602         break;
603       }
604
605       struct GNUNET_PSYC_MessageModifier *mod
606         = (struct GNUNET_PSYC_MessageModifier *) msg;
607
608       uint16_t name_size = ntohs (mod->name_size);
609       ch->recv_mod_value_size_expected = ntohs (mod->value_size);
610       ch->recv_mod_value_size = size - sizeof (*mod) - name_size - 1;
611
612       if (size < sizeof (*mod) + name_size + 1
613           || '\0' != (char *) &mod[1] + mod->name_size
614           || ch->recv_mod_value_size_expected < ch->recv_mod_value_size)
615       {
616         LOG (GNUNET_ERROR_TYPE_WARNING, "Discarding malformed modifier.\n");
617         GNUNET_break_op (0);
618         break;
619       }
620
621       ch->recv_state = MSG_STATE_MODIFIER;
622
623       GNUNET_PSYC_MessageCallback message_cb
624         = ch->recv_flags & GNUNET_PSYC_MESSAGE_HISTORIC
625         ? ch->hist_message_cb
626         : ch->message_cb;
627
628       if (NULL != message_cb)
629         message_cb (ch->cb_cls, ch->recv_message_id, ch->recv_flags, msg);
630
631       break;
632     }
633     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT:
634     {
635       ch->recv_mod_value_size += size - sizeof (*msg);
636
637       if (MSG_STATE_MODIFIER != ch->recv_state
638           || ch->recv_mod_value_size_expected < ch->recv_mod_value_size)
639       {
640         LOG (GNUNET_ERROR_TYPE_WARNING,
641              "Discarding out of order message modifier continuation.\n");
642         GNUNET_break_op (0);
643         recv_reset (ch);
644         break;
645       }
646
647       GNUNET_PSYC_MessageCallback message_cb
648         = ch->recv_flags & GNUNET_PSYC_MESSAGE_HISTORIC
649         ? ch->hist_message_cb
650         : ch->message_cb;
651
652       if (NULL != message_cb)
653         message_cb (ch->cb_cls, ch->recv_message_id, ch->recv_flags, msg);
654       break;
655     }
656     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
657     {
658       if (ch->recv_state < MSG_STATE_METHOD
659           || ch->recv_mod_value_size_expected != ch->recv_mod_value_size)
660       {
661         LOG (GNUNET_ERROR_TYPE_WARNING,
662              "Discarding out of order message data fragment.\n");
663         GNUNET_break_op (0);
664         recv_reset (ch);
665         break;
666       }
667
668       ch->recv_state = MSG_STATE_DATA;
669       break;
670     }
671     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
672     case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
673       recv_reset (ch);
674       break;
675     }
676   }
677 }
678
679
680 /**
681  * Type of a function to call when we receive a message
682  * from the service.
683  *
684  * @param cls closure
685  * @param msg message received, NULL on timeout or fatal error
686  */
687 static void
688 message_handler (void *cls,
689                  const struct GNUNET_MessageHeader *msg)
690 {
691   // YUCK! => please have disjoint message handlers...
692   struct GNUNET_PSYC_Channel *ch = cls;
693   struct GNUNET_PSYC_Master *mst = cls;
694   struct GNUNET_PSYC_Slave *slv = cls;
695
696   if (NULL == msg)
697   {
698     GNUNET_break (0);
699     reschedule_connect (ch);
700     return;
701   }
702   uint16_t size_eq = 0;
703   uint16_t size_min = 0;
704   uint16_t size = ntohs (msg->size);
705   uint16_t type = ntohs (msg->type);
706
707   LOG (GNUNET_ERROR_TYPE_DEBUG,
708        "Received message of type %d and size %u from PSYC service\n",
709        type, size);
710
711   switch (type)
712   {
713   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
714   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
715     size_eq = sizeof (struct CountersResult);
716     break;
717   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE:
718     size_min = sizeof (struct GNUNET_PSYC_MessageHeader);
719     break;
720   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD:
721     size_min = sizeof (struct GNUNET_PSYC_MessageMethod);
722     break;
723   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER:
724     size_min = sizeof (struct GNUNET_PSYC_MessageModifier);
725     break;
726   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA:
727     size_min = sizeof (struct GNUNET_MessageHeader);
728     break;
729   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END:
730   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL:
731   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
732     size_eq = sizeof (struct GNUNET_MessageHeader);
733     break;
734   }
735
736   if (! ((0 < size_eq && size == size_eq)
737          || (0 < size_min && size_min <= size)))
738   {
739     GNUNET_break (0);
740     reschedule_connect (ch);
741     return;
742   }
743
744   switch (type)
745   {
746   case GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK:
747   {
748     struct CountersResult *cres = (struct CountersResult *) msg;
749     mst->max_message_id = GNUNET_ntohll (cres->max_message_id);
750     if (NULL != mst->start_cb)
751       mst->start_cb (ch->cb_cls, mst->max_message_id);
752     break;
753   }
754   case GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK:
755   {
756 #if TODO
757     struct CountersResult *cres = (struct CountersResult *) msg;
758     slv->max_message_id = GNUNET_ntohll (cres->max_message_id);
759     if (NULL != slv->join_ack_cb)
760       mst->join_ack_cb (ch->cb_cls, mst->max_message_id);
761 #endif
762     break;
763   }
764   case GNUNET_MESSAGE_TYPE_PSYC_TRANSMIT_ACK:
765   {
766     ch->tmit_ack_pending = GNUNET_NO;
767
768     if (ch->is_master)
769     {
770       GNUNET_assert (NULL != mst->tmit);
771       switch (mst->tmit->state)
772       {
773       case MSG_STATE_MODIFIER:
774         if (GNUNET_NO == ch->tmit_paused)
775           master_transmit_mod (mst);
776         break;
777
778       case MSG_STATE_MOD_CONT:
779         if (GNUNET_NO == ch->tmit_paused)
780           master_transmit_mod (mst);
781         break;
782
783       case MSG_STATE_DATA:
784         if (GNUNET_NO == ch->tmit_paused)
785           master_transmit_data (mst);
786         break;
787
788       case MSG_STATE_END:
789       case MSG_STATE_CANCEL:
790         if (NULL != mst->tmit)
791         {
792           GNUNET_free (mst->tmit);
793           mst->tmit = NULL;
794         }
795         else
796         {
797           LOG (GNUNET_ERROR_TYPE_WARNING,
798                "Ignoring transmit ack, there's no transmission going on.\n");
799         }
800         break;
801       default:
802         LOG (GNUNET_ERROR_TYPE_WARNING,
803              "Ignoring unexpected transmit ack.\n");
804       }
805     }
806     else
807     {
808       /* TODO: slave */
809     }
810     break;
811   }
812
813   case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE:
814     handle_psyc_message(ch, (const struct GNUNET_PSYC_MessageHeader *) msg);
815     break;
816   }
817
818   GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
819                          GNUNET_TIME_UNIT_FOREVER_REL);
820 }
821
822
823 /**
824  * Transmit next message to service.
825  *
826  * @param cls The 'struct GNUNET_PSYC_Channel'.
827  * @param size Number of bytes available in buf.
828  * @param buf Where to copy the message.
829  * @return Number of bytes copied to buf.
830  */
831 static size_t
832 send_next_message (void *cls, size_t size, void *buf)
833 {
834   struct GNUNET_PSYC_Channel *ch = cls;
835   struct OperationHandle *op = ch->tmit_head;
836   size_t ret;
837   LOG (GNUNET_ERROR_TYPE_DEBUG, "send_next_message()\n");
838   ch->th = NULL;
839   if (NULL == op->msg)
840     return 0;
841   ret = ntohs (op->msg->size);
842   if (ret > size)
843   {
844     reschedule_connect (ch);
845     return 0;
846   }
847   memcpy (buf, op->msg, ret);
848
849   GNUNET_CONTAINER_DLL_remove (ch->tmit_head, ch->tmit_tail, op);
850   GNUNET_free (op);
851
852   if (NULL != ch->tmit_head)
853     transmit_next (ch);
854
855   if (GNUNET_NO == ch->in_receive)
856   {
857     ch->in_receive = GNUNET_YES;
858     GNUNET_CLIENT_receive (ch->client, &message_handler, ch,
859                            GNUNET_TIME_UNIT_FOREVER_REL);
860   }
861   return ret;
862 }
863
864
865 /**
866  * Schedule transmission of the next message from our queue.
867  *
868  * @param ch PSYC handle.
869  */
870 static void
871 transmit_next (struct GNUNET_PSYC_Channel *ch)
872 {
873   LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_next()\n");
874   if (NULL != ch->th || NULL == ch->client)
875     return;
876
877   struct OperationHandle *op = ch->tmit_head;
878   if (NULL == op)
879     return;
880
881   ch->th = GNUNET_CLIENT_notify_transmit_ready (ch->client,
882                                                 ntohs (op->msg->size),
883                                                 GNUNET_TIME_UNIT_FOREVER_REL,
884                                                 GNUNET_NO,
885                                                 &send_next_message,
886                                                 ch);
887 }
888
889
890 /**
891  * Try again to connect to the PSYC service.
892  *
893  * @param cls Channel handle.
894  * @param tc Scheduler context.
895  */
896 static void
897 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
898 {
899   struct GNUNET_PSYC_Channel *ch = cls;
900
901   recv_reset (ch);
902   ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
903   LOG (GNUNET_ERROR_TYPE_DEBUG,
904        "Connecting to PSYC service.\n");
905   GNUNET_assert (NULL == ch->client);
906   ch->client = GNUNET_CLIENT_connect ("psyc", ch->cfg);
907   GNUNET_assert (NULL != ch->client);
908
909   if (NULL == ch->tmit_head ||
910       ch->tmit_head->msg->type != ch->reconnect_msg->type)
911   {
912     uint16_t reconn_size = ntohs (ch->reconnect_msg->size);
913     struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + reconn_size);
914     memcpy (&op[1], ch->reconnect_msg, reconn_size);
915     op->msg = (struct GNUNET_MessageHeader *) &op[1];
916     GNUNET_CONTAINER_DLL_insert (ch->tmit_head, ch->tmit_tail, op);
917   }
918   transmit_next (ch);
919 }
920
921
922 /**
923  * Disconnect from the PSYC service.
924  *
925  * @param c Channel handle to disconnect
926  */
927 static void
928 disconnect (void *c)
929 {
930   struct GNUNET_PSYC_Channel *ch = c;
931
932   GNUNET_assert (NULL != ch);
933   if (ch->tmit_head != ch->tmit_tail)
934   {
935     LOG (GNUNET_ERROR_TYPE_ERROR,
936          "Disconnecting while there are still outstanding messages!\n");
937     GNUNET_break (0);
938   }
939   if (ch->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
940   {
941     GNUNET_SCHEDULER_cancel (ch->reconnect_task);
942     ch->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
943   }
944   if (NULL != ch->th)
945   {
946     GNUNET_CLIENT_notify_transmit_ready_cancel (ch->th);
947     ch->th = NULL;
948   }
949   if (NULL != ch->client)
950   {
951     GNUNET_CLIENT_disconnect (ch->client);
952     ch->client = NULL;
953   }
954   if (NULL != ch->reconnect_msg)
955   {
956     GNUNET_free (ch->reconnect_msg);
957     ch->reconnect_msg = NULL;
958   }
959 }
960
961
962 /**
963  * Start a PSYC master channel.
964  *
965  * Will start a multicast group identified by the given ECC key.  Messages
966  * received from group members will be given to the respective handler methods.
967  * If a new member wants to join a group, the "join" method handler will be
968  * invoked; the join handler must then generate a "join" message to approve the
969  * joining of the new member.  The channel can also change group membership
970  * without explicit requests.  Note that PSYC doesn't itself "understand" join
971  * or part messages, the respective methods must call other PSYC functions to
972  * inform PSYC about the meaning of the respective events.
973  *
974  * @param cfg Configuration to use (to connect to PSYC service).
975  * @param channel_key ECC key that will be used to sign messages for this
976  *        PSYC session. The public key is used to identify the PSYC channel.
977  *        Note that end-users will usually not use the private key directly, but
978  *        rather look it up in GNS for places managed by other users, or select
979  *        a file with the private key(s) when setting up their own channels
980  *        FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper
981  *        one in the future.
982  * @param policy Channel policy specifying join and history restrictions.
983  *        Used to automate join decisions.
984  * @param message_cb Function to invoke on message parts received from slaves.
985  * @param join_cb Function to invoke when a peer wants to join.
986  * @param master_started_cb Function to invoke after the channel master started.
987  * @param cls Closure for @a master_started_cb and @a join_cb.
988  * @return Handle for the channel master, NULL on error.
989  */
990 struct GNUNET_PSYC_Master *
991 GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
992                           const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key,
993                           enum GNUNET_PSYC_Policy policy,
994                           GNUNET_PSYC_MessageCallback message_cb,
995                           GNUNET_PSYC_JoinCallback join_cb,
996                           GNUNET_PSYC_MasterStartCallback master_started_cb,
997                           void *cls)
998 {
999   struct GNUNET_PSYC_Master *mst = GNUNET_malloc (sizeof (*mst));
1000   struct GNUNET_PSYC_Channel *ch = &mst->ch;
1001   struct MasterStartRequest *req = GNUNET_malloc (sizeof (*req));
1002
1003   req->header.size = htons (sizeof (*req));
1004   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START);
1005   req->channel_key = *channel_key;
1006   req->policy = policy;
1007
1008   ch->cfg = cfg;
1009   ch->is_master = GNUNET_YES;
1010   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
1011   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
1012   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, mst);
1013
1014   ch->message_cb = message_cb;
1015   ch->join_cb = join_cb;
1016   ch->cb_cls = cls;
1017   mst->start_cb = master_started_cb;
1018
1019   return mst;
1020 }
1021
1022
1023 /**
1024  * Stop a PSYC master channel.
1025  *
1026  * @param master PSYC channel master to stop.
1027  */
1028 void
1029 GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master)
1030 {
1031   disconnect (master);
1032   GNUNET_free (master);
1033 }
1034
1035
1036 /**
1037  * Function to call with the decision made for a join request.
1038  *
1039  * Must be called once and only once in response to an invocation of the
1040  * #GNUNET_PSYC_JoinCallback.
1041  *
1042  * @param jh Join request handle.
1043  * @param is_admitted #GNUNET_YES if joining is approved,
1044  *        #GNUNET_NO if it is disapproved.
1045  * @param relay_count Number of relays given.
1046  * @param relays Array of suggested peers that might be useful relays to use
1047  *        when joining the multicast group (essentially a list of peers that
1048  *        are already part of the multicast group and might thus be willing
1049  *        to help with routing).  If empty, only this local peer (which must
1050  *        be the multicast origin) is a good candidate for building the
1051  *        multicast tree.  Note that it is unnecessary to specify our own
1052  *        peer identity in this array.
1053  * @param method_name Method name for the message transmitted with the response.
1054  * @param env Environment containing transient variables for the message, or NULL.
1055  * @param data Data of the message.
1056  * @param data_size Size of @a data.
1057  */
1058 void
1059 GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh,
1060                            int is_admitted,
1061                            uint32_t relay_count,
1062                            const struct GNUNET_PeerIdentity *relays,
1063                            const char *method_name,
1064                            const struct GNUNET_ENV_Environment *env,
1065                            const void *data,
1066                            size_t data_size)
1067 {
1068
1069 }
1070
1071
1072 /* FIXME: split up value into <64K chunks and transmit the continuations in
1073  *        MOD_CONT msgs */
1074 static int
1075 send_modifier (void *cls, struct GNUNET_ENV_Modifier *mod)
1076 {
1077   struct GNUNET_PSYC_Channel *ch = cls;
1078   size_t name_size = strlen (mod->name) + 1;
1079   struct GNUNET_PSYC_MessageModifier *pmod;
1080   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*pmod)
1081                                               + name_size + mod->value_size);
1082   pmod = (struct GNUNET_PSYC_MessageModifier *) &op[1];
1083   op->msg = (struct GNUNET_MessageHeader *) pmod;
1084
1085   pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER);
1086   pmod->header.size = htons (sizeof (*pmod) + name_size + mod->value_size);
1087   pmod->name_size = htons (name_size);
1088   memcpy (&pmod[1], mod->name, name_size);
1089   memcpy ((char *) &pmod[1] + name_size, mod->value, mod->value_size);
1090
1091   GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
1092   return GNUNET_YES;
1093 }
1094
1095
1096 /**
1097  * Send a message to call a method to all members in the PSYC channel.
1098  *
1099  * @param master Handle to the PSYC channel.
1100  * @param method_name Which method should be invoked.
1101  * @param notify_mod Function to call to obtain modifiers.
1102  * @param notify_data Function to call to obtain fragments of the data.
1103  * @param notify_cls Closure for @a notify_mod and @a notify_data.
1104  * @param flags Flags for the message being transmitted.
1105  * @return Transmission handle, NULL on error (i.e. more than one request queued).
1106  */
1107 struct GNUNET_PSYC_MasterTransmitHandle *
1108 GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *master,
1109                              const char *method_name,
1110                              GNUNET_PSYC_MasterTransmitNotify notify_mod,
1111                              GNUNET_PSYC_MasterTransmitNotify notify_data,
1112                              void *notify_cls,
1113                              enum GNUNET_PSYC_MasterTransmitFlags flags)
1114 {
1115   GNUNET_assert (NULL != master);
1116   struct GNUNET_PSYC_Channel *ch = &master->ch;
1117   if (GNUNET_NO != ch->in_transmit)
1118     return NULL;
1119   ch->in_transmit = GNUNET_YES;
1120
1121   size_t size = strlen (method_name) + 1;
1122   struct GNUNET_PSYC_MessageMethod *pmeth;
1123   struct OperationHandle *op
1124     = GNUNET_malloc (sizeof (*op) + sizeof (*pmeth) + size);
1125   pmeth = (struct GNUNET_PSYC_MessageMethod *) &op[1];
1126   op->msg = (struct GNUNET_MessageHeader *) pmeth;
1127
1128   pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD);
1129   pmeth->header.size = htons (sizeof (*pmeth) + size);
1130   pmeth->flags = htonl (flags);
1131   memcpy (&pmeth[1], method_name, size);
1132
1133   GNUNET_CONTAINER_DLL_insert_tail (ch->tmit_head, ch->tmit_tail, op);
1134   transmit_next (ch);
1135
1136   master->tmit = GNUNET_malloc (sizeof (*master->tmit));
1137   master->tmit->master = master;
1138   master->tmit->notify_mod = notify_mod;
1139   master->tmit->notify_data = notify_data;
1140   master->tmit->notify_cls = notify_cls;
1141   master->tmit->state = MSG_STATE_START; // FIXME
1142   return master->tmit;
1143 }
1144
1145
1146 /**
1147  * Resume transmission to the channel.
1148  *
1149  * @param th Handle of the request that is being resumed.
1150  */
1151 void
1152 GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
1153 {
1154   struct GNUNET_PSYC_Channel *ch = &th->master->ch;
1155   if (GNUNET_NO == ch->tmit_ack_pending)
1156   {
1157     ch->tmit_paused = GNUNET_NO;
1158     master_transmit_data (th->master);
1159   }
1160 }
1161
1162
1163 /**
1164  * Abort transmission request to the channel.
1165  *
1166  * @param th Handle of the request that is being aborted.
1167  */
1168 void
1169 GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th)
1170 {
1171   struct GNUNET_PSYC_Master *master = th->master;
1172   struct GNUNET_PSYC_Channel *ch = &master->ch;
1173   if (GNUNET_NO != ch->in_transmit)
1174     return;
1175 }
1176
1177
1178 /**
1179  * Join a PSYC channel.
1180  *
1181  * The entity joining is always the local peer.  The user must immediately use
1182  * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the
1183  * channel; if the join request succeeds, the channel state (and @e recent
1184  * method calls) will be replayed to the joining member.  There is no explicit
1185  * notification on failure (as the channel may simply take days to approve,
1186  * and disapproval is simply being ignored).
1187  *
1188  * @param cfg Configuration to use.
1189  * @param channel_key ECC public key that identifies the channel we wish to join.
1190  * @param slave_key ECC private-public key pair that identifies the slave, and
1191  *        used by multicast to sign the join request and subsequent unicast
1192  *        requests sent to the master.
1193  * @param origin Peer identity of the origin.
1194  * @param relay_count Number of peers in the @a relays array.
1195  * @param relays Peer identities of members of the multicast group, which serve
1196  *        as relays and used to join the group at.
1197  * @param message_cb Function to invoke on message parts received from the
1198  *        channel, typically at least contains method handlers for @e join and
1199  *        @e part.
1200  * @param join_cb function invoked once we have joined with the current
1201  *        message ID of the channel
1202  * @param slave_joined_cb Function to invoke when a peer wants to join.
1203  * @param cls Closure for @a message_cb and @a slave_joined_cb.
1204  * @param method_name Method name for the join request.
1205  * @param env Environment containing transient variables for the request, or NULL.
1206  * @param data Payload for the join message.
1207  * @param data_size Number of bytes in @a data.
1208  * @return Handle for the slave, NULL on error.
1209  */
1210 struct GNUNET_PSYC_Slave *
1211 GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
1212                         const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key,
1213                         const struct GNUNET_CRYPTO_EddsaPrivateKey *slave_key,
1214                         const struct GNUNET_PeerIdentity *origin,
1215                         uint32_t relay_count,
1216                         const struct GNUNET_PeerIdentity *relays,
1217                         GNUNET_PSYC_MessageCallback message_cb,
1218                         GNUNET_PSYC_JoinCallback join_cb,
1219                         GNUNET_PSYC_SlaveJoinCallback slave_joined_cb,
1220                         void *cls,
1221                         const char *method_name,
1222                         const struct GNUNET_ENV_Environment *env,
1223                         const void *data,
1224                         uint16_t data_size)
1225 {
1226   struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv));
1227   struct GNUNET_PSYC_Channel *ch = &slv->ch;
1228   struct SlaveJoinRequest *req = GNUNET_malloc (sizeof (*req)
1229                                                 + relay_count * sizeof (*relays));
1230   req->header.size = htons (sizeof (*req)
1231                             + relay_count * sizeof (*relays));
1232   req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN);
1233   req->channel_key = *channel_key;
1234   req->slave_key = *slave_key;
1235   req->origin = *origin;
1236   req->relay_count = relay_count;
1237   memcpy (&req[1], relays, relay_count * sizeof (*relays));
1238
1239   ch->message_cb = message_cb;
1240   ch->join_cb = join_cb;
1241   ch->cb_cls = cls;
1242
1243   ch->cfg = cfg;
1244   ch->is_master = GNUNET_NO;
1245   ch->reconnect_msg = (struct GNUNET_MessageHeader *) req;
1246   ch->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
1247   ch->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, slv);
1248
1249   return slv;
1250 }
1251
1252
1253 /**
1254  * Part a PSYC channel.
1255  *
1256  * Will terminate the connection to the PSYC service.  Polite clients should
1257  * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()).
1258  *
1259  * @param slave Slave handle.
1260  */
1261 void
1262 GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave)
1263 {
1264   disconnect (slave);
1265   GNUNET_free (slave);
1266 }
1267
1268
1269 /**
1270  * Request a message to be sent to the channel master.
1271  *
1272  * @param slave Slave handle.
1273  * @param method_name Which (PSYC) method should be invoked (on host).
1274  * @param env Environment containing transient variables for the message, or
1275  *            NULL.
1276  * @param notify Function to call when we are allowed to transmit (to get data).
1277  * @param notify_cls Closure for @a notify.
1278  * @param flags Flags for the message being transmitted.
1279  * @return Transmission handle, NULL on error (i.e. more than one request
1280  *         queued).
1281  */
1282 struct GNUNET_PSYC_SlaveTransmitHandle *
1283 GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave,
1284                             const char *method_name,
1285                             const struct GNUNET_ENV_Environment *env,
1286                             GNUNET_PSYC_SlaveTransmitNotify notify,
1287                             void *notify_cls,
1288                             enum GNUNET_PSYC_SlaveTransmitFlags flags)
1289 {
1290   return NULL;
1291 }
1292
1293
1294 /**
1295  * Resume transmission to the master.
1296  *
1297  * @param th Handle of the request that is being resumed.
1298  */
1299 void
1300 GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th)
1301 {
1302
1303 }
1304
1305
1306 /**
1307  * Abort transmission request to master.
1308  *
1309  * @param th Handle of the request that is being aborted.
1310  */
1311 void
1312 GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th)
1313 {
1314
1315 }
1316
1317
1318 /**
1319  * Convert a channel @a master to a @e channel handle to access the @e channel
1320  * APIs.
1321  *
1322  * @param master Channel master handle.
1323  * @return Channel handle, valid for as long as @a master is valid.
1324  */
1325 struct GNUNET_PSYC_Channel *
1326 GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master)
1327 {
1328   return (struct GNUNET_PSYC_Channel *) master;
1329 }
1330
1331
1332 /**
1333  * Convert @a slave to a @e channel handle to access the @e channel APIs.
1334  *
1335  * @param slave Slave handle.
1336  * @return Channel handle, valid for as long as @a slave is valid.
1337  */
1338 struct GNUNET_PSYC_Channel *
1339 GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave)
1340 {
1341   return (struct GNUNET_PSYC_Channel *) slave;
1342 }
1343
1344
1345 /**
1346  * Add a slave to the channel's membership list.
1347  *
1348  * Note that this will NOT generate any PSYC traffic, it will merely update the
1349  * local database to modify how we react to <em>membership test</em> queries.
1350  * The channel master still needs to explicitly transmit a @e join message to
1351  * notify other channel members and they then also must still call this function
1352  * in their respective methods handling the @e join message.  This way, how @e
1353  * join and @e part operations are exactly implemented is still up to the
1354  * application; for example, there might be a @e part_all method to kick out
1355  * everyone.
1356  *
1357  * Note that channel slaves are explicitly trusted to execute such methods
1358  * correctly; not doing so correctly will result in either denying other slaves
1359  * access or offering access to channel data to non-members.
1360  *
1361  * @param channel Channel handle.
1362  * @param slave_key Identity of channel slave to add.
1363  * @param announced_at ID of the message that announced the membership change.
1364  * @param effective_since Addition of slave is in effect since this message ID.
1365  */
1366 void
1367 GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel,
1368                                const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
1369                                uint64_t announced_at,
1370                                uint64_t effective_since)
1371 {
1372   struct ChannelSlaveAdd *slvadd;
1373   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvadd));
1374
1375   slvadd = (struct ChannelSlaveAdd *) &op[1];
1376   op->msg = (struct GNUNET_MessageHeader *) slvadd;
1377
1378   slvadd->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_ADD;
1379   slvadd->header.size = htons (sizeof (*slvadd));
1380   slvadd->announced_at = GNUNET_htonll (announced_at);
1381   slvadd->effective_since = GNUNET_htonll (effective_since);
1382   GNUNET_CONTAINER_DLL_insert_tail (channel->tmit_head,
1383                                     channel->tmit_tail,
1384                                     op);
1385   transmit_next (channel);
1386 }
1387
1388
1389 /**
1390  * Remove a slave from the channel's membership list.
1391  *
1392  * Note that this will NOT generate any PSYC traffic, it will merely update the
1393  * local database to modify how we react to <em>membership test</em> queries.
1394  * The channel master still needs to explicitly transmit a @e part message to
1395  * notify other channel members and they then also must still call this function
1396  * in their respective methods handling the @e part message.  This way, how
1397  * @e join and @e part operations are exactly implemented is still up to the
1398  * application; for example, there might be a @e part_all message to kick out
1399  * everyone.
1400  *
1401  * Note that channel members are explicitly trusted to perform these
1402  * operations correctly; not doing so correctly will result in either
1403  * denying members access or offering access to channel data to
1404  * non-members.
1405  *
1406  * @param channel Channel handle.
1407  * @param slave_key Identity of channel slave to remove.
1408  * @param announced_at ID of the message that announced the membership change.
1409  */
1410 void
1411 GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel,
1412                                   const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
1413                                   uint64_t announced_at)
1414 {
1415   struct ChannelSlaveRemove *slvrm;
1416   struct OperationHandle *op = GNUNET_malloc (sizeof (*op) + sizeof (*slvrm));
1417
1418   slvrm = (struct ChannelSlaveRemove *) &op[1];
1419   op->msg = (struct GNUNET_MessageHeader *) slvrm;
1420   slvrm->header.type = GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_SLAVE_RM;
1421   slvrm->header.size = htons (sizeof (*slvrm));
1422   slvrm->announced_at = GNUNET_htonll (announced_at);
1423   GNUNET_CONTAINER_DLL_insert_tail (channel->tmit_head,
1424                                     channel->tmit_tail,
1425                                     op);
1426   transmit_next (channel);
1427 }
1428
1429
1430 /**
1431  * Request to be told the message history of the channel.
1432  *
1433  * Historic messages (but NOT the state at the time) will be replayed (given to
1434  * the normal method handlers) if available and if access is permitted.
1435  *
1436  * To get the latest message, use 0 for both the start and end message ID.
1437  *
1438  * @param channel Which channel should be replayed?
1439  * @param start_message_id Earliest interesting point in history.
1440  * @param end_message_id Last (exclusive) interesting point in history.
1441  * @param message_cb Function to invoke on message parts received from the story.
1442  * @param finish_cb Function to call when the requested story has been fully
1443  *        told (counting message IDs might not suffice, as some messages
1444  *        might be secret and thus the listener would not know the story is
1445  *        finished without being told explicitly) once this function
1446  *        has been called, the client must not call
1447  *        GNUNET_PSYC_channel_story_tell_cancel() anymore.
1448  * @param cls Closure for the callbacks.
1449  * @return Handle to cancel story telling operation.
1450  */
1451 struct GNUNET_PSYC_Story *
1452 GNUNET_PSYC_channel_story_tell (struct GNUNET_PSYC_Channel *channel,
1453                                 uint64_t start_message_id,
1454                                 uint64_t end_message_id,
1455                                 GNUNET_PSYC_MessageCallback message_cb,
1456                                 GNUNET_PSYC_FinishCallback finish_cb,
1457                                 void *cls)
1458 {
1459   return NULL;
1460 }
1461
1462
1463 /**
1464  * Abort story telling.
1465  *
1466  * This function must not be called from within method handlers (as given to
1467  * GNUNET_PSYC_slave_join()) of the slave.
1468  *
1469  * @param story Story telling operation to stop.
1470  */
1471 void
1472 GNUNET_PSYC_channel_story_tell_cancel (struct GNUNET_PSYC_Story *story)
1473 {
1474
1475 }
1476
1477
1478 /**
1479  * Retrieve the best matching channel state variable.
1480  *
1481  * If the requested variable name is not present in the state, the nearest
1482  * less-specific name is matched; for example, requesting "_a_b" will match "_a"
1483  * if "_a_b" does not exist.
1484  *
1485  * @param channel Channel handle.
1486  * @param full_name Full name of the requested variable, the actual variable
1487  *        returned might have a shorter name..
1488  * @param cb Function called once when a matching state variable is found.
1489  *        Not called if there's no matching state variable.
1490  * @param cb_cls Closure for the callbacks.
1491  * @return Handle that can be used to cancel the query operation.
1492  */
1493 struct GNUNET_PSYC_StateQuery *
1494 GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel,
1495                                const char *full_name,
1496                                GNUNET_PSYC_StateCallback cb,
1497                                void *cb_cls)
1498 {
1499   return NULL;
1500 }
1501
1502
1503 /**
1504  * Return all channel state variables whose name matches a given prefix.
1505  *
1506  * A name matches if it starts with the given @a name_prefix, thus requesting
1507  * the empty prefix ("") will match all values; requesting "_a_b" will also
1508  * return values stored under "_a_b_c".
1509  *
1510  * The @a state_cb is invoked on all matching state variables asynchronously, as
1511  * the state is stored in and retrieved from the PSYCstore,
1512  *
1513  * @param channel Channel handle.
1514  * @param name_prefix Prefix of the state variable name to match.
1515  * @param cb Function to call with the matching state variables.
1516  * @param cb_cls Closure for the callbacks.
1517  * @return Handle that can be used to cancel the query operation.
1518  */
1519 struct GNUNET_PSYC_StateQuery *
1520 GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel,
1521                                       const char *name_prefix,
1522                                       GNUNET_PSYC_StateCallback cb,
1523                                       void *cb_cls)
1524 {
1525   return NULL;
1526 }
1527
1528
1529 /**
1530  * Cancel a state query operation.
1531  *
1532  * @param query Handle for the operation to cancel.
1533  */
1534 void
1535 GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateQuery *query)
1536 {
1537
1538 }
1539
1540
1541 /* end of psyc_api.c */