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