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