fc22cbeb4642bb28392c4832d76ccbae71d30c40
[oweals/gnunet.git] / src / mesh / mesh_api.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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 mesh/mesh_api.c
23  * @brief mesh service; API for the Mesh. This is used to talk to arbitrary peers
24  *        as of 2011-01Jan-06 this is a mockup.
25  * @author Philipp Tölke
26  */
27 #include <platform.h>
28 #include <gnunet_constants.h>
29 #include <gnunet_mesh_service.h>
30 #include <gnunet_core_service.h>
31 #include <gnunet_container_lib.h>
32 #include <gnunet_applications.h>
33
34 struct tunnel_id
35 {
36   uint32_t id GNUNET_PACKED;
37   struct GNUNET_PeerIdentity initiator;
38   struct GNUNET_PeerIdentity target;
39 };
40
41 static uint32_t current_id = 0;
42
43 struct tunnel_message
44 {
45   struct GNUNET_MessageHeader hdr;
46   struct tunnel_id id;
47   /* followed by another GNUNET_MessageHeader */
48 };
49
50 struct notify_cls
51 {
52   void* notify_cls;
53   GNUNET_CONNECTION_TransmitReadyNotify notify;
54   struct GNUNET_MESH_Tunnel *tunnel;
55 };
56
57 struct GNUNET_MESH_Tunnel
58 {
59   /* The other peer this tunnel leads to; just unicast for the moment! */
60   struct GNUNET_PeerIdentity peer;
61
62   struct tunnel_id id;
63
64   /* The handlers and cls for outbound tunnels. Are NULL for inbound tunnels. */
65   GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
66   GNUNET_MESH_TunnelConnectHandler connect_handler;
67   void *handler_cls;
68
69   struct GNUNET_MESH_Handle* handle;
70
71   /* The application-type requested for this tunnel. Is only needed for pending
72    * by_tupe-tunnels
73    */
74   uint16_t application_type;
75
76   struct GNUNET_MESH_TransmitHandle* notify_handle;
77
78   /* The context of the receive-function. */
79   void *ctx;
80 };
81
82 struct tunnel_list_element
83 {
84   struct GNUNET_MESH_Tunnel tunnel;
85   struct tunnel_list_element *next, *prev;
86 };
87
88 struct tunnel_list
89 {
90   struct tunnel_list_element *head, *tail;
91 };
92
93 struct type_list_element
94 {
95   GNUNET_MESH_ApplicationType type;
96   struct type_list_element *next, *prev;
97 };
98
99 struct peer_list_element
100 {
101   struct GNUNET_PeerIdentity peer;
102
103   /* list of application-types */
104   struct type_list_element *type_head, *type_tail;
105
106   struct GNUNET_TRANSPORT_ATS_Information atsi;
107   struct peer_list_element *next, *prev;
108 };
109
110 struct peer_list
111 {
112   struct peer_list_element *head, *tail;
113 };
114
115 struct GNUNET_MESH_Handle
116 {
117   struct GNUNET_CORE_Handle *core;
118   struct GNUNET_MESH_MessageHandler *handlers;
119   struct GNUNET_PeerIdentity myself;
120   unsigned int connected_to_core;
121   struct peer_list connected_peers;
122   struct tunnel_list established_tunnels;
123   struct tunnel_list pending_tunnels;
124   struct tunnel_list pending_by_type_tunnels;
125   void *cls;
126   GNUNET_MESH_TunnelEndHandler *cleaner;
127   size_t hello_message_size;
128   uint16_t *hello_message;
129 };
130
131 static void
132 send_end_connect(void* cls,
133                      const struct GNUNET_SCHEDULER_TaskContext* tc)
134 {
135   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
136     return;
137
138   struct GNUNET_MESH_Tunnel* tunnel = cls;
139
140   tunnel->connect_handler(tunnel->handler_cls, NULL, NULL);
141 }
142
143 static void
144 send_self_connect(void* cls,
145                         const struct GNUNET_SCHEDULER_TaskContext* tc)
146 {
147   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
148       return;
149
150   struct GNUNET_MESH_Tunnel* tunnel = cls;
151
152   tunnel->connect_handler(tunnel->handler_cls, &tunnel->handle->myself, NULL);
153   GNUNET_SCHEDULER_add_now(send_end_connect, tunnel);
154 }
155
156 static void
157 call_connect_handler (void *cls,
158                       const struct GNUNET_SCHEDULER_TaskContext *tc)
159 {
160   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
161       return;
162
163   struct GNUNET_MESH_Tunnel *tunnel = cls;
164
165   tunnel->connect_handler (tunnel->handler_cls, &tunnel->peer,
166                            NULL);
167   GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
168 }
169
170 static void
171 core_startup (void *cls,
172               struct GNUNET_CORE_Handle *core __attribute__((unused)),
173               const struct GNUNET_PeerIdentity *my_identity,
174               const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey __attribute__((unused)))
175 {
176   struct GNUNET_MESH_Handle *handle = cls;
177   memcpy (&handle->myself, my_identity, sizeof (struct GNUNET_PeerIdentity));
178   handle->connected_to_core = GNUNET_YES;
179 }
180
181 static size_t
182 send_hello_message (void *cls, size_t size, void *buf)
183 {
184   if (cls == NULL) return 0;
185
186   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending hello\n");
187
188   struct GNUNET_MESH_Handle *handle = cls;
189   struct GNUNET_MessageHeader *hdr = buf;
190
191   size_t sent = sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size;
192
193   if (sent > size) return 0;
194
195   hdr->type = htons(GNUNET_MESSAGE_TYPE_MESH_HELLO);
196   hdr->size = htons(size);
197
198   memcpy(hdr+1, handle->hello_message, handle->hello_message_size);
199   return sent;
200 }
201
202
203 /**
204  * Core calls this if we are connected to a new peer.
205  *
206  * The peer is added to the connected_peers-list.
207  *
208  */
209 static void
210 core_connect (void *cls,
211               const struct GNUNET_PeerIdentity *peer,
212               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
213 {
214   struct GNUNET_MESH_Handle *handle = cls;
215
216   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Core tells us we are connected to peer %s\n", GNUNET_i2s(peer));
217
218   /* Send a hello to this peer */
219   GNUNET_CORE_notify_transmit_ready(handle->core,
220                                     GNUNET_NO,
221                                     42,
222                                     GNUNET_TIME_UNIT_SECONDS,
223                                     peer,
224                                     sizeof(struct GNUNET_MessageHeader) + handle->hello_message_size,
225                                     &send_hello_message,
226                                     cls);
227
228   /* put the new peer into the list of connected peers */
229   struct peer_list_element *element =
230     GNUNET_malloc (sizeof (struct peer_list_element));
231   memcpy (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity));
232
233   if (NULL != atsi)
234     memcpy (&element->atsi, atsi,
235             sizeof (struct GNUNET_TRANSPORT_ATS_Information));
236
237   GNUNET_CONTAINER_DLL_insert_after (handle->connected_peers.head,
238                                      handle->connected_peers.tail,
239                                      handle->connected_peers.tail, element);
240
241   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
242   while (tunnel != NULL)
243     {
244       if (0 ==
245           memcmp (&tunnel->tunnel.peer, peer,
246                   sizeof (struct GNUNET_PeerIdentity)))
247         {
248           struct tunnel_list_element *next = tunnel->next;
249           GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
250                                        handle->pending_tunnels.tail, tunnel);
251           GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
252                                              handle->established_tunnels.tail,
253                                              handle->established_tunnels.tail,
254                                              tunnel);
255           tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
256                                           peer, atsi);
257           GNUNET_SCHEDULER_add_now(send_end_connect, tunnel);
258           tunnel = next;
259         }
260       else
261         tunnel = tunnel->next;
262     }
263 }
264
265 /**
266  * Core calls this if we disconnect a peer
267  *
268  * Remove this peer from the list of connected peers
269  * Close all tunnels this peer belongs to
270  */
271 static void
272 core_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
273 {
274   struct GNUNET_MESH_Handle *handle = cls;
275
276   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Core tells us we are no longer connected to peer %s\n", GNUNET_i2s(peer));
277
278   struct peer_list_element *element = handle->connected_peers.head;
279   while (element != NULL)
280     {
281       if (0 ==
282           memcmp (&element->peer, peer, sizeof (struct GNUNET_PeerIdentity)))
283         break;
284       element = element->next;
285     }
286   if (element != NULL)
287     {
288       GNUNET_CONTAINER_DLL_remove (handle->connected_peers.head,
289                                    handle->connected_peers.tail, element);
290       while (element->type_head != NULL)
291         {
292           struct type_list_element* tail = element->type_tail;
293           GNUNET_CONTAINER_DLL_remove(element->type_head, element->type_tail, tail);
294           GNUNET_free(tail);
295         }
296       GNUNET_free (element);
297     }
298
299   struct tunnel_list_element *telement = handle->established_tunnels.head;
300   while (telement != NULL)
301     {
302       if (0 ==
303           memcmp (&telement->tunnel.peer, peer,
304                   sizeof (struct GNUNET_PeerIdentity)))
305         {
306           /* disconnect tunnels */
307           /* outbound tunnels */
308           if (telement->tunnel.connect_handler != NULL && NULL != telement->tunnel.disconnect_handler)
309             telement->tunnel.disconnect_handler (telement->tunnel.handler_cls,
310                                                  peer);
311           /* inbound tunnels */
312           else if (NULL != handle->cleaner)
313             handle->cleaner (handle->cls, &telement->tunnel,
314                              &telement->tunnel.ctx);
315
316           struct tunnel_list_element *next = telement->next;
317           GNUNET_CONTAINER_DLL_remove (handle->established_tunnels.head,
318                                        handle->established_tunnels.tail,
319                                        telement);
320           GNUNET_free (telement);
321           telement = next;
322         }
323       else
324         {
325           telement = telement->next;
326         }
327     }
328 }
329
330 /**
331  * Receive a message from core.
332  * This is a hello-message, containing the application-types the other peer can receive
333  */
334 static int
335 receive_hello (void *cls,
336                const struct GNUNET_PeerIdentity *other,
337                const struct GNUNET_MessageHeader *message,
338                const struct GNUNET_TRANSPORT_ATS_Information *atsi)
339 {
340   struct GNUNET_MESH_Handle *handle = cls;
341   uint16_t *num = (uint16_t *) (message + 1);
342   GNUNET_MESH_ApplicationType *ports = (GNUNET_MESH_ApplicationType*) (num + 1);
343   unsigned int i;
344
345   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "The peer %s tells us he supports %d application-types.\n", GNUNET_i2s(other), ntohs(*num));
346
347   struct peer_list_element *element = handle->connected_peers.head;
348   while (element != NULL)
349     {
350       if (0 ==
351           memcmp (&element->peer, other, sizeof (struct GNUNET_PeerIdentity)))
352         break;
353       element = element->next;
354     }
355
356   GNUNET_assert(NULL != element);
357
358   for (i = 0; i < ntohs(*num); i++)
359     {
360       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "The peer %s newly supports the application-type %d\n", GNUNET_i2s(other), ntohs(ports[i]));
361       if (GNUNET_APPLICATION_TYPE_END == ntohs(ports[i])) continue;
362       struct type_list_element* new_type = GNUNET_malloc(sizeof *new_type);
363       new_type->type = (GNUNET_MESH_ApplicationType)ntohs (ports[i]);
364       GNUNET_CONTAINER_DLL_insert(element->type_head, element->type_tail, new_type);
365     }
366
367   struct type_list_element *type;
368   for (type = element->type_head; type != NULL; type = type->next)
369     {
370       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "The peer %s supports the application-type %d\n", GNUNET_i2s(other), type->type);
371     }
372
373   struct tunnel_list_element *tunnel = handle->pending_by_type_tunnels.head;
374   while (tunnel != NULL)
375     {
376       struct tunnel_list_element *next = tunnel->next;
377       for (i = 0; i < ntohs(*num); i++)
378         {
379           if (ntohs (ports[i]) == tunnel->tunnel.application_type)
380             {
381               GNUNET_CONTAINER_DLL_remove (handle->pending_tunnels.head,
382                                            handle->pending_tunnels.tail,
383                                            tunnel);
384               GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.
385                                                  head,
386                                                  handle->established_tunnels.
387                                                  tail,
388                                                  handle->established_tunnels.
389                                                  tail, tunnel);
390               tunnel->tunnel.connect_handler (tunnel->tunnel.handler_cls,
391                                               &tunnel->tunnel.peer, atsi);
392               GNUNET_SCHEDULER_add_now (send_end_connect, tunnel);
393               break;
394             }
395         }
396       if (ntohs (ports[i]) == tunnel->tunnel.application_type)
397         tunnel = next;
398       else
399         tunnel = tunnel->next;
400     }
401   return GNUNET_OK;
402 }
403
404 /**
405  * Receive a message from core.
406  */
407 static int
408 core_receive (void *cls,
409               const struct GNUNET_PeerIdentity *other,
410               const struct GNUNET_MessageHeader *message,
411               const struct GNUNET_TRANSPORT_ATS_Information *atsi)
412 {
413   struct GNUNET_MESH_Handle *handle = cls;
414   struct tunnel_message *tmessage = (struct tunnel_message *) message;
415   struct GNUNET_MessageHeader *rmessage =
416     (struct GNUNET_MessageHeader *) (tmessage + 1);
417
418   struct GNUNET_MESH_MessageHandler *handler;
419
420   for (handler = handle->handlers; handler->callback != NULL; handler++)
421     {
422       if ( (ntohs (rmessage->type) == handler->type)
423            && ( (handler->expected_size == 0)
424                 || (handler->expected_size == ntohs (rmessage->size))) )
425         {
426           break;
427         }
428     }
429
430   /* handler->callback handles this message */
431
432   /* If no handler was found, drop the message but keep the channel open */
433   if (handler->callback == NULL)
434     {
435       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received message of type %d from peer %s; dropping it.\n",
436                  ntohs(rmessage->type), GNUNET_i2s(other));
437       return GNUNET_OK;
438     }
439
440   struct tunnel_list_element *tunnel = handle->established_tunnels.head;
441
442   while (tunnel != NULL)
443     {
444       if (tunnel->tunnel.id.id == tmessage->id.id &&
445           (0 ==
446            memcmp (&tmessage->id.initiator, &tunnel->tunnel.id.initiator,
447                    sizeof (struct GNUNET_PeerIdentity)))
448           && (0 ==
449               memcmp (&tmessage->id.target, &tunnel->tunnel.id.target,
450                       sizeof (struct GNUNET_PeerIdentity))))
451         break;
452       tunnel = tunnel->next;
453     }
454
455   /* if no tunnel was found: create a new inbound tunnel */
456   if (tunnel == NULL)
457     {
458       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New inbound tunnel from peer %s; first message has type %d.\n",
459                  GNUNET_i2s(other), ntohs(rmessage->type));
460       tunnel = GNUNET_malloc (sizeof (struct tunnel_list_element));
461       tunnel->tunnel.connect_handler = NULL;
462       tunnel->tunnel.disconnect_handler = NULL;
463       tunnel->tunnel.handler_cls = NULL;
464       tunnel->tunnel.ctx = NULL;
465       tunnel->tunnel.handle = handle;
466       memcpy (&tunnel->tunnel.peer, other,
467               sizeof (struct GNUNET_PeerIdentity));
468       memcpy (&tunnel->tunnel.id, &tmessage->id, sizeof (struct tunnel_id));
469
470       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
471                                          handle->established_tunnels.tail,
472                                          handle->established_tunnels.tail,
473                                          tunnel);
474     }
475   else
476     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Inbound message from peer %s; type %d.\n",
477                GNUNET_i2s(other), ntohs(rmessage->type));
478
479   return handler->callback (handle->cls, &tunnel->tunnel,
480                             &tunnel->tunnel.ctx, other, rmessage, atsi);
481 }
482
483 struct GNUNET_MESH_Tunnel *
484 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Handle *handle,
485                                           struct GNUNET_TIME_Relative timeout,
486                                           GNUNET_MESH_ApplicationType application_type,
487                                           GNUNET_MESH_TunnelConnectHandler
488                                           connect_handler,
489                                           GNUNET_MESH_TunnelDisconnectHandler
490                                           disconnect_handler,
491                                           void *handler_cls)
492 {
493   /* Look in the list of connected peers */
494   struct peer_list_element *element = handle->connected_peers.head;
495   while (element != NULL)
496     {
497       struct type_list_element* i;
498       for (i = element->type_head; i != NULL; i = i->next)
499         if (application_type == i->type)
500           return GNUNET_MESH_peer_request_connect_all (handle, timeout, 1,
501                                                        &element->peer,
502                                                        connect_handler,
503                                                        disconnect_handler,
504                                                        handler_cls);
505       element = element->next;
506     }
507
508   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Trying to connect by tupe %d.\n", application_type);
509
510   /* Put into pending list */
511   struct tunnel_list_element *tunnel =
512     GNUNET_malloc (sizeof (struct tunnel_list_element));
513
514   tunnel->tunnel.connect_handler = connect_handler;
515   tunnel->tunnel.disconnect_handler = disconnect_handler;
516   tunnel->tunnel.handler_cls = handler_cls;
517   tunnel->tunnel.ctx = NULL;
518   tunnel->tunnel.handle = handle;
519   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
520           sizeof (struct GNUNET_PeerIdentity));
521   tunnel->tunnel.id.id = current_id++;
522   tunnel->tunnel.application_type = application_type;
523
524   GNUNET_CONTAINER_DLL_insert_after (handle->pending_by_type_tunnels.head,
525                                      handle->pending_by_type_tunnels.tail,
526                                      handle->pending_by_type_tunnels.tail,
527                                      tunnel);
528   return &tunnel->tunnel;
529 }
530
531
532
533 struct GNUNET_MESH_Tunnel *
534 GNUNET_MESH_peer_request_connect_all (struct GNUNET_MESH_Handle *handle,
535                                       struct GNUNET_TIME_Relative timeout,
536                                       unsigned int num_peers,
537                                       const struct GNUNET_PeerIdentity *peers,
538                                       GNUNET_MESH_TunnelConnectHandler
539                                       connect_handler,
540                                       GNUNET_MESH_TunnelDisconnectHandler
541                                       disconnect_handler, void *handler_cls)
542 {
543   if (num_peers != 1)
544     return NULL;
545
546   struct tunnel_list_element *tunnel =
547     GNUNET_malloc (sizeof (struct tunnel_list_element));
548
549   tunnel->tunnel.connect_handler = connect_handler;
550   tunnel->tunnel.disconnect_handler = disconnect_handler;
551   tunnel->tunnel.handler_cls = handler_cls;
552   tunnel->tunnel.ctx = NULL;
553   tunnel->tunnel.handle = handle;
554   memcpy (&tunnel->tunnel.id.initiator, &handle->myself,
555           sizeof (struct GNUNET_PeerIdentity));
556   memcpy (&tunnel->tunnel.id.target, peers,
557           sizeof (struct GNUNET_PeerIdentity));
558   tunnel->tunnel.id.id = current_id++;
559   memcpy (&tunnel->tunnel.peer, peers, sizeof(struct GNUNET_PeerIdentity));
560
561   struct peer_list_element *element = handle->connected_peers.head;
562   while (element != NULL)
563     {
564       if (0 ==
565           memcmp (&element->peer, peers, sizeof (struct GNUNET_PeerIdentity)))
566         break;
567       element = element->next;
568     }
569
570   if (element != NULL)
571     {
572       /* we are connected to this peer */
573       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
574                                          handle->established_tunnels.tail,
575                                          handle->established_tunnels.tail,
576                                          tunnel);
577       GNUNET_SCHEDULER_add_now(call_connect_handler, tunnel);
578     }
579   else if (0 ==
580            memcmp (peers, &handle->myself,
581                    sizeof (struct GNUNET_PeerIdentity)))
582     {
583       /* we are the peer */
584       GNUNET_CONTAINER_DLL_insert_after (handle->established_tunnels.head,
585                                          handle->established_tunnels.tail,
586                                          handle->established_tunnels.tail,
587                                          tunnel);
588       GNUNET_SCHEDULER_add_now(send_self_connect, tunnel);
589     }
590   else
591     {
592       /* we are not connected to this peer */
593       GNUNET_CONTAINER_DLL_insert_after (handle->pending_tunnels.head,
594                                          handle->pending_tunnels.tail,
595                                          handle->pending_tunnels.tail,
596                                          tunnel);
597       (void) GNUNET_CORE_peer_request_connect (handle->core,
598                                                peers,
599                                                NULL, NULL);
600     }
601
602   return &tunnel->tunnel;
603 }
604
605 const struct GNUNET_PeerIdentity*
606 GNUNET_MESH_get_peer(const struct GNUNET_MESH_Tunnel* tunnel)
607 {
608   return &tunnel->peer;
609 }
610
611 static size_t
612 core_notify(void* cls, size_t size, void* buf)
613 {
614   struct notify_cls *ncls = cls;
615   struct GNUNET_MESH_Tunnel *tunnel = ncls->tunnel;
616   tunnel->notify_handle = NULL;
617   struct tunnel_message* message = buf;
618   void* cbuf = (void*) &message[1];
619   GNUNET_assert(NULL != ncls->notify);
620
621   size_t sent = ncls->notify(ncls->notify_cls, size - sizeof(struct tunnel_message), cbuf);
622
623   GNUNET_free(ncls);
624
625   if (0 == sent) return 0;
626
627   sent += sizeof(struct tunnel_message);
628
629   message->hdr.type = htons(GNUNET_MESSAGE_TYPE_MESH);
630   message->hdr.size = htons(sent);
631   memcpy(&message->id, &tunnel->id, sizeof(struct tunnel_id));
632   return sent;
633 }
634
635
636 /**
637  * Ask the mesh to call "notify" once it is ready to transmit the
638  * given number of bytes to the specified "target".  If we are not yet
639  * connected to the specified peer, a call to this function will cause
640  * us to try to establish a connection.
641  *
642  * @param tunnel tunnel to use for transmission
643  * @param cork is corking allowed for this transmission?
644  * @param priority how important is the message?
645  * @param maxdelay how long can the message wait?
646  * @param target destination for the message, NULL for multicast to all tunnel targets 
647  * @param notify_size how many bytes of buffer space does notify want?
648  * @param notify function to call when buffer space is available;
649  *        will be called with NULL on timeout or if the overall queue
650  *        for this peer is larger than queue_size and this is currently
651  *        the message with the lowest priority
652  * @param notify_cls closure for notify
653  * @return non-NULL if the notify callback was queued,
654  *         NULL if we can not even queue the request (insufficient
655  *         memory); if NULL is returned, "notify" will NOT be called.
656  */
657 struct GNUNET_MESH_TransmitHandle *
658 GNUNET_MESH_notify_transmit_ready (struct
659                                    GNUNET_MESH_Tunnel
660                                    *tunnel,
661                                    int cork,
662                                    uint32_t priority,
663                                    struct
664                                    GNUNET_TIME_Relative
665                                    maxdelay,
666                                    const struct GNUNET_PeerIdentity *target
667                                    __attribute__ ((unused)),
668                                    size_t notify_size,
669                                    GNUNET_CONNECTION_TransmitReadyNotify
670                                    notify, void *notify_cls)
671 {
672   if (NULL != tunnel->notify_handle)
673     {
674       GNUNET_break(0);
675       return NULL;
676     }
677
678   struct notify_cls *cls = GNUNET_malloc (sizeof (struct notify_cls));
679   cls->notify_cls = notify_cls;
680   GNUNET_assert (NULL != notify);
681   cls->notify = notify;
682   cls->tunnel = tunnel;
683
684   tunnel->notify_handle = (struct GNUNET_MESH_TransmitHandle *)
685     GNUNET_CORE_notify_transmit_ready (tunnel->handle->core, cork, priority,
686                                        maxdelay, &tunnel->peer,
687                                        notify_size +
688                                        sizeof (struct tunnel_message),
689                                        &core_notify, (void *) cls);
690
691   return tunnel->notify_handle;
692 }
693
694 void
695 GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle
696                                           *th)
697 {
698   GNUNET_CORE_notify_transmit_ready_cancel ((struct GNUNET_CORE_TransmitHandle
699                                              *) th);
700 }
701
702 void build_hello_message(struct GNUNET_MESH_Handle* handle,
703                          const GNUNET_MESH_ApplicationType *stypes)
704 {
705   int num = 0;
706   const GNUNET_MESH_ApplicationType *t;
707
708   for (t = stypes; *t != GNUNET_APPLICATION_TYPE_END; t++, num++);
709
710   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "I can handle %d app-types.\n", num);
711
712   handle->hello_message_size = sizeof(uint16_t) + /* For the number of types */
713     num * sizeof(GNUNET_MESH_ApplicationType); /* For the types */
714
715   uint16_t *nums = GNUNET_malloc(handle->hello_message_size);
716   GNUNET_MESH_ApplicationType *types = (GNUNET_MESH_ApplicationType*)(nums + 1);
717
718   *nums = htons(num);
719
720   int i;
721   for (i = 0; i < num; i++)
722     {
723       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "I can handle the app-type %d\n", stypes[i]);
724       types[i] = htons(stypes[i]);
725     }
726
727   handle->hello_message = nums;
728 }
729
730
731 struct GNUNET_MESH_Handle *
732 GNUNET_MESH_connect (const struct
733                      GNUNET_CONFIGURATION_Handle
734                      *cfg, void *cls,
735                      GNUNET_MESH_TunnelEndHandler
736                      cleaner,
737                      const struct GNUNET_MESH_MessageHandler *handlers,
738                      const GNUNET_MESH_ApplicationType *stypes)
739 {
740   struct GNUNET_MESH_Handle *ret =
741     GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
742
743   ret->connected_to_core = GNUNET_NO;
744   ret->connected_peers.head = NULL;
745   ret->connected_peers.tail = NULL;
746   ret->cleaner = cleaner;
747   ret->cls = cls;
748
749   const struct GNUNET_MESH_MessageHandler *it;
750   unsigned int len = 1;
751   for (it = handlers; it->callback != NULL; it++)
752     {
753       len++;
754     }
755
756   ret->handlers =
757     GNUNET_malloc (len * sizeof (struct GNUNET_MESH_MessageHandler));
758   memset(ret->handlers, 0, len * sizeof(struct GNUNET_MESH_MessageHandler));
759   memcpy (ret->handlers, handlers,
760           len * sizeof (struct GNUNET_MESH_MessageHandler));
761
762   build_hello_message(ret, stypes);
763
764   static const struct GNUNET_CORE_MessageHandler core_handlers[] = {
765     {&core_receive, GNUNET_MESSAGE_TYPE_MESH, 0},
766     {&receive_hello, GNUNET_MESSAGE_TYPE_MESH_HELLO, 0},
767     {NULL, 0, 0}
768   };
769
770   ret->core = GNUNET_CORE_connect (cfg,
771                                    42,
772                                    ret,
773                                    &core_startup,
774                                    &core_connect,
775                                    &core_disconnect,
776                                    NULL,
777                                    NULL,
778                                    GNUNET_NO, NULL, GNUNET_NO, core_handlers);
779   return ret;
780 }
781
782 void
783 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
784 {
785   GNUNET_free (handle->handlers);
786   GNUNET_free (handle->hello_message);
787   GNUNET_CORE_disconnect (handle->core);
788
789   struct peer_list_element *element = handle->connected_peers.head;
790   while (element != NULL)
791     {
792       struct peer_list_element *next = element->next;
793       while (element->type_head != NULL)
794         {
795           struct type_list_element* tail = element->type_tail;
796           GNUNET_CONTAINER_DLL_remove(element->type_head, element->type_tail, tail);
797           GNUNET_free(tail);
798         }
799       GNUNET_free (element);
800       element = next;
801     }
802
803   struct tunnel_list_element *tunnel = handle->pending_tunnels.head;
804   while (tunnel != NULL)
805     {
806       struct tunnel_list_element *next = tunnel->next;
807       GNUNET_free (tunnel);
808       tunnel = next;
809     }
810   tunnel = handle->established_tunnels.head;;
811   while (tunnel != NULL)
812     {
813       struct tunnel_list_element *next = tunnel->next;
814       GNUNET_free (tunnel);
815       tunnel = next;
816     }
817
818   GNUNET_free (handle);
819 }
820
821 /* end of mesh_api.c */