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