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