diff options
author | Bart Polot <bart@net.in.tum.de> | 2013-05-07 11:36:16 +0000 |
---|---|---|
committer | Bart Polot <bart@net.in.tum.de> | 2013-05-07 11:36:16 +0000 |
commit | b0b173f897b1f2b015667c96f37b8bc383f2c12a (patch) | |
tree | b1e607c702ee0e1f9bdcde1ae5a3cb6c0c6583e4 /src | |
parent | ea931ffc94e1f8145c30c98da50cd5ae9dd5147a (diff) | |
download | gnunet-b0b173f897b1f2b015667c96f37b8bc383f2c12a.tar.gz gnunet-b0b173f897b1f2b015667c96f37b8bc383f2c12a.zip |
Initial mesh2 api import
Diffstat (limited to 'src')
-rw-r--r-- | src/mesh/Makefile.am | 20 | ||||
-rw-r--r-- | src/mesh/mesh2_api.c | 2329 |
2 files changed, 2347 insertions, 2 deletions
diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am index 7d9a4daf8..c0733cafd 100644 --- a/src/mesh/Makefile.am +++ b/src/mesh/Makefile.am | |||
@@ -20,14 +20,19 @@ plugindir = $(libdir)/gnunet | |||
20 | 20 | ||
21 | AM_CLFAGS = -g | 21 | AM_CLFAGS = -g |
22 | 22 | ||
23 | if HAVE_EXPERIMENTAL | ||
24 | EXP_LIB = libgnunetmesh2.la | ||
25 | EXP_LIBEXEC = gnunet-service-mesh-new | ||
26 | endif | ||
27 | |||
23 | libexec_PROGRAMS = \ | 28 | libexec_PROGRAMS = \ |
24 | gnunet-service-mesh gnunet-service-mesh-new | 29 | gnunet-service-mesh $(EXP_LIBEXEC) |
25 | 30 | ||
26 | bin_PROGRAMS = \ | 31 | bin_PROGRAMS = \ |
27 | gnunet-mesh | 32 | gnunet-mesh |
28 | 33 | ||
29 | lib_LTLIBRARIES = \ | 34 | lib_LTLIBRARIES = \ |
30 | libgnunetmesh.la | 35 | libgnunetmesh.la $(EXP_LIB) |
31 | 36 | ||
32 | plugin_LTLIBRARIES = \ | 37 | plugin_LTLIBRARIES = \ |
33 | libgnunet_plugin_block_mesh.la | 38 | libgnunet_plugin_block_mesh.la |
@@ -53,6 +58,17 @@ libgnunetmesh_la_LDFLAGS = \ | |||
53 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | 58 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ |
54 | -version-info 2:1:1 | 59 | -version-info 2:1:1 |
55 | 60 | ||
61 | libgnunetmesh2_la_SOURCES = \ | ||
62 | mesh2_api.c mesh_common.c | ||
63 | libgnunetmesh2_la_LIBADD = \ | ||
64 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
65 | $(XLIB) \ | ||
66 | $(LTLIBINTL) | ||
67 | libgnunetmesh2_la_LDFLAGS = \ | ||
68 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
69 | -version-info 2:2:1 | ||
70 | |||
71 | |||
56 | gnunet_service_mesh_SOURCES = \ | 72 | gnunet_service_mesh_SOURCES = \ |
57 | gnunet-service-mesh.c \ | 73 | gnunet-service-mesh.c \ |
58 | mesh_tunnel_tree.c mesh_tunnel_tree.h \ | 74 | mesh_tunnel_tree.c mesh_tunnel_tree.h \ |
diff --git a/src/mesh/mesh2_api.c b/src/mesh/mesh2_api.c new file mode 100644 index 000000000..c847bc419 --- /dev/null +++ b/src/mesh/mesh2_api.c | |||
@@ -0,0 +1,2329 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2011 Christian Grothoff (and other contributing authors) | ||
4 | GNUnet is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published | ||
6 | by the Free Software Foundation; either version 3, or (at your | ||
7 | option) any later version. | ||
8 | GNUnet is distributed in the hope that it will be useful, but | ||
9 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | General Public License for more details. | ||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with GNUnet; see the file COPYING. If not, write to the | ||
14 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
15 | Boston, MA 02111-1307, USA. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file mesh/mesh2_api.c | ||
20 | * @brief mesh2 api: client implementation of new mesh service | ||
21 | * @author Bartlomiej Polot | ||
22 | * | ||
23 | * STRUCTURE: | ||
24 | * - DATA STRUCTURES | ||
25 | * - DECLARATIONS | ||
26 | * - AUXILIARY FUNCTIONS | ||
27 | * - RECEIVE HANDLERS | ||
28 | * - SEND FUNCTIONS | ||
29 | * - API CALL DEFINITIONS | ||
30 | * | ||
31 | * TODO: add regex to reconnect | ||
32 | */ | ||
33 | #include "platform.h" | ||
34 | #include "gnunet_common.h" | ||
35 | #include "gnunet_client_lib.h" | ||
36 | #include "gnunet_util_lib.h" | ||
37 | #include "gnunet_peer_lib.h" | ||
38 | #include "gnunet_mesh2_service.h" | ||
39 | #include "mesh.h" | ||
40 | #include "mesh_protocol.h" | ||
41 | |||
42 | #define LOG(kind,...) GNUNET_log_from (kind, "mesh2-api",__VA_ARGS__) | ||
43 | |||
44 | #define DEBUG_ACK GNUNET_YES | ||
45 | |||
46 | /******************************************************************************/ | ||
47 | /************************ DATA STRUCTURES ****************************/ | ||
48 | /******************************************************************************/ | ||
49 | |||
50 | /** | ||
51 | * Transmission queue to the service | ||
52 | */ | ||
53 | struct GNUNET_MESH_TransmitHandle | ||
54 | { | ||
55 | |||
56 | /** | ||
57 | * Double Linked list | ||
58 | */ | ||
59 | struct GNUNET_MESH_TransmitHandle *next; | ||
60 | |||
61 | /** | ||
62 | * Double Linked list | ||
63 | */ | ||
64 | struct GNUNET_MESH_TransmitHandle *prev; | ||
65 | |||
66 | /** | ||
67 | * Tunnel this message is sent on / for (may be NULL for control messages). | ||
68 | */ | ||
69 | struct GNUNET_MESH_Tunnel *tunnel; | ||
70 | |||
71 | /** | ||
72 | * Callback to obtain the message to transmit, or NULL if we | ||
73 | * got the message in 'data'. Notice that messages built | ||
74 | * by 'notify' need to be encapsulated with information about | ||
75 | * the 'target'. | ||
76 | */ | ||
77 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
78 | |||
79 | /** | ||
80 | * Closure for 'notify' | ||
81 | */ | ||
82 | void *notify_cls; | ||
83 | |||
84 | /** | ||
85 | * How long is this message valid. Once the timeout has been | ||
86 | * reached, the message must no longer be sent. If this | ||
87 | * is a message with a 'notify' callback set, the 'notify' | ||
88 | * function should be called with 'buf' NULL and size 0. | ||
89 | */ | ||
90 | struct GNUNET_TIME_Absolute timeout; | ||
91 | |||
92 | /** | ||
93 | * Task triggering a timeout, can be NO_TASK if the timeout is FOREVER. | ||
94 | */ | ||
95 | GNUNET_SCHEDULER_TaskIdentifier timeout_task; | ||
96 | |||
97 | /** | ||
98 | * Target of the message, 0 for multicast. This field | ||
99 | * is only valid if 'notify' is non-NULL. | ||
100 | */ | ||
101 | GNUNET_PEER_Id target; | ||
102 | |||
103 | /** | ||
104 | * Size of 'data' -- or the desired size of 'notify' if 'data' is NULL. | ||
105 | */ | ||
106 | size_t size; | ||
107 | }; | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Opaque handle to the service. | ||
112 | */ | ||
113 | struct GNUNET_MESH_Handle | ||
114 | { | ||
115 | |||
116 | /** | ||
117 | * Handle to the server connection, to send messages later | ||
118 | */ | ||
119 | struct GNUNET_CLIENT_Connection *client; | ||
120 | |||
121 | /** | ||
122 | * Set of handlers used for processing incoming messages in the tunnels | ||
123 | */ | ||
124 | const struct GNUNET_MESH_MessageHandler *message_handlers; | ||
125 | |||
126 | /** | ||
127 | * Double linked list of the tunnels this client is connected to, head. | ||
128 | */ | ||
129 | struct GNUNET_MESH_Tunnel *tunnels_head; | ||
130 | |||
131 | /** | ||
132 | * Double linked list of the tunnels this client is connected to, tail. | ||
133 | */ | ||
134 | struct GNUNET_MESH_Tunnel *tunnels_tail; | ||
135 | |||
136 | /** | ||
137 | * Callback for inbound tunnel creation | ||
138 | */ | ||
139 | GNUNET_MESH_InboundTunnelNotificationHandler *new_tunnel; | ||
140 | |||
141 | /** | ||
142 | * Callback for inbound tunnel disconnection | ||
143 | */ | ||
144 | GNUNET_MESH_TunnelEndHandler *cleaner; | ||
145 | |||
146 | /** | ||
147 | * Handle to cancel pending transmissions in case of disconnection | ||
148 | */ | ||
149 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
150 | |||
151 | /** | ||
152 | * Closure for all the handlers given by the client | ||
153 | */ | ||
154 | void *cls; | ||
155 | |||
156 | /** | ||
157 | * Messages to send to the service, head. | ||
158 | */ | ||
159 | struct GNUNET_MESH_TransmitHandle *th_head; | ||
160 | |||
161 | /** | ||
162 | * Messages to send to the service, tail. | ||
163 | */ | ||
164 | struct GNUNET_MESH_TransmitHandle *th_tail; | ||
165 | |||
166 | /** | ||
167 | * tid of the next tunnel to create (to avoid reusing IDs often) | ||
168 | */ | ||
169 | MESH_TunnelNumber next_tid; | ||
170 | |||
171 | /** | ||
172 | * Number of handlers in the handlers array. | ||
173 | */ | ||
174 | unsigned int n_handlers; | ||
175 | |||
176 | /** | ||
177 | * Number of applications in the applications array. | ||
178 | */ | ||
179 | unsigned int n_applications; | ||
180 | |||
181 | /** | ||
182 | * Have we started the task to receive messages from the service | ||
183 | * yet? We do this after we send the 'MESH_LOCAL_CONNECT' message. | ||
184 | */ | ||
185 | int in_receive; | ||
186 | |||
187 | /** | ||
188 | * Configuration given by the client, in case of reconnection | ||
189 | */ | ||
190 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
191 | |||
192 | /** | ||
193 | * Time to the next reconnect in case one reconnect fails | ||
194 | */ | ||
195 | struct GNUNET_TIME_Relative reconnect_time; | ||
196 | |||
197 | /** | ||
198 | * Task for trying to reconnect. | ||
199 | */ | ||
200 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
201 | |||
202 | /** | ||
203 | * Monitor callback | ||
204 | */ | ||
205 | GNUNET_MESH_TunnelsCB tunnels_cb; | ||
206 | |||
207 | /** | ||
208 | * Monitor callback closure. | ||
209 | */ | ||
210 | void *tunnels_cls; | ||
211 | |||
212 | /** | ||
213 | * Tunnel callback. | ||
214 | */ | ||
215 | GNUNET_MESH_TunnelCB tunnel_cb; | ||
216 | |||
217 | /** | ||
218 | * Tunnel callback closure. | ||
219 | */ | ||
220 | void *tunnel_cls; | ||
221 | |||
222 | /** | ||
223 | * All the peer in the tunnel so far. | ||
224 | */ | ||
225 | struct GNUNET_PeerIdentity *peers; | ||
226 | |||
227 | /** | ||
228 | * How many peers we have in this tunnel so far. | ||
229 | */ | ||
230 | unsigned int tunnel_npeers; | ||
231 | |||
232 | #if DEBUG_ACK | ||
233 | unsigned int acks_sent; | ||
234 | unsigned int acks_recv; | ||
235 | #endif | ||
236 | }; | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Description of a peer | ||
241 | */ | ||
242 | struct GNUNET_MESH_Peer | ||
243 | { | ||
244 | /** | ||
245 | * ID of the peer in short form | ||
246 | */ | ||
247 | GNUNET_PEER_Id id; | ||
248 | |||
249 | /** | ||
250 | * Tunnel this peer belongs to | ||
251 | */ | ||
252 | struct GNUNET_MESH_Tunnel *t; | ||
253 | |||
254 | /** | ||
255 | * Flag indicating whether service has informed about its connection | ||
256 | */ | ||
257 | int connected; | ||
258 | |||
259 | }; | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Opaque handle to a tunnel. | ||
264 | */ | ||
265 | struct GNUNET_MESH_Tunnel | ||
266 | { | ||
267 | |||
268 | /** | ||
269 | * DLL next | ||
270 | */ | ||
271 | struct GNUNET_MESH_Tunnel *next; | ||
272 | |||
273 | /** | ||
274 | * DLL prev | ||
275 | */ | ||
276 | struct GNUNET_MESH_Tunnel *prev; | ||
277 | |||
278 | /** | ||
279 | * Handle to the mesh this tunnel belongs to | ||
280 | */ | ||
281 | struct GNUNET_MESH_Handle *mesh; | ||
282 | |||
283 | /** | ||
284 | * Local ID of the tunnel | ||
285 | */ | ||
286 | MESH_TunnelNumber tid; | ||
287 | |||
288 | /** | ||
289 | * Owner of the tunnel. (1 if the tunnel is a local client). | ||
290 | */ | ||
291 | GNUNET_PEER_Id owner; | ||
292 | |||
293 | /** | ||
294 | * Destination of the tunnel. | ||
295 | */ | ||
296 | GNUNET_PEER_Id destination; | ||
297 | |||
298 | /** | ||
299 | * Next hop for the tunnel. | ||
300 | */ | ||
301 | GNUNET_PEER_Id next_hop; | ||
302 | |||
303 | /** | ||
304 | * Previous hop for the tunnel. | ||
305 | */ | ||
306 | GNUNET_PEER_Id prev_hop; | ||
307 | |||
308 | /** | ||
309 | * Any data the caller wants to put in here | ||
310 | */ | ||
311 | void *ctx; | ||
312 | |||
313 | /** | ||
314 | * Size of packet queued in this tunnel | ||
315 | */ | ||
316 | unsigned int packet_size; | ||
317 | |||
318 | /** | ||
319 | * Number of applications requested this tunnel | ||
320 | */ | ||
321 | unsigned int napps; | ||
322 | |||
323 | /** | ||
324 | * Is the tunnel throttled to the slowest peer? | ||
325 | */ | ||
326 | int speed_min; | ||
327 | |||
328 | /** | ||
329 | * Is the tunnel allowed to buffer? | ||
330 | */ | ||
331 | int buffering; | ||
332 | |||
333 | /** | ||
334 | * Next packet ID to send. | ||
335 | */ | ||
336 | uint32_t next_send_pid; | ||
337 | |||
338 | /** | ||
339 | * Maximum allowed PID to send (ACK recevied). | ||
340 | */ | ||
341 | uint32_t max_send_pid; | ||
342 | |||
343 | /** | ||
344 | * Last pid received from the service. | ||
345 | */ | ||
346 | uint32_t last_recv_pid; | ||
347 | |||
348 | /** | ||
349 | * Which ACK value have we last sent to the service? | ||
350 | */ | ||
351 | uint32_t max_recv_pid; | ||
352 | }; | ||
353 | |||
354 | |||
355 | /******************************************************************************/ | ||
356 | /*********************** DECLARATIONS *************************/ | ||
357 | /******************************************************************************/ | ||
358 | |||
359 | /** | ||
360 | * Function called to send a message to the service. | ||
361 | * "buf" will be NULL and "size" zero if the socket was closed for writing in | ||
362 | * the meantime. | ||
363 | * | ||
364 | * @param cls closure, the mesh handle | ||
365 | * @param size number of bytes available in buf | ||
366 | * @param buf where the callee should write the connect message | ||
367 | * @return number of bytes written to buf | ||
368 | */ | ||
369 | static size_t | ||
370 | send_callback (void *cls, size_t size, void *buf); | ||
371 | |||
372 | |||
373 | /******************************************************************************/ | ||
374 | /*********************** AUXILIARY FUNCTIONS *************************/ | ||
375 | /******************************************************************************/ | ||
376 | |||
377 | /** | ||
378 | * Check if transmission is a payload packet. | ||
379 | * | ||
380 | * @param th Transmission handle. | ||
381 | * | ||
382 | * @return GNUNET_YES if it is a payload packet, | ||
383 | * GNUNET_NO if it is a mesh management packet. | ||
384 | */ | ||
385 | static int | ||
386 | th_is_payload (struct GNUNET_MESH_TransmitHandle *th) | ||
387 | { | ||
388 | return (th->notify != NULL) ? GNUNET_YES : GNUNET_NO; | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * Check whether there is any message ready in the queue and find the size. | ||
394 | * | ||
395 | * @param h Mesh handle. | ||
396 | * | ||
397 | * @return The size of the first ready message in the queue, | ||
398 | * 0 if there is none. | ||
399 | */ | ||
400 | static size_t | ||
401 | message_ready_size (struct GNUNET_MESH_Handle *h) | ||
402 | { | ||
403 | struct GNUNET_MESH_TransmitHandle *th; | ||
404 | struct GNUNET_MESH_Tunnel *t; | ||
405 | |||
406 | for (th = h->th_head; NULL != th; th = th->next) | ||
407 | { | ||
408 | t = th->tunnel; | ||
409 | if (GNUNET_NO == th_is_payload (th)) | ||
410 | { | ||
411 | LOG (GNUNET_ERROR_TYPE_DEBUG, " message internal\n"); | ||
412 | return th->size; | ||
413 | } | ||
414 | if (GNUNET_NO == GMC_is_pid_bigger(t->next_send_pid, t->max_send_pid)) | ||
415 | { | ||
416 | LOG (GNUNET_ERROR_TYPE_DEBUG, " message payload ok (%u <= %u)\n", | ||
417 | t->next_send_pid, t->max_send_pid); | ||
418 | return th->size; | ||
419 | } | ||
420 | } | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Get the tunnel handler for the tunnel specified by id from the given handle | ||
427 | * @param h Mesh handle | ||
428 | * @param tid ID of the wanted tunnel | ||
429 | * @return handle to the required tunnel or NULL if not found | ||
430 | */ | ||
431 | static struct GNUNET_MESH_Tunnel * | ||
432 | retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) | ||
433 | { | ||
434 | struct GNUNET_MESH_Tunnel *t; | ||
435 | |||
436 | t = h->tunnels_head; | ||
437 | while (t != NULL) | ||
438 | { | ||
439 | if (t->tid == tid) | ||
440 | return t; | ||
441 | t = t->next; | ||
442 | } | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | * Create a new tunnel and insert it in the tunnel list of the mesh handle | ||
449 | * @param h Mesh handle | ||
450 | * @param tid desired tid of the tunnel, 0 to assign one automatically | ||
451 | * @return handle to the created tunnel | ||
452 | */ | ||
453 | static struct GNUNET_MESH_Tunnel * | ||
454 | create_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) | ||
455 | { | ||
456 | struct GNUNET_MESH_Tunnel *t; | ||
457 | |||
458 | t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel)); | ||
459 | GNUNET_CONTAINER_DLL_insert (h->tunnels_head, h->tunnels_tail, t); | ||
460 | t->mesh = h; | ||
461 | if (0 == tid) | ||
462 | { | ||
463 | t->tid = h->next_tid; | ||
464 | while (NULL != retrieve_tunnel (h, h->next_tid)) | ||
465 | { | ||
466 | h->next_tid++; | ||
467 | h->next_tid &= ~GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; | ||
468 | h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; | ||
469 | } | ||
470 | } | ||
471 | else | ||
472 | { | ||
473 | t->tid = tid; | ||
474 | } | ||
475 | t->max_send_pid = INITIAL_WINDOW_SIZE - 1; | ||
476 | t->last_recv_pid = (uint32_t) -1; | ||
477 | t->buffering = GNUNET_YES; | ||
478 | return t; | ||
479 | } | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Destroy the specified tunnel. | ||
484 | * - Destroys all peers, calling the disconnect callback on each if needed | ||
485 | * - Cancels all outgoing traffic for that tunnel, calling respective notifys | ||
486 | * - Calls cleaner if tunnel was inbound | ||
487 | * - Frees all memory used | ||
488 | * | ||
489 | * @param t Pointer to the tunnel. | ||
490 | * @param call_cleaner Whether to call the cleaner handler. | ||
491 | * | ||
492 | * @return Handle to the required tunnel or NULL if not found. | ||
493 | */ | ||
494 | static void | ||
495 | destroy_tunnel (struct GNUNET_MESH_Tunnel *t, int call_cleaner) | ||
496 | { | ||
497 | struct GNUNET_MESH_Handle *h; | ||
498 | struct GNUNET_PeerIdentity pi; | ||
499 | struct GNUNET_MESH_TransmitHandle *th; | ||
500 | struct GNUNET_MESH_TransmitHandle *next; | ||
501 | unsigned int i; | ||
502 | |||
503 | LOG (GNUNET_ERROR_TYPE_DEBUG, "destroy_tunnel %X\n", t->tid); | ||
504 | |||
505 | if (NULL == t) | ||
506 | { | ||
507 | GNUNET_break (0); | ||
508 | return; | ||
509 | } | ||
510 | h = t->mesh; | ||
511 | |||
512 | /* free all peer's ID */ | ||
513 | GNUNET_CONTAINER_DLL_remove (h->tunnels_head, h->tunnels_tail, t); | ||
514 | GNUNET_PEER_change_rc (t->owner, -1); | ||
515 | GNUNET_PEER_change_rc (t->destination, -1); | ||
516 | GNUNET_PEER_change_rc (t->next_hop, -1); | ||
517 | GNUNET_PEER_change_rc (t->prev_hop, -1); | ||
518 | |||
519 | /* signal tunnel destruction */ | ||
520 | if ( (NULL != h->cleaner) && (0 != t->owner) && (GNUNET_YES == call_cleaner) ) | ||
521 | h->cleaner (h->cls, t, t->ctx); | ||
522 | |||
523 | /* check that clients did not leave messages behind in the queue */ | ||
524 | for (th = h->th_head; NULL != th; th = next) | ||
525 | { | ||
526 | next = th->next; | ||
527 | if (th->tunnel != t) | ||
528 | continue; | ||
529 | /* Clients should have aborted their requests already. | ||
530 | * Management traffic should be ok, as clients can't cancel that */ | ||
531 | GNUNET_break (GNUNET_NO == th_is_payload(th)); | ||
532 | GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); | ||
533 | |||
534 | /* clean up request */ | ||
535 | if (GNUNET_SCHEDULER_NO_TASK != th->timeout_task) | ||
536 | GNUNET_SCHEDULER_cancel (th->timeout_task); | ||
537 | GNUNET_free (th); | ||
538 | } | ||
539 | |||
540 | /* if there are no more pending requests with mesh service, cancel active request */ | ||
541 | /* Note: this should be unnecessary... */ | ||
542 | if ((0 == message_ready_size (h)) && (NULL != h->th)) | ||
543 | { | ||
544 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); | ||
545 | h->th = NULL; | ||
546 | } | ||
547 | |||
548 | |||
549 | if (t->npeers > 0) | ||
550 | GNUNET_free (t->peers); | ||
551 | if (0 != t->owner) | ||
552 | GNUNET_PEER_change_rc (t->owner, -1); | ||
553 | if (0 != t->napps && t->apps) | ||
554 | GNUNET_free (t->apps); | ||
555 | GNUNET_free (t); | ||
556 | return; | ||
557 | } | ||
558 | |||
559 | |||
560 | /** | ||
561 | * Get the peer descriptor for the peer with id from the given tunnel | ||
562 | * @param t Tunnel handle | ||
563 | * @param id Short form ID of the wanted peer | ||
564 | * @return handle to the requested peer or NULL if not found | ||
565 | */ | ||
566 | static struct GNUNET_MESH_Peer * | ||
567 | retrieve_peer (struct GNUNET_MESH_Tunnel *t, GNUNET_PEER_Id id) | ||
568 | { | ||
569 | unsigned int i; | ||
570 | |||
571 | for (i = 0; i < t->npeers; i++) | ||
572 | if (t->peers[i]->id == id) | ||
573 | return t->peers[i]; | ||
574 | return NULL; | ||
575 | } | ||
576 | |||
577 | |||
578 | /** | ||
579 | * Add a peer into a tunnel | ||
580 | * @param t Tunnel handle | ||
581 | * @param pi Full ID of the new peer | ||
582 | * @return handle to the newly created peer | ||
583 | */ | ||
584 | static struct GNUNET_MESH_Peer * | ||
585 | add_peer_to_tunnel (struct GNUNET_MESH_Tunnel *t, | ||
586 | const struct GNUNET_PeerIdentity *pi) | ||
587 | { | ||
588 | struct GNUNET_MESH_Peer *p; | ||
589 | GNUNET_PEER_Id id; | ||
590 | |||
591 | if (0 != t->owner) | ||
592 | { | ||
593 | GNUNET_break (0); | ||
594 | return NULL; | ||
595 | } | ||
596 | id = GNUNET_PEER_intern (pi); | ||
597 | |||
598 | p = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); | ||
599 | p->id = id; | ||
600 | p->t = t; | ||
601 | GNUNET_array_append (t->peers, t->npeers, p); | ||
602 | return p; | ||
603 | } | ||
604 | |||
605 | |||
606 | /** | ||
607 | * Remove a peer from a tunnel | ||
608 | * @param p Peer handle | ||
609 | */ | ||
610 | static void | ||
611 | remove_peer_from_tunnel (struct GNUNET_MESH_Peer *p) | ||
612 | { | ||
613 | unsigned int i; | ||
614 | |||
615 | for (i = 0; i < p->t->npeers; i++) | ||
616 | { | ||
617 | if (p->t->peers[i] == p) | ||
618 | break; | ||
619 | } | ||
620 | if (i == p->t->npeers) | ||
621 | { | ||
622 | GNUNET_break (0); | ||
623 | return; | ||
624 | } | ||
625 | p->t->peers[i] = p->t->peers[p->t->npeers - 1]; | ||
626 | GNUNET_array_grow (p->t->peers, p->t->npeers, p->t->npeers - 1); | ||
627 | } | ||
628 | |||
629 | |||
630 | /** | ||
631 | * Notify client that the transmission has timed out | ||
632 | * | ||
633 | * @param cls closure | ||
634 | * @param tc task context | ||
635 | */ | ||
636 | static void | ||
637 | timeout_transmission (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
638 | { | ||
639 | struct GNUNET_MESH_TransmitHandle *th = cls; | ||
640 | struct GNUNET_MESH_Handle *mesh; | ||
641 | |||
642 | mesh = th->tunnel->mesh; | ||
643 | GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); | ||
644 | th->tunnel->packet_size = 0; | ||
645 | if (GNUNET_YES == th_is_payload (th)) | ||
646 | th->notify (th->notify_cls, 0, NULL); | ||
647 | GNUNET_free (th); | ||
648 | if ((0 == message_ready_size (mesh)) && (NULL != mesh->th)) | ||
649 | { | ||
650 | /* nothing ready to transmit, no point in asking for transmission */ | ||
651 | GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); | ||
652 | mesh->th = NULL; | ||
653 | } | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * Add a transmit handle to the transmission queue and set the | ||
659 | * timeout if needed. | ||
660 | * | ||
661 | * @param h mesh handle with the queue head and tail | ||
662 | * @param th handle to the packet to be transmitted | ||
663 | */ | ||
664 | static void | ||
665 | add_to_queue (struct GNUNET_MESH_Handle *h, | ||
666 | struct GNUNET_MESH_TransmitHandle *th) | ||
667 | { | ||
668 | GNUNET_CONTAINER_DLL_insert_tail (h->th_head, h->th_tail, th); | ||
669 | if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value == th->timeout.abs_value) | ||
670 | return; | ||
671 | th->timeout_task = | ||
672 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
673 | (th->timeout), &timeout_transmission, th); | ||
674 | } | ||
675 | |||
676 | |||
677 | /** | ||
678 | * Auxiliary function to send an already constructed packet to the service. | ||
679 | * Takes care of creating a new queue element, copying the message and | ||
680 | * calling the tmt_rdy function if necessary. | ||
681 | * | ||
682 | * @param h mesh handle | ||
683 | * @param msg message to transmit | ||
684 | * @param tunnel tunnel this send is related to (NULL if N/A) | ||
685 | */ | ||
686 | static void | ||
687 | send_packet (struct GNUNET_MESH_Handle *h, | ||
688 | const struct GNUNET_MessageHeader *msg, | ||
689 | struct GNUNET_MESH_Tunnel *tunnel); | ||
690 | |||
691 | |||
692 | /** | ||
693 | * Send an ack on the tunnel to confirm the processing of a message. | ||
694 | * | ||
695 | * @param h Mesh handle. | ||
696 | * @param t Tunnel on which to send the ACK. | ||
697 | */ | ||
698 | static void | ||
699 | send_ack (struct GNUNET_MESH_Handle *h, struct GNUNET_MESH_Tunnel *t) | ||
700 | { | ||
701 | struct GNUNET_MESH_LocalAck msg; | ||
702 | uint32_t delta; | ||
703 | |||
704 | delta = t->max_recv_pid - t->last_recv_pid; | ||
705 | if (delta > ACK_THRESHOLD) | ||
706 | { | ||
707 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
708 | "Not sending ACK on tunnel %X: ACK: %u, PID: %u, buffer %u\n", | ||
709 | t->tid, t->max_recv_pid, t->last_recv_pid, delta); | ||
710 | return; | ||
711 | } | ||
712 | if (GNUNET_YES == t->buffering) | ||
713 | t->max_recv_pid = t->last_recv_pid + INITIAL_WINDOW_SIZE; | ||
714 | else | ||
715 | t->max_recv_pid = t->last_recv_pid + 1; | ||
716 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
717 | "Sending ACK on tunnel %X: %u\n", | ||
718 | t->tid, t->max_recv_pid); | ||
719 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK); | ||
720 | msg.header.size = htons (sizeof (msg)); | ||
721 | msg.tunnel_id = htonl (t->tid); | ||
722 | msg.max_pid = htonl (t->max_recv_pid); | ||
723 | |||
724 | #if DEBUG_ACK | ||
725 | t->mesh->acks_sent++; | ||
726 | #endif | ||
727 | |||
728 | send_packet (h, &msg.header, t); | ||
729 | return; | ||
730 | } | ||
731 | |||
732 | |||
733 | |||
734 | /** | ||
735 | * Reconnect callback: tries to reconnect again after a failer previous | ||
736 | * reconnecttion | ||
737 | * @param cls closure (mesh handle) | ||
738 | * @param tc task context | ||
739 | */ | ||
740 | static void | ||
741 | reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
742 | |||
743 | |||
744 | /** | ||
745 | * Send a connect packet to the service with the applications and types | ||
746 | * requested by the user. | ||
747 | * | ||
748 | * @param h The mesh handle. | ||
749 | * | ||
750 | */ | ||
751 | static void | ||
752 | send_connect (struct GNUNET_MESH_Handle *h) | ||
753 | { | ||
754 | size_t size; | ||
755 | |||
756 | size = sizeof (struct GNUNET_MESH_ClientConnect); | ||
757 | size += h->n_handlers * sizeof (uint16_t); | ||
758 | { | ||
759 | char buf[size] GNUNET_ALIGN; | ||
760 | struct GNUNET_MESH_ClientConnect *msg; | ||
761 | uint16_t napps; | ||
762 | uint16_t *types; | ||
763 | uint16_t ntypes; | ||
764 | |||
765 | /* build connection packet */ | ||
766 | msg = (struct GNUNET_MESH_ClientConnect *) buf; | ||
767 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT); | ||
768 | msg->header.size = htons (size); | ||
769 | types = (uint16_t *) & apps[napps]; | ||
770 | for (ntypes = 0; ntypes < h->n_handlers; ntypes++) | ||
771 | { | ||
772 | types[ntypes] = htons (h->message_handlers[ntypes].type); | ||
773 | LOG (GNUNET_ERROR_TYPE_DEBUG, " type %u\n", | ||
774 | h->message_handlers[ntypes].type); | ||
775 | } | ||
776 | msg->applications = htons (napps); | ||
777 | msg->types = htons (ntypes); | ||
778 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
779 | "Sending %lu bytes long message %d types and %d apps\n", | ||
780 | ntohs (msg->header.size), ntypes, napps); | ||
781 | send_packet (h, &msg->header, NULL); | ||
782 | } | ||
783 | } | ||
784 | |||
785 | |||
786 | /** | ||
787 | * Reconnect to the service, retransmit all infomation to try to restore the | ||
788 | * original state. | ||
789 | * | ||
790 | * @param h handle to the mesh | ||
791 | * | ||
792 | * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) | ||
793 | */ | ||
794 | static int | ||
795 | do_reconnect (struct GNUNET_MESH_Handle *h) | ||
796 | { | ||
797 | struct GNUNET_MESH_Tunnel *t; | ||
798 | unsigned int i; | ||
799 | |||
800 | LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); | ||
801 | LOG (GNUNET_ERROR_TYPE_DEBUG, "******* RECONNECT *******\n"); | ||
802 | LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); | ||
803 | LOG (GNUNET_ERROR_TYPE_DEBUG, "******** on %p *******\n", h); | ||
804 | LOG (GNUNET_ERROR_TYPE_DEBUG, "*****************************\n"); | ||
805 | |||
806 | /* disconnect */ | ||
807 | if (NULL != h->th) | ||
808 | { | ||
809 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); | ||
810 | h->th = NULL; | ||
811 | } | ||
812 | if (NULL != h->client) | ||
813 | { | ||
814 | GNUNET_CLIENT_disconnect (h->client); | ||
815 | } | ||
816 | |||
817 | /* connect again */ | ||
818 | h->client = GNUNET_CLIENT_connect ("mesh", h->cfg); | ||
819 | if (h->client == NULL) | ||
820 | { | ||
821 | h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, | ||
822 | &reconnect_cbk, h); | ||
823 | h->reconnect_time = | ||
824 | GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, | ||
825 | GNUNET_TIME_relative_multiply | ||
826 | (h->reconnect_time, 2)); | ||
827 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
828 | "Next retry in %s\n", | ||
829 | GNUNET_STRINGS_relative_time_to_string (h->reconnect_time, | ||
830 | GNUNET_NO)); | ||
831 | GNUNET_break (0); | ||
832 | return GNUNET_NO; | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; | ||
837 | } | ||
838 | send_connect (h); | ||
839 | /* Rebuild all tunnels */ | ||
840 | for (t = h->tunnels_head; NULL != t; t = t->next) | ||
841 | { | ||
842 | struct GNUNET_MESH_TunnelMessage tmsg; | ||
843 | struct GNUNET_MESH_PeerControl pmsg; | ||
844 | |||
845 | if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
846 | { | ||
847 | /* Tunnel was created by service (incoming tunnel) */ | ||
848 | /* TODO: Notify service of missing tunnel, to request | ||
849 | * creator to recreate path (find a path to him via DHT?) | ||
850 | */ | ||
851 | continue; | ||
852 | } | ||
853 | t->next_send_pid = 0; | ||
854 | t->max_send_pid = INITIAL_WINDOW_SIZE - 1; | ||
855 | t->last_recv_pid = (uint32_t) -1; | ||
856 | tmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); | ||
857 | tmsg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
858 | tmsg.tunnel_id = htonl (t->tid); | ||
859 | send_packet (h, &tmsg.header, t); | ||
860 | |||
861 | pmsg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); | ||
862 | pmsg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); | ||
863 | pmsg.tunnel_id = htonl (t->tid); | ||
864 | |||
865 | /* Reconnect all peers */ | ||
866 | /* If the tunnel was "by type", dont connect individual peers */ | ||
867 | for (i = 0; i < t->npeers && 0 == t->napps; i++) | ||
868 | { | ||
869 | GNUNET_PEER_resolve (t->peers[i]->id, &pmsg.peer); | ||
870 | if (NULL != t->disconnect_handler && t->peers[i]->connected) | ||
871 | t->disconnect_handler (t->cls, &pmsg.peer); | ||
872 | send_packet (t->mesh, &pmsg.header, t); | ||
873 | } | ||
874 | /* Reconnect all types, if any */ | ||
875 | for (i = 0; i < t->napps; i++) | ||
876 | { | ||
877 | struct GNUNET_MESH_ConnectPeerByType msg; | ||
878 | |||
879 | msg.header.size = htons (sizeof (struct GNUNET_MESH_ConnectPeerByType)); | ||
880 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_TYPE); | ||
881 | msg.tunnel_id = htonl (t->tid); | ||
882 | msg.type = htonl (t->apps[i]); | ||
883 | send_packet (t->mesh, &msg.header, t); | ||
884 | } | ||
885 | if (GNUNET_NO == t->buffering) | ||
886 | GNUNET_MESH_tunnel_buffer (t, GNUNET_NO); | ||
887 | if (GNUNET_YES == t->speed_min) | ||
888 | GNUNET_MESH_tunnel_speed_min (t); | ||
889 | } | ||
890 | return GNUNET_YES; | ||
891 | } | ||
892 | |||
893 | /** | ||
894 | * Reconnect callback: tries to reconnect again after a failer previous | ||
895 | * reconnecttion | ||
896 | * @param cls closure (mesh handle) | ||
897 | * @param tc task context | ||
898 | */ | ||
899 | static void | ||
900 | reconnect_cbk (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
901 | { | ||
902 | struct GNUNET_MESH_Handle *h = cls; | ||
903 | |||
904 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
905 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
906 | return; | ||
907 | do_reconnect (h); | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * Reconnect to the service, retransmit all infomation to try to restore the | ||
913 | * original state. | ||
914 | * | ||
915 | * @param h handle to the mesh | ||
916 | * | ||
917 | * @return GNUNET_YES in case of sucess, GNUNET_NO otherwise (service down...) | ||
918 | */ | ||
919 | static void | ||
920 | reconnect (struct GNUNET_MESH_Handle *h) | ||
921 | { | ||
922 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Requested RECONNECT\n"); | ||
923 | h->in_receive = GNUNET_NO; | ||
924 | if (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task) | ||
925 | h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time, | ||
926 | &reconnect_cbk, h); | ||
927 | } | ||
928 | |||
929 | |||
930 | /******************************************************************************/ | ||
931 | /*********************** RECEIVE HANDLERS ****************************/ | ||
932 | /******************************************************************************/ | ||
933 | |||
934 | /** | ||
935 | * Process the new tunnel notification and add it to the tunnels in the handle | ||
936 | * | ||
937 | * @param h The mesh handle | ||
938 | * @param msg A message with the details of the new incoming tunnel | ||
939 | */ | ||
940 | static void | ||
941 | process_tunnel_created (struct GNUNET_MESH_Handle *h, | ||
942 | const struct GNUNET_MESH_TunnelNotification *msg) | ||
943 | { | ||
944 | struct GNUNET_MESH_Tunnel *t; | ||
945 | MESH_TunnelNumber tid; | ||
946 | |||
947 | tid = ntohl (msg->tunnel_id); | ||
948 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating incoming tunnel %X\n", tid); | ||
949 | if (tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
950 | { | ||
951 | GNUNET_break (0); | ||
952 | return; | ||
953 | } | ||
954 | if (NULL != h->new_tunnel) | ||
955 | { | ||
956 | struct GNUNET_ATS_Information atsi; | ||
957 | |||
958 | t = create_tunnel (h, tid); | ||
959 | t->owner = GNUNET_PEER_intern (&msg->peer); | ||
960 | t->npeers = 1; | ||
961 | t->peers = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer *)); | ||
962 | t->peers[0] = GNUNET_malloc (sizeof (struct GNUNET_MESH_Peer)); | ||
963 | t->peers[0]->t = t; | ||
964 | t->peers[0]->connected = 1; | ||
965 | t->peers[0]->id = t->owner; | ||
966 | GNUNET_PEER_change_rc (t->owner, 1); | ||
967 | t->mesh = h; | ||
968 | t->tid = tid; | ||
969 | if ((msg->opt & MESH_TUNNEL_OPT_NOBUFFER) != 0) | ||
970 | t->buffering = GNUNET_NO; | ||
971 | else | ||
972 | t->buffering = GNUNET_YES; | ||
973 | if ((msg->opt & MESH_TUNNEL_OPT_SPEED_MIN) != 0) | ||
974 | t->speed_min = GNUNET_YES; | ||
975 | atsi.type = 0; | ||
976 | atsi.value = 0; | ||
977 | LOG (GNUNET_ERROR_TYPE_DEBUG, " created tunnel %p\n", t); | ||
978 | t->ctx = h->new_tunnel (h->cls, t, &msg->peer, &atsi); | ||
979 | LOG (GNUNET_ERROR_TYPE_DEBUG, "User notified\n"); | ||
980 | } | ||
981 | else | ||
982 | { | ||
983 | struct GNUNET_MESH_TunnelMessage d_msg; | ||
984 | |||
985 | LOG (GNUNET_ERROR_TYPE_DEBUG, "No handler for incoming tunnels\n"); | ||
986 | |||
987 | d_msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); | ||
988 | d_msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
989 | d_msg.tunnel_id = msg->tunnel_id; | ||
990 | |||
991 | send_packet (h, &d_msg.header, NULL); | ||
992 | } | ||
993 | return; | ||
994 | } | ||
995 | |||
996 | |||
997 | /** | ||
998 | * Process the tunnel destroy notification and free associated resources | ||
999 | * | ||
1000 | * @param h The mesh handle | ||
1001 | * @param msg A message with the details of the tunnel being destroyed | ||
1002 | */ | ||
1003 | static void | ||
1004 | process_tunnel_destroy (struct GNUNET_MESH_Handle *h, | ||
1005 | const struct GNUNET_MESH_TunnelMessage *msg) | ||
1006 | { | ||
1007 | struct GNUNET_MESH_Tunnel *t; | ||
1008 | MESH_TunnelNumber tid; | ||
1009 | |||
1010 | tid = ntohl (msg->tunnel_id); | ||
1011 | t = retrieve_tunnel (h, tid); | ||
1012 | |||
1013 | if (NULL == t) | ||
1014 | { | ||
1015 | return; | ||
1016 | } | ||
1017 | if (0 == t->owner) | ||
1018 | { | ||
1019 | GNUNET_break (0); | ||
1020 | } | ||
1021 | LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X destroyed\n", t->tid); | ||
1022 | destroy_tunnel (t, GNUNET_YES); | ||
1023 | return; | ||
1024 | } | ||
1025 | |||
1026 | |||
1027 | /** | ||
1028 | * Process the new peer event and notify the upper level of it | ||
1029 | * | ||
1030 | * @param h The mesh handle | ||
1031 | * @param msg A message with the details of the peer event | ||
1032 | */ | ||
1033 | static void | ||
1034 | process_peer_event (struct GNUNET_MESH_Handle *h, | ||
1035 | const struct GNUNET_MESH_PeerControl *msg) | ||
1036 | { | ||
1037 | struct GNUNET_MESH_Tunnel *t; | ||
1038 | struct GNUNET_MESH_Peer *p; | ||
1039 | struct GNUNET_ATS_Information atsi; | ||
1040 | GNUNET_PEER_Id id; | ||
1041 | uint16_t size; | ||
1042 | |||
1043 | LOG (GNUNET_ERROR_TYPE_DEBUG, "processig peer event\n"); | ||
1044 | size = ntohs (msg->header.size); | ||
1045 | if (size != sizeof (struct GNUNET_MESH_PeerControl)) | ||
1046 | { | ||
1047 | GNUNET_break (0); | ||
1048 | return; | ||
1049 | } | ||
1050 | t = retrieve_tunnel (h, ntohl (msg->tunnel_id)); | ||
1051 | if (NULL == t) | ||
1052 | { | ||
1053 | GNUNET_break (0); | ||
1054 | return; | ||
1055 | } | ||
1056 | id = GNUNET_PEER_search (&msg->peer); | ||
1057 | if ((p = retrieve_peer (t, id)) == NULL) | ||
1058 | p = add_peer_to_tunnel (t, &msg->peer); | ||
1059 | if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD == ntohs (msg->header.type)) | ||
1060 | { | ||
1061 | LOG (GNUNET_ERROR_TYPE_DEBUG, "adding peer\n"); | ||
1062 | if (NULL != t->connect_handler) | ||
1063 | { | ||
1064 | atsi.type = 0; | ||
1065 | atsi.value = 0; | ||
1066 | t->connect_handler (t->cls, &msg->peer, &atsi); | ||
1067 | } | ||
1068 | p->connected = 1; | ||
1069 | } | ||
1070 | else | ||
1071 | { | ||
1072 | LOG (GNUNET_ERROR_TYPE_DEBUG, "removing peer\n"); | ||
1073 | if (NULL != t->disconnect_handler && p->connected) | ||
1074 | { | ||
1075 | t->disconnect_handler (t->cls, &msg->peer); | ||
1076 | } | ||
1077 | remove_peer_from_tunnel (p); | ||
1078 | GNUNET_free (p); | ||
1079 | } | ||
1080 | LOG (GNUNET_ERROR_TYPE_DEBUG, "processing peer event END\n"); | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /** | ||
1085 | * Process the incoming data packets | ||
1086 | * | ||
1087 | * @param h The mesh handle | ||
1088 | * @param message A message encapsulating the data | ||
1089 | * | ||
1090 | * @return GNUNET_YES if everything went fine | ||
1091 | * GNUNET_NO if client closed connection (h no longer valid) | ||
1092 | */ | ||
1093 | static int | ||
1094 | process_incoming_data (struct GNUNET_MESH_Handle *h, | ||
1095 | const struct GNUNET_MessageHeader *message) | ||
1096 | { | ||
1097 | const struct GNUNET_MessageHeader *payload; | ||
1098 | const struct GNUNET_MESH_MessageHandler *handler; | ||
1099 | const struct GNUNET_PeerIdentity *peer; | ||
1100 | struct GNUNET_MESH_Unicast *ucast; | ||
1101 | struct GNUNET_MESH_Multicast *mcast; | ||
1102 | struct GNUNET_MESH_ToOrigin *to_orig; | ||
1103 | struct GNUNET_MESH_Tunnel *t; | ||
1104 | unsigned int i; | ||
1105 | uint32_t pid; | ||
1106 | uint16_t type; | ||
1107 | |||
1108 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a data message!\n"); | ||
1109 | type = ntohs (message->type); | ||
1110 | switch (type) | ||
1111 | { | ||
1112 | case GNUNET_MESSAGE_TYPE_MESH_UNICAST: | ||
1113 | ucast = (struct GNUNET_MESH_Unicast *) message; | ||
1114 | |||
1115 | t = retrieve_tunnel (h, ntohl (ucast->tid)); | ||
1116 | payload = (struct GNUNET_MessageHeader *) &ucast[1]; | ||
1117 | peer = &ucast->oid; | ||
1118 | pid = ntohl (ucast->pid); | ||
1119 | LOG (GNUNET_ERROR_TYPE_DEBUG, " ucast on tunnel %s [%X]\n", | ||
1120 | GNUNET_i2s (peer), ntohl (ucast->tid)); | ||
1121 | break; | ||
1122 | case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: | ||
1123 | mcast = (struct GNUNET_MESH_Multicast *) message; | ||
1124 | t = retrieve_tunnel (h, ntohl (mcast->tid)); | ||
1125 | payload = (struct GNUNET_MessageHeader *) &mcast[1]; | ||
1126 | peer = &mcast->oid; | ||
1127 | pid = ntohl (mcast->pid); | ||
1128 | LOG (GNUNET_ERROR_TYPE_DEBUG, " mcast on tunnel %s [%X]\n", | ||
1129 | GNUNET_i2s (peer), ntohl (mcast->tid)); | ||
1130 | break; | ||
1131 | case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: | ||
1132 | to_orig = (struct GNUNET_MESH_ToOrigin *) message; | ||
1133 | t = retrieve_tunnel (h, ntohl (to_orig->tid)); | ||
1134 | payload = (struct GNUNET_MessageHeader *) &to_orig[1]; | ||
1135 | peer = &to_orig->sender; | ||
1136 | pid = ntohl (to_orig->pid); | ||
1137 | LOG (GNUNET_ERROR_TYPE_DEBUG, " torig on tunnel %s [%X]\n", | ||
1138 | GNUNET_i2s (peer), ntohl (to_orig->tid)); | ||
1139 | break; | ||
1140 | default: | ||
1141 | GNUNET_break (0); | ||
1142 | return GNUNET_YES; | ||
1143 | } | ||
1144 | LOG (GNUNET_ERROR_TYPE_DEBUG, " pid %u\n", pid); | ||
1145 | if (NULL == t) | ||
1146 | { | ||
1147 | /* Tunnel was ignored/destroyed, probably service didn't get it yet */ | ||
1148 | LOG (GNUNET_ERROR_TYPE_DEBUG, " ignored!\n"); | ||
1149 | return GNUNET_YES; | ||
1150 | } | ||
1151 | if (GNUNET_YES == | ||
1152 | GMC_is_pid_bigger(pid, t->max_recv_pid)) | ||
1153 | { | ||
1154 | GNUNET_break (0); | ||
1155 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1156 | " unauthorized message! (%u, max %u)\n", | ||
1157 | pid, t->max_recv_pid); | ||
1158 | // FIXME fc what now? accept? reject? | ||
1159 | return GNUNET_YES; | ||
1160 | } | ||
1161 | t->last_recv_pid = pid; | ||
1162 | type = ntohs (payload->type); | ||
1163 | send_ack (h, t); | ||
1164 | for (i = 0; i < h->n_handlers; i++) | ||
1165 | { | ||
1166 | handler = &h->message_handlers[i]; | ||
1167 | if (handler->type == type) | ||
1168 | { | ||
1169 | struct GNUNET_ATS_Information atsi; | ||
1170 | |||
1171 | atsi.type = 0; | ||
1172 | atsi.value = 0; | ||
1173 | if (GNUNET_OK != | ||
1174 | handler->callback (h->cls, t, &t->ctx, peer, payload, &atsi)) | ||
1175 | { | ||
1176 | LOG (GNUNET_ERROR_TYPE_DEBUG, "callback caused disconnection\n"); | ||
1177 | GNUNET_MESH_disconnect (h); | ||
1178 | return GNUNET_NO; | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1183 | "callback completed successfully\n"); | ||
1184 | } | ||
1185 | } | ||
1186 | } | ||
1187 | return GNUNET_YES; | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | /** | ||
1192 | * Process a local ACK message, enabling the client to send | ||
1193 | * more data to the service. | ||
1194 | * | ||
1195 | * @param h Mesh handle. | ||
1196 | * @param message Message itself. | ||
1197 | */ | ||
1198 | static void | ||
1199 | process_ack (struct GNUNET_MESH_Handle *h, | ||
1200 | const struct GNUNET_MessageHeader *message) | ||
1201 | { | ||
1202 | struct GNUNET_MESH_LocalAck *msg; | ||
1203 | struct GNUNET_MESH_Tunnel *t; | ||
1204 | uint32_t ack; | ||
1205 | |||
1206 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK!\n"); | ||
1207 | h->acks_recv++; | ||
1208 | msg = (struct GNUNET_MESH_LocalAck *) message; | ||
1209 | |||
1210 | t = retrieve_tunnel (h, ntohl (msg->tunnel_id)); | ||
1211 | |||
1212 | if (NULL == t) | ||
1213 | { | ||
1214 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1215 | "ACK on unknown tunnel %X\n", | ||
1216 | ntohl (msg->tunnel_id)); | ||
1217 | return; | ||
1218 | } | ||
1219 | ack = ntohl (msg->max_pid); | ||
1220 | LOG (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %X, ack %u!\n", t->tid, ack); | ||
1221 | if (GNUNET_YES == GMC_is_pid_bigger(ack, t->max_send_pid)) | ||
1222 | t->max_send_pid = ack; | ||
1223 | else | ||
1224 | return; | ||
1225 | if (NULL == h->th && 0 < t->packet_size) | ||
1226 | { | ||
1227 | LOG (GNUNET_ERROR_TYPE_DEBUG, " tmt rdy was NULL, requesting!\n", t->tid, ack); | ||
1228 | h->th = | ||
1229 | GNUNET_CLIENT_notify_transmit_ready (h->client, t->packet_size, | ||
1230 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1231 | GNUNET_YES, &send_callback, h); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | |||
1236 | /** | ||
1237 | * Process a local reply about info on all tunnels, pass info to the user. | ||
1238 | * | ||
1239 | * @param h Mesh handle. | ||
1240 | * @param message Message itself. | ||
1241 | */ | ||
1242 | static void | ||
1243 | process_get_tunnels (struct GNUNET_MESH_Handle *h, | ||
1244 | const struct GNUNET_MessageHeader *message) | ||
1245 | { | ||
1246 | struct GNUNET_MESH_LocalMonitor *msg; | ||
1247 | uint32_t npeers; | ||
1248 | |||
1249 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Get Tunnels messasge received\n"); | ||
1250 | |||
1251 | if (NULL == h->tunnels_cb) | ||
1252 | { | ||
1253 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); | ||
1254 | return; | ||
1255 | } | ||
1256 | |||
1257 | msg = (struct GNUNET_MESH_LocalMonitor *) message; | ||
1258 | npeers = ntohl (msg->npeers); | ||
1259 | if (ntohs (message->size) != | ||
1260 | (sizeof (struct GNUNET_MESH_LocalMonitor) + | ||
1261 | npeers * sizeof (struct GNUNET_PeerIdentity))) | ||
1262 | { | ||
1263 | GNUNET_break_op (0); | ||
1264 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1265 | "Get tunnels message: size %hu - expected %u (%u peers)\n", | ||
1266 | ntohs (message->size), | ||
1267 | sizeof (struct GNUNET_MESH_LocalMonitor) + | ||
1268 | npeers * sizeof (struct GNUNET_PeerIdentity), | ||
1269 | npeers); | ||
1270 | return; | ||
1271 | } | ||
1272 | h->tunnels_cb (h->tunnels_cls, | ||
1273 | &msg->owner, | ||
1274 | ntohl (msg->tunnel_id), | ||
1275 | (struct GNUNET_PeerIdentity *) &msg[1], | ||
1276 | npeers); | ||
1277 | } | ||
1278 | |||
1279 | |||
1280 | |||
1281 | /** | ||
1282 | * Process a local monitor_tunnel reply, pass info to the user. | ||
1283 | * | ||
1284 | * @param h Mesh handle. | ||
1285 | * @param message Message itself. | ||
1286 | */ | ||
1287 | static void | ||
1288 | process_show_tunnel (struct GNUNET_MESH_Handle *h, | ||
1289 | const struct GNUNET_MessageHeader *message) | ||
1290 | { | ||
1291 | struct GNUNET_MESH_LocalMonitor *msg; | ||
1292 | struct GNUNET_PeerIdentity *new_peers; | ||
1293 | uint32_t *new_parents; | ||
1294 | size_t esize; | ||
1295 | uint32_t npeers; | ||
1296 | unsigned int i; | ||
1297 | |||
1298 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Show Tunnel messasge received\n"); | ||
1299 | |||
1300 | if (NULL == h->tunnel_cb) | ||
1301 | { | ||
1302 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " ignored\n"); | ||
1303 | return; | ||
1304 | } | ||
1305 | |||
1306 | /* Verify message sanity */ | ||
1307 | msg = (struct GNUNET_MESH_LocalMonitor *) message; | ||
1308 | npeers = ntohl (msg->npeers); | ||
1309 | esize = sizeof (struct GNUNET_MESH_LocalMonitor); | ||
1310 | esize += npeers * (sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t)); | ||
1311 | if (ntohs (message->size) != esize) | ||
1312 | { | ||
1313 | GNUNET_break_op (0); | ||
1314 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1315 | "Show tunnel message: size %hu - expected %u (%u peers)\n", | ||
1316 | ntohs (message->size), | ||
1317 | esize, | ||
1318 | npeers); | ||
1319 | |||
1320 | h->tunnel_cb (h->tunnel_cls, NULL, NULL); | ||
1321 | h->tunnel_cb = NULL; | ||
1322 | h->tunnel_cls = NULL; | ||
1323 | h->tunnel_npeers = 0; | ||
1324 | GNUNET_free_non_null (h->peers); | ||
1325 | h->peers = NULL; | ||
1326 | |||
1327 | return; | ||
1328 | } | ||
1329 | |||
1330 | new_peers = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1331 | new_parents = (uint32_t *) &new_peers[npeers]; | ||
1332 | |||
1333 | h->peers = GNUNET_realloc (h->peers, h->tunnel_npeers + npeers); | ||
1334 | memcpy (&h->peers[h->tunnel_npeers], | ||
1335 | new_peers, | ||
1336 | npeers * sizeof (struct GNUNET_PeerIdentity)); | ||
1337 | h->tunnel_npeers += npeers; | ||
1338 | for (i = 0; i < npeers; i++) | ||
1339 | h->tunnel_cb (h->tunnel_cls, | ||
1340 | &new_peers[i], | ||
1341 | &h->peers[new_parents[i]]); | ||
1342 | } | ||
1343 | |||
1344 | |||
1345 | /** | ||
1346 | * Function to process all messages received from the service | ||
1347 | * | ||
1348 | * @param cls closure | ||
1349 | * @param msg message received, NULL on timeout or fatal error | ||
1350 | */ | ||
1351 | static void | ||
1352 | msg_received (void *cls, const struct GNUNET_MessageHeader *msg) | ||
1353 | { | ||
1354 | struct GNUNET_MESH_Handle *h = cls; | ||
1355 | |||
1356 | if (msg == NULL) | ||
1357 | { | ||
1358 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1359 | "Mesh service disconnected, reconnecting\n", h); | ||
1360 | reconnect (h); | ||
1361 | return; | ||
1362 | } | ||
1363 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n", | ||
1364 | GNUNET_MESH_DEBUG_M2S (ntohs (msg->type))); | ||
1365 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a message: %s\n", | ||
1366 | GNUNET_MESH_DEBUG_M2S (ntohs (msg->type))); | ||
1367 | switch (ntohs (msg->type)) | ||
1368 | { | ||
1369 | /* Notify of a new incoming tunnel */ | ||
1370 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE: | ||
1371 | process_tunnel_created (h, (struct GNUNET_MESH_TunnelNotification *) msg); | ||
1372 | break; | ||
1373 | /* Notify of a tunnel disconnection */ | ||
1374 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: | ||
1375 | process_tunnel_destroy (h, (struct GNUNET_MESH_TunnelMessage *) msg); | ||
1376 | break; | ||
1377 | /* Notify of a new peer or a peer disconnect in the tunnel */ | ||
1378 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD: | ||
1379 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL: | ||
1380 | process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg); | ||
1381 | break; | ||
1382 | /* Notify of a new data packet in the tunnel */ | ||
1383 | case GNUNET_MESSAGE_TYPE_MESH_UNICAST: | ||
1384 | case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: | ||
1385 | case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: | ||
1386 | if (GNUNET_NO == process_incoming_data (h, msg)) | ||
1387 | return; | ||
1388 | break; | ||
1389 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK: | ||
1390 | process_ack (h, msg); | ||
1391 | break; | ||
1392 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS: | ||
1393 | process_get_tunnels (h, msg); | ||
1394 | break; | ||
1395 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL: | ||
1396 | process_show_tunnel (h, msg); | ||
1397 | break; | ||
1398 | default: | ||
1399 | /* We shouldn't get any other packages, log and ignore */ | ||
1400 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1401 | "unsolicited message form service (type %s)\n", | ||
1402 | GNUNET_MESH_DEBUG_M2S (ntohs (msg->type))); | ||
1403 | } | ||
1404 | LOG (GNUNET_ERROR_TYPE_DEBUG, "message processed\n"); | ||
1405 | if (GNUNET_YES == h->in_receive) | ||
1406 | { | ||
1407 | GNUNET_CLIENT_receive (h->client, &msg_received, h, | ||
1408 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
1409 | } | ||
1410 | else | ||
1411 | { | ||
1412 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1413 | "in receive off, not calling CLIENT_receive\n"); | ||
1414 | } | ||
1415 | } | ||
1416 | |||
1417 | |||
1418 | /******************************************************************************/ | ||
1419 | /************************ SEND FUNCTIONS ****************************/ | ||
1420 | /******************************************************************************/ | ||
1421 | |||
1422 | /** | ||
1423 | * Function called to send a message to the service. | ||
1424 | * "buf" will be NULL and "size" zero if the socket was closed for writing in | ||
1425 | * the meantime. | ||
1426 | * | ||
1427 | * @param cls closure, the mesh handle | ||
1428 | * @param size number of bytes available in buf | ||
1429 | * @param buf where the callee should write the connect message | ||
1430 | * @return number of bytes written to buf | ||
1431 | */ | ||
1432 | static size_t | ||
1433 | send_callback (void *cls, size_t size, void *buf) | ||
1434 | { | ||
1435 | struct GNUNET_MESH_Handle *h = cls; | ||
1436 | struct GNUNET_MESH_TransmitHandle *th; | ||
1437 | struct GNUNET_MESH_TransmitHandle *next; | ||
1438 | struct GNUNET_MESH_Tunnel *t; | ||
1439 | char *cbuf = buf; | ||
1440 | size_t tsize; | ||
1441 | size_t psize; | ||
1442 | size_t nsize; | ||
1443 | |||
1444 | LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); | ||
1445 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() Buffer %u\n", size); | ||
1446 | if ((0 == size) || (NULL == buf)) | ||
1447 | { | ||
1448 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Received NULL send callback on %p\n", h); | ||
1449 | reconnect (h); | ||
1450 | h->th = NULL; | ||
1451 | return 0; | ||
1452 | } | ||
1453 | tsize = 0; | ||
1454 | next = h->th_head; | ||
1455 | nsize = message_ready_size (h); | ||
1456 | while ((NULL != (th = next)) && (0 < nsize) && (size >= nsize)) | ||
1457 | { | ||
1458 | t = th->tunnel; | ||
1459 | if (GNUNET_YES == th_is_payload (th)) | ||
1460 | { | ||
1461 | LOG (GNUNET_ERROR_TYPE_DEBUG, " payload\n"); | ||
1462 | if (GNUNET_YES == GMC_is_pid_bigger(t->next_send_pid, t->max_send_pid)) | ||
1463 | { | ||
1464 | /* This tunnel is not ready to transmit yet, try next message */ | ||
1465 | next = th->next; | ||
1466 | continue; | ||
1467 | } | ||
1468 | t->packet_size = 0; | ||
1469 | if (t->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
1470 | { | ||
1471 | /* traffic to origin */ | ||
1472 | struct GNUNET_MESH_ToOrigin to; | ||
1473 | struct GNUNET_MessageHeader *mh; | ||
1474 | |||
1475 | GNUNET_assert (size >= th->size); | ||
1476 | mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (to)]; | ||
1477 | psize = th->notify (th->notify_cls, size - sizeof (to), mh); | ||
1478 | LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin, type %s\n", | ||
1479 | GNUNET_MESH_DEBUG_M2S (ntohs (mh->type))); | ||
1480 | if (psize > 0) | ||
1481 | { | ||
1482 | psize += sizeof (to); | ||
1483 | GNUNET_assert (size >= psize); | ||
1484 | to.header.size = htons (psize); | ||
1485 | to.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN); | ||
1486 | to.tid = htonl (t->tid); | ||
1487 | to.pid = htonl (t->next_send_pid); | ||
1488 | to.ttl = 0; | ||
1489 | memset (&to.oid, 0, sizeof (struct GNUNET_PeerIdentity)); | ||
1490 | memset (&to.sender, 0, sizeof (struct GNUNET_PeerIdentity)); | ||
1491 | memcpy (cbuf, &to, sizeof (to)); | ||
1492 | } | ||
1493 | } | ||
1494 | else if (th->target == 0) | ||
1495 | { | ||
1496 | /* multicast */ | ||
1497 | struct GNUNET_MESH_Multicast mc; | ||
1498 | struct GNUNET_MessageHeader *mh; | ||
1499 | |||
1500 | GNUNET_assert (size >= th->size); | ||
1501 | mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (mc)]; | ||
1502 | psize = th->notify (th->notify_cls, size - sizeof (mc), mh); | ||
1503 | LOG (GNUNET_ERROR_TYPE_DEBUG, " multicast, type %s\n", | ||
1504 | GNUNET_MESH_DEBUG_M2S (ntohs (mh->type))); | ||
1505 | if (psize > 0) | ||
1506 | { | ||
1507 | psize += sizeof (mc); | ||
1508 | GNUNET_assert (size >= psize); | ||
1509 | mc.header.size = htons (psize); | ||
1510 | mc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); | ||
1511 | mc.tid = htonl (t->tid); | ||
1512 | mc.pid = htonl (t->next_send_pid); | ||
1513 | mc.ttl = 0; | ||
1514 | memset (&mc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); | ||
1515 | memcpy (cbuf, &mc, sizeof (mc)); | ||
1516 | } | ||
1517 | } | ||
1518 | else | ||
1519 | { | ||
1520 | /* unicast */ | ||
1521 | struct GNUNET_MESH_Unicast uc; | ||
1522 | struct GNUNET_MessageHeader *mh; | ||
1523 | |||
1524 | GNUNET_assert (size >= th->size); | ||
1525 | mh = (struct GNUNET_MessageHeader *) &cbuf[sizeof (uc)]; | ||
1526 | psize = th->notify (th->notify_cls, size - sizeof (uc), mh); | ||
1527 | LOG (GNUNET_ERROR_TYPE_DEBUG, " unicast, type %s\n", | ||
1528 | GNUNET_MESH_DEBUG_M2S (ntohs (mh->type))); | ||
1529 | if (psize > 0) | ||
1530 | { | ||
1531 | psize += sizeof (uc); | ||
1532 | GNUNET_assert (size >= psize); | ||
1533 | uc.header.size = htons (psize); | ||
1534 | uc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_UNICAST); | ||
1535 | uc.tid = htonl (t->tid); | ||
1536 | uc.pid = htonl (t->next_send_pid); | ||
1537 | uc.ttl = 0; | ||
1538 | memset (&uc.oid, 0, sizeof (struct GNUNET_PeerIdentity)); | ||
1539 | GNUNET_PEER_resolve (th->target, &uc.destination); | ||
1540 | memcpy (cbuf, &uc, sizeof (uc)); | ||
1541 | } | ||
1542 | } | ||
1543 | t->next_send_pid++; | ||
1544 | } | ||
1545 | else | ||
1546 | { | ||
1547 | struct GNUNET_MessageHeader *mh = (struct GNUNET_MessageHeader *) &th[1]; | ||
1548 | |||
1549 | LOG (GNUNET_ERROR_TYPE_DEBUG, " mesh traffic, type %s\n", | ||
1550 | GNUNET_MESH_DEBUG_M2S (ntohs (mh->type))); | ||
1551 | memcpy (cbuf, &th[1], th->size); | ||
1552 | psize = th->size; | ||
1553 | } | ||
1554 | if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
1555 | GNUNET_SCHEDULER_cancel (th->timeout_task); | ||
1556 | GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); | ||
1557 | GNUNET_free (th); | ||
1558 | next = h->th_head; | ||
1559 | nsize = message_ready_size (h); | ||
1560 | cbuf += psize; | ||
1561 | size -= psize; | ||
1562 | tsize += psize; | ||
1563 | } | ||
1564 | LOG (GNUNET_ERROR_TYPE_DEBUG, " total size: %u\n", tsize); | ||
1565 | h->th = NULL; | ||
1566 | size = message_ready_size (h); | ||
1567 | if (0 != size) | ||
1568 | { | ||
1569 | LOG (GNUNET_ERROR_TYPE_DEBUG, " next size: %u\n", size); | ||
1570 | h->th = | ||
1571 | GNUNET_CLIENT_notify_transmit_ready (h->client, size, | ||
1572 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1573 | GNUNET_YES, &send_callback, h); | ||
1574 | } | ||
1575 | else | ||
1576 | { | ||
1577 | if (NULL != h->th_head) | ||
1578 | LOG (GNUNET_ERROR_TYPE_DEBUG, " can't transmit any more\n"); | ||
1579 | else | ||
1580 | LOG (GNUNET_ERROR_TYPE_DEBUG, " nothing left to transmit\n"); | ||
1581 | } | ||
1582 | if (GNUNET_NO == h->in_receive) | ||
1583 | { | ||
1584 | LOG (GNUNET_ERROR_TYPE_DEBUG, " start receiving from service\n"); | ||
1585 | h->in_receive = GNUNET_YES; | ||
1586 | GNUNET_CLIENT_receive (h->client, &msg_received, h, | ||
1587 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
1588 | } | ||
1589 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Send packet() END\n"); | ||
1590 | return tsize; | ||
1591 | } | ||
1592 | |||
1593 | |||
1594 | /** | ||
1595 | * Auxiliary function to send an already constructed packet to the service. | ||
1596 | * Takes care of creating a new queue element, copying the message and | ||
1597 | * calling the tmt_rdy function if necessary. | ||
1598 | * | ||
1599 | * @param h mesh handle | ||
1600 | * @param msg message to transmit | ||
1601 | * @param tunnel tunnel this send is related to (NULL if N/A) | ||
1602 | */ | ||
1603 | static void | ||
1604 | send_packet (struct GNUNET_MESH_Handle *h, | ||
1605 | const struct GNUNET_MessageHeader *msg, | ||
1606 | struct GNUNET_MESH_Tunnel *tunnel) | ||
1607 | { | ||
1608 | struct GNUNET_MESH_TransmitHandle *th; | ||
1609 | size_t msize; | ||
1610 | |||
1611 | LOG (GNUNET_ERROR_TYPE_DEBUG, " Sending message to service: %s\n", | ||
1612 | GNUNET_MESH_DEBUG_M2S(ntohs(msg->type))); | ||
1613 | msize = ntohs (msg->size); | ||
1614 | th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle) + msize); | ||
1615 | th->timeout = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
1616 | th->size = msize; | ||
1617 | th->tunnel = tunnel; | ||
1618 | memcpy (&th[1], msg, msize); | ||
1619 | add_to_queue (h, th); | ||
1620 | LOG (GNUNET_ERROR_TYPE_DEBUG, " queued\n"); | ||
1621 | if (NULL != h->th) | ||
1622 | return; | ||
1623 | LOG (GNUNET_ERROR_TYPE_DEBUG, " calling ntfy tmt rdy for %u bytes\n", msize); | ||
1624 | h->th = | ||
1625 | GNUNET_CLIENT_notify_transmit_ready (h->client, msize, | ||
1626 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
1627 | GNUNET_YES, &send_callback, h); | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | /******************************************************************************/ | ||
1632 | /********************** API CALL DEFINITIONS *************************/ | ||
1633 | /******************************************************************************/ | ||
1634 | |||
1635 | /** | ||
1636 | * Connect to the mesh service. | ||
1637 | * | ||
1638 | * @param cfg configuration to use | ||
1639 | * @param cls closure for the various callbacks that follow | ||
1640 | * (including handlers in the handlers array) | ||
1641 | * @param new_tunnel function called when an *inbound* tunnel is created | ||
1642 | * @param cleaner function called when an *inbound* tunnel is destroyed by the | ||
1643 | * remote peer, it is *not* called if GNUNET_MESH_tunnel_destroy | ||
1644 | * is called on the tunnel | ||
1645 | * @param handlers callbacks for messages we care about, NULL-terminated | ||
1646 | * note that the mesh is allowed to drop notifications about | ||
1647 | * inbound messages if the client does not process them fast | ||
1648 | * enough (for this notification type, a bounded queue is used) | ||
1649 | * @param stypes list of the applications that this client claims to provide | ||
1650 | * @return handle to the mesh service NULL on error | ||
1651 | * (in this case, init is never called) | ||
1652 | */ | ||
1653 | struct GNUNET_MESH_Handle * | ||
1654 | GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls, | ||
1655 | GNUNET_MESH_InboundTunnelNotificationHandler new_tunnel, | ||
1656 | GNUNET_MESH_TunnelEndHandler cleaner, | ||
1657 | const struct GNUNET_MESH_MessageHandler *handlers, | ||
1658 | const GNUNET_MESH_ApplicationType *stypes) | ||
1659 | { | ||
1660 | struct GNUNET_MESH_Handle *h; | ||
1661 | size_t size; | ||
1662 | |||
1663 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect()\n"); | ||
1664 | h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle)); | ||
1665 | LOG (GNUNET_ERROR_TYPE_DEBUG, " addr %p\n", h); | ||
1666 | h->cfg = cfg; | ||
1667 | h->new_tunnel = new_tunnel; | ||
1668 | h->cleaner = cleaner; | ||
1669 | h->client = GNUNET_CLIENT_connect ("mesh", cfg); | ||
1670 | if (h->client == NULL) | ||
1671 | { | ||
1672 | GNUNET_break (0); | ||
1673 | GNUNET_free (h); | ||
1674 | return NULL; | ||
1675 | } | ||
1676 | h->cls = cls; | ||
1677 | h->message_handlers = handlers; | ||
1678 | h->next_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_CLI; | ||
1679 | h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1680 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
1681 | |||
1682 | /* count apps */ | ||
1683 | for (h->n_applications = 0; | ||
1684 | stypes && stypes[h->n_applications]; | ||
1685 | h->n_applications++) ; | ||
1686 | if (0 < h->n_applications) | ||
1687 | { | ||
1688 | size = h->n_applications * sizeof (GNUNET_MESH_ApplicationType *); | ||
1689 | h->applications = GNUNET_malloc (size); | ||
1690 | memcpy (h->applications, stypes, size); | ||
1691 | } | ||
1692 | /* count handlers */ | ||
1693 | for (h->n_handlers = 0; | ||
1694 | handlers && handlers[h->n_handlers].type; | ||
1695 | h->n_handlers++) ; | ||
1696 | send_connect (h); | ||
1697 | LOG (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_MESH_connect() END\n"); | ||
1698 | return h; | ||
1699 | } | ||
1700 | |||
1701 | |||
1702 | /** | ||
1703 | * Disconnect from the mesh service. All tunnels will be destroyed. All tunnel | ||
1704 | * disconnect callbacks will be called on any still connected peers, notifying | ||
1705 | * about their disconnection. The registered inbound tunnel cleaner will be | ||
1706 | * called should any inbound tunnels still exist. | ||
1707 | * | ||
1708 | * @param handle connection to mesh to disconnect | ||
1709 | */ | ||
1710 | void | ||
1711 | GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) | ||
1712 | { | ||
1713 | struct GNUNET_MESH_Tunnel *t; | ||
1714 | struct GNUNET_MESH_Tunnel *aux; | ||
1715 | struct GNUNET_MESH_TransmitHandle *th; | ||
1716 | |||
1717 | LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH DISCONNECT\n"); | ||
1718 | |||
1719 | #if DEBUG_ACK | ||
1720 | LOG (GNUNET_ERROR_TYPE_INFO, "Sent %d ACKs\n", handle->acks_sent); | ||
1721 | LOG (GNUNET_ERROR_TYPE_INFO, "Recv %d ACKs\n\n", handle->acks_recv); | ||
1722 | #endif | ||
1723 | |||
1724 | t = handle->tunnels_head; | ||
1725 | while (NULL != t) | ||
1726 | { | ||
1727 | aux = t->next; | ||
1728 | if (t->tid < GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
1729 | { | ||
1730 | GNUNET_break (0); | ||
1731 | LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel %X not destroyed\n", t->tid); | ||
1732 | } | ||
1733 | destroy_tunnel (t, GNUNET_YES); | ||
1734 | t = aux; | ||
1735 | } | ||
1736 | while ( (th = handle->th_head) != NULL) | ||
1737 | { | ||
1738 | struct GNUNET_MessageHeader *msg; | ||
1739 | |||
1740 | /* Make sure it is an allowed packet (everything else should have been | ||
1741 | * already canceled). | ||
1742 | */ | ||
1743 | GNUNET_break (GNUNET_NO == th_is_payload (th)); | ||
1744 | msg = (struct GNUNET_MessageHeader *) &th[1]; | ||
1745 | switch (ntohs(msg->type)) | ||
1746 | { | ||
1747 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT: | ||
1748 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY: | ||
1749 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS: | ||
1750 | case GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL: | ||
1751 | break; | ||
1752 | default: | ||
1753 | GNUNET_break (0); | ||
1754 | LOG (GNUNET_ERROR_TYPE_ERROR, "unexpected msg %u\n", | ||
1755 | ntohs(msg->type)); | ||
1756 | } | ||
1757 | |||
1758 | GNUNET_CONTAINER_DLL_remove (handle->th_head, handle->th_tail, th); | ||
1759 | GNUNET_free (th); | ||
1760 | } | ||
1761 | |||
1762 | if (NULL != handle->th) | ||
1763 | { | ||
1764 | GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); | ||
1765 | handle->th = NULL; | ||
1766 | } | ||
1767 | if (NULL != handle->client) | ||
1768 | { | ||
1769 | GNUNET_CLIENT_disconnect (handle->client); | ||
1770 | handle->client = NULL; | ||
1771 | } | ||
1772 | if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) | ||
1773 | { | ||
1774 | GNUNET_SCHEDULER_cancel(handle->reconnect_task); | ||
1775 | handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
1776 | } | ||
1777 | GNUNET_free_non_null (handle->applications); | ||
1778 | GNUNET_free (handle); | ||
1779 | } | ||
1780 | |||
1781 | |||
1782 | /** | ||
1783 | * Announce to ther peer the availability of services described by the regex, | ||
1784 | * in order to be reachable to other peers via connect_by_string. | ||
1785 | * | ||
1786 | * Note that the first 8 characters are considered to be part of a prefix, | ||
1787 | * (for instance 'gnunet://'). If you put a variable part in there (*, +. ()), | ||
1788 | * all matching strings will be stored in the DHT. | ||
1789 | * | ||
1790 | * @param h Handle to mesh. | ||
1791 | * @param regex String with the regular expression describing local services. | ||
1792 | * @param compression_characters How many characters can be assigned to one | ||
1793 | * edge of the graph. The bigger the variability | ||
1794 | * of the data, the smaller this parameter should | ||
1795 | * be (down to 1). | ||
1796 | * For maximum compression, use strlen (regex) | ||
1797 | * or 0 (special value). Use with care! | ||
1798 | */ | ||
1799 | void | ||
1800 | GNUNET_MESH_announce_regex (struct GNUNET_MESH_Handle *h, | ||
1801 | const char *regex, | ||
1802 | unsigned int compression_characters) | ||
1803 | { | ||
1804 | struct GNUNET_MESH_RegexAnnounce *msg; | ||
1805 | size_t payload; | ||
1806 | size_t len; | ||
1807 | size_t msgsize; | ||
1808 | size_t offset; | ||
1809 | char buffer[UINT16_MAX]; | ||
1810 | |||
1811 | len = strlen (regex); | ||
1812 | payload = UINT16_MAX - sizeof(struct GNUNET_MESH_RegexAnnounce); | ||
1813 | msg = (struct GNUNET_MESH_RegexAnnounce *) buffer; | ||
1814 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ANNOUNCE_REGEX); | ||
1815 | msg->compression_characters = htons (compression_characters); | ||
1816 | offset = 0; | ||
1817 | do | ||
1818 | { | ||
1819 | msgsize = (len - offset > payload) ? payload : len - offset; | ||
1820 | memcpy (&msg[1], ®ex[offset], msgsize); | ||
1821 | offset += msgsize; | ||
1822 | msgsize += sizeof(struct GNUNET_MESH_RegexAnnounce); | ||
1823 | |||
1824 | msg->header.size = htons (msgsize); | ||
1825 | msg->last = htons (offset >= len); | ||
1826 | |||
1827 | send_packet (h, &msg->header, NULL); | ||
1828 | } while (len > offset); | ||
1829 | } | ||
1830 | |||
1831 | /** | ||
1832 | * Create a new tunnel (we're initiator and will be allowed to add/remove peers | ||
1833 | * and to broadcast). | ||
1834 | * | ||
1835 | * @param h mesh handle | ||
1836 | * @param tunnel_ctx client's tunnel context to associate with the tunnel | ||
1837 | * @param connect_handler function to call when peers are actually connected | ||
1838 | * @param disconnect_handler function to call when peers are disconnected | ||
1839 | * @param handler_cls closure for connect/disconnect handlers | ||
1840 | */ | ||
1841 | struct GNUNET_MESH_Tunnel * | ||
1842 | GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h, void *tunnel_ctx, | ||
1843 | GNUNET_MESH_PeerConnectHandler connect_handler, | ||
1844 | GNUNET_MESH_PeerDisconnectHandler disconnect_handler, | ||
1845 | void *handler_cls) | ||
1846 | { | ||
1847 | struct GNUNET_MESH_Tunnel *t; | ||
1848 | struct GNUNET_MESH_TunnelMessage msg; | ||
1849 | |||
1850 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating new tunnel\n"); | ||
1851 | t = create_tunnel (h, 0); | ||
1852 | LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", t); | ||
1853 | LOG (GNUNET_ERROR_TYPE_DEBUG, " number %X\n", t->tid); | ||
1854 | t->connect_handler = connect_handler; | ||
1855 | t->disconnect_handler = disconnect_handler; | ||
1856 | t->cls = handler_cls; | ||
1857 | t->ctx = tunnel_ctx; | ||
1858 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE); | ||
1859 | msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
1860 | msg.tunnel_id = htonl (t->tid); | ||
1861 | send_packet (h, &msg.header, t); | ||
1862 | return t; | ||
1863 | } | ||
1864 | |||
1865 | |||
1866 | /** | ||
1867 | * Destroy an existing tunnel. The existing callback for the tunnel will NOT | ||
1868 | * be called. | ||
1869 | * | ||
1870 | * @param tunnel tunnel handle | ||
1871 | */ | ||
1872 | void | ||
1873 | GNUNET_MESH_tunnel_destroy (struct GNUNET_MESH_Tunnel *tunnel) | ||
1874 | { | ||
1875 | struct GNUNET_MESH_Handle *h; | ||
1876 | struct GNUNET_MESH_TunnelMessage msg; | ||
1877 | struct GNUNET_MESH_TransmitHandle *th; | ||
1878 | |||
1879 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying tunnel\n"); | ||
1880 | h = tunnel->mesh; | ||
1881 | |||
1882 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); | ||
1883 | msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
1884 | msg.tunnel_id = htonl (tunnel->tid); | ||
1885 | th = h->th_head; | ||
1886 | while (th != NULL) | ||
1887 | { | ||
1888 | struct GNUNET_MESH_TransmitHandle *aux; | ||
1889 | if (th->tunnel == tunnel) | ||
1890 | { | ||
1891 | aux = th->next; | ||
1892 | /* FIXME call the handler? */ | ||
1893 | if (GNUNET_YES == th_is_payload (th)) | ||
1894 | th->notify (th->notify_cls, 0, NULL); | ||
1895 | GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th); | ||
1896 | GNUNET_free (th); | ||
1897 | th = aux; | ||
1898 | } | ||
1899 | else | ||
1900 | th = th->next; | ||
1901 | } | ||
1902 | |||
1903 | destroy_tunnel (tunnel, GNUNET_NO); | ||
1904 | send_packet (h, &msg.header, NULL); | ||
1905 | } | ||
1906 | |||
1907 | /** | ||
1908 | * Request that the tunnel data rate is limited to the speed of the slowest | ||
1909 | * receiver. | ||
1910 | * | ||
1911 | * @param tunnel Tunnel affected. | ||
1912 | */ | ||
1913 | void | ||
1914 | GNUNET_MESH_tunnel_speed_min (struct GNUNET_MESH_Tunnel *tunnel) | ||
1915 | { | ||
1916 | struct GNUNET_MESH_TunnelMessage msg; | ||
1917 | struct GNUNET_MESH_Handle *h; | ||
1918 | |||
1919 | h = tunnel->mesh; | ||
1920 | tunnel->speed_min = GNUNET_YES; | ||
1921 | |||
1922 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_MIN); | ||
1923 | msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
1924 | msg.tunnel_id = htonl (tunnel->tid); | ||
1925 | |||
1926 | send_packet (h, &msg.header, NULL); | ||
1927 | } | ||
1928 | |||
1929 | |||
1930 | /** | ||
1931 | * Request that the tunnel data rate is limited to the speed of the fastest | ||
1932 | * receiver. This is the default behavior. | ||
1933 | * | ||
1934 | * @param tunnel Tunnel affected. | ||
1935 | */ | ||
1936 | void | ||
1937 | GNUNET_MESH_tunnel_speed_max (struct GNUNET_MESH_Tunnel *tunnel) | ||
1938 | { | ||
1939 | struct GNUNET_MESH_TunnelMessage msg; | ||
1940 | struct GNUNET_MESH_Handle *h; | ||
1941 | |||
1942 | h = tunnel->mesh; | ||
1943 | tunnel->speed_min = GNUNET_NO; | ||
1944 | |||
1945 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_MAX); | ||
1946 | msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
1947 | msg.tunnel_id = htonl (tunnel->tid); | ||
1948 | |||
1949 | send_packet (h, &msg.header, NULL); | ||
1950 | } | ||
1951 | |||
1952 | /** | ||
1953 | * Turn on/off the buffering status of the tunnel. | ||
1954 | * | ||
1955 | * @param tunnel Tunnel affected. | ||
1956 | * @param buffer GNUNET_YES to turn buffering on (default), | ||
1957 | * GNUNET_NO otherwise. | ||
1958 | */ | ||
1959 | void | ||
1960 | GNUNET_MESH_tunnel_buffer (struct GNUNET_MESH_Tunnel *tunnel, int buffer) | ||
1961 | { | ||
1962 | struct GNUNET_MESH_TunnelMessage msg; | ||
1963 | struct GNUNET_MESH_Handle *h; | ||
1964 | |||
1965 | h = tunnel->mesh; | ||
1966 | tunnel->buffering = buffer; | ||
1967 | tunnel->max_send_pid = tunnel->next_send_pid; | ||
1968 | |||
1969 | if (GNUNET_YES == buffer) | ||
1970 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_BUFFER); | ||
1971 | else | ||
1972 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_NOBUFFER); | ||
1973 | msg.header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage)); | ||
1974 | msg.tunnel_id = htonl (tunnel->tid); | ||
1975 | |||
1976 | send_packet (h, &msg.header, NULL); | ||
1977 | } | ||
1978 | |||
1979 | |||
1980 | /** | ||
1981 | * Request that a peer should be added to the tunnel. The existing | ||
1982 | * connect handler will be called ONCE with either success or failure. | ||
1983 | * This function should NOT be called again with the same peer before the | ||
1984 | * connect handler is called. | ||
1985 | * FIXME: I think the above documentation is false. I think it should | ||
1986 | * read: "The connect handler will be called once the peer was actually | ||
1987 | * successfully added to the multicast group. This function should | ||
1988 | * not be called twice for the same peer (unless, of course, | ||
1989 | * the peer was removed using GNUNET_MESH_peer_Request_connect_del in | ||
1990 | * the meantime). | ||
1991 | * | ||
1992 | * @param tunnel handle to existing tunnel | ||
1993 | * @param peer peer to add | ||
1994 | */ | ||
1995 | void | ||
1996 | GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel, | ||
1997 | const struct GNUNET_PeerIdentity *peer) | ||
1998 | { | ||
1999 | struct GNUNET_MESH_PeerControl msg; | ||
2000 | GNUNET_PEER_Id peer_id; | ||
2001 | unsigned int i; | ||
2002 | |||
2003 | peer_id = GNUNET_PEER_intern (peer); | ||
2004 | for (i = 0; i < tunnel->npeers; i++) | ||
2005 | { | ||
2006 | if (tunnel->peers[i]->id == peer_id) | ||
2007 | { | ||
2008 | /* Peer already exists in tunnel */ | ||
2009 | GNUNET_PEER_change_rc (peer_id, -1); | ||
2010 | GNUNET_break (0); | ||
2011 | return; | ||
2012 | } | ||
2013 | } | ||
2014 | if (NULL == add_peer_to_tunnel (tunnel, peer)) | ||
2015 | return; | ||
2016 | |||
2017 | msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); | ||
2018 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); | ||
2019 | msg.tunnel_id = htonl (tunnel->tid); | ||
2020 | msg.peer = *peer; | ||
2021 | send_packet (tunnel->mesh, &msg.header, tunnel); | ||
2022 | } | ||
2023 | |||
2024 | |||
2025 | /** | ||
2026 | * Request that a peer should be removed from the tunnel. The existing | ||
2027 | * disconnect handler will be called ONCE if we were connected. | ||
2028 | * | ||
2029 | * @param tunnel handle to existing tunnel | ||
2030 | * @param peer peer to remove | ||
2031 | */ | ||
2032 | void | ||
2033 | GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel, | ||
2034 | const struct GNUNET_PeerIdentity *peer) | ||
2035 | { | ||
2036 | struct GNUNET_MESH_PeerControl msg; | ||
2037 | GNUNET_PEER_Id peer_id; | ||
2038 | unsigned int i; | ||
2039 | |||
2040 | peer_id = GNUNET_PEER_search (peer); | ||
2041 | if (0 == peer_id) | ||
2042 | { | ||
2043 | GNUNET_break (0); | ||
2044 | return; | ||
2045 | } | ||
2046 | for (i = 0; i < tunnel->npeers; i++) | ||
2047 | if (tunnel->peers[i]->id == peer_id) | ||
2048 | break; | ||
2049 | if (i == tunnel->npeers) | ||
2050 | { | ||
2051 | GNUNET_break (0); | ||
2052 | return; | ||
2053 | } | ||
2054 | if (NULL != tunnel->disconnect_handler && tunnel->peers[i]->connected == 1) | ||
2055 | tunnel->disconnect_handler (tunnel->cls, peer); | ||
2056 | GNUNET_PEER_change_rc (peer_id, -1); | ||
2057 | GNUNET_free (tunnel->peers[i]); | ||
2058 | tunnel->peers[i] = tunnel->peers[tunnel->npeers - 1]; | ||
2059 | GNUNET_array_grow (tunnel->peers, tunnel->npeers, tunnel->npeers - 1); | ||
2060 | |||
2061 | msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); | ||
2062 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL); | ||
2063 | msg.tunnel_id = htonl (tunnel->tid); | ||
2064 | memcpy (&msg.peer, peer, sizeof (struct GNUNET_PeerIdentity)); | ||
2065 | send_packet (tunnel->mesh, &msg.header, tunnel); | ||
2066 | } | ||
2067 | |||
2068 | /** | ||
2069 | * Request that the mesh should try to connect to a peer matching the | ||
2070 | * description given in the service string. | ||
2071 | * | ||
2072 | * FIXME: allow multiple? how to deal with reconnect? | ||
2073 | * | ||
2074 | * @param tunnel handle to existing tunnel | ||
2075 | * @param description string describing the destination node requirements | ||
2076 | */ | ||
2077 | void | ||
2078 | GNUNET_MESH_peer_request_connect_by_string (struct GNUNET_MESH_Tunnel *tunnel, | ||
2079 | const char *description) | ||
2080 | { | ||
2081 | struct GNUNET_MESH_ConnectPeerByString *m; | ||
2082 | size_t len; | ||
2083 | size_t msgsize; | ||
2084 | |||
2085 | len = strlen (description); | ||
2086 | msgsize = sizeof(struct GNUNET_MESH_ConnectPeerByString) + len; | ||
2087 | GNUNET_assert (UINT16_MAX > msgsize); | ||
2088 | { | ||
2089 | char buffer[msgsize]; | ||
2090 | |||
2091 | m = (struct GNUNET_MESH_ConnectPeerByString *) buffer; | ||
2092 | m->header.size = htons (msgsize); | ||
2093 | m->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD_BY_STRING); | ||
2094 | m->tunnel_id = htonl (tunnel->tid); | ||
2095 | memcpy(&m[1], description, len); | ||
2096 | |||
2097 | send_packet (tunnel->mesh, &m->header, tunnel); | ||
2098 | } | ||
2099 | } | ||
2100 | |||
2101 | |||
2102 | /** | ||
2103 | * Request that the given peer isn't added to this tunnel in calls to | ||
2104 | * connect_by_* calls, (due to misbehaviour, bad performance, ...). | ||
2105 | * | ||
2106 | * @param tunnel handle to existing tunnel. | ||
2107 | * @param peer peer identity of the peer which should be blacklisted | ||
2108 | * for the tunnel. | ||
2109 | */ | ||
2110 | void | ||
2111 | GNUNET_MESH_peer_blacklist (struct GNUNET_MESH_Tunnel *tunnel, | ||
2112 | const struct GNUNET_PeerIdentity *peer) | ||
2113 | { | ||
2114 | struct GNUNET_MESH_PeerControl msg; | ||
2115 | |||
2116 | msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); | ||
2117 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_BLACKLIST); | ||
2118 | msg.tunnel_id = htonl (tunnel->tid); | ||
2119 | msg.peer = *peer; | ||
2120 | send_packet (tunnel->mesh, &msg.header, tunnel); | ||
2121 | |||
2122 | return; | ||
2123 | } | ||
2124 | |||
2125 | |||
2126 | /** | ||
2127 | * Request that the given peer isn't blacklisted anymore from this tunnel, | ||
2128 | * and therefore can be added in future calls to connect_by_*. | ||
2129 | * The peer must have been previously blacklisted for this tunnel. | ||
2130 | * | ||
2131 | * @param tunnel handle to existing tunnel. | ||
2132 | * @param peer peer identity of the peer which shouldn't be blacklisted | ||
2133 | * for the tunnel anymore. | ||
2134 | */ | ||
2135 | void | ||
2136 | GNUNET_MESH_peer_unblacklist (struct GNUNET_MESH_Tunnel *tunnel, | ||
2137 | const struct GNUNET_PeerIdentity *peer) | ||
2138 | { | ||
2139 | struct GNUNET_MESH_PeerControl msg; | ||
2140 | |||
2141 | msg.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); | ||
2142 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_UNBLACKLIST); | ||
2143 | msg.tunnel_id = htonl (tunnel->tid); | ||
2144 | msg.peer = *peer; | ||
2145 | send_packet (tunnel->mesh, &msg.header, tunnel); | ||
2146 | |||
2147 | return; | ||
2148 | } | ||
2149 | |||
2150 | |||
2151 | struct GNUNET_MESH_TransmitHandle * | ||
2152 | GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel, int cork, | ||
2153 | struct GNUNET_TIME_Relative maxdelay, | ||
2154 | size_t notify_size, | ||
2155 | GNUNET_CONNECTION_TransmitReadyNotify notify, | ||
2156 | void *notify_cls) | ||
2157 | { | ||
2158 | struct GNUNET_MESH_TransmitHandle *th; | ||
2159 | size_t overhead; | ||
2160 | |||
2161 | GNUNET_assert (NULL != tunnel); | ||
2162 | LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY\n"); | ||
2163 | LOG (GNUNET_ERROR_TYPE_DEBUG, " on tunnel %X\n", tunnel->tid); | ||
2164 | if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
2165 | LOG (GNUNET_ERROR_TYPE_DEBUG, " to origin\n"); | ||
2166 | else | ||
2167 | LOG (GNUNET_ERROR_TYPE_DEBUG, " to destination\n"); | ||
2168 | LOG (GNUNET_ERROR_TYPE_DEBUG, " payload size %u\n", notify_size); | ||
2169 | GNUNET_assert (NULL != notify); | ||
2170 | GNUNET_assert (0 == tunnel->packet_size); // Only one data packet allowed | ||
2171 | th = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle)); | ||
2172 | th->tunnel = tunnel; | ||
2173 | th->timeout = GNUNET_TIME_relative_to_absolute (maxdelay); | ||
2174 | th->target = GNUNET_PEER_intern (target); | ||
2175 | if (tunnel->tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) | ||
2176 | overhead = sizeof (struct GNUNET_MESH_ToOrigin); | ||
2177 | else if (NULL == target) | ||
2178 | overhead = sizeof (struct GNUNET_MESH_Multicast); | ||
2179 | else | ||
2180 | overhead = sizeof (struct GNUNET_MESH_Unicast); | ||
2181 | tunnel->packet_size = th->size = notify_size + overhead; | ||
2182 | LOG (GNUNET_ERROR_TYPE_DEBUG, " total size %u\n", th->size); | ||
2183 | th->notify = notify; | ||
2184 | th->notify_cls = notify_cls; | ||
2185 | add_to_queue (tunnel->mesh, th); | ||
2186 | if (NULL != tunnel->mesh->th) | ||
2187 | return th; | ||
2188 | if (GMC_is_pid_bigger(tunnel->next_send_pid, tunnel->max_send_pid)) | ||
2189 | return th; | ||
2190 | LOG (GNUNET_ERROR_TYPE_DEBUG, " call notify tmt rdy\n"); | ||
2191 | tunnel->mesh->th = | ||
2192 | GNUNET_CLIENT_notify_transmit_ready (tunnel->mesh->client, th->size, | ||
2193 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
2194 | GNUNET_YES, &send_callback, | ||
2195 | tunnel->mesh); | ||
2196 | LOG (GNUNET_ERROR_TYPE_DEBUG, "MESH NOTIFY TRANSMIT READY END\n"); | ||
2197 | return th; | ||
2198 | } | ||
2199 | |||
2200 | |||
2201 | /** | ||
2202 | * Cancel the specified transmission-ready notification. | ||
2203 | * | ||
2204 | * @param th handle that was returned by "notify_transmit_ready". | ||
2205 | */ | ||
2206 | void | ||
2207 | GNUNET_MESH_notify_transmit_ready_cancel (struct GNUNET_MESH_TransmitHandle *th) | ||
2208 | { | ||
2209 | struct GNUNET_MESH_Handle *mesh; | ||
2210 | |||
2211 | th->tunnel->packet_size = 0; | ||
2212 | mesh = th->tunnel->mesh; | ||
2213 | if (th->timeout_task != GNUNET_SCHEDULER_NO_TASK) | ||
2214 | GNUNET_SCHEDULER_cancel (th->timeout_task); | ||
2215 | GNUNET_CONTAINER_DLL_remove (mesh->th_head, mesh->th_tail, th); | ||
2216 | GNUNET_free (th); | ||
2217 | if ((0 == message_ready_size (mesh)) && (NULL != mesh->th)) | ||
2218 | { | ||
2219 | /* queue empty, no point in asking for transmission */ | ||
2220 | GNUNET_CLIENT_notify_transmit_ready_cancel (mesh->th); | ||
2221 | mesh->th = NULL; | ||
2222 | } | ||
2223 | } | ||
2224 | |||
2225 | |||
2226 | /** | ||
2227 | * Request information about the running mesh peer. | ||
2228 | * The callback will be called for every tunnel known to the service, | ||
2229 | * listing all active peers that blong to the tunnel. | ||
2230 | * | ||
2231 | * If called again on the same handle, it will overwrite the previous | ||
2232 | * callback and cls. To retrieve the cls, monitor_cancel must be | ||
2233 | * called first. | ||
2234 | * | ||
2235 | * WARNING: unstable API, likely to change in the future! | ||
2236 | * | ||
2237 | * @param h Handle to the mesh peer. | ||
2238 | * @param callback Function to call with the requested data. | ||
2239 | * @param callback_cls Closure for @c callback. | ||
2240 | */ | ||
2241 | void | ||
2242 | GNUNET_MESH_get_tunnels (struct GNUNET_MESH_Handle *h, | ||
2243 | GNUNET_MESH_TunnelsCB callback, | ||
2244 | void *callback_cls) | ||
2245 | { | ||
2246 | struct GNUNET_MessageHeader msg; | ||
2247 | |||
2248 | msg.size = htons (sizeof (msg)); | ||
2249 | msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS); | ||
2250 | send_packet (h, &msg, NULL); | ||
2251 | h->tunnels_cb = callback; | ||
2252 | h->tunnels_cls = callback_cls; | ||
2253 | |||
2254 | return; | ||
2255 | } | ||
2256 | |||
2257 | |||
2258 | /** | ||
2259 | * Cancel a monitor request. The monitor callback will not be called. | ||
2260 | * | ||
2261 | * @param h Mesh handle. | ||
2262 | * | ||
2263 | * @return Closure given to GNUNET_MESH_monitor, if any. | ||
2264 | */ | ||
2265 | void * | ||
2266 | GNUNET_MESH_get_tunnels_cancel (struct GNUNET_MESH_Handle *h) | ||
2267 | { | ||
2268 | void *cls; | ||
2269 | |||
2270 | cls = h->tunnels_cls; | ||
2271 | h->tunnels_cb = NULL; | ||
2272 | h->tunnels_cls = NULL; | ||
2273 | return cls; | ||
2274 | } | ||
2275 | |||
2276 | |||
2277 | /** | ||
2278 | * Request information about a specific tunnel of the running mesh peer. | ||
2279 | * | ||
2280 | * WARNING: unstable API, likely to change in the future! | ||
2281 | * | ||
2282 | * @param h Handle to the mesh peer. | ||
2283 | * @param initiator ID of the owner of the tunnel. | ||
2284 | * @param tunnel_number Tunnel number. | ||
2285 | * @param callback Function to call with the requested data. | ||
2286 | * @param callback_cls Closure for @c callback. | ||
2287 | */ | ||
2288 | void | ||
2289 | GNUNET_MESH_show_tunnel (struct GNUNET_MESH_Handle *h, | ||
2290 | struct GNUNET_PeerIdentity *initiator, | ||
2291 | unsigned int tunnel_number, | ||
2292 | GNUNET_MESH_TunnelCB callback, | ||
2293 | void *callback_cls) | ||
2294 | { | ||
2295 | struct GNUNET_MESH_LocalMonitor msg; | ||
2296 | |||
2297 | msg.header.size = htons (sizeof (msg)); | ||
2298 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL); | ||
2299 | msg.npeers = htonl (0); | ||
2300 | msg.owner = *initiator; | ||
2301 | msg.tunnel_id = htonl (tunnel_number); | ||
2302 | msg.reserved = 0; | ||
2303 | send_packet (h, &msg.header, NULL); | ||
2304 | h->tunnel_cb = callback; | ||
2305 | h->tunnel_cls = callback_cls; | ||
2306 | |||
2307 | return; | ||
2308 | } | ||
2309 | |||
2310 | |||
2311 | /** | ||
2312 | * Transition API for tunnel ctx management | ||
2313 | */ | ||
2314 | void | ||
2315 | GNUNET_MESH_tunnel_set_data (struct GNUNET_MESH_Tunnel *tunnel, void *data) | ||
2316 | { | ||
2317 | tunnel->ctx = data; | ||
2318 | } | ||
2319 | |||
2320 | /** | ||
2321 | * Transition API for tunnel ctx management | ||
2322 | */ | ||
2323 | void * | ||
2324 | GNUNET_MESH_tunnel_get_data (struct GNUNET_MESH_Tunnel *tunnel) | ||
2325 | { | ||
2326 | return tunnel->ctx; | ||
2327 | } | ||
2328 | |||
2329 | |||