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