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