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