- fix doc
[oweals/gnunet.git] / src / multicast / multicast_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file multicast/multicast_api.c
23  * @brief multicast service; establish tunnels to distant peers
24  * @author Christian Grothoff
25  * @author Gabor X Toth
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_signatures.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  * Started origins.
38  * Group's pub_key_hash -> struct GNUNET_MULTICAST_Origin
39  */
40 static struct GNUNET_CONTAINER_MultiHashMap *origins;
41
42 /**
43  * Joined members.
44  * group_key_hash -> struct GNUNET_MULTICAST_Member
45  */
46 static struct GNUNET_CONTAINER_MultiHashMap *members;
47
48
49 /**
50  * Handle for a request to send a message to all multicast group members
51  * (from the origin).
52  */
53 struct GNUNET_MULTICAST_OriginMessageHandle
54 {
55   GNUNET_MULTICAST_OriginTransmitNotify notify;
56   void *notify_cls;
57   struct GNUNET_MULTICAST_Origin *origin;
58
59   uint64_t message_id;
60   uint64_t group_generation;
61   uint64_t fragment_offset;
62 };
63
64
65 struct GNUNET_MULTICAST_Group
66 {
67   uint8_t is_origin;
68 };
69
70 /**
71  * Handle for the origin of a multicast group.
72  */
73 struct GNUNET_MULTICAST_Origin
74 {
75   struct GNUNET_MULTICAST_Group grp;
76
77   struct GNUNET_MULTICAST_OriginMessageHandle msg_handle;
78   struct GNUNET_CRYPTO_EddsaPrivateKey priv_key;
79
80   GNUNET_MULTICAST_JoinCallback join_cb;
81   GNUNET_MULTICAST_MembershipTestCallback mem_test_cb;
82   GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
83   GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
84   GNUNET_MULTICAST_RequestCallback request_cb;
85   GNUNET_MULTICAST_MessageCallback message_cb;
86   void *cls;
87
88   uint64_t next_fragment_id;
89
90   struct GNUNET_CRYPTO_EddsaPublicKey pub_key;
91   struct GNUNET_HashCode pub_key_hash;
92 };
93
94
95 /**
96  * Handle for a message to be delivered from a member to the origin.
97  */
98 struct GNUNET_MULTICAST_MemberRequestHandle
99 {
100   GNUNET_MULTICAST_MemberTransmitNotify notify;
101   void *notify_cls;
102   struct GNUNET_MULTICAST_Member *member;
103
104   uint64_t request_id;
105   uint64_t fragment_offset;
106 };
107
108
109 /**
110  * Handle for a multicast group member.
111  */
112 struct GNUNET_MULTICAST_Member
113 {
114   struct GNUNET_MULTICAST_Group grp;
115
116   struct GNUNET_MULTICAST_MemberRequestHandle req_handle;
117
118   struct GNUNET_CRYPTO_EddsaPublicKey group_key;
119   struct GNUNET_CRYPTO_EddsaPrivateKey member_key;
120   struct GNUNET_PeerIdentity origin;
121   struct GNUNET_PeerIdentity relays;
122   uint32_t relay_count;
123   struct GNUNET_MessageHeader *join_request;
124   GNUNET_MULTICAST_JoinCallback join_cb;
125   GNUNET_MULTICAST_MembershipTestCallback member_test_cb;
126   GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb;
127   GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb;
128   GNUNET_MULTICAST_MessageCallback message_cb;
129   void *cls;
130
131   uint64_t next_fragment_id;
132   struct GNUNET_HashCode group_key_hash;
133 };
134
135
136 /**
137  * Handle that identifies a join request.
138  *
139  * Used to match calls to #GNUNET_MULTICAST_JoinCallback to the
140  * corresponding calls to #GNUNET_MULTICAST_join_decision().
141  */
142 struct GNUNET_MULTICAST_JoinHandle
143 {
144 };
145
146
147 /**
148  * Handle to pass back for the answer of a membership test.
149  */
150 struct GNUNET_MULTICAST_MembershipTestHandle
151 {
152 };
153
154
155 /**
156  * Opaque handle to a replay request from the multicast service.
157  */
158 struct GNUNET_MULTICAST_ReplayHandle
159 {
160 };
161
162
163 /**
164  * Handle for a replay request.
165  */
166 struct GNUNET_MULTICAST_MemberReplayHandle
167 {
168 };
169
170
171 /**
172  * Iterator callback for calling message callbacks for all groups.
173  */
174 static int
175 message_callback (void *cls, const struct GNUNET_HashCode *chan_key_hash,
176                    void *group)
177 {
178   const struct GNUNET_MessageHeader *msg = cls;
179   struct GNUNET_MULTICAST_Group *grp = group;
180
181   if (GNUNET_YES == grp->is_origin)
182   {
183     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184                 "Calling origin's message callback "
185                 "with a message of type %u and size %u.\n",
186               ntohs (msg->type), ntohs (msg->size));
187     struct GNUNET_MULTICAST_Origin *orig = (struct GNUNET_MULTICAST_Origin *) grp;
188     orig->message_cb (orig->cls, msg);
189   }
190   else
191   {
192     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193                 "Calling member's message callback "
194                 "with a message of type %u and size %u.\n",
195                 ntohs (msg->type), ntohs (msg->size));
196     struct GNUNET_MULTICAST_Member *mem = (struct GNUNET_MULTICAST_Member *) grp;
197     mem->message_cb (mem->cls, msg);
198   }
199
200   return GNUNET_YES;
201 }
202
203
204 /**
205  * Handle a multicast message from the service.
206  *
207  * Call message callbacks of all origins and members of the destination group.
208  *
209  * @param grp Destination group of the message.
210  * @param msg The message.
211  */
212 static void
213 handle_multicast_message (struct GNUNET_MULTICAST_Group *grp,
214                           const struct GNUNET_MULTICAST_MessageHeader *msg)
215 {
216   struct GNUNET_HashCode *hash;
217
218   if (GNUNET_YES == grp->is_origin)
219   {
220     struct GNUNET_MULTICAST_Origin *orig = (struct GNUNET_MULTICAST_Origin *) grp;
221     hash = &orig->pub_key_hash;
222   }
223   else
224   {
225     struct GNUNET_MULTICAST_Member *mem = (struct GNUNET_MULTICAST_Member *) grp;
226     hash = &mem->group_key_hash;
227   }
228
229   if (origins != NULL)
230     GNUNET_CONTAINER_multihashmap_get_multiple (origins, hash, message_callback,
231                                                 (void *) msg);
232   if (members != NULL)
233     GNUNET_CONTAINER_multihashmap_get_multiple (members, hash, message_callback,
234                                                 (void *) msg);
235 }
236
237
238 /**
239  * Iterator callback for calling request callbacks of origins.
240  */
241 static int
242 request_callback (void *cls, const struct GNUNET_HashCode *chan_key_hash,
243                   void *origin)
244 {
245   const struct GNUNET_MULTICAST_RequestHeader *req = cls;
246   struct GNUNET_MULTICAST_Origin *orig = origin;
247
248   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
249               "Calling request callback for a request of type %u and size %u.\n",
250               ntohs (req->header.type), ntohs (req->header.size));
251
252   orig->request_cb (orig->cls, &req->member_key,
253                     (const struct GNUNET_MessageHeader *) req, 0);
254   return GNUNET_YES;
255 }
256
257
258 /**
259  * Handle a multicast request from the service.
260  *
261  * Call request callbacks of all origins of the destination group.
262  *
263  * @param grp Destination group of the message.
264  * @param msg The message.
265  */
266 static void
267 handle_multicast_request (const struct GNUNET_HashCode *group_key_hash,
268                           const struct GNUNET_MULTICAST_RequestHeader *req)
269 {
270   if (NULL != origins)
271     GNUNET_CONTAINER_multihashmap_get_multiple (origins, group_key_hash,
272                                                 request_callback, (void *) req);
273 }
274
275
276 /**
277  * Function to call with the decision made for a join request.
278  *
279  * Must be called once and only once in response to an invocation of the
280  * #GNUNET_MULTICAST_JoinCallback.
281  *
282  * @param jh Join request handle.
283  * @param is_admitted #GNUNET_YES if joining is approved,
284  *        #GNUNET_NO if it is disapproved
285  * @param relay_count Number of relays given.
286  * @param relays Array of suggested peers that might be useful relays to use
287  *        when joining the multicast group (essentially a list of peers that
288  *        are already part of the multicast group and might thus be willing
289  *        to help with routing).  If empty, only this local peer (which must
290  *        be the multicast origin) is a good candidate for building the
291  *        multicast tree.  Note that it is unnecessary to specify our own
292  *        peer identity in this array.
293  * @param join_response Message to send in response to the joining peer;
294  *        can also be used to redirect the peer to a different group at the
295  *        application layer; this response is to be transmitted to the
296  *        peer that issued the request even if admission is denied.
297  */
298 struct GNUNET_MULTICAST_ReplayHandle *
299 GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh,
300                                 int is_admitted,
301                                 unsigned int relay_count,
302                                 const struct GNUNET_PeerIdentity *relays,
303                                 const struct GNUNET_MessageHeader *join_response)
304 {
305   return NULL;
306 }
307
308
309 /**
310  * Call informing multicast about the decision taken for a membership test.
311  *
312  * @param mth Handle that was given for the query.
313  * @param result #GNUNET_YES if peer was a member, #GNUNET_NO if peer was not a member,
314  *        #GNUNET_SYSERR if we cannot answer the membership test.
315  */
316 void
317 GNUNET_MULTICAST_membership_test_result (struct GNUNET_MULTICAST_MembershipTestHandle *mth,
318                                          int result)
319 {
320 }
321
322
323 /**
324  * Replay a message fragment for the multicast group.
325  *
326  * @param rh Replay handle identifying which replay operation was requested.
327  * @param msg Replayed message fragment, NULL if unknown/error.
328  * @param ec Error code.
329  */
330 void
331 GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh,
332                                   const struct GNUNET_MessageHeader *msg,
333                                   enum GNUNET_MULTICAST_ReplayErrorCode ec)
334 {
335 }
336
337
338 /**
339  * Indicate the end of the replay session.
340  *
341  * Invalidates the replay handle.
342  *
343  * @param rh Replay session to end.
344  */
345 void
346 GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh)
347 {
348 }
349
350
351 /**
352  * Replay a message for the multicast group.
353  *
354  * @param rh Replay handle identifying which replay operation was requested.
355  * @param notify Function to call to get the message.
356  * @param notify_cls Closure for @a notify.
357  */
358 void
359 GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh,
360                                    GNUNET_MULTICAST_ReplayTransmitNotify notify,
361                                    void *notify_cls)
362 {
363 }
364
365
366 /**
367  * Start a multicast group.
368  *
369  * Will advertise the origin in the P2P overlay network under the respective
370  * public key so that other peer can find this peer to join it.  Peers that
371  * issue GNUNET_MULTICAST_member_join() can then transmit a join request to
372  * either an existing group member or to the origin.  If the joining is
373  * approved, the member is cleared for @e replay and will begin to receive
374  * messages transmitted to the group.  If joining is disapproved, the failed
375  * candidate will be given a response.  Members in the group can send messages
376  * to the origin (one at a time).
377  *
378  * @param cfg Configuration to use.
379  * @param priv_key ECC key that will be used to sign messages for this
380  *        multicast session; public key is used to identify the multicast group;
381  * @param next_fragment_id Next fragment ID to continue counting fragments from
382  *        when restarting the origin.  0 for a new group.
383  * @param join_cb Function called to approve / disapprove joining of a peer.
384  * @param mem_test_cb Function multicast can use to test group membership.
385  * @param replay_frag_cb Function that can be called to replay a message fragment.
386  * @param replay_msg_cb Function that can be called to replay a message.
387  * @param request_cb Function called with message fragments from group members.
388  * @param message_cb Function called with the message fragments sent to the
389  *        network by GNUNET_MULTICAST_origin_to_all().  These message fragments
390  *        should be stored for answering replay requests later.
391  * @param cls Closure for the various callbacks that follow.
392  * @return Handle for the origin, NULL on error.
393  */
394 struct GNUNET_MULTICAST_Origin *
395 GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
396                                const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key,
397                                uint64_t next_fragment_id,
398                                GNUNET_MULTICAST_JoinCallback join_cb,
399                                GNUNET_MULTICAST_MembershipTestCallback mem_test_cb,
400                                GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
401                                GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
402                                GNUNET_MULTICAST_RequestCallback request_cb,
403                                GNUNET_MULTICAST_MessageCallback message_cb,
404                                void *cls)
405 {
406   struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig));
407   orig->grp.is_origin = GNUNET_YES;
408   orig->priv_key = *priv_key;
409   orig->next_fragment_id = next_fragment_id;
410   orig->join_cb = join_cb;
411   orig->mem_test_cb = mem_test_cb;
412   orig->replay_frag_cb = replay_frag_cb;
413   orig->replay_msg_cb = replay_msg_cb;
414   orig->request_cb = request_cb;
415   orig->message_cb = message_cb;
416   orig->cls = cls;
417
418   GNUNET_CRYPTO_eddsa_key_get_public (&orig->priv_key, &orig->pub_key);
419   GNUNET_CRYPTO_hash (&orig->pub_key, sizeof (orig->pub_key),
420                       &orig->pub_key_hash);
421
422   if (NULL == origins)
423     origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
424
425   GNUNET_CONTAINER_multihashmap_put (origins, &orig->pub_key_hash, orig,
426                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
427
428   /* FIXME: send ORIGIN_START to service */
429
430   return orig;
431 }
432
433
434 /**
435  * Stop a multicast group.
436  *
437  * @param origin Multicast group to stop.
438  */
439 void
440 GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig)
441 {
442   GNUNET_CONTAINER_multihashmap_remove (origins, &orig->pub_key_hash, orig);
443   GNUNET_free (orig);
444 }
445
446
447 /* FIXME: for now just call clients' callbacks
448  *        without sending anything to multicast. */
449 static void
450 schedule_origin_to_all (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
451 {
452   LOG (GNUNET_ERROR_TYPE_DEBUG, "schedule_origin_to_all()\n");
453   struct GNUNET_MULTICAST_Origin *orig = cls;
454   struct GNUNET_MULTICAST_OriginMessageHandle *mh = &orig->msg_handle;
455
456   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE;
457   char buf[GNUNET_MULTICAST_FRAGMENT_MAX_SIZE] = "";
458   struct GNUNET_MULTICAST_MessageHeader *msg
459     = (struct GNUNET_MULTICAST_MessageHeader *) buf;
460   int ret = mh->notify (mh->notify_cls, &buf_size, &msg[1]);
461
462   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
463       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < buf_size)
464   {
465     LOG (GNUNET_ERROR_TYPE_ERROR,
466          "OriginTransmitNotify() returned error or invalid message size.\n");
467     /* FIXME: handle error */
468     return;
469   }
470
471   if (GNUNET_NO == ret && 0 == buf_size)
472     return; /* Transmission paused. */
473
474   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
475   msg->header.size = htons (sizeof (*msg) + buf_size);
476   msg->message_id = GNUNET_htonll (mh->message_id);
477   msg->group_generation = mh->group_generation;
478
479   /* FIXME: add fragment ID and signature in the service instead of here */
480   msg->fragment_id = GNUNET_htonll (orig->next_fragment_id++);
481   msg->fragment_offset = GNUNET_htonll (mh->fragment_offset);
482   mh->fragment_offset += sizeof (*msg) + buf_size;
483   msg->purpose.size = htonl (sizeof (*msg) + buf_size
484                              - sizeof (msg->header)
485                              - sizeof (msg->hop_counter)
486                              - sizeof (msg->signature));
487   msg->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
488
489   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &msg->purpose,
490                                            &msg->signature))
491   {
492     /* FIXME: handle error */
493     return;
494   }
495
496   /* FIXME: send msg to the service and only then call handle_multicast_message
497    *        with the returned signed message.
498    */
499   handle_multicast_message (&orig->grp, msg);
500
501   if (GNUNET_NO == ret)
502     GNUNET_SCHEDULER_add_delayed (
503       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
504       schedule_origin_to_all, orig);
505 }
506
507
508 /**
509  * Send a message to the multicast group.
510  *
511  * @param origin Handle to the multicast group.
512  * @param message_id Application layer ID for the message.  Opaque to multicast.
513  * @param group_generation Group generation of the message.  Documented in
514  *             `struct GNUNET_MULTICAST_MessageHeader`.
515  * @param notify Function to call to get the message.
516  * @param notify_cls Closure for @a notify.
517  * @return NULL on error (i.e. request already pending).
518  */
519 struct GNUNET_MULTICAST_OriginMessageHandle *
520 GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin,
521                                 uint64_t message_id,
522                                 uint64_t group_generation,
523                                 GNUNET_MULTICAST_OriginTransmitNotify notify,
524                                 void *notify_cls)
525 {
526   struct GNUNET_MULTICAST_OriginMessageHandle *mh = &origin->msg_handle;
527   mh->origin = origin;
528   mh->message_id = message_id;
529   mh->group_generation = group_generation;
530   mh->notify = notify;
531   mh->notify_cls = notify_cls;
532
533   /* add some delay for testing */
534   GNUNET_SCHEDULER_add_delayed (
535     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1),
536     schedule_origin_to_all, origin);
537   return &origin->msg_handle;
538 }
539
540
541 /**
542  * Resume message transmission to multicast group.
543  *
544  * @param mh Request to cancel.
545  */
546 void
547 GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginMessageHandle *mh)
548 {
549   GNUNET_SCHEDULER_add_now (schedule_origin_to_all, mh->origin);
550 }
551
552
553 /**
554  * Cancel request for message transmission to multicast group.
555  *
556  * @param mh Request to cancel.
557  */
558 void
559 GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginMessageHandle *mh)
560 {
561 }
562
563
564 /**
565  * Join a multicast group.
566  *
567  * The entity joining is always the local peer.  Further information about the
568  * candidate can be provided in the @a join_request message.  If the join fails, the
569  * @a message_cb is invoked with a (failure) response and then with NULL.  If
570  * the join succeeds, outstanding (state) messages and ongoing multicast
571  * messages will be given to the @a message_cb until the member decides to part
572  * the group.  The @a test_cb and @a replay_cb functions may be called at
573  * anytime by the multicast service to support relaying messages to other
574  * members of the group.
575  *
576  * @param cfg Configuration to use.
577  * @param group_key ECC public key that identifies the group to join.
578  * @param member_key ECC key that identifies the member and used to sign
579  *        requests sent to the origin.
580  * @param origin Peer ID of the origin to send unicast requsets to.  If NULL,
581  *        unicast requests are sent back via multiple hops on the reverse path
582  *        of multicast messages.
583  * @param relay_count Number of peers in the @a relays array.
584  * @param relays Peer identities of members of the group, which serve as relays
585  *        and can be used to join the group at. and send the @a join_request to.
586  *        If empty, the @a join_request is sent directly to the @a origin.
587  * @param join_request  Application-dependent join request to be passed to the peer
588  *        @a relay (might, for example, contain a user, bind user
589  *        identity/pseudonym to peer identity, application-level message to
590  *        origin, etc.).
591  * @param join_cb Function called to approve / disapprove joining of a peer.
592  * @param mem_test_cb Function multicast can use to test group membership.
593  * @param replay_frag_cb Function that can be called to replay message fragments
594  *        this peer already knows from this group. NULL if this
595  *        client is unable to support replay.
596  * @param replay_msg_cb Function that can be called to replay message fragments
597  *        this peer already knows from this group. NULL if this
598  *        client is unable to support replay.
599  * @param message_cb Function to be called for all message fragments we
600  *        receive from the group, excluding those our @a replay_cb
601  *        already has.
602  * @param cls Closure for callbacks.
603  * @return Handle for the member, NULL on error.
604  */
605 struct GNUNET_MULTICAST_Member *
606 GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg,
607                               const struct GNUNET_CRYPTO_EddsaPublicKey *group_key,
608                               const struct GNUNET_CRYPTO_EddsaPrivateKey *member_key,
609                               const struct GNUNET_PeerIdentity *origin,
610                               uint32_t relay_count,
611                               const struct GNUNET_PeerIdentity *relays,
612                               const struct GNUNET_MessageHeader *join_request,
613                               GNUNET_MULTICAST_JoinCallback join_cb,
614                               GNUNET_MULTICAST_MembershipTestCallback member_test_cb,
615                               GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb,
616                               GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb,
617                               GNUNET_MULTICAST_MessageCallback message_cb,
618                               void *cls)
619 {
620   struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem));
621   mem->group_key = *group_key;
622   mem->member_key = *member_key;
623   mem->origin = *origin;
624   mem->relay_count = relay_count;
625   mem->relays = *relays;
626   mem->join_cb = join_cb;
627   mem->member_test_cb = member_test_cb;
628   mem->replay_frag_cb = replay_frag_cb;
629   mem->message_cb = message_cb;
630   mem->cls = cls;
631
632   if (NULL != join_request)
633   {
634     uint16_t size = ntohs (join_request->size);
635     mem->join_request = GNUNET_malloc (size);
636     memcpy (mem->join_request, join_request, size);
637   }
638
639   GNUNET_CRYPTO_hash (&mem->group_key, sizeof (mem->group_key), &mem->group_key_hash);
640
641   if (NULL == members)
642     members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
643
644   GNUNET_CONTAINER_multihashmap_put (members, &mem->group_key_hash, mem,
645                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
646
647   /* FIXME: send MEMBER_JOIN to service */
648
649   return mem;
650 }
651
652
653 /**
654  * Part a multicast group.
655  *
656  * Disconnects from all group members and invalidates the @a member handle.
657  *
658  * An application-dependent part message can be transmitted beforehand using
659  * #GNUNET_MULTICAST_member_to_origin())
660  *
661  * @param member Membership handle.
662  */
663 void
664 GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem)
665 {
666   GNUNET_CONTAINER_multihashmap_remove (members, &mem->group_key_hash, mem);
667   GNUNET_free (mem);
668 }
669
670
671 /**
672  * Request a fragment to be replayed by fragment ID.
673  *
674  * Useful if messages below the @e max_known_fragment_id given when joining are
675  * needed and not known to the client.
676  *
677  * @param member Membership handle.
678  * @param fragment_id ID of a message fragment that this client would like to
679           see replayed.
680  * @param flags Additional flags for the replay request.  It is used and defined
681  *        by the replay callback.  FIXME: which replay callback? FIXME: use enum?
682  *        FIXME: why not pass reply cb here?
683  * @return Replay request handle, NULL on error.
684  */
685 struct GNUNET_MULTICAST_MemberReplayHandle *
686 GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member,
687                                          uint64_t fragment_id,
688                                          uint64_t flags)
689 {
690   return NULL;
691 }
692
693
694 /**
695  * Request a message fragment to be replayed.
696  *
697  * Useful if messages below the @e max_known_fragment_id given when joining are
698  * needed and not known to the client.
699  *
700  * @param member Membership handle.
701  * @param message_id ID of the message this client would like to see replayed.
702  * @param fragment_offset Offset of the fragment within the message to replay.
703  * @param flags Additional flags for the replay request.  It is used & defined
704  *        by the replay callback.
705  * @param result_cb Function to be called for the replayed message.
706  * @param result_cb_cls Closure for @a result_cb.
707  * @return Replay request handle, NULL on error.
708  */
709 struct GNUNET_MULTICAST_MemberReplayHandle *
710 GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member,
711                                         uint64_t message_id,
712                                         uint64_t fragment_offset,
713                                         uint64_t flags,
714                                         GNUNET_MULTICAST_ResultCallback result_cb,
715                                         void *result_cb_cls)
716 {
717   return NULL;
718 }
719
720
721 /**
722  * Cancel a replay request.
723  *
724  * @param rh Request to cancel.
725  */
726 void
727 GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh)
728 {
729 }
730
731
732 /* FIXME: for now just send back to the client what it sent. */
733 static void
734 schedule_member_to_origin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
735 {
736   LOG (GNUNET_ERROR_TYPE_DEBUG, "schedule_member_to_origin()\n");
737   struct GNUNET_MULTICAST_Member *mem = cls;
738   struct GNUNET_MULTICAST_MemberRequestHandle *rh = &mem->req_handle;
739
740   size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD;
741   char buf[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = "";
742   struct GNUNET_MULTICAST_RequestHeader *req
743     = (struct GNUNET_MULTICAST_RequestHeader *) buf;
744   int ret = rh->notify (rh->notify_cls, &buf_size, &req[1]);
745
746   if (! (GNUNET_YES == ret || GNUNET_NO == ret)
747       || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < buf_size)
748   {
749     LOG (GNUNET_ERROR_TYPE_ERROR,
750          "MemberTransmitNotify() returned error or invalid message size.\n");
751     /* FIXME: handle error */
752     return;
753   }
754
755   if (GNUNET_NO == ret && 0 == buf_size)
756     return; /* Transmission paused. */
757
758   req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST);
759   req->header.size = htons (sizeof (*req) + buf_size);
760   req->request_id = GNUNET_htonll (rh->request_id);
761
762   /* FIXME: add fragment ID and signature in the service instead of here */
763   req->fragment_id = GNUNET_ntohll (mem->next_fragment_id++);
764   req->fragment_offset = GNUNET_ntohll (rh->fragment_offset);
765   rh->fragment_offset += sizeof (*req) + buf_size;
766   req->purpose.size = htonl (sizeof (*req) + buf_size
767                              - sizeof (req->header)
768                              - sizeof (req->member_key)
769                              - sizeof (req->signature));
770   req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE);
771
772   if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&mem->member_key, &req->purpose,
773                                            &req->signature))
774   {
775     /* FIXME: handle error */
776     return;
777   }
778
779   /* FIXME: send req to the service and only then call handle_multicast_request
780    *        with the returned request.
781    */
782   handle_multicast_request (&mem->group_key_hash, req);
783
784   if (GNUNET_NO == ret)
785     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
786                                   (GNUNET_TIME_UNIT_SECONDS, 1),
787                                   schedule_member_to_origin, mem);
788 }
789
790
791 /**
792  * Send a message to the origin of the multicast group.
793  *
794  * @param member Membership handle.
795  * @param request_id Application layer ID for the request.  Opaque to multicast.
796  * @param notify Callback to call to get the message.
797  * @param notify_cls Closure for @a notify.
798  * @return Handle to cancel request, NULL on error (i.e. request already pending).
799  */
800 struct GNUNET_MULTICAST_MemberRequestHandle *
801 GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member,
802                                    uint64_t request_id,
803                                    GNUNET_MULTICAST_MemberTransmitNotify notify,
804                                    void *notify_cls)
805 {
806   struct GNUNET_MULTICAST_MemberRequestHandle *rh = &member->req_handle;
807   rh->member = member;
808   rh->request_id = request_id;
809   rh->notify = notify;
810   rh->notify_cls = notify_cls;
811
812   /* FIXME: remove delay, it's there only for testing */
813   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
814                                 (GNUNET_TIME_UNIT_SECONDS, 1),
815                                 schedule_member_to_origin, member);
816   return &member->req_handle;
817 }
818
819
820 /**
821  * Resume message transmission to origin.
822  *
823  * @param rh Request to cancel.
824  */
825 void
826 GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberRequestHandle *rh)
827 {
828
829 }
830
831
832 /**
833  * Cancel request for message transmission to origin.
834  *
835  * @param rh Request to cancel.
836  */
837 void
838 GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberRequestHandle *rh)
839 {
840 }
841
842
843 /* end of multicast_api.c */