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