-disable NSE POW during cadet tests
[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; 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   uint64_t next_fragment_id;
141 };
142
143
144 /**
145  * Handle that identifies a join request.
146  *
147  * Used to match calls to #GNUNET_MULTICAST_JoinCallback to the
148  * corresponding calls to #GNUNET_MULTICAST_join_decision().
149  */
150 struct GNUNET_MULTICAST_JoinHandle
151 {
152   struct GNUNET_MULTICAST_Group *group;
153
154   /**
155    * Public key of the member requesting join.
156    */
157   struct GNUNET_CRYPTO_EcdsaPublicKey member_key;
158
159   /**
160    * Peer identity of the member requesting join.
161    */
162   struct GNUNET_PeerIdentity peer;
163 };
164
165
166 /**
167  * Handle to pass back for the answer of a membership test.
168  */
169 struct GNUNET_MULTICAST_MembershipTestHandle
170 {
171 };
172
173
174 /**
175  * Opaque handle to a replay request from the multicast service.
176  */
177 struct GNUNET_MULTICAST_ReplayHandle
178 {
179 };
180
181
182 /**
183  * Handle for a replay request.
184  */
185 struct GNUNET_MULTICAST_MemberReplayHandle
186 {
187 };
188
189
190 /**
191  * Send first message to the service after connecting.
192  */
193 static void
194 group_send_connect_msg (struct GNUNET_MULTICAST_Group *grp)
195 {
196   uint16_t cmsg_size = ntohs (grp->connect_msg->size);
197   struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size);
198   memcpy (cmsg, grp->connect_msg, cmsg_size);
199   GNUNET_CLIENT_MANAGER_transmit_now (grp->client, cmsg);
200 }
201
202
203 /**
204  * Got disconnected from service.  Reconnect.
205  */
206 static void
207 group_recv_disconnect (void *cls,
208                         struct GNUNET_CLIENT_MANAGER_Connection *client,
209                         const struct GNUNET_MessageHeader *msg)
210 {
211   struct GNUNET_MULTICAST_Group *
212     grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
213   GNUNET_CLIENT_MANAGER_reconnect (client);
214   group_send_connect_msg (grp);
215 }
216
217
218 /**
219  * Receive join request from service.
220  */
221 static void
222 group_recv_join_request (void *cls,
223                           struct GNUNET_CLIENT_MANAGER_Connection *client,
224                           const struct GNUNET_MessageHeader *msg)
225 {
226   struct GNUNET_MULTICAST_Group *
227     grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
228
229   const struct MulticastJoinRequestMessage *
230     jreq = (const struct MulticastJoinRequestMessage *) msg;
231
232   struct GNUNET_MULTICAST_JoinHandle *jh = GNUNET_malloc (sizeof (*jh));
233   jh->group = grp;
234   jh->member_key = jreq->member_key;
235   jh->peer = jreq->peer;
236
237   const struct GNUNET_MessageHeader *jmsg = NULL;
238   if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size))
239     jmsg = (const struct GNUNET_MessageHeader *) &jreq[1];
240
241   if (NULL != grp->join_req_cb)
242     grp->join_req_cb (grp->cb_cls, &jreq->member_key, jmsg, jh);
243 }
244
245
246 /**
247  * Receive multicast message from service.
248  */
249 static void
250 group_recv_message (void *cls,
251                     struct GNUNET_CLIENT_MANAGER_Connection *client,
252                     const struct GNUNET_MessageHeader *msg)
253 {
254   struct GNUNET_MULTICAST_Group *
255     grp = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
256   struct GNUNET_MULTICAST_MessageHeader *
257     mmsg = (struct GNUNET_MULTICAST_MessageHeader *) msg;
258
259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
260               "Calling message callback with a message of size %u.\n",
261               ntohs (mmsg->header.size));
262
263   if (NULL != grp->message_cb)
264     grp->message_cb (grp->cb_cls, mmsg);
265 }
266
267
268 /**
269  * Origin receives uniquest request from a member.
270  */
271 static void
272 origin_recv_request (void *cls,
273                      struct GNUNET_CLIENT_MANAGER_Connection *client,
274                      const struct GNUNET_MessageHeader *msg)
275 {
276   struct GNUNET_MULTICAST_Group *grp;
277   struct GNUNET_MULTICAST_Origin *
278     orig = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
279   grp = &orig->grp;
280   struct GNUNET_MULTICAST_RequestHeader *
281     req = (struct GNUNET_MULTICAST_RequestHeader *) msg;
282
283   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284               "Calling request callback with a request of size %u.\n",
285               ntohs (req->header.size));
286
287   if (NULL != orig->request_cb)
288     orig->request_cb (grp->cb_cls, req);
289 }
290
291
292 /**
293  * Member receives join decision.
294  */
295 static void
296 member_recv_join_decision (void *cls,
297                            struct GNUNET_CLIENT_MANAGER_Connection *client,
298                            const struct GNUNET_MessageHeader *msg)
299 {
300   struct GNUNET_MULTICAST_Group *grp;
301   struct GNUNET_MULTICAST_Member *
302     mem = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*grp));
303   grp = &mem->grp;
304
305   const struct MulticastJoinDecisionMessageHeader *
306     hdcsn = (const struct MulticastJoinDecisionMessageHeader *) msg;
307   const struct MulticastJoinDecisionMessage *
308     dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1];
309
310   uint16_t dcsn_size = ntohs (dcsn->header.size);
311   int is_admitted = ntohl (dcsn->is_admitted);
312
313   LOG (GNUNET_ERROR_TYPE_DEBUG,
314        "%p Member got join decision from multicast: %d\n",
315        mem, is_admitted);
316
317   const struct GNUNET_MessageHeader *join_resp = NULL;
318   uint16_t join_resp_size = 0;
319
320   uint16_t relay_count = ntohl (dcsn->relay_count);
321   const struct GNUNET_PeerIdentity *relays = NULL;
322   uint16_t relay_size = relay_count * sizeof (*relays);
323   if (0 < relay_count && dcsn_size < sizeof (*dcsn) + relay_size)
324     relays = (struct GNUNET_PeerIdentity *) &dcsn[1];
325
326   if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size)
327   {
328     join_resp = (const struct GNUNET_MessageHeader *) &dcsn[1];
329     join_resp_size = ntohs (join_resp->size);
330   }
331   if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size)
332   {
333     LOG (GNUNET_ERROR_TYPE_DEBUG,
334          "Received invalid join decision message from multicast.\n");
335     GNUNET_break_op (0);
336     is_admitted = GNUNET_SYSERR;
337   }
338
339   if (NULL != mem->join_dcsn_cb)
340     mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer,
341                        relay_count, relays, join_resp);
342
343   // FIXME:
344   //if (GNUNET_YES != is_admitted)
345   //  GNUNET_MULTICAST_member_part (mem);
346 }
347
348
349 /**
350  * Message handlers for an origin.
351  */
352 static struct GNUNET_CLIENT_MANAGER_MessageHandler origin_handlers[] =
353 {
354   { &group_recv_disconnect, NULL, 0, 0, GNUNET_NO },
355
356   { &group_recv_message, NULL,
357     GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
358     sizeof (struct GNUNET_MULTICAST_MessageHeader), GNUNET_YES },
359
360   { &origin_recv_request, NULL,
361     GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST,
362     sizeof (struct GNUNET_MULTICAST_RequestHeader), GNUNET_YES },
363
364   { &group_recv_join_request, NULL,
365     GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
366     sizeof (struct MulticastJoinRequestMessage), GNUNET_YES },
367
368   { NULL, NULL, 0, 0, GNUNET_NO }
369 };
370
371
372 /**
373  * Message handlers for a member.
374  */
375 static struct GNUNET_CLIENT_MANAGER_MessageHandler member_handlers[] =
376 {
377   { &group_recv_disconnect, NULL, 0, 0, GNUNET_NO },
378
379   { &group_recv_message, NULL,
380     GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE,
381     sizeof (struct GNUNET_MULTICAST_MessageHeader), GNUNET_YES },
382
383   { &group_recv_join_request, NULL,
384     GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST,
385     sizeof (struct MulticastJoinRequestMessage), GNUNET_YES },
386
387   { &member_recv_join_decision, NULL,
388     GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION,
389     sizeof (struct MulticastJoinDecisionMessage), GNUNET_YES },
390
391   { NULL, NULL, 0, 0, GNUNET_NO }
392 };
393
394
395 static void
396 group_cleanup (struct GNUNET_MULTICAST_Group *grp)
397 {
398   GNUNET_free (grp->connect_msg);
399   if (NULL != grp->disconnect_cb)
400     grp->disconnect_cb (grp->disconnect_cls);
401 }
402
403
404 static void
405 origin_cleanup (void *cls)
406 {
407   struct GNUNET_MULTICAST_Origin *orig = cls;
408   group_cleanup (&orig->grp);
409   GNUNET_free (orig);
410 }
411
412
413 static void
414 member_cleanup (void *cls)
415 {
416   struct GNUNET_MULTICAST_Member *mem = cls;
417   group_cleanup (&mem->grp);
418   GNUNET_free (mem);
419 }
420
421
422 /**
423  * Function to call with the decision made for a join request.
424  *
425  * Must be called once and only once in response to an invocation of the
426  * #GNUNET_MULTICAST_JoinRequestCallback.
427  *
428  * @param join  Join request handle.
429  * @param is_admitted  #GNUNET_YES    if the join is approved,
430  *                     #GNUNET_NO     if it is disapproved,
431  *                     #GNUNET_SYSERR if we cannot answer the request.
432  * @param relay_count Number of relays given.
433  * @param relays Array of suggested peers that might be useful relays to use
434  *        when joining the multicast group (essentially a list of peers that
435  *        are already part of the multicast group and might thus be willing
436  *        to help with routing).  If empty, only this local peer (which must
437  *        be the multicast origin) is a good candidate for building the
438  *        multicast tree.  Note that it is unnecessary to specify our own
439  *        peer identity in this array.
440  * @param join_resp  Message to send in response to the joining peer;
441  *        can also be used to redirect the peer to a different group at the
442  *        application layer; this response is to be transmitted to the
443  *        peer that issued the request even if admission is denied.
444  */
445 struct GNUNET_MULTICAST_ReplayHandle *
446 GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join,
447                                 int is_admitted,
448                                 uint16_t relay_count,
449                                 const struct GNUNET_PeerIdentity *relays,
450                                 const struct GNUNET_MessageHeader *join_resp)
451 {
452   struct GNUNET_MULTICAST_Group *grp = join->group;
453   uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0;
454   uint16_t relay_size = relay_count * sizeof (*relays);
455
456   struct MulticastJoinDecisionMessageHeader * hdcsn;
457   struct MulticastJoinDecisionMessage *dcsn;
458   hdcsn = GNUNET_malloc (sizeof (*hdcsn) + sizeof (*dcsn)
459                          + relay_size + join_resp_size);
460   hdcsn->header.size = htons (sizeof (*hdcsn) + sizeof (*dcsn)
461                               + relay_size + join_resp_size);
462   hdcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
463   hdcsn->member_key = join->member_key;
464   hdcsn->peer = join->peer;
465
466   dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1];
467   dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION);
468   dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size);
469   dcsn->is_admitted = htonl (is_admitted);
470   dcsn->relay_count = htonl (relay_count);
471   if (0 < relay_size)
472     memcpy (&dcsn[1], relays, relay_size);
473   if (0 < join_resp_size)
474     memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size);
475
476   GNUNET_CLIENT_MANAGER_transmit (grp->client, &hdcsn->header);
477   GNUNET_free (join);
478   return NULL;
479 }
480
481
482 /**
483  * Call informing multicast about the decision taken for a membership test.
484  *
485  * @param mth Handle that was given for the query.
486  * @param result #GNUNET_YES if peer was a member, #GNUNET_NO if peer was not a member,
487  *        #GNUNET_SYSERR if we cannot answer the membership test.
488  */
489 void
490 GNUNET_MULTICAST_membership_test_result (struct GNUNET_MULTICAST_MembershipTestHandle *mth,
491                                          int result)
492 {
493 }
494
495
496 /**
497  * Replay a message fragment for the multicast group.
498  *
499  * @param rh Replay handle identifying which replay operation was requested.
500  * @param msg Replayed message fragment, NULL if unknown/error.
501  * @param ec Error code.
502  */
503 void
504 GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
505                                   const struct GNUNET_MessageHeader *msg,
506                                   enum GNUNET_MULTICAST_ReplayErrorCode ec)
507 {
508 }
509
510
511 /**
512  * Indicate the end of the replay session.
513  *
514  * Invalidates the replay handle.
515  *
516  * @param rh Replay session to end.
517  */
518 void
519 GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
520 {
521 }
522
523
524 /**
525  * Replay a message for the multicast group.
526  *
527  * @param rh Replay handle identifying which replay operation was requested.
528  * @param notify Function to call to get the message.
529  * @param notify_cls Closure for @a notify.
530  */
531 void
532 GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
533                                    GNUNET_MULTICAST_ReplayTransmitNotify notify,
534                                    void *notify_cls)
535 {
536 }
537
538
539 /**
540  * Start a multicast group.
541  *
542  * Will advertise the origin in the P2P overlay network under the respective
543  * public key so that other peer can find this peer to join it.  Peers that
544  * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
545  * either an existing group member or to the origin.  If the joining is
546  * approved, the member is cleared for @e replay and will begin to receive
547  * messages transmitted to the group.  If joining is disapproved, the failed
548  * candidate will be given a response.  Members in the group can send messages
549  * to the origin (one at a time).
550  *
551  * @param cfg  Configuration to use.
552  * @param priv_key  ECC key that will be used to sign messages for this
553  *        multicast session; public key is used to identify the multicast group;
554  * @param max_fragment_id  Maximum fragment ID already sent to the group.
555  *        0 for a new group.
556  * @param join_request_cb Function called to approve / disapprove joining of a peer.
557  * @param member_test_cb  Function multicast can use to test group membership.
558  * @param replay_frag_cb  Function that can be called to replay a message fragment.
559  * @param replay_msg_cb  Function that can be called to replay a message.
560  * @param request_cb  Function called with message fragments from group members.
561  * @param message_cb  Function called with the message fragments sent to the
562  *        network by GNUNET_MULTICAST_origin_to_all().  These message fragments
563  *        should be stored for answering replay requests later.
564  * @param cls  Closure for the various callbacks that follow.
565  *
566  * @return Handle for the origin, NULL on error.
567  */
568 struct GNUNET_MULTICAST_Origin *
569 GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
570                                const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
571                                uint64_t max_fragment_id,
572                                GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
573                                GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
574                                GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
575                                GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
576                                GNUNET_MULTICAST_RequestCallback request_cb,
577                                GNUNET_MULTICAST_MessageCallback message_cb,
578                                void *cls)
579 {
580   struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
581   struct GNUNET_MULTICAST_Group *grp = &orig->grp;
582   struct MulticastOriginStartMessage *start = GNUNET_malloc (sizeof (*start));
583
584   start->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START);
585   start->header.size = htons (sizeof (*start));
586   start->max_fragment_id = max_fragment_id;
587   memcpy (&start->group_key, priv_key, sizeof (*priv_key));
588
589   grp->connect_msg = (struct GNUNET_MessageHeader *) start;
590   grp->is_origin = GNUNET_YES;
591   grp->cfg = cfg;
592
593   grp->cb_cls = cls;
594   grp->join_req_cb = join_request_cb;
595   grp->member_test_cb = member_test_cb;
596   grp->replay_frag_cb = replay_frag_cb;
597   grp->replay_msg_cb = replay_msg_cb;
598   grp->message_cb = message_cb;
599
600   orig->request_cb = request_cb;
601
602   grp->client = GNUNET_CLIENT_MANAGER_connect (cfg, "multicast", origin_handlers);
603   GNUNET_CLIENT_MANAGER_set_user_context_ (grp->client, orig, sizeof (*grp));
604   group_send_connect_msg (grp);
605
606   return orig;
607 }
608
609
610 /**
611  * Stop a multicast group.
612  *
613  * @param origin Multicast group to stop.
614  */
615 void
616 GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig,
617                               GNUNET_ContinuationCallback stop_cb,
618                               void *stop_cls)
619 {
620   struct GNUNET_MULTICAST_Group *grp = &orig->grp;
621
622   grp->is_disconnecting = GNUNET_YES;
623   grp->disconnect_cb = stop_cb;
624   grp->disconnect_cls = stop_cls;
625
626   GNUNET_CLIENT_MANAGER_disconnect (orig->grp.client, GNUNET_YES,
627                                     &origin_cleanup, orig);
628 }
629
630
631 static void
632 origin_to_all (struct GNUNET_MULTICAST_Origin *orig)
633 {
634   LOG (GNUNET_ERROR_TYPE_DEBUG, "origin_to_all()\n");
635   struct GNUNET_MULTICAST_Group *grp = &orig->grp;
636   struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
637
638   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
639   struct GNUNET_MULTICAST_MessageHeader *msg = GNUNET_malloc (buf_size);
640   int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]);
641
642   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
643       || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
644   {
645     LOG (GNUNET_ERROR_TYPE_ERROR,
646          "OriginTransmitNotify() returned error or invalid message size.\n");
647     /* FIXME: handle error */
648     GNUNET_free (msg);
649     return;
650   }
651
652   if (GNUNET_NO == ret && 0 == buf_size)
653   {
654     GNUNET_free (msg);
655     return; /* Transmission paused. */
656   }
657
658   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
659   msg->header.size = htons (sizeof (*msg) + buf_size);
660   msg->message_id = GNUNET_htonll (tmit->message_id);
661   msg->group_generation = tmit->group_generation;
662   msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset);
663   tmit->fragment_offset += sizeof (*msg) + buf_size;
664
665   GNUNET_CLIENT_MANAGER_transmit (grp->client, &msg->header);
666 }
667
668
669 /**
670  * Send a message to the multicast group.
671  *
672  * @param orig  Handle to the multicast group.
673  * @param message_id  Application layer ID for the message.  Opaque to multicast.
674  * @param group_generation  Group generation of the message.
675  *                          Documented in struct GNUNET_MULTICAST_MessageHeader.
676  * @param notify  Function to call to get the message.
677  * @param notify_cls  Closure for @a notify.
678  *
679  * @return Message handle on success,
680  *         NULL on error (i.e. another request is already pending).
681  */
682 struct GNUNET_MULTICAST_OriginTransmitHandle *
683 GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig,
684                                 uint64_t message_id,
685                                 uint64_t group_generation,
686                                 GNUNET_MULTICAST_OriginTransmitNotify notify,
687                                 void *notify_cls)
688 {
689 /* FIXME
690   if (GNUNET_YES == orig->grp.in_transmit)
691     return NULL;
692   orig->grp.in_transmit = GNUNET_YES;
693 */
694
695   struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit;
696   tmit->origin = orig;
697   tmit->message_id = message_id;
698   tmit->group_generation = group_generation;
699   tmit->notify = notify;
700   tmit->notify_cls = notify_cls;
701
702   origin_to_all (orig);
703   return tmit;
704 }
705
706
707 /**
708  * Resume message transmission to multicast group.
709  *
710  * @param th  Transmission to cancel.
711  */
712 void
713 GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
714 {
715   origin_to_all (th->origin);
716 }
717
718
719 /**
720  * Cancel request for message transmission to multicast group.
721  *
722  * @param th  Transmission to cancel.
723  */
724 void
725 GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th)
726 {
727 }
728
729
730 /**
731  * Join a multicast group.
732  *
733  * The entity joining is always the local peer.  Further information about the
734  * candidate can be provided in the @a join_request message.  If the join fails, the
735  * @a message_cb is invoked with a (failure) response and then with NULL.  If
736  * the join succeeds, outstanding (state) messages and ongoing multicast
737  * messages will be given to the @a message_cb until the member decides to part
738  * the group.  The @a test_cb and @a replay_cb functions may be called at
739  * anytime by the multicast service to support relaying messages to other
740  * members of the group.
741  *
742  * @param cfg Configuration to use.
743  * @param group_key ECC public key that identifies the group to join.
744  * @param member_key ECC key that identifies the member and used to sign
745  *        requests sent to the origin.
746  * @param origin Peer ID of the origin to send unicast requsets to.  If NULL,
747  *        unicast requests are sent back via multiple hops on the reverse path
748  *        of multicast messages.
749  * @param relay_count Number of peers in the @a relays array.
750  * @param relays Peer identities of members of the group, which serve as relays
751  *        and can be used to join the group at. and send the @a join_request to.
752  *        If empty, the @a join_request is sent directly to the @a origin.
753  * @param join_msg  Application-dependent join message to be passed to the peer
754  *        @a origin.
755  * @param join_request_cb Function called to approve / disapprove joining of a peer.
756  * @param join_decision_cb Function called to inform about the join decision.
757  * @param member_test_cb Function multicast can use to test group membership.
758  * @param replay_frag_cb Function that can be called to replay message fragments
759  *        this peer already knows from this group. NULL if this
760  *        client is unable to support replay.
761  * @param replay_msg_cb Function that can be called to replay message fragments
762  *        this peer already knows from this group. NULL if this
763  *        client is unable to support replay.
764  * @param message_cb Function to be called for all message fragments we
765  *        receive from the group, excluding those our @a replay_cb
766  *        already has.
767  * @param cls Closure for callbacks.
768  * @return Handle for the member, NULL on error.
769  */
770 struct GNUNET_MULTICAST_Member *
771 GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
772                               const struct GNUNET_CRYPTO_EddsaPublicKey *group_key,
773                               const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key,
774                               const struct GNUNET_PeerIdentity *origin,
775                               uint16_t relay_count,
776                               const struct GNUNET_PeerIdentity *relays,
777                               const struct GNUNET_MessageHeader *join_msg,
778                               GNUNET_MULTICAST_JoinRequestCallback join_request_cb,
779                               GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb,
780                               GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
781                               GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
782                               GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
783                               GNUNET_MULTICAST_MessageCallback message_cb,
784                               void *cls)
785 {
786   struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
787   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
788
789   uint16_t relay_size = relay_count * sizeof (*relays);
790   uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0;
791   struct MulticastMemberJoinMessage *
792     join = GNUNET_malloc (sizeof (*join) + relay_size + join_msg_size);
793   join->header.size = htons (sizeof (*join) + relay_size + join_msg_size);
794   join->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN);
795   join->group_key = *group_key;
796   join->member_key = *member_key;
797   join->origin = *origin;
798   if (0 < relay_size)
799     memcpy (&join[1], relays, relay_size);
800   if (0 < join_msg_size)
801     memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size);
802
803   grp->connect_msg = (struct GNUNET_MessageHeader *) join;
804   grp->is_origin = GNUNET_NO;
805   grp->cfg = cfg;
806
807   mem->join_dcsn_cb = join_decision_cb;
808   grp->join_req_cb = join_request_cb;
809   grp->member_test_cb = member_test_cb;
810   grp->replay_frag_cb = replay_frag_cb;
811   grp->message_cb = message_cb;
812   grp->cb_cls = cls;
813
814   grp->client = GNUNET_CLIENT_MANAGER_connect (cfg, "multicast", member_handlers);
815   GNUNET_CLIENT_MANAGER_set_user_context_ (grp->client, mem, sizeof (*grp));
816   group_send_connect_msg (grp);
817
818   return mem;
819 }
820
821
822 /**
823  * Part a multicast group.
824  *
825  * Disconnects from all group members and invalidates the @a member handle.
826  *
827  * An application-dependent part message can be transmitted beforehand using
828  * #GNUNET_MULTICAST_member_to_origin())
829  *
830  * @param member Membership handle.
831  */
832 void
833 GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem,
834                               GNUNET_ContinuationCallback part_cb,
835                               void *part_cls)
836 {
837   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
838
839   grp->is_disconnecting = GNUNET_YES;
840   grp->disconnect_cb = part_cb;
841   grp->disconnect_cls = part_cls;
842
843   GNUNET_CLIENT_MANAGER_disconnect (mem->grp.client, GNUNET_YES,
844                                     &member_cleanup, mem);
845 }
846
847
848 /**
849  * Request a fragment to be replayed by fragment ID.
850  *
851  * Useful if messages below the @e max_known_fragment_id given when joining are
852  * needed and not known to the client.
853  *
854  * @param member Membership handle.
855  * @param fragment_id ID of a message fragment that this client would like to
856           see replayed.
857  * @param flags Additional flags for the replay request.  It is used and defined
858  *        by the replay callback.  FIXME: which replay callback? FIXME: use enum?
859  *        FIXME: why not pass reply cb here?
860  * @return Replay request handle, NULL on error.
861  */
862 struct GNUNET_MULTICAST_MemberReplayHandle *
863 GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member,
864                                          uint64_t fragment_id,
865                                          uint64_t flags)
866 {
867   return NULL;
868 }
869
870
871 /**
872  * Request a message fragment to be replayed.
873  *
874  * Useful if messages below the @e max_known_fragment_id given when joining are
875  * needed and not known to the client.
876  *
877  * @param member Membership handle.
878  * @param message_id ID of the message this client would like to see replayed.
879  * @param fragment_offset Offset of the fragment within the message to replay.
880  * @param flags Additional flags for the replay request.  It is used & defined
881  *        by the replay callback.
882  * @param result_cb Function to be called for the replayed message.
883  * @param result_cb_cls Closure for @a result_cb.
884  * @return Replay request handle, NULL on error.
885  */
886 struct GNUNET_MULTICAST_MemberReplayHandle *
887 GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member,
888                                         uint64_t message_id,
889                                         uint64_t fragment_offset,
890                                         uint64_t flags,
891                                         GNUNET_MULTICAST_ResultCallback result_cb,
892                                         void *result_cb_cls)
893 {
894   return NULL;
895 }
896
897
898 /**
899  * Cancel a replay request.
900  *
901  * @param rh Request to cancel.
902  */
903 void
904 GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh)
905 {
906 }
907
908
909 static void
910 member_to_origin (struct GNUNET_MULTICAST_Member *mem)
911 {
912   LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n");
913   struct GNUNET_MULTICAST_Group *grp = &mem->grp;
914   struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
915
916   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
917   struct GNUNET_MULTICAST_RequestHeader *req = GNUNET_malloc (buf_size);
918   int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]);
919
920   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
921       || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size)
922   {
923     LOG (GNUNET_ERROR_TYPE_ERROR,
924          "MemberTransmitNotify() returned error or invalid message size.\n");
925     /* FIXME: handle error */
926     GNUNET_free (req);
927     return;
928   }
929
930   if (GNUNET_NO == ret && 0 == buf_size)
931   {
932     /* Transmission paused. */
933     GNUNET_free (req);
934     return;
935   }
936
937   req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
938   req->header.size = htons (sizeof (*req) + buf_size);
939   req->request_id = GNUNET_htonll (tmit->request_id);
940   req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset);
941   tmit->fragment_offset += sizeof (*req) + buf_size;
942
943   GNUNET_CLIENT_MANAGER_transmit (grp->client, &req->header);
944 }
945
946
947 /**
948  * Send a message to the origin of the multicast group.
949  *
950  * @param mem Membership handle.
951  * @param request_id Application layer ID for the request.  Opaque to multicast.
952  * @param notify Callback to call to get the message.
953  * @param notify_cls Closure for @a notify.
954  * @return Handle to cancel request, NULL on error (i.e. request already pending).
955  */
956 struct GNUNET_MULTICAST_MemberTransmitHandle *
957 GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem,
958                                    uint64_t request_id,
959                                    GNUNET_MULTICAST_MemberTransmitNotify notify,
960                                    void *notify_cls)
961 {
962 /* FIXME
963   if (GNUNET_YES == mem->grp.in_transmit)
964     return NULL;
965   mem->grp.in_transmit = GNUNET_YES;
966 */
967
968   struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit;
969   tmit->member = mem;
970   tmit->request_id = request_id;
971   tmit->notify = notify;
972   tmit->notify_cls = notify_cls;
973
974   member_to_origin (mem);
975   return tmit;
976 }
977
978
979 /**
980  * Resume message transmission to origin.
981  *
982  * @param th  Transmission to cancel.
983  */
984 void
985 GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
986 {
987   member_to_origin (th->member);
988 }
989
990
991 /**
992  * Cancel request for message transmission to origin.
993  *
994  * @param th  Transmission to cancel.
995  */
996 void
997 GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th)
998 {
999 }
1000
1001
1002 /* end of multicast_api.c */