e568e77ee1bc66eda659548093c378051c2301cd
[oweals/gnunet.git] / src / multicast / multicast_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 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 multicast/multicast_api.c
23  * @brief multicast service; establish tunnels to distant peers
24  * @author Christian Grothoff
25  * @author Gabor X Toth
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_multicast_service.h"
30 #include "multicast.h"
31
32 #define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__)
33
34
35 /**
36  * Started origins.
37  * Group's pub_key_hash -> struct GNUNET_MULTICAST_Origin
38  */
39 static struct GNUNET_CONTAINER_MultiHashMap *origins;
40
41 /**
42  * Joined members.
43  * group_key_hash -> struct GNUNET_MULTICAST_Member
44  */
45 static struct GNUNET_CONTAINER_MultiHashMap *members;
46
47
48 struct MessageQueue
49 {
50   struct MessageQueue *prev;
51   struct MessageQueue *next;
52 };
53
54
55 /**
56  * Handle for a request to send a message to all multicast group members
57  * (from the origin).
58  */
59 struct GNUNET_MULTICAST_OriginTransmitHandle
60 {
61   GNUNET_MULTICAST_OriginTransmitNotify notify;
62   void *notify_cls;
63   struct GNUNET_MULTICAST_Origin *origin;
64
65   uint64_t message_id;
66   uint64_t group_generation;
67   uint64_t fragment_offset;
68 };
69
70
71 /**
72  * Handle for a message to be delivered from a member to the origin.
73  */
74 struct GNUNET_MULTICAST_MemberTransmitHandle
75 {
76   GNUNET_MULTICAST_MemberTransmitNotify notify;
77   void *notify_cls;
78   struct GNUNET_MULTICAST_Member *member;
79
80   uint64_t request_id;
81   uint64_t fragment_offset;
82 };
83
84
85 struct GNUNET_MULTICAST_Group
86 {
87   /**
88    * Configuration to use.
89    */
90   const struct GNUNET_CONFIGURATION_Handle *cfg;
91
92   /**
93    * Socket (if available).
94    */
95   struct GNUNET_CLIENT_Connection *client;
96
97   /**
98    * Currently pending transmission request, or NULL for none.
99    */
100   struct GNUNET_CLIENT_TransmitHandle *th;
101
102   /**
103    * Head of operations to transmit.
104    */
105   struct MessageQueue *tmit_head;
106
107   /**
108    * Tail of operations to transmit.
109    */
110   struct MessageQueue *tmit_tail;
111
112   /**
113    * Message being transmitted to the Multicast service.
114    */
115   struct MessageQueue *tmit_msg;
116
117   /**
118    * Message to send on reconnect.
119    */
120   struct GNUNET_MessageHeader *reconnect_msg;
121
122   /**
123    * Task doing exponential back-off trying to reconnect.
124    */
125   GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
126
127   /**
128    * Time for next connect retry.
129    */
130   struct GNUNET_TIME_Relative reconnect_delay;
131
132   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
133   struct GNUNET_HashCode pub_key_hash;
134
135   GNUNET_MULTICAST_JoinRequestCallback join_req_cb;
136   GNUNET_MULTICAST_MembershipTestCallback member_test_cb;
137   GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
138   GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
139   GNUNET_MULTICAST_MessageCallback message_cb;
140   void *cb_cls;
141
142   /**
143    * Are we polling for incoming messages right now?
144    */
145   uint8_t in_receive;
146
147   /**
148    * Are we currently transmitting a message?
149    */
150   uint8_t in_transmit;
151
152   /**
153    * Is this the origin or a member?
154    */
155   uint8_t is_origin;
156 };
157
158
159 /**
160  * Handle for the origin of a multicast group.
161  */
162 struct GNUNET_MULTICAST_Origin
163 {
164   struct GNUNET_MULTICAST_Group grp;
165   struct GNUNET_MULTICAST_OriginTransmitHandle tmit;
166   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
167
168   GNUNET_MULTICAST_RequestCallback request_cb;
169 };
170
171
172 /**
173  * Handle for a multicast group member.
174  */
175 struct GNUNET_MULTICAST_Member
176 {
177   struct GNUNET_MULTICAST_Group grp;
178   struct GNUNET_MULTICAST_MemberTransmitHandle tmit;
179
180   GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb;
181
182   uint64_t next_fragment_id;
183 };
184
185
186 /**
187  * Handle that identifies a join request.
188  *
189  * Used to match calls to #GNUNET_MULTICAST_JoinCallback to the
190  * corresponding calls to #GNUNET_MULTICAST_join_decision().
191  */
192 struct GNUNET_MULTICAST_JoinHandle
193 {
194   struct GNUNET_MULTICAST_Group *group;
195
196   /**
197    * Public key of the member requesting join.
198    */
199   struct GNUNET_CRYPTO_EddsaPublicKey member_key;
200
201   /**
202    * Peer identity of the member requesting join.
203    */
204   struct GNUNET_PeerIdentity member_peer;
205 };
206
207
208 /**
209  * Handle to pass back for the answer of a membership test.
210  */
211 struct GNUNET_MULTICAST_MembershipTestHandle
212 {
213 };
214
215
216 /**
217  * Opaque handle to a replay request from the multicast service.
218  */
219 struct GNUNET_MULTICAST_ReplayHandle
220 {
221 };
222
223
224 /**
225  * Handle for a replay request.
226  */
227 struct GNUNET_MULTICAST_MemberReplayHandle
228 {
229 };
230
231
232 static void
233 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
234
235
236 static void
237 reschedule_connect (struct GNUNET_MULTICAST_Group *grp);
238
239
240 /**
241  * Schedule transmission of the next message from our queue.
242  *
243  * @param grp PSYC channel handle
244  */
245 static void
246 transmit_next (struct GNUNET_MULTICAST_Group *grp);
247
248
249 static void
250 message_handler (void *cls, const struct GNUNET_MessageHeader *msg);
251
252
253 /**
254  * Reschedule a connect attempt to the service.
255  *
256  * @param c channel to reconnect
257  */
258 static void
259 reschedule_connect (struct GNUNET_MULTICAST_Group *grp)
260 {
261   GNUNET_assert (grp->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
262
263   if (NULL != grp->th)
264   {
265     GNUNET_CLIENT_notify_transmit_ready_cancel (grp->th);
266     grp->th = NULL;
267   }
268   if (NULL != grp->client)
269   {
270     GNUNET_CLIENT_disconnect (grp->client);
271     grp->client = NULL;
272   }
273   grp->in_receive = GNUNET_NO;
274   LOG (GNUNET_ERROR_TYPE_DEBUG,
275        "Scheduling task to reconnect to Multicast service in %s.\n",
276        GNUNET_STRINGS_relative_time_to_string (grp->reconnect_delay, GNUNET_YES));
277   grp->reconnect_task =
278       GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay, &reconnect, grp);
279   grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay);
280 }
281
282
283 /**
284  * Reset stored data related to the last received message.
285  */
286 static void
287 recv_reset (struct GNUNET_MULTICAST_Group *grp)
288 {
289 }
290
291
292 static void
293 recv_error (struct GNUNET_MULTICAST_Group *grp)
294 {
295   if (NULL != grp->message_cb)
296     grp->message_cb (grp->cb_cls, NULL);
297
298   recv_reset (grp);
299 }
300
301
302 /**
303  * Transmit next message to service.
304  *
305  * @param cls   The struct GNUNET_MULTICAST_Group.
306  * @param size  Number of bytes available in @a buf.
307  * @param buf   Where to copy the message.
308  *
309  * @return Number of bytes copied to @a buf.
310  */
311 static size_t
312 send_next_message (void *cls, size_t size, void *buf)
313 {
314   LOG (GNUNET_ERROR_TYPE_DEBUG, "send_next_message()\n");
315   struct GNUNET_MULTICAST_Group *grp = cls;
316   struct MessageQueue *mq = grp->tmit_head;
317   if (NULL == mq)
318     return 0;
319   struct GNUNET_MessageHeader *qmsg = (struct GNUNET_MessageHeader *) &mq[1];
320   size_t ret = ntohs (qmsg->size);
321   grp->th = NULL;
322   if (ret > size)
323   {
324     reschedule_connect (grp);
325     return 0;
326   }
327   memcpy (buf, qmsg, ret);
328
329   GNUNET_CONTAINER_DLL_remove (grp->tmit_head, grp->tmit_tail, mq);
330   GNUNET_free (mq);
331
332   if (NULL != grp->tmit_head)
333     transmit_next (grp);
334
335   if (GNUNET_NO == grp->in_receive)
336   {
337     grp->in_receive = GNUNET_YES;
338     GNUNET_CLIENT_receive (grp->client, &message_handler, grp,
339                            GNUNET_TIME_UNIT_FOREVER_REL);
340   }
341   return ret;
342 }
343
344
345 /**
346  * Schedule transmission of the next message from our queue.
347  *
348  * @param grp  Multicast group handle.
349  */
350 static void
351 transmit_next (struct GNUNET_MULTICAST_Group *grp)
352 {
353   LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_next()\n");
354   if (NULL != grp->th || NULL == grp->client)
355     return;
356
357   struct MessageQueue *mq = grp->tmit_head;
358   if (NULL == mq)
359     return;
360   struct GNUNET_MessageHeader *qmsg = (struct GNUNET_MessageHeader *) &mq[1];
361
362   grp->th = GNUNET_CLIENT_notify_transmit_ready (grp->client,
363                                                  ntohs (qmsg->size),
364                                                  GNUNET_TIME_UNIT_FOREVER_REL,
365                                                  GNUNET_NO,
366                                                  &send_next_message,
367                                                  grp);
368 }
369
370
371 /**
372  * Try again to connect to the Multicast service.
373  *
374  * @param cls Channel handle.
375  * @param tc Scheduler context.
376  */
377 static void
378 reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
379 {
380   struct GNUNET_MULTICAST_Group *grp = cls;
381
382   recv_reset (grp);
383   grp->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
384   LOG (GNUNET_ERROR_TYPE_DEBUG,
385        "Connecting to Multicast service.\n");
386   GNUNET_assert (NULL == grp->client);
387   grp->client = GNUNET_CLIENT_connect ("multicast", grp->cfg);
388   GNUNET_assert (NULL != grp->client);
389   uint16_t reconn_size = ntohs (grp->reconnect_msg->size);
390
391   if (NULL == grp->tmit_head ||
392       0 != memcmp (&grp->tmit_head[1], grp->reconnect_msg, reconn_size))
393   {
394     struct MessageQueue *mq = GNUNET_malloc (sizeof (*mq) + reconn_size);
395     memcpy (&mq[1], grp->reconnect_msg, reconn_size);
396     GNUNET_CONTAINER_DLL_insert (grp->tmit_head, grp->tmit_tail, mq);
397   }
398   transmit_next (grp);
399 }
400
401
402 /**
403  * Disconnect from the Multicast service.
404  *
405  * @param g  Group handle to disconnect.
406  */
407 static void
408 disconnect (void *g)
409 {
410   struct GNUNET_MULTICAST_Group *grp = g;
411
412   GNUNET_assert (NULL != grp);
413   if (grp->tmit_head != grp->tmit_tail)
414   {
415     LOG (GNUNET_ERROR_TYPE_ERROR,
416          "Disconnecting while there are still outstanding messages!\n");
417     GNUNET_break (0);
418   }
419   if (grp->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
420   {
421     GNUNET_SCHEDULER_cancel (grp->reconnect_task);
422     grp->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
423   }
424   if (NULL != grp->th)
425   {
426     GNUNET_CLIENT_notify_transmit_ready_cancel (grp->th);
427     grp->th = NULL;
428   }
429   if (NULL != grp->client)
430   {
431     GNUNET_CLIENT_disconnect (grp->client);
432     grp->client = NULL;
433   }
434   if (NULL != grp->reconnect_msg)
435   {
436     GNUNET_free (grp->reconnect_msg);
437     grp->reconnect_msg = NULL;
438   }
439 }
440
441
442 /**
443  * Iterator callback for calling message callbacks for all groups.
444  */
445 static int
446 message_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, void *group)
447 {
448   const struct GNUNET_MessageHeader *msg = cls;
449   struct GNUNET_MULTICAST_Group *grp = group;
450
451   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452               "Calling message callback with a message "
453               "of type %u and size %u.\n",
454               ntohs (msg->type), ntohs (msg->size));
455
456   if (NULL != grp->message_cb)
457     grp->message_cb (grp->cb_cls, msg);
458
459   return GNUNET_YES;
460 }
461
462
463 /**
464  * Iterator callback for calling request callbacks of origins.
465  */
466 static int
467 request_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, void *origin)
468 {
469   const struct GNUNET_MULTICAST_RequestHeader *req = cls;
470   struct GNUNET_MULTICAST_Origin *orig = origin;
471
472   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473               "Calling request callback for a request of type %u and size %u.\n",
474               ntohs (req->header.type), ntohs (req->header.size));
475
476   if (NULL != orig->request_cb)
477     orig->request_cb (orig->grp.cb_cls, &req->member_key,
478                       (const struct GNUNET_MessageHeader *) req, 0);
479   return GNUNET_YES;
480 }
481
482
483 /**
484  * Iterator callback for calling join request callbacks of origins.
485  */
486 static int
487 join_request_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
488                  void *group)
489 {
490   const struct MulticastJoinRequestMessage *req = cls;
491   struct GNUNET_MULTICAST_Group *grp = group;
492
493   struct GNUNET_MULTICAST_JoinHandle *jh = GNUNET_malloc (sizeof (*jh));
494   jh->group = grp;
495   jh->member_key = req->member_key;
496   jh->member_peer = req->member_peer;
497
498   const struct GNUNET_MessageHeader *msg = NULL;
499   if (sizeof (*req) + sizeof (*msg) <= ntohs (req->header.size))
500     msg = (const struct GNUNET_MessageHeader *) &req[1];
501
502   if (NULL != grp->join_req_cb)
503     grp->join_req_cb (grp->cb_cls, &req->member_key, msg, jh);
504   return GNUNET_YES;
505 }
506
507
508 /**
509  * Iterator callback for calling join decision callbacks of members.
510  */
511 static int
512 join_decision_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash,
513                   void *member)
514 {
515   const struct MulticastJoinDecisionMessageHeader *hdcsn = cls;
516   const struct MulticastJoinDecisionMessage *
517     dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
518   struct GNUNET_MULTICAST_Member *mem = member;
519   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
520
521   uint16_t dcsn_size = ntohs (dcsn->header.size);
522   int is_admitted = ntohl (dcsn->is_admitted);
523
524   const struct GNUNET_MessageHeader *join_resp = NULL;
525   uint16_t join_resp_size = 0;
526
527   uint16_t relay_count = ntohl (dcsn->relay_count);
528   const struct GNUNET_PeerIdentity *relays = NULL;
529   uint16_t relay_size = relay_count * sizeof (*relays);
530   if (0 < relay_count && dcsn_size < sizeof (*dcsn) + relay_size)
531     relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
532
533   if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
534   {
535     join_resp = (const struct GNUNET_MessageHeader *) &dcsn[1];
536     join_resp_size = ntohs (join_resp->size);
537   }
538   if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
539   {
540     LOG (GNUNET_ERROR_TYPE_DEBUG,
541          "Received invalid join decision message from multicast.\n");
542     GNUNET_break_op (0);
543     is_admitted = GNUNET_SYSERR;
544   }
545
546   if (NULL != mem->join_dcsn_cb)
547     mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
548                        relay_count, relays, join_resp);
549
550   if (GNUNET_YES != is_admitted)
551     GNUNET_MULTICAST_member_part (mem);
552
553   return GNUNET_YES;
554 }
555
556 /**
557  * Function called when we receive a message from the service.
558  *
559  * @param cls   struct GNUNET_MULTICAST_Group
560  * @param msg   Message received, NULL on timeout or fatal error.
561  */
562 static void
563 message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
564 {
565   struct GNUNET_MULTICAST_Group *grp = cls;
566
567   if (NULL == msg)
568   {
569     // timeout / disconnected from service, reconnect
570     reschedule_connect (grp);
571     return;
572   }
573
574   uint16_t size_eq = 0;
575   uint16_t size_min = 0;
576   uint16_t size = ntohs (msg->size);
577   uint16_t type = ntohs (msg->type);
578
579   LOG (GNUNET_ERROR_TYPE_DEBUG,
580        "Received message of type %d and size %u from Multicast service\n",
581        type, size);
582
583   switch (type)
584   {
585   case GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE:
586     size_min = sizeof (struct GNUNET_MULTICAST_MessageHeader);
587     break;
588
589   case GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST:
590     size_min = sizeof (struct GNUNET_MULTICAST_RequestHeader);
591     break;
592
593   case GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST:
594     size_min = sizeof (struct MulticastJoinRequestMessage);
595     break;
596
597   case GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION:
598     size_min = sizeof (struct MulticastJoinDecisionMessage);
599     break;
600
601   default:
602     GNUNET_break_op (0);
603     type = 0;
604   }
605
606   if (! ((0 < size_eq && size == size_eq)
607          || (0 < size_min && size_min <= size)))
608   {
609     GNUNET_break_op (0);
610     type = 0;
611   }
612
613   switch (type)
614   {
615   case GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE:
616     if (origins != NULL)
617       GNUNET_CONTAINER_multihashmap_get_multiple (origins, &grp->pub_key_hash,
618                                                   message_cb, (void *) msg);
619     if (members != NULL)
620       GNUNET_CONTAINER_multihashmap_get_multiple (members, &grp->pub_key_hash,
621                                                   message_cb, (void *) msg);
622     break;
623
624   case GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST:
625     if (GNUNET_YES != grp->is_origin)
626     {
627       GNUNET_break (0);
628       break;
629     }
630     if (NULL != origins)
631       GNUNET_CONTAINER_multihashmap_get_multiple (origins, &grp->pub_key_hash,
632                                                   request_cb, (void *) msg);
633     break;
634
635   case GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST:
636     if (NULL != origins)
637       GNUNET_CONTAINER_multihashmap_get_multiple (origins, &grp->pub_key_hash,
638                                                   join_request_cb, (void *) msg);
639     if (NULL != members)
640       GNUNET_CONTAINER_multihashmap_get_multiple (members, &grp->pub_key_hash,
641                                                   join_request_cb, (void *) msg);
642     break;
643
644   case GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION:
645     if (GNUNET_NO != grp->is_origin)
646     {
647       GNUNET_break (0);
648       break;
649     }
650     if (NULL != members)
651       GNUNET_CONTAINER_multihashmap_get_multiple (members, &grp->pub_key_hash,
652                                                   join_decision_cb, (void *) msg);
653     break;
654   }
655
656   if (NULL != grp->client)
657   {
658     GNUNET_CLIENT_receive (grp->client, &message_handler, grp,
659                            GNUNET_TIME_UNIT_FOREVER_REL);
660   }
661 }
662
663
664 /**
665  * Function to call with the decision made for a join request.
666  *
667  * Must be called once and only once in response to an invocation of the
668  * #GNUNET_MULTICAST_JoinRequestCallback.
669  *
670  * @param jh Join request handle.
671  * @param is_admitted  #GNUNET_YES    if the join is approved,
672  *                     #GNUNET_NO     if it is disapproved,
673  *                     #GNUNET_SYSERR if we cannot answer the request.
674  * @param relay_count Number of relays given.
675  * @param relays Array of suggested peers that might be useful relays to use
676  *        when joining the multicast group (essentially a list of peers that
677  *        are already part of the multicast group and might thus be willing
678  *        to help with routing).  If empty, only this local peer (which must
679  *        be the multicast origin) is a good candidate for building the
680  *        multicast tree.  Note that it is unnecessary to specify our own
681  *        peer identity in this array.
682  * @param join_resp  Message to send in response to the joining peer;
683  *        can also be used to redirect the peer to a different group at the
684  *        application layer; this response is to be transmitted to the
685  *        peer that issued the request even if admission is denied.
686  */
687 struct GNUNET_MULTICAST_ReplayHandle *
688 GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh,
689                                 int is_admitted,
690                                 uint16_t relay_count,
691                                 const struct GNUNET_PeerIdentity *relays,
692                                 const struct GNUNET_MessageHeader *join_resp)
693 {
694   struct GNUNET_MULTICAST_Group *grp = jh->group;
695   uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
696   uint16_t relay_size = relay_count * sizeof (*relays);
697   struct MulticastJoinDecisionMessageHeader * hdcsn;
698   struct MulticastJoinDecisionMessage *dcsn;
699   struct MessageQueue *
700     mq = GNUNET_malloc (sizeof (*mq) + sizeof (*hdcsn) + sizeof (*dcsn)
701                         + relay_size + join_resp_size);
702
703   hdcsn = (struct MulticastJoinDecisionMessageHeader *) &mq[1];
704   hdcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
705   hdcsn->header.size = htons (sizeof (*hdcsn) + sizeof (*dcsn)
706                                 + relay_size + join_resp_size);
707   hdcsn->member_key = jh->member_key;
708   hdcsn->peer = jh->member_peer;
709
710   dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
711   dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
712   dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
713   dcsn->is_admitted = htonl (is_admitted);
714   dcsn->relay_count = htonl (relay_count);
715   if (0 < relay_size)
716     memcpy (&dcsn[1], relays, relay_size);
717   if (0 < join_resp_size)
718     memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
719
720   GNUNET_CONTAINER_DLL_insert_tail (grp->tmit_head, grp->tmit_tail, mq);
721   transmit_next (grp);
722
723   GNUNET_free (jh);
724   return NULL;
725 }
726
727
728 /**
729  * Call informing multicast about the decision taken for a membership test.
730  *
731  * @param mth Handle that was given for the query.
732  * @param result #GNUNET_YES if peer was a member, #GNUNET_NO if peer was not a member,
733  *        #GNUNET_SYSERR if we cannot answer the membership test.
734  */
735 void
736 GNUNET_MULTICAST_membership_test_result (struct GNUNET_MULTICAST_MembershipTestHandle *mth,
737                                          int result)
738 {
739 }
740
741
742 /**
743  * Replay a message fragment for the multicast group.
744  *
745  * @param rh Replay handle identifying which replay operation was requested.
746  * @param msg Replayed message fragment, NULL if unknown/error.
747  * @param ec Error code.
748  */
749 void
750 GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
751                                   const struct GNUNET_MessageHeader *msg,
752                                   enum GNUNET_MULTICAST_ReplayErrorCode ec)
753 {
754 }
755
756
757 /**
758  * Indicate the end of the replay session.
759  *
760  * Invalidates the replay handle.
761  *
762  * @param rh Replay session to end.
763  */
764 void
765 GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
766 {
767 }
768
769
770 /**
771  * Replay a message for the multicast group.
772  *
773  * @param rh Replay handle identifying which replay operation was requested.
774  * @param notify Function to call to get the message.
775  * @param notify_cls Closure for @a notify.
776  */
777 void
778 GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
779                                    GNUNET_MULTICAST_ReplayTransmitNotify notify,
780                                    void *notify_cls)
781 {
782 }
783
784
785 /**
786  * Start a multicast group.
787  *
788  * Will advertise the origin in the P2P overlay network under the respective
789  * public key so that other peer can find this peer to join it.  Peers that
790  * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
791  * either an existing group member or to the origin.  If the joining is
792  * approved, the member is cleared for @e replay and will begin to receive
793  * messages transmitted to the group.  If joining is disapproved, the failed
794  * candidate will be given a response.  Members in the group can send messages
795  * to the origin (one at a time).
796  *
797  * @param cfg  Configuration to use.
798  * @param priv_key  ECC key that will be used to sign messages for this
799  *        multicast session; public key is used to identify the multicast group;
800  * @param max_fragment_id  Maximum fragment ID already sent to the group.
801  *        0 for a new group.
802  * @param join_request_cb Function called to approve / disapprove joining of a peer.
803  * @param member_test_cb  Function multicast can use to test group membership.
804  * @param replay_frag_cb  Function that can be called to replay a message fragment.
805  * @param replay_msg_cb  Function that can be called to replay a message.
806  * @param request_cb  Function called with message fragments from group members.
807  * @param message_cb  Function called with the message fragments sent to the
808  *        network by GNUNET_MULTICAST_origin_to_all().  These message fragments
809  *        should be stored for answering replay requests later.
810  * @param cls  Closure for the various callbacks that follow.
811  *
812  * @return Handle for the origin, NULL on error.
813  */
814 struct GNUNET_MULTICAST_Origin *
815 GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
816                                const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
817                                uint64_t max_fragment_id,
818                                GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
819                                GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
820                                GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
821                                GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
822                                GNUNET_MULTICAST_RequestCallback request_cb,
823                                GNUNET_MULTICAST_MessageCallback message_cb,
824                                void *cls)
825 {
826   struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
827   struct GNUNET_MULTICAST_Group *grp = &orig->grp;
828   struct MulticastOriginStartMessage *start = GNUNET_malloc (sizeof (*start));
829
830   start->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
831   start->header.size = htons (sizeof (*start));
832   start->max_fragment_id = max_fragment_id;
833   memcpy (&start->group_key, priv_key, sizeof (*priv_key));
834
835   grp->reconnect_msg = (struct GNUNET_MessageHeader *) start;
836   grp->is_origin = GNUNET_YES;
837   grp->cfg = cfg;
838
839   grp->cb_cls = cls;
840   grp->join_req_cb = join_request_cb;
841   grp->member_test_cb = member_test_cb;
842   grp->replay_frag_cb = replay_frag_cb;
843   grp->replay_msg_cb = replay_msg_cb;
844   grp->message_cb = message_cb;
845
846   orig->request_cb = request_cb;
847   orig->priv_key = *priv_key;
848
849   GNUNET_CRYPTO_eddsa_key_get_public (&orig->priv_key, &grp->pub_key);
850   GNUNET_CRYPTO_hash (&grp->pub_key, sizeof (grp->pub_key),
851                       &grp->pub_key_hash);
852
853   if (NULL == origins)
854     origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
855
856   GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig,
857                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
858
859   grp->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
860   grp->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, grp);
861
862   return orig;
863 }
864
865
866 /**
867  * Stop a multicast group.
868  *
869  * @param origin Multicast group to stop.
870  */
871 void
872 GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig)
873 {
874   disconnect (&orig->grp);
875   GNUNET_CONTAINER_multihashmap_remove (origins, &orig->grp.pub_key_hash, orig);
876   GNUNET_free (orig);
877 }
878
879
880 static void
881 origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
882 {
883   LOG (GNUNET_ERROR_TYPE_DEBUG, "origin_to_all()\n");
884   struct GNUNET_MULTICAST_Group *grp = &orig->grp;
885   struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
886
887   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
888   struct MessageQueue *mq = GNUNET_malloc (sizeof (*mq) + buf_size);
889   GNUNET_CONTAINER_DLL_insert_tail (grp->tmit_head, grp->tmit_tail, mq);
890
891   struct GNUNET_MULTICAST_MessageHeader *
892     msg = (struct GNUNET_MULTICAST_MessageHeader *) &mq[1];
893   int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
894
895   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
896       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < buf_size)
897   {
898     LOG (GNUNET_ERROR_TYPE_ERROR,
899          "OriginTransmitNotify() returned error or invalid message size.\n");
900     /* FIXME: handle error */
901     GNUNET_free (mq);
902     return;
903   }
904
905   if (GNUNET_NO == ret && 0 == buf_size)
906   {
907     GNUNET_free (mq);
908     return; /* Transmission paused. */
909   }
910
911   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
912   msg->header.size = htons (sizeof (*msg) + buf_size);
913   msg->message_id = GNUNET_htonll (tmit->message_id);
914   msg->group_generation = tmit->group_generation;
915   msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
916   tmit->fragment_offset += sizeof (*msg) + buf_size;
917
918   transmit_next (grp);
919 }
920
921
922 /**
923  * Send a message to the multicast group.
924  *
925  * @param orig  Handle to the multicast group.
926  * @param message_id  Application layer ID for the message.  Opaque to multicast.
927  * @param group_generation  Group generation of the message.
928  *                          Documented in struct GNUNET_MULTICAST_MessageHeader.
929  * @param notify  Function to call to get the message.
930  * @param notify_cls  Closure for @a notify.
931  *
932  * @return Message handle on success,
933  *         NULL on error (i.e. another request is already pending).
934  */
935 struct GNUNET_MULTICAST_OriginTransmitHandle *
936 GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
937                                 uint64_t message_id,
938                                 uint64_t group_generation,
939                                 GNUNET_MULTICAST_OriginTransmitNotify notify,
940                                 void *notify_cls)
941 {
942   struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
943   tmit->origin = orig;
944   tmit->message_id = message_id;
945   tmit->group_generation = group_generation;
946   tmit->notify = notify;
947   tmit->notify_cls = notify_cls;
948
949   origin_to_all (orig);
950   return tmit;
951 }
952
953
954 /**
955  * Resume message transmission to multicast group.
956  *
957  * @param th  Transmission to cancel.
958  */
959 void
960 GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
961 {
962   origin_to_all (th->origin);
963 }
964
965
966 /**
967  * Cancel request for message transmission to multicast group.
968  *
969  * @param th  Transmission to cancel.
970  */
971 void
972 GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
973 {
974 }
975
976
977 /**
978  * Join a multicast group.
979  *
980  * The entity joining is always the local peer.  Further information about the
981  * candidate can be provided in the @a join_request message.  If the join fails, the
982  * @a message_cb is invoked with a (failure) response and then with NULL.  If
983  * the join succeeds, outstanding (state) messages and ongoing multicast
984  * messages will be given to the @a message_cb until the member decides to part
985  * the group.  The @a test_cb and @a replay_cb functions may be called at
986  * anytime by the multicast service to support relaying messages to other
987  * members of the group.
988  *
989  * @param cfg Configuration to use.
990  * @param group_key ECC public key that identifies the group to join.
991  * @param member_key ECC key that identifies the member and used to sign
992  *        requests sent to the origin.
993  * @param origin Peer ID of the origin to send unicast requsets to.  If NULL,
994  *        unicast requests are sent back via multiple hops on the reverse path
995  *        of multicast messages.
996  * @param relay_count Number of peers in the @a relays array.
997  * @param relays Peer identities of members of the group, which serve as relays
998  *        and can be used to join the group at. and send the @a join_request to.
999  *        If empty, the @a join_request is sent directly to the @a origin.
1000  * @param join_msg  Application-dependent join message to be passed to the peer
1001  *        @a origin.
1002  * @param join_request_cb Function called to approve / disapprove joining of a peer.
1003  * @param join_decision_cb Function called to inform about the join decision.
1004  * @param member_test_cb Function multicast can use to test group membership.
1005  * @param replay_frag_cb Function that can be called to replay message fragments
1006  *        this peer already knows from this group. NULL if this
1007  *        client is unable to support replay.
1008  * @param replay_msg_cb Function that can be called to replay message fragments
1009  *        this peer already knows from this group. NULL if this
1010  *        client is unable to support replay.
1011  * @param message_cb Function to be called for all message fragments we
1012  *        receive from the group, excluding those our @a replay_cb
1013  *        already has.
1014  * @param cls Closure for callbacks.
1015  * @return Handle for the member, NULL on error.
1016  */
1017 struct GNUNET_MULTICAST_Member *
1018 GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
1019                               const struct GNUNET_CRYPTO_EddsaPublicKey *group_key,
1020                               const struct GNUNET_CRYPTO_EddsaPrivateKey *member_key,
1021                               const struct GNUNET_PeerIdentity *origin,
1022                               uint16_t relay_count,
1023                               const struct GNUNET_PeerIdentity *relays,
1024                               const struct GNUNET_MessageHeader *join_msg,
1025                               GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
1026                               GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
1027                               GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
1028                               GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
1029                               GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
1030                               GNUNET_MULTICAST_MessageCallback message_cb,
1031                               void *cls)
1032 {
1033   struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
1034   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1035
1036   uint16_t relay_size = relay_count * sizeof (*relays);
1037   uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
1038   struct MulticastMemberJoinMessage *
1039     join = GNUNET_malloc (sizeof (*join) + relay_size + join_msg_size);
1040   join->header.size = htons (sizeof (*join) + relay_size + join_msg_size);
1041   join->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
1042   join->group_key = *group_key;
1043   join->member_key = *member_key;
1044   join->origin = *origin;
1045   if (0 < relay_size)
1046     memcpy (&join[1], relays, relay_size);
1047   if (0 < join_msg_size)
1048     memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
1049
1050   grp->reconnect_msg = (struct GNUNET_MessageHeader *) join;
1051   grp->is_origin = GNUNET_NO;
1052   grp->cfg = cfg;
1053   grp->pub_key = *group_key;
1054
1055   mem->join_dcsn_cb = join_decision_cb;
1056   grp->join_req_cb = join_request_cb;
1057   grp->member_test_cb = member_test_cb;
1058   grp->replay_frag_cb = replay_frag_cb;
1059   grp->message_cb = message_cb;
1060   grp->cb_cls = cls;
1061
1062   GNUNET_CRYPTO_eddsa_key_get_public (member_key, &grp->pub_key);
1063   GNUNET_CRYPTO_hash (&grp->pub_key, sizeof (grp->pub_key), &grp->pub_key_hash);
1064
1065   if (NULL == members)
1066     members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
1067
1068   GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem,
1069                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1070
1071   grp->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
1072   grp->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, grp);
1073
1074   return mem;
1075 }
1076
1077
1078 /**
1079  * Part a multicast group.
1080  *
1081  * Disconnects from all group members and invalidates the @a member handle.
1082  *
1083  * An application-dependent part message can be transmitted beforehand using
1084  * #GNUNET_MULTICAST_member_to_origin())
1085  *
1086  * @param member Membership handle.
1087  */
1088 void
1089 GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem)
1090 {
1091   disconnect (&mem->grp);
1092   GNUNET_CONTAINER_multihashmap_remove (members, &mem->grp.pub_key_hash, mem);
1093   GNUNET_free (mem);
1094 }
1095
1096
1097 /**
1098  * Request a fragment to be replayed by fragment ID.
1099  *
1100  * Useful if messages below the @e max_known_fragment_id given when joining are
1101  * needed and not known to the client.
1102  *
1103  * @param member Membership handle.
1104  * @param fragment_id ID of a message fragment that this client would like to
1105           see replayed.
1106  * @param flags Additional flags for the replay request.  It is used and defined
1107  *        by the replay callback.  FIXME: which replay callback? FIXME: use enum?
1108  *        FIXME: why not pass reply cb here?
1109  * @return Replay request handle, NULL on error.
1110  */
1111 struct GNUNET_MULTICAST_MemberReplayHandle *
1112 GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member,
1113                                          uint64_t fragment_id,
1114                                          uint64_t flags)
1115 {
1116   return NULL;
1117 }
1118
1119
1120 /**
1121  * Request a message fragment to be replayed.
1122  *
1123  * Useful if messages below the @e max_known_fragment_id given when joining are
1124  * needed and not known to the client.
1125  *
1126  * @param member Membership handle.
1127  * @param message_id ID of the message this client would like to see replayed.
1128  * @param fragment_offset Offset of the fragment within the message to replay.
1129  * @param flags Additional flags for the replay request.  It is used & defined
1130  *        by the replay callback.
1131  * @param result_cb Function to be called for the replayed message.
1132  * @param result_cb_cls Closure for @a result_cb.
1133  * @return Replay request handle, NULL on error.
1134  */
1135 struct GNUNET_MULTICAST_MemberReplayHandle *
1136 GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member,
1137                                         uint64_t message_id,
1138                                         uint64_t fragment_offset,
1139                                         uint64_t flags,
1140                                         GNUNET_MULTICAST_ResultCallback result_cb,
1141                                         void *result_cb_cls)
1142 {
1143   return NULL;
1144 }
1145
1146
1147 /**
1148  * Cancel a replay request.
1149  *
1150  * @param rh Request to cancel.
1151  */
1152 void
1153 GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh)
1154 {
1155 }
1156
1157
1158 static void
1159 member_to_origin (struct GNUNET_MULTICAST_Member *mem)
1160 {
1161   LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
1162   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
1163   struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1164
1165   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD;
1166   struct MessageQueue *mq = GNUNET_malloc (sizeof (*mq) + buf_size);
1167   GNUNET_CONTAINER_DLL_insert_tail (grp->tmit_head, grp->tmit_tail, mq);
1168
1169   struct GNUNET_MULTICAST_RequestHeader *
1170     req = (struct GNUNET_MULTICAST_RequestHeader *) &mq[1];
1171   int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
1172
1173   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
1174       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < buf_size)
1175   {
1176     LOG (GNUNET_ERROR_TYPE_ERROR,
1177          "MemberTransmitNotify() returned error or invalid message size.\n");
1178     /* FIXME: handle error */
1179     return;
1180   }
1181
1182   if (GNUNET_NO == ret && 0 == buf_size)
1183     return; /* Transmission paused. */
1184
1185   req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
1186   req->header.size = htons (sizeof (*req) + buf_size);
1187   req->request_id = GNUNET_htonll (tmit->request_id);
1188   req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
1189   tmit->fragment_offset += sizeof (*req) + buf_size;
1190
1191   transmit_next (grp);
1192 }
1193
1194
1195 /**
1196  * Send a message to the origin of the multicast group.
1197  *
1198  * @param mem Membership handle.
1199  * @param request_id Application layer ID for the request.  Opaque to multicast.
1200  * @param notify Callback to call to get the message.
1201  * @param notify_cls Closure for @a notify.
1202  * @return Handle to cancel request, NULL on error (i.e. request already pending).
1203  */
1204 struct GNUNET_MULTICAST_MemberTransmitHandle *
1205 GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
1206                                    uint64_t request_id,
1207                                    GNUNET_MULTICAST_MemberTransmitNotify notify,
1208                                    void *notify_cls)
1209 {
1210   struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
1211   tmit->member = mem;
1212   tmit->request_id = request_id;
1213   tmit->notify = notify;
1214   tmit->notify_cls = notify_cls;
1215
1216   member_to_origin (mem);
1217   return tmit;
1218 }
1219
1220
1221 /**
1222  * Resume message transmission to origin.
1223  *
1224  * @param th  Transmission to cancel.
1225  */
1226 void
1227 GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1228 {
1229
1230 }
1231
1232
1233 /**
1234  * Cancel request for message transmission to origin.
1235  *
1236  * @param th  Transmission to cancel.
1237  */
1238 void
1239 GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
1240 {
1241 }
1242
1243
1244 /* end of multicast_api.c */