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