aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBart Polot <bart@net.in.tum.de>2013-01-17 17:09:37 +0000
committerBart Polot <bart@net.in.tum.de>2013-01-17 17:09:37 +0000
commit47cb85c43071a16ec899e7f8fb45b3eec39895ec (patch)
tree4b3ec6dd6eb72488826053d0ce9fc45d26df3df6 /src
parent37a8306064f1fe08c1471c46a3cd913cd22f8a60 (diff)
downloadgnunet-47cb85c43071a16ec899e7f8fb45b3eec39895ec.tar.gz
gnunet-47cb85c43071a16ec899e7f8fb45b3eec39895ec.zip
Move regex DHT integration from mesh to regex
Diffstat (limited to 'src')
-rw-r--r--src/include/block_regex.h (renamed from src/include/block_mesh.h)53
-rw-r--r--src/include/gnunet_block_lib.h4
-rw-r--r--src/include/gnunet_regex_lib.h101
-rw-r--r--src/mesh/Makefile.am19
-rw-r--r--src/mesh/gnunet-service-mesh-new.c2147
-rw-r--r--src/mesh/gnunet-service-mesh.c1026
-rw-r--r--src/mesh/plugin_block_mesh.c91
-rw-r--r--src/regex/Makefile.am42
-rw-r--r--src/regex/plugin_block_regex.c221
-rw-r--r--src/regex/regex.c3
-rw-r--r--src/regex/regex_block_lib.c (renamed from src/mesh/mesh_block_lib.c)42
-rw-r--r--src/regex/regex_block_lib.h (renamed from src/mesh/mesh_block_lib.h)36
-rw-r--r--src/regex/regex_dht.c754
13 files changed, 2487 insertions, 2052 deletions
diff --git a/src/include/block_mesh.h b/src/include/block_regex.h
index f051e6666..282c626a2 100644
--- a/src/include/block_mesh.h
+++ b/src/include/block_regex.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors) 3 (C) 2012,2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -19,37 +19,30 @@
19*/ 19*/
20 20
21/** 21/**
22 * @file include/block_mesh.h 22 * @file include/block_regex.h
23 * @brief fs block formats (shared between fs and block) 23 * @brief regex block formats
24 * @author Bartlomiej Polot 24 * @author Bartlomiej Polot
25 */ 25 */
26#ifndef BLOCK_MESH_H 26#ifndef BLOCK_REGEX_H
27#define BLOCK_MESH_H 27#define BLOCK_REGEX_H
28
29#ifdef __cplusplus
30extern "C"
31{
32#if 0
33 /* keep Emacsens' auto-indent happy */
34}
35#endif
36#endif
28 37
29#include "gnunet_util_lib.h" 38#include "gnunet_util_lib.h"
30#include "gnunet_mesh_service.h"
31#include <stdint.h> 39#include <stdint.h>
32 40
33/**
34 * @brief peer block (announce peer + type)
35 */
36struct PBlock
37{
38 /**
39 * Identity of the peer
40 */
41 struct GNUNET_PeerIdentity id;
42
43 /**
44 * Type of service offered
45 */
46 GNUNET_MESH_ApplicationType type;
47};
48 41
49/** 42/**
50 * @brief A MeshRegexBlock contains one or more of this struct in the payload. 43 * @brief A RegexBlock contains one or more of this struct in the payload.
51 */ 44 */
52struct MeshRegexEdge 45struct RegexEdge
53{ 46{
54 /** 47 /**
55 * Destination of this edge. 48 * Destination of this edge.
@@ -67,7 +60,7 @@ struct MeshRegexEdge
67/** 60/**
68 * @brief Block to announce a regex state. 61 * @brief Block to announce a regex state.
69 */ 62 */
70struct MeshRegexBlock 63struct RegexBlock
71{ 64{
72 /** 65 /**
73 * The key of the state. 66 * The key of the state.
@@ -90,13 +83,13 @@ struct MeshRegexBlock
90 int accepting; 83 int accepting;
91 84
92 /* char proof[n_proof] */ 85 /* char proof[n_proof] */
93 /* struct MeshEdge edges[n_edges] */ 86 /* struct RegexEdge edges[n_edges] */
94}; 87};
95 88
96/** 89/**
97 * @brief Block to announce a peer accepting a state. 90 * @brief Block to announce a peer accepting a state.
98 */ 91 */
99struct MeshRegexAccept 92struct RegexAccept
100{ 93{
101 /** 94 /**
102 * The key of the state. 95 * The key of the state.
@@ -116,4 +109,12 @@ struct MeshRegexAccept
116 struct GNUNET_PeerIdentity id; 109 struct GNUNET_PeerIdentity id;
117 110
118}; 111};
112
113#if 0 /* keep Emacsens' auto-indent happy */
114{
115#endif
116#ifdef __cplusplus
117}
118#endif
119
119#endif \ No newline at end of file 120#endif \ No newline at end of file
diff --git a/src/include/gnunet_block_lib.h b/src/include/gnunet_block_lib.h
index cd4b2a0ac..002d5c11b 100644
--- a/src/include/gnunet_block_lib.h
+++ b/src/include/gnunet_block_lib.h
@@ -113,12 +113,12 @@ enum GNUNET_BLOCK_Type
113 /** 113 /**
114 * Block to store a mesh regex state 114 * Block to store a mesh regex state
115 */ 115 */
116 GNUNET_BLOCK_TYPE_MESH_REGEX = 22, 116 GNUNET_BLOCK_TYPE_REGEX = 22,
117 117
118 /** 118 /**
119 * Block to store a mesh regex accepting state 119 * Block to store a mesh regex accepting state
120 */ 120 */
121 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT = 23 121 GNUNET_BLOCK_TYPE_REGEX_ACCEPT = 23
122}; 122};
123 123
124 124
diff --git a/src/include/gnunet_regex_lib.h b/src/include/gnunet_regex_lib.h
index 105ccee54..ebeb9e50c 100644
--- a/src/include/gnunet_regex_lib.h
+++ b/src/include/gnunet_regex_lib.h
@@ -28,6 +28,8 @@
28#define GNUNET_REGEX_LIB_H 28#define GNUNET_REGEX_LIB_H
29 29
30#include "gnunet_util_lib.h" 30#include "gnunet_util_lib.h"
31#include "gnunet_dht_service.h"
32#include "gnunet_statistics_service.h"
31 33
32#ifdef __cplusplus 34#ifdef __cplusplus
33extern "C" 35extern "C"
@@ -250,6 +252,105 @@ GNUNET_REGEX_ipv6toregex (const struct in6_addr *ipv6,
250 252
251 253
252 254
255/**
256 * Handle to store cached data about a regex announce.
257 */
258struct GNUNET_REGEX_announce_handle;
259
260/**
261 * Handle to store data about a regex search.
262 */
263struct GNUNET_REGEX_search_handle;
264
265/**
266 * Announce a regular expression: put all states of the automaton in the DHT.
267 * Does not free resources, must call GNUNET_REGEX_announce_cancel for that.
268 *
269 * @param dht An existing and valid DHT service handle.
270 * @param id ID to announce as provider of regex. Own ID in most cases.
271 * @param regex Regular expression to announce.
272 * @param compression How many characters per edge can we squeeze?
273 * @param stats Optional statistics handle to report usage. Can be NULL.
274 *
275 * @return Handle to reuse o free cached resources.
276 * Must be freed by calling GNUNET_REGEX_announce_cancel.
277 */
278struct GNUNET_REGEX_announce_handle *
279GNUNET_REGEX_announce (struct GNUNET_DHT_Handle *dht,
280 struct GNUNET_PeerIdentity *id,
281 const char *regex,
282 uint16_t compression,
283 struct GNUNET_STATISTICS_Handle *stats);
284
285/**
286 * Announce again a regular expression previously announced.
287 * Does use caching to speed up process.
288 *
289 * @param h Handle returned by a previous GNUNET_REGEX_announce call.
290 */
291void
292GNUNET_REGEX_reannounce (struct GNUNET_REGEX_announce_handle *h);
293
294
295/**
296 * Clear all cached data used by a regex announce.
297 * Does not close DHT connection.
298 *
299 * @param h Handle returned by a previous GNUNET_REGEX_announce call.
300 */
301void
302GNUNET_REGEX_announce_cancel (struct GNUNET_REGEX_announce_handle *h);
303
304
305/**
306 * Search callback function.
307 *
308 * @param cls Closure provided in GNUNET_REGEX_search.
309 * @param id Peer providing a regex that matches the string.
310 * @param get_path Path of the get request.
311 * @param get_path_length Lenght of get_path.
312 * @param put_path Path of the put request.
313 * @param put_path_length Length of the put_path.
314 */
315typedef void (*GNUNET_REGEX_Found)(void *cls,
316 const struct GNUNET_PeerIdentity *id,
317 const struct GNUNET_PeerIdentity *get_path,
318 unsigned int get_path_length,
319 const struct GNUNET_PeerIdentity *put_path,
320 unsigned int put_path_length);
321
322
323/**
324 * Search for a peer offering a regex matching certain string in the DHT.
325 * The search runs until GNUNET_REGEX_search_cancel is called, even if results
326 * are returned.
327 *
328 * @param dht An existing and valid DHT service handle.
329 * @param string String to match against the regexes in the DHT.
330 * @param callback Callback for found peers.
331 * @param callback_cls Closure for @c callback.
332 * @param stats Optional statistics handle to report usage. Can be NULL.
333 *
334 * @return Handle to stop search and free resources.
335 * Must be freed by calling GNUNET_REGEX_search_cancel.
336 */
337struct GNUNET_REGEX_search_handle *
338GNUNET_REGEX_search (struct GNUNET_DHT_Handle *dht,
339 const char *string,
340 GNUNET_REGEX_Found callback,
341 void *callback_cls,
342 struct GNUNET_STATISTICS_Handle *stats);
343
344/**
345 * Stop search and free all data used by a GNUNET_REGEX_search call.
346 * Does not close DHT connection.
347 *
348 * @param h Handle returned by a previous GNUNET_REGEX_search call.
349 */
350void
351GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_search_handle *h);
352
353
253#if 0 /* keep Emacsens' auto-indent happy */ 354#if 0 /* keep Emacsens' auto-indent happy */
254{ 355{
255#endif 356#endif
diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am
index 41f8c0444..5db9868ab 100644
--- a/src/mesh/Makefile.am
+++ b/src/mesh/Makefile.am
@@ -27,8 +27,7 @@ bin_PROGRAMS = \
27 gnunet-mesh 27 gnunet-mesh
28 28
29lib_LTLIBRARIES = \ 29lib_LTLIBRARIES = \
30 libgnunetmesh.la \ 30 libgnunetmesh.la
31 libgnunetmeshblock.la
32 31
33plugin_LTLIBRARIES = \ 32plugin_LTLIBRARIES = \
34 libgnunet_plugin_block_mesh.la 33 libgnunet_plugin_block_mesh.la
@@ -36,13 +35,11 @@ plugin_LTLIBRARIES = \
36libgnunet_plugin_block_mesh_la_SOURCES = \ 35libgnunet_plugin_block_mesh_la_SOURCES = \
37 plugin_block_mesh.c 36 plugin_block_mesh.c
38libgnunet_plugin_block_mesh_la_LIBADD = \ 37libgnunet_plugin_block_mesh_la_LIBADD = \
39 $(top_builddir)/src/mesh/libgnunetmeshblock.la \
40 $(top_builddir)/src/block/libgnunetblock.la \ 38 $(top_builddir)/src/block/libgnunetblock.la \
41 $(top_builddir)/src/util/libgnunetutil.la 39 $(top_builddir)/src/util/libgnunetutil.la
42libgnunet_plugin_block_mesh_la_LDFLAGS = \ 40libgnunet_plugin_block_mesh_la_LDFLAGS = \
43 $(GN_PLUGIN_LDFLAGS) 41 $(GN_PLUGIN_LDFLAGS)
44libgnunet_plugin_block_mesh_la_DEPENDENCIES = \ 42libgnunet_plugin_block_mesh_la_DEPENDENCIES = \
45 libgnunetmeshblock.la \
46 $(top_builddir)/src/block/libgnunetblock.la \ 43 $(top_builddir)/src/block/libgnunetblock.la \
47 $(top_builddir)/src/util/libgnunetutil.la 44 $(top_builddir)/src/util/libgnunetutil.la
48 45
@@ -56,16 +53,6 @@ libgnunetmesh_la_LDFLAGS = \
56 $(GN_LIB_LDFLAGS) $(WINFLAGS) \ 53 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
57 -version-info 2:0:1 54 -version-info 2:0:1
58 55
59libgnunetmeshblock_la_SOURCES = \
60 mesh_block_lib.c mesh_block_lib.h
61libgnunetmeshblock_la_LIBADD = \
62 $(top_builddir)/src/util/libgnunetutil.la \
63 $(XLIB) \
64 $(LTLIBINTL)
65libgnunetmeshblock_la_LDFLAGS = \
66 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
67 -version-info 2:0:0
68
69gnunet_service_mesh_SOURCES = \ 56gnunet_service_mesh_SOURCES = \
70 gnunet-service-mesh.c \ 57 gnunet-service-mesh.c \
71 mesh_tunnel_tree.c mesh_tunnel_tree.h \ 58 mesh_tunnel_tree.c mesh_tunnel_tree.h \
@@ -77,7 +64,6 @@ gnunet_service_mesh_LDADD = \
77 $(top_builddir)/src/dht/libgnunetdht.la \ 64 $(top_builddir)/src/dht/libgnunetdht.la \
78 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 65 $(top_builddir)/src/statistics/libgnunetstatistics.la \
79 $(top_builddir)/src/block/libgnunetblock.la \ 66 $(top_builddir)/src/block/libgnunetblock.la \
80 $(top_builddir)/src/mesh/libgnunetmeshblock.la \
81 $(top_builddir)/src/regex/libgnunetregex.la 67 $(top_builddir)/src/regex/libgnunetregex.la
82gnunet_service_mesh_DEPENDENCIES = \ 68gnunet_service_mesh_DEPENDENCIES = \
83 $(top_builddir)/src/util/libgnunetutil.la \ 69 $(top_builddir)/src/util/libgnunetutil.la \
@@ -85,7 +71,6 @@ gnunet_service_mesh_DEPENDENCIES = \
85 $(top_builddir)/src/dht/libgnunetdht.la \ 71 $(top_builddir)/src/dht/libgnunetdht.la \
86 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 72 $(top_builddir)/src/statistics/libgnunetstatistics.la \
87 $(top_builddir)/src/block/libgnunetblock.la \ 73 $(top_builddir)/src/block/libgnunetblock.la \
88 libgnunetmeshblock.la \
89 $(top_builddir)/src/regex/libgnunetregex.la 74 $(top_builddir)/src/regex/libgnunetregex.la
90if LINUX 75if LINUX
91gnunet_service_mesh_LDFLAGS = -lrt 76gnunet_service_mesh_LDFLAGS = -lrt
@@ -110,7 +95,6 @@ gnunet_service_mesh_new_LDADD = \
110 $(top_builddir)/src/dht/libgnunetdht.la \ 95 $(top_builddir)/src/dht/libgnunetdht.la \
111 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 96 $(top_builddir)/src/statistics/libgnunetstatistics.la \
112 $(top_builddir)/src/block/libgnunetblock.la \ 97 $(top_builddir)/src/block/libgnunetblock.la \
113 $(top_builddir)/src/mesh/libgnunetmeshblock.la \
114 $(top_builddir)/src/regex/libgnunetregex.la 98 $(top_builddir)/src/regex/libgnunetregex.la
115gnunet_service_mesh_new_DEPENDENCIES = \ 99gnunet_service_mesh_new_DEPENDENCIES = \
116 $(top_builddir)/src/util/libgnunetutil.la \ 100 $(top_builddir)/src/util/libgnunetutil.la \
@@ -118,7 +102,6 @@ gnunet_service_mesh_new_DEPENDENCIES = \
118 $(top_builddir)/src/dht/libgnunetdht.la \ 102 $(top_builddir)/src/dht/libgnunetdht.la \
119 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 103 $(top_builddir)/src/statistics/libgnunetstatistics.la \
120 $(top_builddir)/src/block/libgnunetblock.la \ 104 $(top_builddir)/src/block/libgnunetblock.la \
121 libgnunetmeshblock.la \
122 $(top_builddir)/src/regex/libgnunetregex.la 105 $(top_builddir)/src/regex/libgnunetregex.la
123if LINUX 106if LINUX
124gnunet_service_mesh_new_LDFLAGS = -lrt 107gnunet_service_mesh_new_LDFLAGS = -lrt
diff --git a/src/mesh/gnunet-service-mesh-new.c b/src/mesh/gnunet-service-mesh-new.c
index 2e8b094bd..82bfc5e8d 100644
--- a/src/mesh/gnunet-service-mesh-new.c
+++ b/src/mesh/gnunet-service-mesh-new.c
@@ -35,7 +35,6 @@
35 * - MAIN FUNCTIONS (main & run) 35 * - MAIN FUNCTIONS (main & run)
36 * 36 *
37 * TODO: 37 * TODO:
38 * - Backport r24764, r24767.
39 * - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message! 38 * - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message!
40 * - partial disconnect reporting -- same as error reporting? 39 * - partial disconnect reporting -- same as error reporting?
41 * - add ping message 40 * - add ping message
@@ -51,7 +50,6 @@
51#include "mesh_protocol.h" 50#include "mesh_protocol.h"
52#include "mesh_tunnel_tree.h" 51#include "mesh_tunnel_tree.h"
53#include "block_mesh.h" 52#include "block_mesh.h"
54#include "mesh_block_lib.h"
55#include "gnunet_dht_service.h" 53#include "gnunet_dht_service.h"
56#include "gnunet_statistics_service.h" 54#include "gnunet_statistics_service.h"
57#include "gnunet_regex_lib.h" 55#include "gnunet_regex_lib.h"
@@ -62,6 +60,10 @@
62#define MESH_DEBUG_CONNECTION GNUNET_NO 60#define MESH_DEBUG_CONNECTION GNUNET_NO
63#define MESH_DEBUG_TIMING __LINUX__ && GNUNET_NO 61#define MESH_DEBUG_TIMING __LINUX__ && GNUNET_NO
64 62
63#define MESH_MAX_POLL_TIME GNUNET_TIME_relative_multiply (\
64 GNUNET_TIME_UNIT_MINUTES,\
65 10)
66
65#if MESH_DEBUG_CONNECTION 67#if MESH_DEBUG_CONNECTION
66#define DEBUG_CONN(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__) 68#define DEBUG_CONN(...) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
67#else 69#else
@@ -185,8 +187,65 @@ struct MeshRegexDescriptor
185 * How many characters per edge can we squeeze? 187 * How many characters per edge can we squeeze?
186 */ 188 */
187 uint16_t compression; 189 uint16_t compression;
190
191 /**
192 * Handle to announce the regex.
193 */
194 struct GNUNET_REGEX_announce_handle *h;
188}; 195};
189 196
197
198/**
199 * Struct to keep information of searches of services described by a regex
200 * using a user-provided string service description.
201 */
202struct MeshRegexSearchInfo
203{
204 /**
205 * Which tunnel is this for
206 */
207 struct MeshTunnel *t;
208
209 /**
210 * User provided description of the searched service.
211 */
212 char *description;
213
214 /**
215 * Regex search handle.
216 */
217 struct GNUNET_REGEX_search_handle *search_handle;
218
219 /**
220 * Peer that is connecting via connect_by_string. When connected, free ctx.
221 */
222 GNUNET_PEER_Id peer;
223
224 /**
225 * Other peers that are found but not yet being connected to.
226 */
227 GNUNET_PEER_Id *peers;
228
229 /**
230 * Number of elements in peers.
231 */
232 unsigned int n_peers;
233
234 /**
235 * Next peer to try to connect to.
236 */
237 unsigned int i_peer;
238
239 /**
240 * Timeout for a connect attempt.
241 * When reached, try to connect to a different peer, if any. If not,
242 * try the same peer again.
243 */
244 GNUNET_SCHEDULER_TaskIdentifier timeout;
245
246};
247
248
190/** 249/**
191 * Struct containing all info possibly needed to build a package when called 250 * Struct containing all info possibly needed to build a package when called
192 * back by core. 251 * back by core.
@@ -352,13 +411,18 @@ struct MeshTunnel
352 */ 411 */
353 uint32_t bck_pid; 412 uint32_t bck_pid;
354 413
355 /** 414 /**
356 * SKIP value for this tunnel. 415 * SKIP value for this tunnel.
357 */ 416 */
358 uint32_t skip; 417 uint32_t skip;
359 418
360 /** 419 /**
361 * MeshTunnelFlowControlInfo of all children, indexed by GNUNET_PEER_Id. 420 * Force sending ACK? Flag to allow duplicate ACK on POLL.
421 */
422 int force_ack;
423
424 /**
425 * MeshTunnelChildInfo of all children, indexed by GNUNET_PEER_Id.
362 * Contains the Flow Control info: FWD ACK value received, 426 * Contains the Flow Control info: FWD ACK value received,
363 * last BCK ACK sent, PID and SKIP values. 427 * last BCK ACK sent, PID and SKIP values.
364 */ 428 */
@@ -434,7 +498,7 @@ struct MeshTunnel
434 /** 498 /**
435 * Flow control info for each client. 499 * Flow control info for each client.
436 */ 500 */
437 struct MeshTunnelFlowControlInfo *clients_fc; 501 struct MeshTunnelClientInfo *clients_fc;
438 502
439 /** 503 /**
440 * Number of elements in clients/clients_fc 504 * Number of elements in clients/clients_fc
@@ -482,9 +546,9 @@ struct MeshTunnel
482 struct GNUNET_DHT_GetHandle *dht_get_type; 546 struct GNUNET_DHT_GetHandle *dht_get_type;
483 547
484 /** 548 /**
485 * Initial context of the regex search for a connect_by_string 549 * Handle for the regex search for a connect_by_string
486 */ 550 */
487 struct MeshRegexSearchContext *regex_ctx; 551 struct MeshRegexSearchInfo *regex_search;
488 552
489 /** 553 /**
490 * Task to keep the used paths alive 554 * Task to keep the used paths alive
@@ -505,24 +569,28 @@ struct MeshTunnel
505 * when the queue is empty. 569 * when the queue is empty.
506 */ 570 */
507 int destroy; 571 int destroy;
572
573 /**
574 * Total messages pending for this tunnels, payload or not.
575 */
576 unsigned int pending_messages;
577
578 /**
579 * If the tunnel is empty, destoy it.
580 */
581 GNUNET_SCHEDULER_TaskIdentifier delayed_destroy;
508}; 582};
509 583
510 584
511/** 585/**
512 * Flow control info about a node in a tunnel. The node can be a local client 586 * Info about a child node in a tunnel, needed to perform flow control.
513 * or a remote peer.
514 */ 587 */
515struct MeshTunnelFlowControlInfo 588struct MeshTunnelChildInfo
516{ 589{
517 /** 590 /**
518 * Peer info of the node, NULL if local client. 591 * ID of the child node.
519 */ 592 */
520 struct MeshPeerInfo *peer; 593 GNUNET_PEER_Id id;
521
522 /**
523 * Client info of the node, NULL if remote peer.
524 */
525 struct MeshClient *client;
526 594
527 /** 595 /**
528 * SKIP value. 596 * SKIP value.
@@ -530,28 +598,28 @@ struct MeshTunnelFlowControlInfo
530 uint32_t skip; 598 uint32_t skip;
531 599
532 /** 600 /**
533 * Last PID sent. 601 * Last sent PID.
534 */ 602 */
535 uint32_t fwd_pid; 603 uint32_t fwd_pid;
536 604
537 /** 605 /**
538 * Last PID received. 606 * Last received PID.
539 */ 607 */
540 uint32_t bck_pid; 608 uint32_t bck_pid;
541 609
542 /** 610 /**
543 * Maximum PID they allowed us to send (FWD ACK received). 611 * Maximum PID allowed (FWD ACK received).
544 */ 612 */
545 uint32_t fwd_ack; 613 uint32_t fwd_ack;
546 614
547 /** 615 /**
548 * Maximum PID we allowed them to send (BCK ACK sent). 616 * Last ACK sent to that child (BCK ACK).
549 */ 617 */
550 uint32_t bck_ack; 618 uint32_t bck_ack;
551 619
552 /** 620 /**
553 * Circular buffer pointing to MeshPeerQueue elements for all 621 * Circular buffer pointing to MeshPeerQueue elements for all
554 * payload traffic going to this node. 622 * payload traffic going to this child.
555 * Size determined by the tunnel queue size (@c t->fwd_queue_max). 623 * Size determined by the tunnel queue size (@c t->fwd_queue_max).
556 */ 624 */
557 struct MeshPeerQueue **send_buffer; 625 struct MeshPeerQueue **send_buffer;
@@ -574,10 +642,43 @@ struct MeshTunnelFlowControlInfo
574 /** 642 /**
575 * Task to poll peer in case of a stall. 643 * Task to poll peer in case of a stall.
576 */ 644 */
577 GNUNET_SCHEDULER_TaskIdentifier fc_poll; 645 GNUNET_SCHEDULER_TaskIdentifier fc_poll;
646
647 /**
648 * Time to use for next polling call.
649 */
650 struct GNUNET_TIME_Relative fc_poll_time;
651};
652
653
654/**
655 * Info about a leaf client of a tunnel, needed to perform flow control.
656 */
657struct MeshTunnelClientInfo
658{
659 /**
660 * PID of the last packet sent to the client (FWD).
661 */
662 uint32_t fwd_pid;
663
664 /**
665 * PID of the last packet received from the client (BCK).
666 */
667 uint32_t bck_pid;
668
669 /**
670 * Maximum PID allowed (FWD ACK received).
671 */
672 uint32_t fwd_ack;
673
674 /**
675 * Last ACK sent to that child (BCK ACK).
676 */
677 uint32_t bck_ack;
578}; 678};
579 679
580 680
681
581/** 682/**
582 * Info collected during iteration of child nodes in order to get the ACK value 683 * Info collected during iteration of child nodes in order to get the ACK value
583 * for a tunnel. 684 * for a tunnel.
@@ -698,107 +799,13 @@ struct MeshClient
698 */ 799 */
699 GNUNET_SCHEDULER_TaskIdentifier regex_announce_task; 800 GNUNET_SCHEDULER_TaskIdentifier regex_announce_task;
700 801
701};
702
703
704/**
705 * Struct to keep information of searches of services described by a regex
706 * using a user-provided string service description.
707 */
708struct MeshRegexSearchInfo
709{
710 /** 802 /**
711 * Which tunnel is this for 803 * Tmp store for partially retrieved regex.
712 */
713 struct MeshTunnel *t;
714
715 /**
716 * User provided description of the searched service.
717 */
718 char *description;
719
720 /**
721 * Part of the description already consumed by the search.
722 */ 804 */
723 size_t position; 805 char *partial_regex;
724
725 /**
726 * Running DHT GETs.
727 */
728 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
729
730 /**
731 * Results from running DHT GETs.
732 */
733 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
734
735 /**
736 * Contexts, for each running DHT GET. Free all on end of search.
737 */
738 struct MeshRegexSearchContext **contexts;
739
740 /**
741 * Number of contexts (branches/steps in search).
742 */
743 unsigned int n_contexts;
744
745 /**
746 * Peer that is connecting via connect_by_string. When connected, free ctx.
747 */
748 GNUNET_PEER_Id peer;
749
750 /**
751 * Other peers that are found but not yet being connected to.
752 */
753 GNUNET_PEER_Id *peers;
754
755 /**
756 * Number of elements in peers.
757 */
758 unsigned int n_peers;
759
760 /**
761 * Next peer to try to connect to.
762 */
763 unsigned int i_peer;
764
765 /**
766 * Timeout for a connect attempt.
767 * When reached, try to connect to a different peer, if any. If not,
768 * try the same peer again.
769 */
770 GNUNET_SCHEDULER_TaskIdentifier timeout;
771 806
772}; 807};
773 808
774/**
775 * Struct to keep state of running searches that have consumed a part of
776 * the inital string.
777 */
778struct MeshRegexSearchContext
779{
780 /**
781 * Part of the description already consumed by
782 * this particular search branch.
783 */
784 size_t position;
785
786 /**
787 * Information about the search.
788 */
789 struct MeshRegexSearchInfo *info;
790
791 /**
792 * We just want to look for one edge, the longer the better.
793 * Keep its length.
794 */
795 unsigned int longest_match;
796
797 /**
798 * Destination hash of the longest match.
799 */
800 struct GNUNET_HashCode hash;
801};
802 809
803/******************************************************************************/ 810/******************************************************************************/
804/************************ DEBUG FUNCTIONS ****************************/ 811/************************ DEBUG FUNCTIONS ****************************/
@@ -878,6 +885,11 @@ static unsigned long long max_tunnels;
878 */ 885 */
879static unsigned long long max_msgs_queue; 886static unsigned long long max_msgs_queue;
880 887
888/**
889 * How many peers do we want to remember?
890 */
891static unsigned long long max_peers;
892
881 893
882/*************************** Static global variables **************************/ 894/*************************** Static global variables **************************/
883 895
@@ -1030,56 +1042,15 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
1030 1042
1031 1043
1032/** 1044/**
1033 * Function to process DHT string to regex matching. 1045 * Retrieve the MeshPeerInfo stucture associated with the peer, create one
1034 * Called on each result obtained for the DHT search. 1046 * and insert it in the appropiate structures if the peer is not known yet.
1035 *
1036 * @param cls closure (search context)
1037 * @param exp when will this value expire
1038 * @param key key of the result
1039 * @param get_path path of the get request (not used)
1040 * @param get_path_length lenght of get_path (not used)
1041 * @param put_path path of the put request (not used)
1042 * @param put_path_length length of the put_path (not used)
1043 * @param type type of the result
1044 * @param size number of bytes in data
1045 * @param data pointer to the result data
1046 * 1047 *
1047 * TODO: re-issue the request after certain time? cancel after X results? 1048 * @param peer Full identity of the peer.
1048 */
1049static void
1050dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
1051 const struct GNUNET_HashCode * key,
1052 const struct GNUNET_PeerIdentity *get_path,
1053 unsigned int get_path_length,
1054 const struct GNUNET_PeerIdentity *put_path,
1055 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
1056 size_t size, const void *data);
1057
1058
1059/**
1060 * Function to process DHT string to regex matching.
1061 * Called on each result obtained for the DHT search.
1062 * 1049 *
1063 * @param cls closure (search context) 1050 * @return Existing or newly created peer info.
1064 * @param exp when will this value expire
1065 * @param key key of the result
1066 * @param get_path path of the get request (not used)
1067 * @param get_path_length lenght of get_path (not used)
1068 * @param put_path path of the put request (not used)
1069 * @param put_path_length length of the put_path (not used)
1070 * @param type type of the result
1071 * @param size number of bytes in data
1072 * @param data pointer to the result data
1073 */ 1051 */
1074static void 1052static struct MeshPeerInfo *
1075dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp, 1053peer_info_get (const struct GNUNET_PeerIdentity *peer);
1076 const struct GNUNET_HashCode * key,
1077 const struct GNUNET_PeerIdentity *get_path,
1078 unsigned int get_path_length,
1079 const struct GNUNET_PeerIdentity *put_path,
1080 unsigned int put_path_length,
1081 enum GNUNET_BLOCK_Type type,
1082 size_t size, const void *data);
1083 1054
1084 1055
1085/** 1056/**
@@ -1108,6 +1079,29 @@ peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t);
1108 1079
1109 1080
1110/** 1081/**
1082 * Build a PeerPath from the paths returned from the DHT, reversing the paths
1083 * to obtain a local peer -> destination path and interning the peer ids.
1084 *
1085 * @return Newly allocated and created path
1086 */
1087static struct MeshPeerPath *
1088path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
1089 unsigned int get_path_length,
1090 const struct GNUNET_PeerIdentity *put_path,
1091 unsigned int put_path_length);
1092
1093
1094/**
1095 * Adds a path to the peer_infos of all the peers in the path
1096 *
1097 * @param p Path to process.
1098 * @param confirmed Whether we know if the path works or not.
1099 */
1100static void
1101path_add_to_peers (struct MeshPeerPath *p, int confirmed);
1102
1103
1104/**
1111 * Add a peer to a tunnel, accomodating paths accordingly and initializing all 1105 * Add a peer to a tunnel, accomodating paths accordingly and initializing all
1112 * needed rescources. 1106 * needed rescources.
1113 * If peer already exists, reevaluate shortest path and change if different. 1107 * If peer already exists, reevaluate shortest path and change if different.
@@ -1141,7 +1135,7 @@ tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer);
1141 * @return tunnel handler, NULL if doesn't exist. 1135 * @return tunnel handler, NULL if doesn't exist.
1142 */ 1136 */
1143static struct MeshTunnel * 1137static struct MeshTunnel *
1144tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid); 1138tunnel_get (const struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid);
1145 1139
1146 1140
1147/** 1141/**
@@ -1192,33 +1186,6 @@ tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c);
1192 1186
1193 1187
1194/** 1188/**
1195 * Jump to the next edge, with the longest matching token.
1196 *
1197 * @param block Block found in the DHT.
1198 * @param size Size of the block.
1199 * @param ctx Context of the search.
1200 *
1201 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1202 */
1203static void
1204regex_next_edge (const struct MeshRegexBlock *block,
1205 size_t size,
1206 struct MeshRegexSearchContext *ctx);
1207
1208
1209/**
1210 * Find a path to a peer that offers a regex servcie compatible
1211 * with a given string.
1212 *
1213 * @param key The key of the accepting state.
1214 * @param ctx Context containing info about the string, tunnel, etc.
1215 */
1216static void
1217regex_find_path (const struct GNUNET_HashCode *key,
1218 struct MeshRegexSearchContext *ctx);
1219
1220
1221/**
1222 * @brief Queue and pass message to core when possible. 1189 * @brief Queue and pass message to core when possible.
1223 * 1190 *
1224 * If type is payload (UNICAST, TO_ORIGIN, MULTICAST) checks for queue status 1191 * If type is payload (UNICAST, TO_ORIGIN, MULTICAST) checks for queue status
@@ -1279,383 +1246,23 @@ static size_t
1279queue_send (void *cls, size_t size, void *buf); 1246queue_send (void *cls, size_t size, void *buf);
1280 1247
1281/******************************************************************************/ 1248/******************************************************************************/
1282/************************ ITERATORS ****************************/ 1249/************************ REGEX INTEGRATION ****************************/
1283/******************************************************************************/ 1250/******************************************************************************/
1284 1251
1285/** 1252/**
1286 * Iterator over found existing mesh regex blocks that match an ongoing search. 1253 * Cancel a mesh regex search and free resources.
1287 *
1288 * @param cls closure
1289 * @param key current key code
1290 * @param value value in the hash map
1291 * @return GNUNET_YES if we should continue to iterate,
1292 * GNUNET_NO if not.
1293 */
1294static int
1295regex_result_iterator (void *cls,
1296 const struct GNUNET_HashCode * key,
1297 void *value)
1298{
1299 struct MeshRegexBlock *block = value;
1300 struct MeshRegexSearchContext *ctx = cls;
1301
1302 if (GNUNET_YES == ntohl(block->accepting) &&
1303 ctx->position == strlen (ctx->info->description))
1304 {
1305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Found accepting known block\n");
1306 regex_find_path (key, ctx);
1307 return GNUNET_YES; // We found an accept state!
1308 }
1309 else
1310 {
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* %u, %u, [%u]\n",
1312 ctx->position, strlen(ctx->info->description),
1313 ntohl(block->accepting));
1314
1315 }
1316 regex_next_edge(block, SIZE_MAX, ctx);
1317
1318 GNUNET_STATISTICS_update (stats, "# regex mesh blocks iterated", 1, GNUNET_NO);
1319
1320 return GNUNET_YES;
1321}
1322
1323
1324/**
1325 * Iterator over edges in a regex block retrieved from the DHT.
1326 *
1327 * @param cls Closure (context of the search).
1328 * @param token Token that follows to next state.
1329 * @param len Lenght of token.
1330 * @param key Hash of next state.
1331 *
1332 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1333 */
1334static int
1335regex_edge_iterator (void *cls,
1336 const char *token,
1337 size_t len,
1338 const struct GNUNET_HashCode *key)
1339{
1340 struct MeshRegexSearchContext *ctx = cls;
1341 struct MeshRegexSearchInfo *info = ctx->info;
1342 char *current;
1343 size_t current_len;
1344
1345 GNUNET_STATISTICS_update (stats, "# regex edges iterated", 1, GNUNET_NO);
1346
1347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Start of regex edge iterator\n");
1348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* descr : %s\n", info->description);
1349 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* posit : %u\n", ctx->position);
1350 current = &info->description[ctx->position];
1351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* currt : %s\n", current);
1352 current_len = strlen (info->description) - ctx->position;
1353 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* ctlen : %u\n", current_len);
1354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* tklen : %u\n", len);
1355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* tk[0] : %c\n", token[0]);
1356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* nextk : %s\n", GNUNET_h2s(key));
1357 if (len > current_len)
1358 {
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token too long, END\n");
1360 return GNUNET_YES; // Token too long, wont match
1361 }
1362 if (0 != strncmp (current, token, len))
1363 {
1364 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token doesn't match, END\n");
1365 return GNUNET_YES; // Token doesn't match
1366 }
1367
1368 if (len > ctx->longest_match)
1369 {
1370 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is longer, KEEP\n");
1371 ctx->longest_match = len;
1372 ctx->hash = *key;
1373 }
1374 else
1375 {
1376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is not longer, IGNORE\n");
1377 }
1378
1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
1380 return GNUNET_YES;
1381}
1382
1383
1384/**
1385 * Jump to the next edge, with the longest matching token.
1386 *
1387 * @param block Block found in the DHT.
1388 * @param size Size of the block.
1389 * @param ctx Context of the search.
1390 *
1391 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1392 */ 1254 */
1393static void 1255static void
1394regex_next_edge (const struct MeshRegexBlock *block, 1256regex_cancel_search (struct MeshRegexSearchInfo *regex_search)
1395 size_t size,
1396 struct MeshRegexSearchContext *ctx)
1397{ 1257{
1398 struct MeshRegexSearchContext *new_ctx; 1258 GNUNET_REGEX_search_cancel (regex_search->search_handle);
1399 struct MeshRegexSearchInfo *info = ctx->info; 1259 if (0 < regex_search->n_peers)
1400 struct GNUNET_DHT_GetHandle *get_h; 1260 GNUNET_free (regex_search->peers);
1401 1261 if (GNUNET_SCHEDULER_NO_TASK != regex_search->timeout)
1402 int result;
1403
1404 /* Find the longest match for the current string position,
1405 * among tokens in the given block */
1406 ctx->longest_match = 0;
1407 result = GNUNET_MESH_regex_block_iterate (block, size,
1408 &regex_edge_iterator, ctx);
1409 GNUNET_break (GNUNET_OK == result || SIZE_MAX == size);
1410
1411 /* Did anything match? */
1412 if (0 == ctx->longest_match)
1413 return;
1414
1415 new_ctx = GNUNET_malloc (sizeof (struct MeshRegexSearchContext));
1416 new_ctx->info = info;
1417 new_ctx->position = ctx->position + ctx->longest_match;
1418 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
1419
1420 /* Check whether we already have a DHT GET running for it */
1421 if (GNUNET_YES ==
1422 GNUNET_CONTAINER_multihashmap_contains(info->dht_get_handles, &ctx->hash))
1423 {
1424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* GET running, END\n");
1425 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
1426 &ctx->hash,
1427 &regex_result_iterator,
1428 new_ctx);
1429 return; // We are already looking for it
1430 }
1431
1432 GNUNET_STATISTICS_update (stats, "# regex nodes traversed", 1, GNUNET_NO);
1433
1434 /* Start search in DHT */
1435 get_h =
1436 GNUNET_DHT_get_start (dht_handle, /* handle */
1437 GNUNET_BLOCK_TYPE_MESH_REGEX, /* type */
1438 &ctx->hash, /* key to search */
1439 dht_replication_level, /* replication level */
1440 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1441 NULL, /* xquery */ // FIXME BLOOMFILTER
1442 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
1443 &dht_get_string_handler, new_ctx);
1444 if (GNUNET_OK !=
1445 GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
1446 &ctx->hash,
1447 get_h,
1448 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1449 { 1262 {
1450 GNUNET_break (0); 1263 GNUNET_SCHEDULER_cancel(regex_search->timeout);
1451 return;
1452 } 1264 }
1453} 1265 GNUNET_free (regex_search);
1454
1455
1456/**
1457 * Iterator over hash map entries to cancel DHT GET requests after a
1458 * successful connect_by_string.
1459 *
1460 * @param cls Closure (unused).
1461 * @param key Current key code (unused).
1462 * @param value Value in the hash map (get handle).
1463 * @return GNUNET_YES if we should continue to iterate,
1464 * GNUNET_NO if not.
1465 */
1466static int
1467regex_cancel_dht_get (void *cls,
1468 const struct GNUNET_HashCode * key,
1469 void *value)
1470{
1471 struct GNUNET_DHT_GetHandle *h = value;
1472
1473 GNUNET_DHT_get_stop (h);
1474 return GNUNET_YES;
1475}
1476
1477
1478/**
1479 * Iterator over hash map entries to free MeshRegexBlocks stored during the
1480 * search for connect_by_string.
1481 *
1482 * @param cls Closure (unused).
1483 * @param key Current key code (unused).
1484 * @param value MeshRegexBlock in the hash map.
1485 * @return GNUNET_YES if we should continue to iterate,
1486 * GNUNET_NO if not.
1487 */
1488static int
1489regex_free_result (void *cls,
1490 const struct GNUNET_HashCode * key,
1491 void *value)
1492{
1493
1494 GNUNET_free (value);
1495 return GNUNET_YES;
1496}
1497
1498
1499/**
1500 * Regex callback iterator to store own service description in the DHT.
1501 *
1502 * @param cls closure.
1503 * @param key hash for current state.
1504 * @param proof proof for current state.
1505 * @param accepting GNUNET_YES if this is an accepting state, GNUNET_NO if not.
1506 * @param num_edges number of edges leaving current state.
1507 * @param edges edges leaving current state.
1508 */
1509void
1510regex_iterator (void *cls,
1511 const struct GNUNET_HashCode *key,
1512 const char *proof,
1513 int accepting,
1514 unsigned int num_edges,
1515 const struct GNUNET_REGEX_Edge *edges)
1516{
1517 struct MeshRegexBlock *block;
1518 struct MeshRegexEdge *block_edge;
1519 enum GNUNET_DHT_RouteOption opt;
1520 size_t size;
1521 size_t len;
1522 unsigned int i;
1523 unsigned int offset;
1524 char *aux;
1525
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 " regex dht put for state %s\n",
1528 GNUNET_h2s(key));
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1530 " proof: %s\n",
1531 proof);
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1533 " num edges: %u\n",
1534 num_edges);
1535
1536 opt = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
1537 if (GNUNET_YES == accepting)
1538 {
1539 struct MeshRegexAccept block;
1540
1541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1542 " state %s is accepting, putting own id\n",
1543 GNUNET_h2s(key));
1544 size = sizeof (block);
1545 block.key = *key;
1546 block.id = my_full_id;
1547 (void)
1548 GNUNET_DHT_put(dht_handle, key,
1549 dht_replication_level,
1550 opt | GNUNET_DHT_RO_RECORD_ROUTE,
1551 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT,
1552 size,
1553 (char *) &block,
1554 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1555 app_announce_time),
1556 app_announce_time,
1557 NULL, NULL);
1558 }
1559 len = strlen(proof);
1560 size = sizeof (struct MeshRegexBlock) + len;
1561 block = GNUNET_malloc (size);
1562
1563 block->key = *key;
1564 block->n_proof = htonl (len);
1565 block->n_edges = htonl (num_edges);
1566 block->accepting = htonl (accepting);
1567
1568 /* Store the proof at the end of the block. */
1569 aux = (char *) &block[1];
1570 memcpy (aux, proof, len);
1571 aux = &aux[len];
1572
1573 /* Store each edge in a variable length MeshEdge struct at the
1574 * very end of the MeshRegexBlock structure.
1575 */
1576 for (i = 0; i < num_edges; i++)
1577 {
1578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1579 " edge %s towards %s\n",
1580 edges[i].label,
1581 GNUNET_h2s(&edges[i].destination));
1582
1583 /* aux points at the end of the last block */
1584 len = strlen (edges[i].label);
1585 size += sizeof (struct MeshRegexEdge) + len;
1586 // Calculate offset FIXME is this ok? use size instead?
1587 offset = aux - (char *) block;
1588 block = GNUNET_realloc (block, size);
1589 aux = &((char *) block)[offset];
1590 block_edge = (struct MeshRegexEdge *) aux;
1591 block_edge->key = edges[i].destination;
1592 block_edge->n_token = htonl (len);
1593 aux = (char *) &block_edge[1];
1594 memcpy (aux, edges[i].label, len);
1595 aux = &aux[len];
1596 }
1597 (void)
1598 GNUNET_DHT_put(dht_handle, key,
1599 dht_replication_level,
1600 opt,
1601 GNUNET_BLOCK_TYPE_MESH_REGEX, size,
1602 (char *) block,
1603 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
1604 app_announce_time),
1605 app_announce_time,
1606 NULL, NULL);
1607 GNUNET_free (block);
1608}
1609
1610
1611/**
1612 * Store the regular expression describing a local service into the DHT.
1613 *
1614 * @param regex The regular expresion.
1615 */
1616static void
1617regex_put (const struct MeshRegexDescriptor *regex)
1618{
1619 struct GNUNET_REGEX_Automaton *dfa;
1620
1621 DEBUG_DHT (" regex_put (%s) start\n", regex->regex);
1622 dfa = GNUNET_REGEX_construct_dfa (regex->regex,
1623 strlen(regex->regex),
1624 regex->compression);
1625 GNUNET_REGEX_iterate_all_edges (dfa, &regex_iterator, NULL);
1626 GNUNET_REGEX_automaton_destroy (dfa);
1627 DEBUG_DHT (" regex_put (%s) end\n", regex);
1628
1629}
1630
1631/**
1632 * Find a path to a peer that offers a regex servcie compatible
1633 * with a given string.
1634 *
1635 * @param key The key of the accepting state.
1636 * @param ctx Context containing info about the string, tunnel, etc.
1637 */
1638static void
1639regex_find_path (const struct GNUNET_HashCode *key,
1640 struct MeshRegexSearchContext *ctx)
1641{
1642 struct GNUNET_DHT_GetHandle *get_h;
1643
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found peer by service\n");
1645 get_h = GNUNET_DHT_get_start (dht_handle, /* handle */
1646 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT, /* type */
1647 key, /* key to search */
1648 dht_replication_level, /* replication level */
1649 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE |
1650 GNUNET_DHT_RO_RECORD_ROUTE,
1651 NULL, /* xquery */ // FIXME BLOOMFILTER
1652 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
1653 &dht_get_string_accept_handler, ctx);
1654 GNUNET_break (GNUNET_OK ==
1655 GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles,
1656 key,
1657 get_h,
1658 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1659} 1266}
1660 1267
1661 1268
@@ -1679,6 +1286,7 @@ regex_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1679 info->timeout = GNUNET_SCHEDULER_NO_TASK; 1286 info->timeout = GNUNET_SCHEDULER_NO_TASK;
1680 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 1287 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1681 { 1288 {
1289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " due to shutdown\n");
1682 return; 1290 return;
1683 } 1291 }
1684 1292
@@ -1712,37 +1320,109 @@ regex_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1712 1320
1713 1321
1714/** 1322/**
1715 * Cancel an ongoing regex search in the DHT and free all resources. 1323 * Function to process DHT string to regex matching.
1324 * Called on each result obtained for the DHT search.
1716 * 1325 *
1717 * @param ctx The search context. 1326 * @param cls Closure provided in GNUNET_REGEX_search.
1327 * @param id Peer providing a regex that matches the string.
1328 * @param get_path Path of the get request.
1329 * @param get_path_length Lenght of get_path.
1330 * @param put_path Path of the put request.
1331 * @param put_path_length Length of the put_path.
1718 */ 1332 */
1719static void 1333static void
1720regex_cancel_search(struct MeshRegexSearchContext *ctx) 1334regex_found_handler (void *cls,
1335 const struct GNUNET_PeerIdentity *id,
1336 const struct GNUNET_PeerIdentity *get_path,
1337 unsigned int get_path_length,
1338 const struct GNUNET_PeerIdentity *put_path,
1339 unsigned int put_path_length)
1721{ 1340{
1722 struct MeshRegexSearchInfo *info = ctx->info; 1341 struct MeshRegexSearchInfo *info = cls;
1723 int i; 1342 struct MeshPeerPath *p;
1343 struct MeshPeerInfo *peer_info;
1344
1345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", info->description);
1347
1348 peer_info = peer_info_get (id);
1349 p = path_build_from_dht (get_path, get_path_length,
1350 put_path, put_path_length);
1351 path_add_to_peers (p, GNUNET_NO);
1352 path_destroy(p);
1724 1353
1725 GNUNET_free (info->description); 1354 tunnel_add_peer (info->t, peer_info);
1726 GNUNET_CONTAINER_multihashmap_iterate (info->dht_get_handles, 1355 peer_info_connect (peer_info, info->t);
1727 &regex_cancel_dht_get, NULL); 1356 if (0 == info->peer)
1728 GNUNET_CONTAINER_multihashmap_iterate (info->dht_get_results,
1729 &regex_free_result, NULL);
1730 GNUNET_CONTAINER_multihashmap_destroy (info->dht_get_results);
1731 GNUNET_CONTAINER_multihashmap_destroy (info->dht_get_handles);
1732 info->t->regex_ctx = NULL;
1733 for (i = 0; i < info->n_contexts; i++)
1734 { 1357 {
1735 GNUNET_free (info->contexts[i]); 1358 info->peer = peer_info->id;
1736 } 1359 }
1737 if (0 < info->n_contexts) 1360 else
1738 GNUNET_free (info->contexts); 1361 {
1739 if (0 < info->n_peers) 1362 GNUNET_array_append (info->peers, info->n_peers, peer_info->id);
1740 GNUNET_free (info->peers); 1363 }
1364
1741 if (GNUNET_SCHEDULER_NO_TASK != info->timeout) 1365 if (GNUNET_SCHEDULER_NO_TASK != info->timeout)
1366 return;
1367
1368 info->timeout = GNUNET_SCHEDULER_add_delayed (connect_timeout,
1369 &regex_connect_timeout,
1370 info);
1371
1372 return;
1373}
1374
1375
1376/**
1377 * Store the regular expression describing a local service into the DHT.
1378 *
1379 * @param regex The regular expresion.
1380 */
1381static void
1382regex_put (struct MeshRegexDescriptor *regex)
1383{
1384 DEBUG_DHT (" regex_put (%s) start\n", regex->regex);
1385 if (NULL == regex->h)
1742 { 1386 {
1743 GNUNET_SCHEDULER_cancel(info->timeout); 1387 DEBUG_DHT (" first put, creating DFA\n");
1388 regex->h = GNUNET_REGEX_announce (dht_handle,
1389 &my_full_id,
1390 regex->regex,
1391 regex->compression,
1392 stats);
1744 } 1393 }
1745 GNUNET_free (info); 1394 else
1395 {
1396 DEBUG_DHT (" not first put, using cached data\n");
1397 GNUNET_REGEX_reannounce (regex->h);
1398 }
1399 DEBUG_DHT (" regex_put (%s) end\n", regex->regex);
1400}
1401
1402
1403/**
1404 * Periodically announce what applications are provided by local clients
1405 * (by regex)
1406 *
1407 * @param cls closure
1408 * @param tc task context
1409 */
1410static void
1411regex_announce (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1412{
1413 struct MeshClient *c = cls;
1414 unsigned int i;
1415
1416 c->regex_announce_task = GNUNET_SCHEDULER_NO_TASK;
1417 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1418 return;
1419 DEBUG_DHT ("Starting PUT for regex\n");
1420 for (i = 0; i < c->n_regex; i++)
1421 regex_put (&c->regexes[i]);
1422 c->regex_announce_task = GNUNET_SCHEDULER_add_delayed (app_announce_time,
1423 &regex_announce,
1424 cls);
1425 DEBUG_DHT ("Finished PUT for regex\n");
1746} 1426}
1747 1427
1748 1428
@@ -1779,55 +1459,20 @@ announce_application (void *cls, const struct GNUNET_HashCode * key, void *value
1779 1459
1780 GNUNET_break (NULL != 1460 GNUNET_break (NULL !=
1781 GNUNET_DHT_put (dht_handle, key, 1461 GNUNET_DHT_put (dht_handle, key,
1782 dht_replication_level, 1462 dht_replication_level,
1783 GNUNET_DHT_RO_RECORD_ROUTE | 1463 GNUNET_DHT_RO_RECORD_ROUTE |
1784 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, 1464 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1785 GNUNET_BLOCK_TYPE_MESH_PEER_BY_TYPE, 1465 GNUNET_BLOCK_TYPE_MESH_PEER_BY_TYPE,
1786 sizeof (block), 1466 sizeof (block),
1787 (const char *) &block, 1467 (const char *) &block,
1788 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), 1468 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), /* FIXME: this should be an option */
1789 app_announce_time), 1469 app_announce_time, NULL, NULL));
1790 app_announce_time, NULL, NULL));
1791 return GNUNET_OK; 1470 return GNUNET_OK;
1792} 1471}
1793 1472
1794 1473
1795/** 1474/**
1796 * Periodically announce what applications are provided by local clients 1475 * Periodically announce what applications are provided by local clients
1797 * (by regex)
1798 *
1799 * @param cls closure
1800 * @param tc task context
1801 */
1802static void
1803announce_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1804{
1805 struct MeshClient *c = cls;
1806 unsigned int i;
1807
1808 c->regex_announce_task = GNUNET_SCHEDULER_NO_TASK;
1809 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1810 {
1811 return;
1812 }
1813
1814 DEBUG_DHT ("Starting PUT for regex\n");
1815
1816 for (i = 0; i < c->n_regex; i++)
1817 {
1818 regex_put (&c->regexes[i]);
1819 }
1820 c->regex_announce_task = GNUNET_SCHEDULER_add_delayed (app_announce_time,
1821 &announce_regex,
1822 cls);
1823 DEBUG_DHT ("Finished PUT for regex\n");
1824
1825 return;
1826}
1827
1828
1829/**
1830 * Periodically announce what applications are provided by local clients
1831 * (by type) 1476 * (by type)
1832 * 1477 *
1833 * @param cls closure 1478 * @param cls closure
@@ -1850,8 +1495,6 @@ announce_applications (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1850 GNUNET_SCHEDULER_add_delayed (app_announce_time, &announce_applications, 1495 GNUNET_SCHEDULER_add_delayed (app_announce_time, &announce_applications,
1851 cls); 1496 cls);
1852 DEBUG_DHT ("Finished PUT for apps\n"); 1497 DEBUG_DHT ("Finished PUT for apps\n");
1853
1854 return;
1855} 1498}
1856 1499
1857 1500
@@ -2073,6 +1716,32 @@ client_delete_tunnel (struct MeshClient *c, struct MeshTunnel *t)
2073 1716
2074 1717
2075/** 1718/**
1719 * Notify the owner of a tunnel that a peer has disconnected.
1720 *
1721 * @param c Client (owner of tunnel).
1722 * @param t Tunnel this message is about.
1723 * @param peer_id Short ID of the disconnected peer.
1724 */
1725void
1726client_notify_peer_disconnected (struct MeshClient *c,
1727 struct MeshTunnel *t,
1728 GNUNET_PEER_Id peer_id)
1729{
1730 struct GNUNET_MESH_PeerControl msg;
1731
1732 if (NULL == t->owner || NULL == nc)
1733 return;
1734
1735 msg.header.size = htons (sizeof (msg));
1736 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
1737 msg.tunnel_id = htonl (t->local_tid);
1738 GNUNET_PEER_resolve (peer_id, &msg.peer);
1739 GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
1740 &msg.header, GNUNET_NO);
1741}
1742
1743
1744/**
2076 * Send the message to all clients that have subscribed to its type 1745 * Send the message to all clients that have subscribed to its type
2077 * 1746 *
2078 * @param msg Pointer to the message itself 1747 * @param msg Pointer to the message itself
@@ -2189,6 +1858,9 @@ send_client_peer_connected (const struct MeshTunnel *t, const GNUNET_PEER_Id id)
2189{ 1858{
2190 struct GNUNET_MESH_PeerControl pc; 1859 struct GNUNET_MESH_PeerControl pc;
2191 1860
1861 if (NULL == t->owner || GNUNET_YES == t->destroy)
1862 return;
1863
2192 pc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD); 1864 pc.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_ADD);
2193 pc.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl)); 1865 pc.header.size = htons (sizeof (struct GNUNET_MESH_PeerControl));
2194 pc.tunnel_id = htonl (t->local_tid); 1866 pc.tunnel_id = htonl (t->local_tid);
@@ -2259,6 +1931,23 @@ send_client_tunnel_disconnect (struct MeshTunnel *t, struct MeshClient *c)
2259 1931
2260 1932
2261/** 1933/**
1934 * Iterator over all the peers to remove the oldest not-used entry.
1935 *
1936 * @param cls Closure (unsued).
1937 * @param key ID of the peer.
1938 * @param value Peer_Info of the peer.
1939 *
1940 * FIXME implement
1941 */
1942static int
1943peer_info_timeout (void *cls,
1944 const struct GNUNET_HashCode *key,
1945 void *value)
1946{
1947 return GNUNET_YES;
1948}
1949
1950/**
2262 * Retrieve the MeshPeerInfo stucture associated with the peer, create one 1951 * Retrieve the MeshPeerInfo stucture associated with the peer, create one
2263 * and insert it in the appropiate structures if the peer is not known yet. 1952 * and insert it in the appropiate structures if the peer is not known yet.
2264 * 1953 *
@@ -2276,10 +1965,17 @@ peer_info_get (const struct GNUNET_PeerIdentity *peer)
2276 { 1965 {
2277 peer_info = 1966 peer_info =
2278 (struct MeshPeerInfo *) GNUNET_malloc (sizeof (struct MeshPeerInfo)); 1967 (struct MeshPeerInfo *) GNUNET_malloc (sizeof (struct MeshPeerInfo));
1968 if (GNUNET_CONTAINER_multihashmap_size (peers) > max_peers)
1969 {
1970 GNUNET_CONTAINER_multihashmap_iterate (peers,
1971 &peer_info_timeout,
1972 NULL);
1973 }
2279 GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, peer_info, 1974 GNUNET_CONTAINER_multihashmap_put (peers, &peer->hashPubKey, peer_info,
2280 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 1975 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
2281 peer_info->id = GNUNET_PEER_intern (peer); 1976 peer_info->id = GNUNET_PEER_intern (peer);
2282 } 1977 }
1978 peer_info->last_contact = GNUNET_TIME_absolute_get();
2283 1979
2284 return peer_info; 1980 return peer_info;
2285} 1981}
@@ -2447,6 +2143,9 @@ send_prebuilt_message (const struct GNUNET_MessageHeader *message,
2447 } 2143 }
2448#endif 2144#endif
2449 GNUNET_break (0); // FIXME sometimes fails (testing disconnect?) 2145 GNUNET_break (0); // FIXME sometimes fails (testing disconnect?)
2146 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2147 " no direct connection to %s\n",
2148 GNUNET_i2s (peer));
2450 GNUNET_free (info->mesh_data->data); 2149 GNUNET_free (info->mesh_data->data);
2451 GNUNET_free (info->mesh_data); 2150 GNUNET_free (info->mesh_data);
2452 GNUNET_free (info); 2151 GNUNET_free (info);
@@ -2932,38 +2631,37 @@ peer_info_add_path_to_origin (struct MeshPeerInfo *peer_info,
2932 * Function called if the connection to the peer has been stalled for a while, 2631 * Function called if the connection to the peer has been stalled for a while,
2933 * possibly due to a missed ACK. Poll the peer about its ACK status. 2632 * possibly due to a missed ACK. Poll the peer about its ACK status.
2934 * 2633 *
2935 * @param cls Closure (MeshPeerInfo of stalled peer). 2634 * @param cls Closure (cinfo).
2936 * @param tc TaskContext. 2635 * @param tc TaskContext.
2937 */ 2636 */
2938static void 2637static void
2939tunnel_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 2638tunnel_poll (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2940{ 2639{
2941 struct MeshTunnelFlowControlInfo *fcinfo = cls; 2640 struct MeshTunnelChildInfo *cinfo = cls;
2942 struct GNUNET_MESH_Poll msg; 2641 struct GNUNET_MESH_Poll msg;
2943 struct GNUNET_PeerIdentity id; 2642 struct GNUNET_PeerIdentity id;
2944 struct MeshTunnel *t; 2643 struct MeshTunnel *t;
2945 2644
2946 // FIXME fc include code to poll clients 2645 cinfo->fc_poll = GNUNET_SCHEDULER_NO_TASK;
2947 if (NULL == fcinfo->peer)
2948 return;
2949 fcinfo->fc_poll = GNUNET_SCHEDULER_NO_TASK;
2950 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 2646 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2951 { 2647 {
2952 return; 2648 return;
2953 } 2649 }
2954 2650
2955 t = fcinfo->t; 2651 t = cinfo->t;
2956 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_POLL); 2652 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_POLL);
2957 msg.header.size = htons (sizeof (msg)); 2653 msg.header.size = htons (sizeof (msg));
2958 msg.tid = htonl (t->id.tid); 2654 msg.tid = htonl (t->id.tid);
2959 GNUNET_PEER_resolve (t->id.oid, &msg.oid); 2655 GNUNET_PEER_resolve (t->id.oid, &msg.oid);
2960 msg.last_ack = htonl (fcinfo->fwd_ack); 2656 msg.last_ack = htonl (cinfo->fwd_ack);
2961
2962 GNUNET_PEER_resolve (fcinfo->peer->id, &id);
2963 send_prebuilt_message (&msg.header, &id, fcinfo->t);
2964 fcinfo->fc_poll = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
2965 &tunnel_poll, fcinfo);
2966 2657
2658 GNUNET_PEER_resolve (cinfo->id, &id);
2659 send_prebuilt_message (&msg.header, &id, cinfo->t);
2660 cinfo->fc_poll_time = GNUNET_TIME_relative_min (
2661 MESH_MAX_POLL_TIME,
2662 GNUNET_TIME_relative_multiply (cinfo->fc_poll_time, 2));
2663 cinfo->fc_poll = GNUNET_SCHEDULER_add_delayed (cinfo->fc_poll_time,
2664 &tunnel_poll, cinfo);
2967} 2665}
2968 2666
2969 2667
@@ -3166,7 +2864,7 @@ tunnel_get_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid)
3166 * @return tunnel handler, NULL if doesn't exist 2864 * @return tunnel handler, NULL if doesn't exist
3167 */ 2865 */
3168static struct MeshTunnel * 2866static struct MeshTunnel *
3169tunnel_get (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid) 2867tunnel_get (const struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid)
3170{ 2868{
3171 return tunnel_get_by_pi (GNUNET_PEER_search (oid), tid); 2869 return tunnel_get_by_pi (GNUNET_PEER_search (oid), tid);
3172} 2870}
@@ -3253,7 +2951,7 @@ tunnel_destroy_child (void *cls,
3253 const struct GNUNET_HashCode * key, 2951 const struct GNUNET_HashCode * key,
3254 void *value) 2952 void *value)
3255{ 2953{
3256 struct MeshTunnelFlowControlInfo *cinfo = value; 2954 struct MeshTunnelChildInfo *cinfo = value;
3257 struct MeshTunnel *t = cls; 2955 struct MeshTunnel *t = cls;
3258 struct MeshPeerQueue *q; 2956 struct MeshPeerQueue *q;
3259 unsigned int c; 2957 unsigned int c;
@@ -3271,6 +2969,11 @@ tunnel_destroy_child (void *cls,
3271 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u %u\n", c, cinfo->send_buffer_n); 2969 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "%u %u\n", c, cinfo->send_buffer_n);
3272 } 2970 }
3273 GNUNET_free_non_null (cinfo->send_buffer); 2971 GNUNET_free_non_null (cinfo->send_buffer);
2972 if (GNUNET_SCHEDULER_NO_TASK != cinfo->fc_poll)
2973 {
2974 GNUNET_SCHEDULER_cancel (cinfo->fc_poll);
2975 cinfo->fc_poll = GNUNET_SCHEDULER_NO_TASK;
2976 }
3274 GNUNET_free (cinfo); 2977 GNUNET_free (cinfo);
3275 return GNUNET_YES; 2978 return GNUNET_YES;
3276} 2979}
@@ -3290,17 +2993,8 @@ tunnel_notify_client_peer_disconnected (void *cls, GNUNET_PEER_Id peer_id)
3290 struct MeshPeerInfo *peer; 2993 struct MeshPeerInfo *peer;
3291 struct MeshPathInfo *path_info; 2994 struct MeshPathInfo *path_info;
3292 2995
3293 if (NULL != t->owner && NULL != nc) 2996 client_notify_peer_disconnected (t->owner, t, peer_id);
3294 {
3295 struct GNUNET_MESH_PeerControl msg;
3296 2997
3297 msg.header.size = htons (sizeof (msg));
3298 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DEL);
3299 msg.tunnel_id = htonl (t->local_tid);
3300 GNUNET_PEER_resolve (peer_id, &msg.peer);
3301 GNUNET_SERVER_notification_context_unicast (nc, t->owner->handle,
3302 &msg.header, GNUNET_NO);
3303 }
3304 peer = peer_info_get_short (peer_id); 2998 peer = peer_info_get_short (peer_id);
3305 path_info = GNUNET_malloc (sizeof (struct MeshPathInfo)); 2999 path_info = GNUNET_malloc (sizeof (struct MeshPathInfo));
3306 path_info->peer = peer; 3000 path_info->peer = peer;
@@ -3403,25 +3097,15 @@ tunnel_add_path (struct MeshTunnel *t, struct MeshPeerPath *p,
3403static void 3097static void
3404tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c) 3098tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c)
3405{ 3099{
3406 struct MeshTunnelFlowControlInfo fcinfo; 3100 struct MeshTunnelClientInfo clinfo;
3407 3101
3408 GNUNET_array_append (t->clients, t->nclients, c); 3102 GNUNET_array_append (t->clients, t->nclients, c);
3409 fcinfo.t = t; 3103 clinfo.fwd_ack = t->fwd_pid + 1;
3410 fcinfo.client = c; 3104 clinfo.bck_ack = t->nobuffer ? 1 : INITIAL_WINDOW_SIZE - 1;
3411 fcinfo.peer = NULL; 3105 clinfo.fwd_pid = t->fwd_pid;
3412 fcinfo.fwd_ack = t->fwd_pid + 1; 3106 clinfo.bck_pid = (uint32_t) -1; // Expected next: 0
3413 fcinfo.bck_ack = t->nobuffer ? 1 : INITIAL_WINDOW_SIZE - 1;
3414 fcinfo.fwd_pid = t->fwd_pid;
3415 fcinfo.bck_pid = (uint32_t) -1; // Expected next: 0
3416 fcinfo.fc_poll = GNUNET_SCHEDULER_NO_TASK;
3417 fcinfo.send_buffer = NULL;
3418 fcinfo.send_buffer_n = 0;
3419 fcinfo.send_buffer_start = 0;
3420 fcinfo.skip = t->fwd_pid;
3421 // FIXME fc buffering is done by context_notify. Confirm this is OK.
3422
3423 t->nclients--; 3107 t->nclients--;
3424 GNUNET_array_append (t->clients_fc, t->nclients, fcinfo); 3108 GNUNET_array_append (t->clients_fc, t->nclients, clinfo);
3425} 3109}
3426 3110
3427 3111
@@ -3564,7 +3248,8 @@ tunnel_send_multicast (struct MeshTunnel *t,
3564 " no one to send data to\n"); 3248 " no one to send data to\n");
3565 GNUNET_free (mdata->data); 3249 GNUNET_free (mdata->data);
3566 GNUNET_free (mdata); 3250 GNUNET_free (mdata);
3567 t->fwd_queue_n--; 3251 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_MESH_MULTICAST)
3252 t->fwd_queue_n--;
3568 } 3253 }
3569 else 3254 else
3570 { 3255 {
@@ -3582,7 +3267,7 @@ tunnel_send_multicast (struct MeshTunnel *t,
3582 * 3267 *
3583 * @param cls Closure (ID of the peer that HAS received the message). 3268 * @param cls Closure (ID of the peer that HAS received the message).
3584 * @param key ID of the neighbor. 3269 * @param key ID of the neighbor.
3585 * @param value FLow control information about the neighbor. 3270 * @param value Information about the neighbor.
3586 * 3271 *
3587 * @return GNUNET_YES to keep iterating. 3272 * @return GNUNET_YES to keep iterating.
3588 */ 3273 */
@@ -3592,14 +3277,14 @@ tunnel_add_skip (void *cls,
3592 void *value) 3277 void *value)
3593{ 3278{
3594 struct GNUNET_PeerIdentity *neighbor = cls; 3279 struct GNUNET_PeerIdentity *neighbor = cls;
3595 struct MeshTunnelFlowControlInfo *fcinfo = value; 3280 struct MeshTunnelChildInfo *cinfo = value;
3596 3281
3597 /* TODO compare only pointers? key == neighbor? */ 3282 /* TODO compare only pointers? key == neighbor? */
3598 if (0 == memcmp (&neighbor->hashPubKey, key, sizeof (struct GNUNET_HashCode))) 3283 if (0 == memcmp (&neighbor->hashPubKey, key, sizeof (struct GNUNET_HashCode)))
3599 { 3284 {
3600 return GNUNET_YES; 3285 return GNUNET_YES;
3601 } 3286 }
3602 fcinfo->skip++; 3287 cinfo->skip++;
3603 return GNUNET_YES; 3288 return GNUNET_YES;
3604} 3289}
3605 3290
@@ -3607,8 +3292,8 @@ tunnel_add_skip (void *cls,
3607/** 3292/**
3608 * @brief Get neighbor's Flow Control information. 3293 * @brief Get neighbor's Flow Control information.
3609 * 3294 *
3610 * Retrieves the MeshTunnelFlowControlInfo containing Flow Control data about 3295 * Retrieves the MeshTunnelChildInfo containing Flow Control data about a direct
3611 * a direct descendant of the local node in a certain tunnel. 3296 * descendant of the local node in a certain tunnel.
3612 * If the info is not yet there (recently created path), creates the data struct 3297 * If the info is not yet there (recently created path), creates the data struct
3613 * and inserts it into the tunnel info, initialized to the current tunnel ACK 3298 * and inserts it into the tunnel info, initialized to the current tunnel ACK
3614 * values. 3299 * values.
@@ -3618,41 +3303,44 @@ tunnel_add_skip (void *cls,
3618 * 3303 *
3619 * @return Neighbor's Flow Control info. 3304 * @return Neighbor's Flow Control info.
3620 */ 3305 */
3621static struct MeshTunnelFlowControlInfo * 3306static struct MeshTunnelChildInfo *
3622tunnel_get_neighbor_fc (struct MeshTunnel *t, 3307tunnel_get_neighbor_fc (struct MeshTunnel *t,
3623 const struct GNUNET_PeerIdentity *peer) 3308 const struct GNUNET_PeerIdentity *peer)
3624{ 3309{
3625 struct MeshTunnelFlowControlInfo *fcinfo; 3310 struct MeshTunnelChildInfo *cinfo;
3626 3311
3627 if (NULL == t->children_fc) 3312 if (NULL == t->children_fc)
3628 return NULL; 3313 return NULL;
3629 3314
3630 fcinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc, 3315 cinfo = GNUNET_CONTAINER_multihashmap_get (t->children_fc,
3631 &peer->hashPubKey); 3316 &peer->hashPubKey);
3632 if (NULL == fcinfo) 3317 if (NULL == cinfo)
3633 { 3318 {
3634 uint32_t delta; 3319 uint32_t delta;
3635 3320
3636 fcinfo = GNUNET_malloc (sizeof (struct MeshTunnelFlowControlInfo)); 3321 cinfo = GNUNET_malloc (sizeof (struct MeshTunnelChildInfo));
3637 fcinfo->peer = peer_info_get(peer); 3322 cinfo->id = GNUNET_PEER_intern (peer);
3638 fcinfo->skip = t->fwd_pid; 3323 cinfo->skip = t->fwd_pid;
3639 fcinfo->t = t; 3324 cinfo->t = t;
3640 3325
3641 delta = t->nobuffer ? 1 : INITIAL_WINDOW_SIZE; 3326 delta = t->nobuffer ? 1 : INITIAL_WINDOW_SIZE;
3642 fcinfo->fwd_ack = t->fwd_pid + delta; 3327 cinfo->fwd_ack = t->fwd_pid + delta;
3643 fcinfo->bck_ack = delta; 3328 cinfo->bck_ack = delta;
3644 fcinfo->bck_pid = -1; 3329 cinfo->bck_pid = -1;
3330
3331 cinfo->fc_poll = GNUNET_SCHEDULER_NO_TASK;
3332 cinfo->fc_poll_time = GNUNET_TIME_UNIT_SECONDS;
3645 3333
3646 fcinfo->send_buffer = 3334 cinfo->send_buffer =
3647 GNUNET_malloc (sizeof(struct MeshPeerQueue *) * t->fwd_queue_max); 3335 GNUNET_malloc (sizeof(struct MeshPeerQueue *) * t->fwd_queue_max);
3648 3336
3649 GNUNET_assert (GNUNET_OK == 3337 GNUNET_assert (GNUNET_OK ==
3650 GNUNET_CONTAINER_multihashmap_put (t->children_fc, 3338 GNUNET_CONTAINER_multihashmap_put (t->children_fc,
3651 &peer->hashPubKey, 3339 &peer->hashPubKey,
3652 fcinfo, 3340 cinfo,
3653 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); 3341 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
3654 } 3342 }
3655 return fcinfo; 3343 return cinfo;
3656} 3344}
3657 3345
3658 3346
@@ -3664,7 +3352,7 @@ tunnel_get_neighbor_fc (struct MeshTunnel *t,
3664 * 3352 *
3665 * @return ACK value. 3353 * @return ACK value.
3666 */ 3354 */
3667static struct MeshTunnelFlowControlInfo * 3355static struct MeshTunnelClientInfo *
3668tunnel_get_client_fc (struct MeshTunnel *t, 3356tunnel_get_client_fc (struct MeshTunnel *t,
3669 struct MeshClient *c) 3357 struct MeshClient *c)
3670{ 3358{
@@ -3677,7 +3365,7 @@ tunnel_get_client_fc (struct MeshTunnel *t,
3677 return &t->clients_fc[i]; 3365 return &t->clients_fc[i];
3678 } 3366 }
3679 GNUNET_assert (0); 3367 GNUNET_assert (0);
3680 return NULL; // won't get here. Just to avoid compiler / coverity complaints. 3368 return NULL; // avoid compiler / coverity complaints
3681} 3369}
3682 3370
3683 3371
@@ -3692,14 +3380,14 @@ tunnel_get_child_fwd_ack (void *cls,
3692 GNUNET_PEER_Id id) 3380 GNUNET_PEER_Id id)
3693{ 3381{
3694 struct GNUNET_PeerIdentity peer_id; 3382 struct GNUNET_PeerIdentity peer_id;
3695 struct MeshTunnelFlowControlInfo *fcinfo; 3383 struct MeshTunnelChildInfo *cinfo;
3696 struct MeshTunnelChildIteratorContext *ctx = cls; 3384 struct MeshTunnelChildIteratorContext *ctx = cls;
3697 struct MeshTunnel *t = ctx->t; 3385 struct MeshTunnel *t = ctx->t;
3698 uint32_t ack; 3386 uint32_t ack;
3699 3387
3700 GNUNET_PEER_resolve (id, &peer_id); 3388 GNUNET_PEER_resolve (id, &peer_id);
3701 fcinfo = tunnel_get_neighbor_fc (t, &peer_id); 3389 cinfo = tunnel_get_neighbor_fc (t, &peer_id);
3702 ack = fcinfo->fwd_ack; 3390 ack = cinfo->fwd_ack;
3703 3391
3704 ctx->nchildren++; 3392 ctx->nchildren++;
3705 if (GNUNET_NO == ctx->init) 3393 if (GNUNET_NO == ctx->init)
@@ -3716,6 +3404,7 @@ tunnel_get_child_fwd_ack (void *cls,
3716 { 3404 {
3717 ctx->max_child_ack = ctx->max_child_ack > ack ? ctx->max_child_ack : ack; 3405 ctx->max_child_ack = ctx->max_child_ack > ack ? ctx->max_child_ack : ack;
3718 } 3406 }
3407
3719} 3408}
3720 3409
3721 3410
@@ -3857,7 +3546,12 @@ tunnel_get_fwd_ack (struct MeshTunnel *t)
3857 if (-1LL == child_ack) 3546 if (-1LL == child_ack)
3858 { 3547 {
3859 // Node has no children, child_ack AND core buffer are irrelevant. 3548 // Node has no children, child_ack AND core buffer are irrelevant.
3860 GNUNET_break (-1LL != client_ack); // No children AND no clients? Not good! 3549 if (-1LL == client_ack) // No children AND no clients? Not good!
3550 {
3551 GNUNET_STATISTICS_update (stats, "# mesh acks with no target",
3552 1, GNUNET_NO);
3553
3554 }
3861 return (uint32_t) client_ack; 3555 return (uint32_t) client_ack;
3862 } 3556 }
3863 if (-1LL == client_ack) 3557 if (-1LL == client_ack)
@@ -3993,13 +3687,17 @@ tunnel_send_fwd_ack (struct MeshTunnel *t, uint16_t type)
3993 case GNUNET_MESSAGE_TYPE_MESH_ACK: 3687 case GNUNET_MESSAGE_TYPE_MESH_ACK:
3994 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK: 3688 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
3995 break; 3689 break;
3690 case GNUNET_MESSAGE_TYPE_MESH_POLL:
3691 t->force_ack = GNUNET_YES;
3692 break;
3996 default: 3693 default:
3997 GNUNET_break (0); 3694 GNUNET_break (0);
3998 } 3695 }
3999 3696
4000 /* Check if we need no retransmit the ACK */ 3697 /* Check if we need to transmit the ACK */
4001 if (t->fwd_queue_max > t->fwd_queue_n * 4 && 3698 if (t->fwd_queue_max > t->fwd_queue_n * 4 &&
4002 GMC_is_pid_bigger(t->last_fwd_ack, t->fwd_pid)) 3699 GMC_is_pid_bigger(t->last_fwd_ack, t->fwd_pid) &&
3700 GNUNET_NO == t->force_ack)
4003 { 3701 {
4004 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer free\n"); 3702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, buffer free\n");
4005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4015,7 +3713,7 @@ tunnel_send_fwd_ack (struct MeshTunnel *t, uint16_t type)
4015 ack = tunnel_get_fwd_ack (t); 3713 ack = tunnel_get_fwd_ack (t);
4016 3714
4017 /* If speed_min and not all children have ack'd, dont send yet */ 3715 /* If speed_min and not all children have ack'd, dont send yet */
4018 if (ack == t->last_fwd_ack) 3716 if (ack == t->last_fwd_ack && GNUNET_NO == t->force_ack)
4019 { 3717 {
4020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not ready\n"); 3718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not ready\n");
4021 return; 3719 return;
@@ -4025,6 +3723,7 @@ tunnel_send_fwd_ack (struct MeshTunnel *t, uint16_t type)
4025 GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); 3723 GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id);
4026 send_ack (t, &id, ack); 3724 send_ack (t, &id, ack);
4027 debug_fwd_ack++; 3725 debug_fwd_ack++;
3726 t->force_ack = GNUNET_NO;
4028} 3727}
4029 3728
4030 3729
@@ -4040,27 +3739,25 @@ tunnel_send_child_bck_ack (void *cls,
4040 GNUNET_PEER_Id id) 3739 GNUNET_PEER_Id id)
4041{ 3740{
4042 struct MeshTunnel *t = cls; 3741 struct MeshTunnel *t = cls;
4043 struct MeshTunnelFlowControlInfo *fcinfo; 3742 struct MeshTunnelChildInfo *cinfo;
4044 struct GNUNET_PeerIdentity peer; 3743 struct GNUNET_PeerIdentity peer;
4045 uint32_t ack; 3744 uint32_t ack;
4046 3745
4047 GNUNET_PEER_resolve (id, &peer); 3746 GNUNET_PEER_resolve (id, &peer);
4048 fcinfo = tunnel_get_neighbor_fc (t, &peer); 3747 cinfo = tunnel_get_neighbor_fc (t, &peer);
4049 ack = fcinfo->bck_pid + t->bck_queue_max - t->bck_queue_n; 3748 ack = cinfo->bck_pid + t->bck_queue_max - t->bck_queue_n;
4050
4051 3749
4052 if (fcinfo->bck_ack == ack) 3750 if (cinfo->bck_ack == ack && GNUNET_NO == t->force_ack)
4053 { 3751 {
4054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4055 " Not sending ACK, not needed\n"); 3753 " Not sending ACK, not needed\n");
4056 return; 3754 return;
4057 } 3755 }
4058 fcinfo->bck_ack = ack; 3756 cinfo->bck_ack = ack;
4059 3757
4060 fcinfo->bck_ack = fcinfo->bck_pid + t->bck_queue_max - t->bck_queue_n;
4061 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4062 " Sending BCK ACK %u (last sent: %u)\n", 3759 " Sending BCK ACK %u (last sent: %u)\n",
4063 ack, fcinfo->bck_ack); 3760 ack, cinfo->bck_ack);
4064 send_ack (t, &peer, ack); 3761 send_ack (t, &peer, ack);
4065} 3762}
4066 3763
@@ -4094,11 +3791,11 @@ tunnel_send_clients_bck_ack (struct MeshTunnel *t)
4094 /* Find client whom to allow to send to origin (with lowest buffer space) */ 3791 /* Find client whom to allow to send to origin (with lowest buffer space) */
4095 for (i = 0; i < t->nclients; i++) 3792 for (i = 0; i < t->nclients; i++)
4096 { 3793 {
4097 struct MeshTunnelFlowControlInfo *fcinfo; 3794 struct MeshTunnelClientInfo *clinfo;
4098 unsigned int delta; 3795 unsigned int delta;
4099 3796
4100 fcinfo = &t->clients_fc[i]; 3797 clinfo = &t->clients_fc[i];
4101 delta = fcinfo->bck_ack - fcinfo->bck_pid; 3798 delta = clinfo->bck_ack - clinfo->bck_pid;
4102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client %u delta: %u\n", 3799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " client %u delta: %u\n",
4103 t->clients[i]->id, delta); 3800 t->clients[i]->id, delta);
4104 3801
@@ -4107,13 +3804,13 @@ tunnel_send_clients_bck_ack (struct MeshTunnel *t)
4107 { 3804 {
4108 uint32_t ack; 3805 uint32_t ack;
4109 3806
4110 ack = fcinfo->bck_pid; 3807 ack = clinfo->bck_pid;
4111 ack += t->nobuffer ? 1 : tunnel_delta; 3808 ack += t->nobuffer ? 1 : tunnel_delta;
4112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 3809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4113 " sending ack to client %u: %u\n", 3810 " sending ack to client %u: %u\n",
4114 t->clients[i]->id, ack); 3811 t->clients[i]->id, ack);
4115 send_local_ack (t, t->clients[i], ack); 3812 send_local_ack (t, t->clients[i], ack);
4116 fcinfo->bck_ack = ack; 3813 clinfo->bck_ack = ack;
4117 } 3814 }
4118 else 3815 else
4119 { 3816 {
@@ -4155,7 +3852,9 @@ tunnel_send_bck_ack (struct MeshTunnel *t, uint16_t type)
4155 break; 3852 break;
4156 case GNUNET_MESSAGE_TYPE_MESH_ACK: 3853 case GNUNET_MESSAGE_TYPE_MESH_ACK:
4157 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK: 3854 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK:
3855 break;
4158 case GNUNET_MESSAGE_TYPE_MESH_POLL: 3856 case GNUNET_MESSAGE_TYPE_MESH_POLL:
3857 t->force_ack = GNUNET_YES;
4159 break; 3858 break;
4160 default: 3859 default:
4161 GNUNET_break (0); 3860 GNUNET_break (0);
@@ -4163,6 +3862,7 @@ tunnel_send_bck_ack (struct MeshTunnel *t, uint16_t type)
4163 3862
4164 tunnel_send_clients_bck_ack (t); 3863 tunnel_send_clients_bck_ack (t);
4165 tree_iterate_children (t->tree, &tunnel_send_child_bck_ack, t); 3864 tree_iterate_children (t->tree, &tunnel_send_child_bck_ack, t);
3865 t->force_ack = GNUNET_NO;
4166} 3866}
4167 3867
4168 3868
@@ -4254,17 +3954,37 @@ tunnel_unlock_bck_queue (struct MeshTunnel *t)
4254 * valid. 3954 * valid.
4255 * 3955 *
4256 * @param t The tunnel whose peers to notify. 3956 * @param t The tunnel whose peers to notify.
3957 * @param parent ID of the parent, in case the tree is already destroyed.
4257 */ 3958 */
4258static void 3959static void
4259tunnel_send_destroy (struct MeshTunnel *t) 3960tunnel_send_destroy (struct MeshTunnel *t, GNUNET_PEER_Id parent)
4260{ 3961{
4261 struct GNUNET_MESH_TunnelDestroy msg; 3962 struct GNUNET_MESH_TunnelDestroy msg;
3963 struct GNUNET_PeerIdentity id;
4262 3964
4263 msg.header.size = htons (sizeof (msg)); 3965 msg.header.size = htons (sizeof (msg));
4264 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY); 3966 msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY);
4265 GNUNET_PEER_resolve (t->id.oid, &msg.oid); 3967 GNUNET_PEER_resolve (t->id.oid, &msg.oid);
4266 msg.tid = htonl (t->id.tid); 3968 msg.tid = htonl (t->id.tid);
4267 tunnel_send_multicast (t, &msg.header); 3969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3970 " sending tunnel destroy for tunnel: %s [%X]\n",
3971 GNUNET_i2s (&msg.oid), t->id.tid);
3972 if (tree_count_children(t->tree) > 0)
3973 {
3974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " sending multicast to children\n");
3975 tunnel_send_multicast (t, &msg.header);
3976 }
3977 if (0 == parent)
3978 parent = tree_get_predecessor (t->tree);
3979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " parent: %u\n", parent);
3980 if (0 == parent)
3981 return;
3982
3983 GNUNET_PEER_resolve (parent, &id);
3984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3985 " sending back to %s\n",
3986 GNUNET_i2s (&id));
3987 send_prebuilt_message (&msg.header, &id, t);
4268} 3988}
4269 3989
4270 3990
@@ -4377,17 +4097,10 @@ tunnel_destroy (struct MeshTunnel *t)
4377 } 4097 }
4378 } 4098 }
4379 4099
4380 if (t->nclients > 0) 4100 (void) GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t);
4381 { 4101 GNUNET_free_non_null (t->clients);
4382 if (GNUNET_YES != 4102 GNUNET_free_non_null (t->ignore);
4383 GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels, &hash, t)) 4103 GNUNET_free_non_null (t->clients_fc);
4384 {
4385 GNUNET_break (0);
4386 r = GNUNET_SYSERR;
4387 }
4388 GNUNET_free (t->clients);
4389 GNUNET_free (t->clients_fc);
4390 }
4391 4104
4392 if (NULL != t->peers) 4105 if (NULL != t->peers)
4393 { 4106 {
@@ -4405,8 +4118,8 @@ tunnel_destroy (struct MeshTunnel *t)
4405 tree_iterate_children (t->tree, &tunnel_cancel_queues, t); 4118 tree_iterate_children (t->tree, &tunnel_cancel_queues, t);
4406 tree_destroy (t->tree); 4119 tree_destroy (t->tree);
4407 4120
4408 if (NULL != t->regex_ctx) 4121 if (NULL != t->regex_search)
4409 regex_cancel_search (t->regex_ctx); 4122 GNUNET_REGEX_search_cancel (t->regex_search->search_handle);
4410 if (NULL != t->dht_get_type) 4123 if (NULL != t->dht_get_type)
4411 GNUNET_DHT_get_stop (t->dht_get_type); 4124 GNUNET_DHT_get_stop (t->dht_get_type);
4412 if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) 4125 if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task)
@@ -4420,6 +4133,82 @@ tunnel_destroy (struct MeshTunnel *t)
4420 return r; 4133 return r;
4421} 4134}
4422 4135
4136#define TUNNEL_DESTROY_EMPTY_TIME GNUNET_TIME_UNIT_MILLISECONDS
4137
4138/**
4139 * Tunnel is empty: destroy it.
4140 *
4141 * @param cls Closure (Tunnel).
4142 * @param tc TaskContext.
4143 */
4144static void
4145tunnel_destroy_empty_delayed (void *cls,
4146 const struct GNUNET_SCHEDULER_TaskContext *tc)
4147{
4148 struct MeshTunnel *t = cls;
4149
4150 t->delayed_destroy = GNUNET_SCHEDULER_NO_TASK;
4151 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
4152 return;
4153
4154 if (0 != t->nclients ||
4155 0 != tree_count_children (t->tree))
4156 return;
4157
4158 #if MESH_DEBUG
4159 {
4160 struct GNUNET_PeerIdentity id;
4161
4162 GNUNET_PEER_resolve (t->id.oid, &id);
4163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4164 "executing destruction of empty tunnel %s [%X]\n",
4165 GNUNET_i2s (&id), t->id.tid);
4166 }
4167 #endif
4168
4169 tunnel_send_destroy (t, 0);
4170 if (0 == t->pending_messages)
4171 tunnel_destroy (t);
4172 else
4173 t->destroy = GNUNET_YES;
4174}
4175
4176
4177/**
4178 * Schedule tunnel destruction if is empty and no new traffic comes in a time.
4179 *
4180 * @param t Tunnel to destroy if empty.
4181 */
4182static void
4183tunnel_destroy_empty (struct MeshTunnel *t)
4184{
4185 if (GNUNET_SCHEDULER_NO_TASK != t->delayed_destroy ||
4186 0 != t->nclients ||
4187 0 != tree_count_children (t->tree))
4188 {
4189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4190 "%u %u %u\n",
4191 t->delayed_destroy, t->nclients, tree_count_children(t->tree));
4192 return;
4193 }
4194
4195 #if MESH_DEBUG
4196 {
4197 struct GNUNET_PeerIdentity id;
4198
4199 GNUNET_PEER_resolve (t->id.oid, &id);
4200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4201 "scheduling destruction of empty tunnel %s [%X]\n",
4202 GNUNET_i2s (&id), t->id.tid);
4203 }
4204 #endif
4205
4206 t->delayed_destroy =
4207 GNUNET_SCHEDULER_add_delayed (TUNNEL_DESTROY_EMPTY_TIME,
4208 &tunnel_destroy_empty_delayed,
4209 t);
4210}
4211
4423 4212
4424/** 4213/**
4425 * Create a new tunnel 4214 * Create a new tunnel
@@ -4491,6 +4280,19 @@ tunnel_new (GNUNET_PEER_Id owner,
4491 return t; 4280 return t;
4492} 4281}
4493 4282
4283/**
4284 * Callback when removing children from a tunnel tree. Notify owner.
4285 *
4286 * @param cls Closure (tunnel).
4287 * @param peer_id Short ID of the peer deleted.
4288 */
4289void
4290tunnel_child_removed (void *cls, GNUNET_PEER_Id peer_id)
4291{
4292 struct MeshTunnel *t = cls;
4293
4294 client_notify_peer_disconnected (t->owner, t, peer_id);
4295}
4494 4296
4495/** 4297/**
4496 * Removes an explicit path from a tunnel, freeing all intermediate nodes 4298 * Removes an explicit path from a tunnel, freeing all intermediate nodes
@@ -4503,8 +4305,15 @@ tunnel_new (GNUNET_PEER_Id owner,
4503static void 4305static void
4504tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer) 4306tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer)
4505{ 4307{
4506 if (GNUNET_NO == tree_del_peer (t->tree, peer, NULL, NULL)) 4308 int r;
4507 tunnel_destroy (t); 4309
4310 r = tree_del_peer (t->tree, peer, &tunnel_child_removed, t);
4311 if (GNUNET_NO == r)
4312 {
4313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4314 "Tunnel %u [%u] has no more nodes\n",
4315 t->id.oid, t->id.tid);
4316 }
4508} 4317}
4509 4318
4510 4319
@@ -4521,21 +4330,23 @@ tunnel_delete_peer (struct MeshTunnel *t, GNUNET_PEER_Id peer)
4521 * @return GNUNET_OK, keep iterating. 4330 * @return GNUNET_OK, keep iterating.
4522 */ 4331 */
4523static int 4332static int
4524tunnel_destroy_iterator (void *cls, const struct GNUNET_HashCode * key, void *value) 4333tunnel_destroy_iterator (void *cls,
4334 const struct GNUNET_HashCode * key,
4335 void *value)
4525{ 4336{
4526 struct MeshTunnel *t = value; 4337 struct MeshTunnel *t = value;
4527 struct MeshClient *c = cls; 4338 struct MeshClient *c = cls;
4528 4339
4529 send_client_tunnel_disconnect(t, c); 4340 send_client_tunnel_disconnect (t, c);
4530 if (c != t->owner) 4341 if (c != t->owner)
4531 { 4342 {
4532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %u is destination.\n", c->id);
4533 "Client %u is destination, keeping the tunnel alive.\n", c->id); 4344 tunnel_delete_client (t, c);
4534 tunnel_delete_client(t, c); 4345 client_delete_tunnel (c, t);
4535 client_delete_tunnel(c, t); 4346 tunnel_destroy_empty (t);
4536 return GNUNET_OK; 4347 return GNUNET_OK;
4537 } 4348 }
4538 tunnel_send_destroy(t); 4349 tunnel_send_destroy (t, 0);
4539 t->owner = NULL; 4350 t->owner = NULL;
4540 t->destroy = GNUNET_YES; 4351 t->destroy = GNUNET_YES;
4541 4352
@@ -4751,7 +4562,7 @@ queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
4751{ 4562{
4752 struct MeshTransmissionDescriptor *dd; 4563 struct MeshTransmissionDescriptor *dd;
4753 struct MeshPathInfo *path_info; 4564 struct MeshPathInfo *path_info;
4754 struct MeshTunnelFlowControlInfo *fcinfo; 4565 struct MeshTunnelChildInfo *cinfo;
4755 struct GNUNET_PeerIdentity id; 4566 struct GNUNET_PeerIdentity id;
4756 unsigned int i; 4567 unsigned int i;
4757 unsigned int max; 4568 unsigned int max;
@@ -4761,14 +4572,14 @@ queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
4761 switch (queue->type) 4572 switch (queue->type)
4762 { 4573 {
4763 case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY: 4574 case GNUNET_MESSAGE_TYPE_MESH_TUNNEL_DESTROY:
4764 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " cancelling TUNNEL_DESTROY\n"); 4575 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " cancelling TUNNEL_DESTROY\n");
4765 GNUNET_assert (GNUNET_YES == queue->tunnel->destroy); 4576 GNUNET_break (GNUNET_YES == queue->tunnel->destroy);
4766 /* FIXME: don't cancel, send and destroy tunnel in queue_send */
4767 /* fall through */ 4577 /* fall through */
4768 case GNUNET_MESSAGE_TYPE_MESH_UNICAST: 4578 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
4769 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: 4579 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
4770 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: 4580 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
4771 case GNUNET_MESSAGE_TYPE_MESH_ACK: 4581 case GNUNET_MESSAGE_TYPE_MESH_ACK:
4582 case GNUNET_MESSAGE_TYPE_MESH_POLL:
4772 case GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE: 4583 case GNUNET_MESSAGE_TYPE_MESH_PATH_KEEPALIVE:
4773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4774 " prebuilt message\n"); 4585 " prebuilt message\n");
@@ -4798,30 +4609,29 @@ queue_destroy (struct MeshPeerQueue *queue, int clear_cls)
4798 /* Delete from child_fc in the appropiate tunnel */ 4609 /* Delete from child_fc in the appropiate tunnel */
4799 max = queue->tunnel->fwd_queue_max; 4610 max = queue->tunnel->fwd_queue_max;
4800 GNUNET_PEER_resolve (queue->peer->id, &id); 4611 GNUNET_PEER_resolve (queue->peer->id, &id);
4801 fcinfo = tunnel_get_neighbor_fc (queue->tunnel, &id); 4612 cinfo = tunnel_get_neighbor_fc (queue->tunnel, &id);
4802 if (NULL != fcinfo) 4613 if (NULL != cinfo)
4803 { 4614 {
4804 GNUNET_assert (NULL != fcinfo->peer); 4615 for (i = 0; i < cinfo->send_buffer_n; i++)
4805 for (i = 0; i < fcinfo->send_buffer_n; i++)
4806 { 4616 {
4807 unsigned int i2; 4617 unsigned int i2;
4808 i2 = (fcinfo->send_buffer_start + i) % max; 4618 i2 = (cinfo->send_buffer_start + i) % max;
4809 if (fcinfo->send_buffer[i2] == queue) 4619 if (cinfo->send_buffer[i2] == queue)
4810 { 4620 {
4811 /* Found corresponding entry in the send_buffer. Move all others back. */ 4621 /* Found corresponding entry in the send_buffer. Move all others back. */
4812 unsigned int j; 4622 unsigned int j;
4813 unsigned int j2; 4623 unsigned int j2;
4814 unsigned int j3; 4624 unsigned int j3;
4815 4625
4816 for (j = i, j2 = 0, j3 = 0; j < fcinfo->send_buffer_n - 1; j++) 4626 for (j = i, j2 = 0, j3 = 0; j < cinfo->send_buffer_n - 1; j++)
4817 { 4627 {
4818 j2 = (fcinfo->send_buffer_start + j) % max; 4628 j2 = (cinfo->send_buffer_start + j) % max;
4819 j3 = (fcinfo->send_buffer_start + j + 1) % max; 4629 j3 = (cinfo->send_buffer_start + j + 1) % max;
4820 fcinfo->send_buffer[j2] = fcinfo->send_buffer[j3]; 4630 cinfo->send_buffer[j2] = cinfo->send_buffer[j3];
4821 } 4631 }
4822 4632
4823 fcinfo->send_buffer[j3] = NULL; 4633 cinfo->send_buffer[j3] = NULL;
4824 fcinfo->send_buffer_n--; 4634 cinfo->send_buffer_n--;
4825 } 4635 }
4826 } 4636 }
4827 } 4637 }
@@ -4847,7 +4657,7 @@ queue_get_next (const struct MeshPeerInfo *peer)
4847 struct MeshPeerQueue *q; 4657 struct MeshPeerQueue *q;
4848 struct MeshTunnel *t; 4658 struct MeshTunnel *t;
4849 struct MeshTransmissionDescriptor *info; 4659 struct MeshTransmissionDescriptor *info;
4850 struct MeshTunnelFlowControlInfo *fcinfo; 4660 struct MeshTunnelChildInfo *cinfo;
4851 struct GNUNET_MESH_Unicast *ucast; 4661 struct GNUNET_MESH_Unicast *ucast;
4852 struct GNUNET_MESH_ToOrigin *to_orig; 4662 struct GNUNET_MESH_ToOrigin *to_orig;
4853 struct GNUNET_MESH_Multicast *mcast; 4663 struct GNUNET_MESH_Multicast *mcast;
@@ -4869,8 +4679,8 @@ queue_get_next (const struct MeshPeerInfo *peer)
4869 ucast = (struct GNUNET_MESH_Unicast *) info->mesh_data->data; 4679 ucast = (struct GNUNET_MESH_Unicast *) info->mesh_data->data;
4870 pid = ntohl (ucast->pid); 4680 pid = ntohl (ucast->pid);
4871 GNUNET_PEER_resolve (info->peer->id, &id); 4681 GNUNET_PEER_resolve (info->peer->id, &id);
4872 fcinfo = tunnel_get_neighbor_fc (t, &id); 4682 cinfo = tunnel_get_neighbor_fc(t, &id);
4873 ack = fcinfo->fwd_ack; 4683 ack = cinfo->fwd_ack;
4874 break; 4684 break;
4875 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: 4685 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
4876 to_orig = (struct GNUNET_MESH_ToOrigin *) info->mesh_data->data; 4686 to_orig = (struct GNUNET_MESH_ToOrigin *) info->mesh_data->data;
@@ -4886,8 +4696,8 @@ queue_get_next (const struct MeshPeerInfo *peer)
4886 } 4696 }
4887 pid = ntohl (mcast->pid); 4697 pid = ntohl (mcast->pid);
4888 GNUNET_PEER_resolve (info->peer->id, &id); 4698 GNUNET_PEER_resolve (info->peer->id, &id);
4889 fcinfo = tunnel_get_neighbor_fc (t, &id); 4699 cinfo = tunnel_get_neighbor_fc(t, &id);
4890 ack = fcinfo->fwd_ack; 4700 ack = cinfo->fwd_ack;
4891 break; 4701 break;
4892 default: 4702 default:
4893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 4703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -4931,12 +4741,12 @@ queue_send (void *cls, size_t size, void *buf)
4931 struct GNUNET_MessageHeader *msg; 4741 struct GNUNET_MessageHeader *msg;
4932 struct MeshPeerQueue *queue; 4742 struct MeshPeerQueue *queue;
4933 struct MeshTunnel *t; 4743 struct MeshTunnel *t;
4934 struct MeshTunnelFlowControlInfo *fcinfo; 4744 struct MeshTunnelChildInfo *cinfo;
4935 struct GNUNET_PeerIdentity dst_id; 4745 struct GNUNET_PeerIdentity dst_id;
4936 size_t data_size; 4746 size_t data_size;
4937 4747
4938 peer->core_transmit = NULL; 4748 peer->core_transmit = NULL;
4939 fcinfo = NULL; 4749 cinfo = NULL;
4940 4750
4941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* Queue send\n"); 4751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* Queue send\n");
4942 queue = queue_get_next (peer); 4752 queue = queue_get_next (peer);
@@ -4974,6 +4784,8 @@ queue_send (void *cls, size_t size, void *buf)
4974 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* size ok\n"); 4784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* size ok\n");
4975 4785
4976 t = queue->tunnel; 4786 t = queue->tunnel;
4787 GNUNET_assert (0 < t->pending_messages);
4788 t->pending_messages--;
4977 if (GNUNET_MESSAGE_TYPE_MESH_UNICAST == queue->type) 4789 if (GNUNET_MESSAGE_TYPE_MESH_UNICAST == queue->type)
4978 { 4790 {
4979 t->fwd_queue_n--; 4791 t->fwd_queue_n--;
@@ -5031,6 +4843,12 @@ queue_send (void *cls, size_t size, void *buf)
5031 "********* considered sent\n"); 4843 "********* considered sent\n");
5032 t->fwd_queue_n--; 4844 t->fwd_queue_n--;
5033 } 4845 }
4846 else
4847 {
4848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4849 "********* NOT considered sent yet\n");
4850 t->pending_messages++;
4851 }
5034 } 4852 }
5035 data_size = send_core_data_multicast(queue->cls, size, buf); 4853 data_size = send_core_data_multicast(queue->cls, size, buf);
5036 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_MULTICAST); 4854 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_MULTICAST);
@@ -5059,22 +4877,22 @@ queue_send (void *cls, size_t size, void *buf)
5059 case GNUNET_MESSAGE_TYPE_MESH_UNICAST: 4877 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
5060 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN: 4878 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
5061 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST: 4879 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
5062 fcinfo = tunnel_get_neighbor_fc (t, &dst_id); 4880 cinfo = tunnel_get_neighbor_fc (t, &dst_id);
5063 if (fcinfo->send_buffer[fcinfo->send_buffer_start] != queue) 4881 if (cinfo->send_buffer[cinfo->send_buffer_start] != queue)
5064 { 4882 {
5065 GNUNET_break (0); 4883 GNUNET_break (0);
5066 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 4884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5067 "at pos %u (%p) != %p\n", 4885 "at pos %u (%p) != %p\n",
5068 fcinfo->send_buffer_start, 4886 cinfo->send_buffer_start,
5069 fcinfo->send_buffer[fcinfo->send_buffer_start], 4887 cinfo->send_buffer[cinfo->send_buffer_start],
5070 queue); 4888 queue);
5071 } 4889 }
5072 if (fcinfo->send_buffer_n > 0) 4890 if (cinfo->send_buffer_n > 0)
5073 { 4891 {
5074 fcinfo->send_buffer[fcinfo->send_buffer_start] = NULL; 4892 cinfo->send_buffer[cinfo->send_buffer_start] = NULL;
5075 fcinfo->send_buffer_n--; 4893 cinfo->send_buffer_n--;
5076 fcinfo->send_buffer_start++; 4894 cinfo->send_buffer_start++;
5077 fcinfo->send_buffer_start %= t->fwd_queue_max; 4895 cinfo->send_buffer_start %= t->fwd_queue_max;
5078 } 4896 }
5079 else 4897 else
5080 { 4898 {
@@ -5088,9 +4906,8 @@ queue_send (void *cls, size_t size, void *buf)
5088 /* Free queue, but cls was freed by send_core_* */ 4906 /* Free queue, but cls was freed by send_core_* */
5089 queue_destroy (queue, GNUNET_NO); 4907 queue_destroy (queue, GNUNET_NO);
5090 4908
5091 if (GNUNET_YES == t->destroy) 4909 if (GNUNET_YES == t->destroy && 0 == t->pending_messages)
5092 { 4910 {
5093 // FIXME fc tunnel destroy all pending traffic? wait for it?
5094 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* destroying tunnel!\n"); 4911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* destroying tunnel!\n");
5095 tunnel_destroy (t); 4912 tunnel_destroy (t);
5096 } 4913 }
@@ -5120,10 +4937,14 @@ queue_send (void *cls, size_t size, void *buf)
5120 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4937 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5121 "********* %s stalled\n", 4938 "********* %s stalled\n",
5122 GNUNET_i2s(&my_full_id)); 4939 GNUNET_i2s(&my_full_id));
5123 if (NULL == fcinfo) 4940 if (NULL == cinfo)
5124 fcinfo = tunnel_get_neighbor_fc (t, &dst_id); 4941 cinfo = tunnel_get_neighbor_fc (t, &dst_id);
5125 fcinfo->fc_poll = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS, 4942 // FIXME unify bck/fwd structures, bck does not have cinfo right now
5126 &tunnel_poll, fcinfo); 4943 if (NULL != cinfo && GNUNET_SCHEDULER_NO_TASK == cinfo->fc_poll)
4944 {
4945 cinfo->fc_poll = GNUNET_SCHEDULER_add_delayed (cinfo->fc_poll_time,
4946 &tunnel_poll, cinfo);
4947 }
5127 } 4948 }
5128 } 4949 }
5129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* return %d\n", data_size); 4950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "********* return %d\n", data_size);
@@ -5153,7 +4974,7 @@ queue_add (void *cls, uint16_t type, size_t size,
5153 struct MeshPeerInfo *dst, struct MeshTunnel *t) 4974 struct MeshPeerInfo *dst, struct MeshTunnel *t)
5154{ 4975{
5155 struct MeshPeerQueue *queue; 4976 struct MeshPeerQueue *queue;
5156 struct MeshTunnelFlowControlInfo *fcinfo; 4977 struct MeshTunnelChildInfo *cinfo;
5157 struct GNUNET_PeerIdentity id; 4978 struct GNUNET_PeerIdentity id;
5158 unsigned int *max; 4979 unsigned int *max;
5159 unsigned int *n; 4980 unsigned int *n;
@@ -5175,17 +4996,11 @@ queue_add (void *cls, uint16_t type, size_t size,
5175 { 4996 {
5176 if (*n >= *max) 4997 if (*n >= *max)
5177 { 4998 {
5178 struct MeshTransmissionDescriptor *td = cls;
5179 struct GNUNET_MESH_ToOrigin *to;
5180
5181 to = td->mesh_data->data;
5182 GNUNET_break(0); 4999 GNUNET_break(0);
5183 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 5000 GNUNET_STATISTICS_update(stats,
5184 "bck pid %u, bck ack %u, msg pid %u\n", 5001 "# messages dropped (buffer full)",
5185 t->bck_pid, t->bck_ack, ntohl(to->pid));
5186 GNUNET_STATISTICS_update(stats, "# messages dropped (buffer full)",
5187 1, GNUNET_NO); 5002 1, GNUNET_NO);
5188 return; // Drop message 5003 return; // Drop message
5189 } 5004 }
5190 (*n)++; 5005 (*n)++;
5191 } 5006 }
@@ -5209,28 +5024,29 @@ queue_add (void *cls, uint16_t type, size_t size,
5209 &queue_send, 5024 &queue_send,
5210 dst); 5025 dst);
5211 } 5026 }
5027 t->pending_messages++;
5212 if (NULL == n) // Is this internal mesh traffic? 5028 if (NULL == n) // Is this internal mesh traffic?
5213 return; 5029 return;
5214 5030
5215 // It's payload, keep track of buffer per peer. 5031 // It's payload, keep track of buffer per peer.
5216 fcinfo = tunnel_get_neighbor_fc (t, &id); 5032 cinfo = tunnel_get_neighbor_fc(t, &id);
5217 i = (fcinfo->send_buffer_start + fcinfo->send_buffer_n) % t->fwd_queue_max; 5033 i = (cinfo->send_buffer_start + cinfo->send_buffer_n) % t->fwd_queue_max;
5218 if (NULL != fcinfo->send_buffer[i]) 5034 if (NULL != cinfo->send_buffer[i])
5219 { 5035 {
5220 GNUNET_break (fcinfo->send_buffer_n == t->fwd_queue_max); // aka i == start 5036 GNUNET_break (cinfo->send_buffer_n == t->fwd_queue_max); // aka i == start
5221 queue_destroy (fcinfo->send_buffer[fcinfo->send_buffer_start], GNUNET_YES); 5037 queue_destroy (cinfo->send_buffer[cinfo->send_buffer_start], GNUNET_YES);
5222 fcinfo->send_buffer_start++; 5038 cinfo->send_buffer_start++;
5223 fcinfo->send_buffer_start %= t->fwd_queue_max; 5039 cinfo->send_buffer_start %= t->fwd_queue_max;
5224 } 5040 }
5225 else 5041 else
5226 { 5042 {
5227 fcinfo->send_buffer_n++; 5043 cinfo->send_buffer_n++;
5228 } 5044 }
5229 fcinfo->send_buffer[i] = queue; 5045 cinfo->send_buffer[i] = queue;
5230 if (fcinfo->send_buffer_n > t->fwd_queue_max) 5046 if (cinfo->send_buffer_n > t->fwd_queue_max)
5231 { 5047 {
5232 GNUNET_break (0); 5048 GNUNET_break (0);
5233 fcinfo->send_buffer_n = t->fwd_queue_max; 5049 cinfo->send_buffer_n = t->fwd_queue_max;
5234 } 5050 }
5235} 5051}
5236 5052
@@ -5571,26 +5387,43 @@ handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
5571{ 5387{
5572 struct GNUNET_MESH_TunnelDestroy *msg; 5388 struct GNUNET_MESH_TunnelDestroy *msg;
5573 struct MeshTunnel *t; 5389 struct MeshTunnel *t;
5390 GNUNET_PEER_Id parent;
5391 GNUNET_PEER_Id pid;
5574 5392
5575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5576 "Got a TUNNEL DESTROY packet from %s\n", GNUNET_i2s (peer));
5577 msg = (struct GNUNET_MESH_TunnelDestroy *) message; 5393 msg = (struct GNUNET_MESH_TunnelDestroy *) message;
5578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for tunnel %s [%u]\n", 5394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5395 "Got a TUNNEL DESTROY packet from %s\n",
5396 GNUNET_i2s (peer));
5397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5398 " for tunnel %s [%u]\n",
5579 GNUNET_i2s (&msg->oid), ntohl (msg->tid)); 5399 GNUNET_i2s (&msg->oid), ntohl (msg->tid));
5580 t = tunnel_get (&msg->oid, ntohl (msg->tid)); 5400 t = tunnel_get (&msg->oid, ntohl (msg->tid));
5401 /* Check signature */
5581 if (NULL == t) 5402 if (NULL == t)
5582 { 5403 {
5583 /* Probably already got the message from another path, 5404 /* Probably already got the message from another path,
5584 * destroyed the tunnel and retransmitted to children. 5405 * destroyed the tunnel and retransmitted to children.
5585 * Safe to ignore. 5406 * Safe to ignore.
5586 */ 5407 */
5587 GNUNET_STATISTICS_update (stats, "# control on unknown tunnel", 1, GNUNET_NO); 5408 GNUNET_STATISTICS_update (stats, "# control on unknown tunnel",
5409 1, GNUNET_NO);
5588 return GNUNET_OK; 5410 return GNUNET_OK;
5589 } 5411 }
5590 if (t->id.oid == myid) 5412 parent = tree_get_predecessor (t->tree);
5413 pid = GNUNET_PEER_search (peer);
5414 if (pid != parent)
5591 { 5415 {
5592 GNUNET_break_op (0); 5416 unsigned int nc;
5593 return GNUNET_OK; 5417
5418 tree_del_peer (t->tree, pid, &tunnel_child_removed, t);
5419 nc = tree_count_children (t->tree);
5420 if (nc > 0 || NULL != t->owner || t->nclients > 0)
5421 {
5422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5423 "still in use: %u cl, %u ch\n",
5424 t->nclients, nc);
5425 return GNUNET_OK;
5426 }
5594 } 5427 }
5595 if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) 5428 if (t->local_tid_dest >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
5596 { 5429 {
@@ -5599,7 +5432,7 @@ handle_mesh_tunnel_destroy (void *cls, const struct GNUNET_PeerIdentity *peer,
5599 t->local_tid, t->local_tid_dest); 5432 t->local_tid, t->local_tid_dest);
5600 send_clients_tunnel_destroy (t); 5433 send_clients_tunnel_destroy (t);
5601 } 5434 }
5602 tunnel_send_destroy (t); 5435 tunnel_send_destroy (t, parent);
5603 t->destroy = GNUNET_YES; 5436 t->destroy = GNUNET_YES;
5604 // TODO: add timeout to destroy the tunnel anyway 5437 // TODO: add timeout to destroy the tunnel anyway
5605 return GNUNET_OK; 5438 return GNUNET_OK;
@@ -5625,7 +5458,7 @@ handle_mesh_data_unicast (void *cls, const struct GNUNET_PeerIdentity *peer,
5625{ 5458{
5626 struct GNUNET_MESH_Unicast *msg; 5459 struct GNUNET_MESH_Unicast *msg;
5627 struct GNUNET_PeerIdentity *neighbor; 5460 struct GNUNET_PeerIdentity *neighbor;
5628 struct MeshTunnelFlowControlInfo *fcinfo; 5461 struct MeshTunnelChildInfo *cinfo;
5629 struct MeshTunnel *t; 5462 struct MeshTunnel *t;
5630 GNUNET_PEER_Id dest_id; 5463 GNUNET_PEER_Id dest_id;
5631 uint32_t pid; 5464 uint32_t pid;
@@ -5706,16 +5539,16 @@ handle_mesh_data_unicast (void *cls, const struct GNUNET_PeerIdentity *peer,
5706 " not for us, retransmitting...\n"); 5539 " not for us, retransmitting...\n");
5707 5540
5708 neighbor = tree_get_first_hop (t->tree, dest_id); 5541 neighbor = tree_get_first_hop (t->tree, dest_id);
5709 fcinfo = tunnel_get_neighbor_fc (t, neighbor); 5542 cinfo = tunnel_get_neighbor_fc (t, neighbor);
5710 fcinfo->fwd_pid = pid; 5543 cinfo->fwd_pid = pid;
5711 GNUNET_CONTAINER_multihashmap_iterate (t->children_fc, 5544 GNUNET_CONTAINER_multihashmap_iterate (t->children_fc,
5712 &tunnel_add_skip, 5545 &tunnel_add_skip,
5713 &neighbor); 5546 &neighbor);
5714 if (GNUNET_YES == t->nobuffer && 5547 if (GNUNET_YES == t->nobuffer &&
5715 GNUNET_YES == GMC_is_pid_bigger (pid, fcinfo->fwd_ack)) 5548 GNUNET_YES == GMC_is_pid_bigger (pid, cinfo->fwd_ack))
5716 { 5549 {
5717 GNUNET_STATISTICS_update (stats, "# unsolicited unicast", 1, GNUNET_NO); 5550 GNUNET_STATISTICS_update (stats, "# unsolicited unicast", 1, GNUNET_NO);
5718 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u > %u\n", pid, fcinfo->fwd_ack); 5551 GNUNET_log (GNUNET_ERROR_TYPE_INFO, " %u > %u\n", pid, cinfo->fwd_ack);
5719 GNUNET_break_op (0); 5552 GNUNET_break_op (0);
5720 return GNUNET_OK; 5553 return GNUNET_OK;
5721 } 5554 }
@@ -5831,7 +5664,8 @@ handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
5831 struct GNUNET_PeerIdentity id; 5664 struct GNUNET_PeerIdentity id;
5832 struct MeshPeerInfo *peer_info; 5665 struct MeshPeerInfo *peer_info;
5833 struct MeshTunnel *t; 5666 struct MeshTunnel *t;
5834 struct MeshTunnelFlowControlInfo *fcinfo; 5667 struct MeshTunnelChildInfo *cinfo;
5668 GNUNET_PEER_Id predecessor;
5835 size_t size; 5669 size_t size;
5836 uint32_t pid; 5670 uint32_t pid;
5837 5671
@@ -5854,21 +5688,20 @@ handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
5854 { 5688 {
5855 /* TODO notify that we dont know this tunnel (whom)? */ 5689 /* TODO notify that we dont know this tunnel (whom)? */
5856 GNUNET_STATISTICS_update (stats, "# data on unknown tunnel", 1, GNUNET_NO); 5690 GNUNET_STATISTICS_update (stats, "# data on unknown tunnel", 1, GNUNET_NO);
5857 GNUNET_break_op (0);
5858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 5691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5859 "Received to_origin with PID %u on unknown tunnel\n", 5692 "Received to_origin with PID %u on unknown tunnel %s [%u]\n",
5860 pid); 5693 pid, GNUNET_i2s (&msg->oid), ntohl (msg->tid));
5861 return GNUNET_OK; 5694 return GNUNET_OK;
5862 } 5695 }
5863 5696
5864 fcinfo = tunnel_get_neighbor_fc (t, peer); 5697 cinfo = tunnel_get_neighbor_fc(t, peer);
5865 if (NULL == fcinfo) 5698 if (NULL == cinfo)
5866 { 5699 {
5867 GNUNET_break (0); 5700 GNUNET_break (0);
5868 return GNUNET_OK; 5701 return GNUNET_OK;
5869 } 5702 }
5870 5703
5871 if (fcinfo->bck_pid == pid) 5704 if (cinfo->bck_pid == pid)
5872 { 5705 {
5873 /* already seen this packet, drop */ 5706 /* already seen this packet, drop */
5874 GNUNET_STATISTICS_update (stats, "# duplicate PID drops BCK", 1, GNUNET_NO); 5707 GNUNET_STATISTICS_update (stats, "# duplicate PID drops BCK", 1, GNUNET_NO);
@@ -5880,7 +5713,7 @@ handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
5880 5713
5881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 5714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5882 " pid %u not seen yet, forwarding\n", pid); 5715 " pid %u not seen yet, forwarding\n", pid);
5883 fcinfo->bck_pid = pid; 5716 cinfo->bck_pid = pid;
5884 5717
5885 if (NULL != t->owner) 5718 if (NULL != t->owner)
5886 { 5719 {
@@ -5911,7 +5744,31 @@ handle_mesh_data_to_orig (void *cls, const struct GNUNET_PeerIdentity *peer,
5911 GNUNET_break (0); 5744 GNUNET_break (0);
5912 return GNUNET_OK; 5745 return GNUNET_OK;
5913 } 5746 }
5914 GNUNET_PEER_resolve (tree_get_predecessor (t->tree), &id); 5747 predecessor = tree_get_predecessor (t->tree);
5748 if (0 == predecessor)
5749 {
5750 if (GNUNET_YES == t->destroy)
5751 {
5752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5753 "to orig received on a dying tunnel %s [%X]\n",
5754 GNUNET_i2s (&msg->oid), ntohl(msg->tid));
5755 return GNUNET_OK;
5756 }
5757 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5758 "unknown to origin at %s\n",
5759 GNUNET_i2s (&my_full_id));
5760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5761 "from peer %s\n",
5762 GNUNET_i2s (peer));
5763 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5764 "for tunnel %s [%X]\n",
5765 GNUNET_i2s (&msg->oid), ntohl(msg->tid));
5766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5767 "current tree:\n");
5768 tree_debug (t->tree);
5769 return GNUNET_OK;
5770 }
5771 GNUNET_PEER_resolve (predecessor, &id);
5915 send_prebuilt_message (message, &id, t); 5772 send_prebuilt_message (message, &id, t);
5916 GNUNET_STATISTICS_update (stats, "# to origin forwarded", 1, GNUNET_NO); 5773 GNUNET_STATISTICS_update (stats, "# to origin forwarded", 1, GNUNET_NO);
5917 5774
@@ -5951,7 +5808,6 @@ handle_mesh_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
5951 { 5808 {
5952 /* TODO notify that we dont know this tunnel (whom)? */ 5809 /* TODO notify that we dont know this tunnel (whom)? */
5953 GNUNET_STATISTICS_update (stats, "# ack on unknown tunnel", 1, GNUNET_NO); 5810 GNUNET_STATISTICS_update (stats, "# ack on unknown tunnel", 1, GNUNET_NO);
5954 GNUNET_break_op (0);
5955 return GNUNET_OK; 5811 return GNUNET_OK;
5956 } 5812 }
5957 ack = ntohl (msg->pid); 5813 ack = ntohl (msg->pid);
@@ -5960,14 +5816,20 @@ handle_mesh_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
5960 /* Is this a forward or backward ACK? */ 5816 /* Is this a forward or backward ACK? */
5961 if (tree_get_predecessor(t->tree) != GNUNET_PEER_search(peer)) 5817 if (tree_get_predecessor(t->tree) != GNUNET_PEER_search(peer))
5962 { 5818 {
5963 struct MeshTunnelFlowControlInfo *fcinfo; 5819 struct MeshTunnelChildInfo *cinfo;
5964 5820
5965 debug_bck_ack++; 5821 debug_bck_ack++;
5966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n"); 5822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " FWD ACK\n");
5967 fcinfo = tunnel_get_neighbor_fc (t, peer); 5823 cinfo = tunnel_get_neighbor_fc (t, peer);
5968 fcinfo->fwd_ack = ack; 5824 cinfo->fwd_ack = ack;
5969 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK); 5825 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_ACK);
5970 tunnel_unlock_fwd_queues (t); 5826 tunnel_unlock_fwd_queues (t);
5827 if (GNUNET_SCHEDULER_NO_TASK != cinfo->fc_poll)
5828 {
5829 GNUNET_SCHEDULER_cancel (cinfo->fc_poll);
5830 cinfo->fc_poll = GNUNET_SCHEDULER_NO_TASK;
5831 cinfo->fc_poll_time = GNUNET_TIME_UNIT_SECONDS;
5832 }
5971 } 5833 }
5972 else 5834 else
5973 { 5835 {
@@ -6019,11 +5881,11 @@ handle_mesh_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
6019 /* Is this a forward or backward ACK? */ 5881 /* Is this a forward or backward ACK? */
6020 if (tree_get_predecessor(t->tree) != GNUNET_PEER_search(peer)) 5882 if (tree_get_predecessor(t->tree) != GNUNET_PEER_search(peer))
6021 { 5883 {
6022 struct MeshTunnelFlowControlInfo *fcinfo; 5884 struct MeshTunnelChildInfo *cinfo;
6023 5885
6024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " from FWD\n"); 5886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " from FWD\n");
6025 fcinfo = tunnel_get_neighbor_fc (t, peer); 5887 cinfo = tunnel_get_neighbor_fc (t, peer);
6026 fcinfo->bck_ack = fcinfo->fwd_pid; // mark as ready to send 5888 cinfo->bck_ack = cinfo->fwd_pid; // mark as ready to send
6027 tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_POLL); 5889 tunnel_send_bck_ack (t, GNUNET_MESSAGE_TYPE_MESH_POLL);
6028 } 5890 }
6029 else 5891 else
@@ -6035,7 +5897,6 @@ handle_mesh_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
6035 return GNUNET_OK; 5897 return GNUNET_OK;
6036} 5898}
6037 5899
6038
6039/** 5900/**
6040 * Core handler for path ACKs 5901 * Core handler for path ACKs
6041 * 5902 *
@@ -6081,12 +5942,12 @@ handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
6081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", 5942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
6082 GNUNET_i2s (peer)); 5943 GNUNET_i2s (peer));
6083 5944
6084 if (NULL != t->regex_ctx && t->regex_ctx->info->peer == peer_info->id) 5945 if (NULL != t->regex_search && t->regex_search->peer == peer_info->id)
6085 { 5946 {
6086 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 5947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6087 "connect_by_string completed, stopping search\n"); 5948 "connect_by_string completed, stopping search\n");
6088 regex_cancel_search (t->regex_ctx); 5949 regex_cancel_search (t->regex_search);
6089 t->regex_ctx = NULL; 5950 t->regex_search = NULL;
6090 } 5951 }
6091 5952
6092 /* Add paths to peers? */ 5953 /* Add paths to peers? */
@@ -6169,8 +6030,8 @@ handle_mesh_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
6169 if (NULL == t) 6030 if (NULL == t)
6170 { 6031 {
6171 /* TODO notify that we dont know that tunnel */ 6032 /* TODO notify that we dont know that tunnel */
6172 GNUNET_STATISTICS_update (stats, "# keepalive on unknown tunnel", 1, GNUNET_NO); 6033 GNUNET_STATISTICS_update (stats, "# keepalive on unknown tunnel", 1,
6173 GNUNET_break_op (0); 6034 GNUNET_NO);
6174 return GNUNET_OK; 6035 return GNUNET_OK;
6175 } 6036 }
6176 6037
@@ -6414,140 +6275,6 @@ dht_get_type_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6414} 6275}
6415 6276
6416 6277
6417/**
6418 * Function to process DHT string to regex matching.
6419 * Called on each result obtained for the DHT search.
6420 *
6421 * @param cls closure (search context)
6422 * @param exp when will this value expire
6423 * @param key key of the result
6424 * @param get_path path of the get request (not used)
6425 * @param get_path_length lenght of get_path (not used)
6426 * @param put_path path of the put request (not used)
6427 * @param put_path_length length of the put_path (not used)
6428 * @param type type of the result
6429 * @param size number of bytes in data
6430 * @param data pointer to the result data
6431 */
6432static void
6433dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6434 const struct GNUNET_HashCode * key,
6435 const struct GNUNET_PeerIdentity *get_path,
6436 unsigned int get_path_length,
6437 const struct GNUNET_PeerIdentity *put_path,
6438 unsigned int put_path_length,
6439 enum GNUNET_BLOCK_Type type,
6440 size_t size, const void *data)
6441{
6442 const struct MeshRegexAccept *block = data;
6443 struct MeshRegexSearchContext *ctx = cls;
6444 struct MeshRegexSearchInfo *info = ctx->info;
6445 struct MeshPeerPath *p;
6446 struct MeshPeerInfo *peer_info;
6447
6448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
6449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", info->description);
6450
6451 peer_info = peer_info_get(&block->id);
6452 p = path_build_from_dht (get_path, get_path_length, put_path,
6453 put_path_length);
6454 path_add_to_peers (p, GNUNET_NO);
6455 path_destroy(p);
6456
6457 tunnel_add_peer (info->t, peer_info);
6458 peer_info_connect (peer_info, info->t);
6459 if (0 == info->peer)
6460 {
6461 info->peer = peer_info->id;
6462 }
6463 else
6464 {
6465 GNUNET_array_append (info->peers, info->n_peers, peer_info->id);
6466 }
6467
6468 info->timeout = GNUNET_SCHEDULER_add_delayed (connect_timeout,
6469 &regex_connect_timeout,
6470 info);
6471
6472 return;
6473}
6474
6475
6476/**
6477 * Function to process DHT string to regex matching.
6478 * Called on each result obtained for the DHT search.
6479 *
6480 * @param cls closure (search context)
6481 * @param exp when will this value expire
6482 * @param key key of the result
6483 * @param get_path path of the get request (not used)
6484 * @param get_path_length lenght of get_path (not used)
6485 * @param put_path path of the put request (not used)
6486 * @param put_path_length length of the put_path (not used)
6487 * @param type type of the result
6488 * @param size number of bytes in data
6489 * @param data pointer to the result data
6490 *
6491 * TODO: re-issue the request after certain time? cancel after X results?
6492 */
6493static void
6494dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6495 const struct GNUNET_HashCode * key,
6496 const struct GNUNET_PeerIdentity *get_path,
6497 unsigned int get_path_length,
6498 const struct GNUNET_PeerIdentity *put_path,
6499 unsigned int put_path_length,
6500 enum GNUNET_BLOCK_Type type,
6501 size_t size, const void *data)
6502{
6503 const struct MeshRegexBlock *block = data;
6504 struct MeshRegexSearchContext *ctx = cls;
6505 struct MeshRegexSearchInfo *info = ctx->info;
6506 void *copy;
6507 size_t len;
6508
6509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6510 "DHT GET STRING RETURNED RESULTS\n");
6511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6512 " key: %s\n", GNUNET_h2s (key));
6513
6514 copy = GNUNET_malloc (size);
6515 memcpy (copy, data, size);
6516 GNUNET_break (GNUNET_OK ==
6517 GNUNET_CONTAINER_multihashmap_put(info->dht_get_results, key, copy,
6518 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
6519 len = ntohl (block->n_proof);
6520 {
6521 char proof[len + 1];
6522
6523 memcpy (proof, &block[1], len);
6524 proof[len] = '\0';
6525 if (GNUNET_OK != GNUNET_REGEX_check_proof (proof, key))
6526 {
6527 GNUNET_break_op (0);
6528 return;
6529 }
6530 }
6531 len = strlen (info->description);
6532 if (len == ctx->position) // String processed
6533 {
6534 if (GNUNET_YES == ntohl (block->accepting))
6535 {
6536 regex_find_path(key, ctx);
6537 }
6538 else
6539 {
6540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " block not accepting!\n");
6541 // FIXME REGEX this block not successful, wait for more? start timeout?
6542 }
6543 return;
6544 }
6545
6546 regex_next_edge (block, size, ctx);
6547
6548 return;
6549}
6550
6551/******************************************************************************/ 6278/******************************************************************************/
6552/********************* MESH LOCAL HANDLES **************************/ 6279/********************* MESH LOCAL HANDLES **************************/
6553/******************************************************************************/ 6280/******************************************************************************/
@@ -6573,6 +6300,7 @@ handle_local_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
6573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n"); 6300 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " (SERVER DOWN)\n");
6574 return; 6301 return;
6575 } 6302 }
6303
6576 c = clients; 6304 c = clients;
6577 while (NULL != c) 6305 while (NULL != c)
6578 { 6306 {
@@ -6615,6 +6343,8 @@ handle_local_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
6615 for (i = 0; i < c->n_regex; i++) 6343 for (i = 0; i < c->n_regex; i++)
6616 { 6344 {
6617 GNUNET_free (c->regexes[i].regex); 6345 GNUNET_free (c->regexes[i].regex);
6346 if (NULL != c->regexes[i].h)
6347 GNUNET_REGEX_announce_cancel (c->regexes[i].h);
6618 } 6348 }
6619 GNUNET_free_non_null (c->regexes); 6349 GNUNET_free_non_null (c->regexes);
6620 if (GNUNET_SCHEDULER_NO_TASK != c->regex_announce_task) 6350 if (GNUNET_SCHEDULER_NO_TASK != c->regex_announce_task)
@@ -6742,11 +6472,12 @@ static void
6742handle_local_announce_regex (void *cls, struct GNUNET_SERVER_Client *client, 6472handle_local_announce_regex (void *cls, struct GNUNET_SERVER_Client *client,
6743 const struct GNUNET_MessageHeader *message) 6473 const struct GNUNET_MessageHeader *message)
6744{ 6474{
6745 struct GNUNET_MESH_RegexAnnounce *msg; 6475 const struct GNUNET_MESH_RegexAnnounce *msg;
6746 struct MeshRegexDescriptor rd; 6476 struct MeshRegexDescriptor rd;
6747 struct MeshClient *c; 6477 struct MeshClient *c;
6748 char *regex; 6478 char *regex;
6749 size_t len; 6479 size_t len;
6480 size_t offset;
6750 6481
6751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "announce regex started\n"); 6482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "announce regex started\n");
6752 6483
@@ -6759,20 +6490,46 @@ handle_local_announce_regex (void *cls, struct GNUNET_SERVER_Client *client,
6759 } 6490 }
6760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); 6491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id);
6761 6492
6762 msg = (struct GNUNET_MESH_RegexAnnounce *) message; 6493 msg = (const struct GNUNET_MESH_RegexAnnounce *) message;
6494
6763 len = ntohs (message->size) - sizeof(struct GNUNET_MESH_RegexAnnounce); 6495 len = ntohs (message->size) - sizeof(struct GNUNET_MESH_RegexAnnounce);
6764 regex = GNUNET_malloc (len + 1); 6496 if (NULL != c->partial_regex)
6765 memcpy (regex, &msg[1], len); 6497 {
6766 regex[len] = '\0'; 6498 regex = c->partial_regex;
6499 offset = strlen (c->partial_regex);
6500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6501 " continuation, already have %u bytes\n",
6502 offset);
6503 }
6504 else
6505 {
6506 regex = NULL;
6507 offset = 0;
6508 }
6509
6510 regex = GNUNET_realloc (regex, offset + len + 1);
6511 memcpy (&regex[offset], &msg[1], len);
6512 regex[offset + len] = '\0';
6513 if (0 == ntohs (msg->last))
6514 {
6515 c->partial_regex = regex;
6516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6517 " not ended, stored %u bytes for later\n",
6518 len);
6519 GNUNET_SERVER_receive_done (client, GNUNET_OK);
6520 return;
6521 }
6767 rd.regex = regex; 6522 rd.regex = regex;
6768 rd.compression = ntohs (msg->compression_characters); 6523 rd.compression = ntohs (msg->compression_characters);
6524 rd.h = NULL;
6769 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " length %u\n", len); 6525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " length %u\n", len);
6770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regex %s\n", regex); 6526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regex %s\n", regex);
6771 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " cm %u\n", ntohs(rd.compression)); 6527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " cm %u\n", ntohs(rd.compression));
6772 GNUNET_array_append (c->regexes, c->n_regex, rd); 6528 GNUNET_array_append (c->regexes, c->n_regex, rd);
6529 c->partial_regex = NULL;
6773 if (GNUNET_SCHEDULER_NO_TASK == c->regex_announce_task) 6530 if (GNUNET_SCHEDULER_NO_TASK == c->regex_announce_task)
6774 { 6531 {
6775 c->regex_announce_task = GNUNET_SCHEDULER_add_now(&announce_regex, c); 6532 c->regex_announce_task = GNUNET_SCHEDULER_add_now(&regex_announce, c);
6776 } 6533 }
6777 else 6534 else
6778 { 6535 {
@@ -6907,30 +6664,18 @@ handle_local_tunnel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
6907 if (c != t->owner || tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV) 6664 if (c != t->owner || tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_SERV)
6908 { 6665 {
6909 client_ignore_tunnel (c, t); 6666 client_ignore_tunnel (c, t);
6910#if 0 6667 tunnel_destroy_empty (t);
6911 // TODO: when to destroy incoming tunnel?
6912 if (t->nclients == 0)
6913 {
6914 GNUNET_assert (GNUNET_YES ==
6915 GNUNET_CONTAINER_multihashmap_remove (incoming_tunnels,
6916 &hash, t));
6917 GNUNET_assert (GNUNET_YES ==
6918 GNUNET_CONTAINER_multihashmap_remove (t->peers,
6919 &my_full_id.hashPubKey,
6920 t));
6921 }
6922#endif
6923 GNUNET_SERVER_receive_done (client, GNUNET_OK); 6668 GNUNET_SERVER_receive_done (client, GNUNET_OK);
6924 return; 6669 return;
6925 } 6670 }
6926 send_client_tunnel_disconnect(t, c); 6671 send_client_tunnel_disconnect (t, c);
6927 client_delete_tunnel(c, t); 6672 client_delete_tunnel (c, t);
6928 6673
6929 /* Don't try to ACK the client about the tunnel_destroy multicast packet */ 6674 /* Don't try to ACK the client about the tunnel_destroy multicast packet */
6930 t->owner = NULL; 6675 t->owner = NULL;
6931 tunnel_send_destroy (t); 6676 tunnel_send_destroy (t, 0);
6932 t->destroy = GNUNET_YES; 6677 t->destroy = GNUNET_YES;
6933 // The tunnel will be destroyed when the last message is transmitted. 6678 /* The tunnel will be destroyed when the last message is transmitted. */
6934 GNUNET_SERVER_receive_done (client, GNUNET_OK); 6679 GNUNET_SERVER_receive_done (client, GNUNET_OK);
6935 return; 6680 return;
6936} 6681}
@@ -7441,9 +7186,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7441 const struct GNUNET_MessageHeader *message) 7186 const struct GNUNET_MessageHeader *message)
7442{ 7187{
7443 struct GNUNET_MESH_ConnectPeerByString *msg; 7188 struct GNUNET_MESH_ConnectPeerByString *msg;
7444 struct MeshRegexSearchContext *ctx;
7445 struct MeshRegexSearchInfo *info; 7189 struct MeshRegexSearchInfo *info;
7446 struct GNUNET_DHT_GetHandle *get_h;
7447 struct GNUNET_HashCode key; 7190 struct GNUNET_HashCode key;
7448 struct MeshTunnel *t; 7191 struct MeshTunnel *t;
7449 struct MeshClient *c; 7192 struct MeshClient *c;
@@ -7451,6 +7194,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7451 const char *string; 7194 const char *string;
7452 size_t size; 7195 size_t size;
7453 size_t len; 7196 size_t len;
7197
7454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7455 "Connect by string started\n"); 7199 "Connect by string started\n");
7456 msg = (struct GNUNET_MESH_ConnectPeerByString *) message; 7200 msg = (struct GNUNET_MESH_ConnectPeerByString *) message;
@@ -7498,7 +7242,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7498 7242
7499 /* Only one connect_by_string allowed at the same time! */ 7243 /* Only one connect_by_string allowed at the same time! */
7500 /* FIXME: allow more, return handle at api level to cancel, document */ 7244 /* FIXME: allow more, return handle at api level to cancel, document */
7501 if (NULL != t->regex_ctx) 7245 if (NULL != t->regex_search)
7502 { 7246 {
7503 GNUNET_break (0); 7247 GNUNET_break (0);
7504 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 7248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
@@ -7510,7 +7254,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7510 string = (const char *) &msg[1]; 7254 string = (const char *) &msg[1];
7511 7255
7512 /* Initialize context */ 7256 /* Initialize context */
7513 size = GNUNET_REGEX_get_first_key(string, len, &key); 7257 size = GNUNET_REGEX_get_first_key (string, len, &key);
7514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7515 " consumed %u bits out of %u\n", size, len); 7259 " consumed %u bits out of %u\n", size, len);
7516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 7260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -7518,35 +7262,15 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7518 7262
7519 info = GNUNET_malloc (sizeof (struct MeshRegexSearchInfo)); 7263 info = GNUNET_malloc (sizeof (struct MeshRegexSearchInfo));
7520 info->t = t; 7264 info->t = t;
7521 info->description = GNUNET_malloc (len + 1); 7265 info->description = GNUNET_strndup (string, len);
7522 memcpy (info->description, string, len);
7523 info->description[len] = '\0';
7524 info->dht_get_handles = GNUNET_CONTAINER_multihashmap_create(32, GNUNET_NO);
7525 info->dht_get_results = GNUNET_CONTAINER_multihashmap_create(32, GNUNET_NO);
7526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " string: %s\n", info->description); 7266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " string: %s\n", info->description);
7527 7267
7528 ctx = GNUNET_malloc (sizeof (struct MeshRegexSearchContext)); 7268 t->regex_search = info;
7529 ctx->position = size;
7530 ctx->info = info;
7531 t->regex_ctx = ctx;
7532 7269
7533 GNUNET_array_append (info->contexts, info->n_contexts, ctx); 7270 info->search_handle = GNUNET_REGEX_search (dht_handle,
7534 7271 info->description,
7535 /* Start search in DHT */ 7272 &regex_found_handler, info,
7536 get_h = GNUNET_DHT_get_start (dht_handle, /* handle */ 7273 stats);
7537 GNUNET_BLOCK_TYPE_MESH_REGEX, /* type */
7538 &key, /* key to search */
7539 dht_replication_level, /* replication level */
7540 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
7541 NULL, /* xquery */ // FIXME BLOOMFILTER
7542 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
7543 &dht_get_string_handler, ctx);
7544
7545 GNUNET_break (GNUNET_OK ==
7546 GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
7547 &key,
7548 get_h,
7549 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
7550 7274
7551 GNUNET_SERVER_receive_done (client, GNUNET_OK); 7275 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connect by string processed\n"); 7276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connect by string processed\n");
@@ -7670,7 +7394,7 @@ handle_local_to_origin (void *cls, struct GNUNET_SERVER_Client *client,
7670 const struct GNUNET_MessageHeader *message) 7394 const struct GNUNET_MessageHeader *message)
7671{ 7395{
7672 struct GNUNET_MESH_ToOrigin *data_msg; 7396 struct GNUNET_MESH_ToOrigin *data_msg;
7673 struct MeshTunnelFlowControlInfo *fcinfo; 7397 struct MeshTunnelClientInfo *clinfo;
7674 struct MeshClient *c; 7398 struct MeshClient *c;
7675 struct MeshTunnel *t; 7399 struct MeshTunnel *t;
7676 MESH_TunnelNumber tid; 7400 MESH_TunnelNumber tid;
@@ -7727,18 +7451,18 @@ handle_local_to_origin (void *cls, struct GNUNET_SERVER_Client *client,
7727 } 7451 }
7728 7452
7729 /* PID should be as expected */ 7453 /* PID should be as expected */
7730 fcinfo = tunnel_get_client_fc (t, c); 7454 clinfo = tunnel_get_client_fc (t, c);
7731 if (ntohl (data_msg->pid) != fcinfo->bck_pid + 1) 7455 if (ntohl (data_msg->pid) != clinfo->bck_pid + 1)
7732 { 7456 {
7733 GNUNET_break (0); 7457 GNUNET_break (0);
7734 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 7458 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7735 "To Origin PID, expected %u, got %u\n", 7459 "To Origin PID, expected %u, got %u\n",
7736 fcinfo->bck_pid + 1, 7460 clinfo->bck_pid + 1,
7737 ntohl (data_msg->pid)); 7461 ntohl (data_msg->pid));
7738 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 7462 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
7739 return; 7463 return;
7740 } 7464 }
7741 fcinfo->bck_pid++; 7465 clinfo->bck_pid++;
7742 7466
7743 /* Ok, everything is correct, send the message 7467 /* Ok, everything is correct, send the message
7744 * (pretend we got it from a mesh peer) 7468 * (pretend we got it from a mesh peer)
@@ -7902,7 +7626,7 @@ handle_local_ack (void *cls, struct GNUNET_SERVER_Client *client,
7902 ack = ntohl (msg->max_pid); 7626 ack = ntohl (msg->max_pid);
7903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ack); 7627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " ack %u\n", ack);
7904 7628
7905 /* Does client own tunnel? I.E: Is this and ACK for BCK traffic? */ 7629 /* Does client own tunnel? I.E: Is this an ACK for BCK traffic? */
7906 if (NULL != t->owner && t->owner->handle == client) 7630 if (NULL != t->owner && t->owner->handle == client)
7907 { 7631 {
7908 /* The client owns the tunnel, ACK is for data to_origin, send BCK ACK. */ 7632 /* The client owns the tunnel, ACK is for data to_origin, send BCK ACK. */
@@ -7916,13 +7640,300 @@ handle_local_ack (void *cls, struct GNUNET_SERVER_Client *client,
7916 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK); 7640 tunnel_send_fwd_ack (t, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
7917 } 7641 }
7918 7642
7919 GNUNET_SERVER_receive_done (client, GNUNET_OK); 7643 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7920 7644
7921 return; 7645 return;
7922} 7646}
7923 7647
7924 7648
7925/** 7649/**
7650 * Iterator over all peers to send a monitoring client info about a tunnel.
7651 *
7652 * @param cls Closure (message being built).
7653 * @param key Key (hashed tunnel ID, unused).
7654 * @param value Peer info.
7655 *
7656 * @return GNUNET_YES, to keep iterating.
7657 */
7658static int
7659monitor_peers_iterator (void *cls,
7660 const struct GNUNET_HashCode * key,
7661 void *value)
7662{
7663 struct GNUNET_MESH_LocalMonitor *msg = cls;
7664 struct GNUNET_PeerIdentity *id;
7665 struct MeshPeerInfo *info = value;
7666
7667 id = (struct GNUNET_PeerIdentity *) &msg[1];
7668 GNUNET_PEER_resolve (info->id, &id[msg->npeers]);
7669 msg->npeers++;
7670
7671 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7672 "* sending info about peer %s [%u]\n",
7673 GNUNET_i2s (&id[msg->npeers - 1]), msg->npeers);
7674
7675 return GNUNET_YES;
7676}
7677
7678
7679
7680/**
7681 * Iterator over all tunnels to send a monitoring client info about each tunnel.
7682 *
7683 * @param cls Closure (client handle).
7684 * @param key Key (hashed tunnel ID, unused).
7685 * @param value Tunnel info.
7686 *
7687 * @return GNUNET_YES, to keep iterating.
7688 */
7689static int
7690monitor_all_tunnels_iterator (void *cls,
7691 const struct GNUNET_HashCode * key,
7692 void *value)
7693{
7694 struct GNUNET_SERVER_Client *client = cls;
7695 struct MeshTunnel *t = value;
7696 struct GNUNET_MESH_LocalMonitor *msg;
7697 uint32_t npeers;
7698
7699 npeers = GNUNET_CONTAINER_multihashmap_size (t->peers);
7700 msg = GNUNET_malloc (sizeof(struct GNUNET_MESH_LocalMonitor) +
7701 npeers * sizeof (struct GNUNET_PeerIdentity));
7702 GNUNET_PEER_resolve(t->id.oid, &msg->owner);
7703 msg->tunnel_id = htonl (t->id.tid);
7704 msg->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor) +
7705 npeers * sizeof (struct GNUNET_PeerIdentity));
7706 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
7707 msg->npeers = 0;
7708 (void) GNUNET_CONTAINER_multihashmap_iterate (t->peers,
7709 monitor_peers_iterator,
7710 msg);
7711
7712 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7713 "* sending info about tunnel %s [%u] (%u peers)\n",
7714 GNUNET_i2s (&msg->owner), t->id.tid, npeers);
7715
7716 if (msg->npeers != npeers)
7717 {
7718 GNUNET_break (0);
7719 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7720 "Get tunnels fail: size %u - iter %u\n",
7721 npeers, msg->npeers);
7722 }
7723
7724 msg->npeers = htonl (npeers);
7725 GNUNET_SERVER_notification_context_unicast (nc, client,
7726 &msg->header, GNUNET_NO);
7727 return GNUNET_YES;
7728}
7729
7730
7731/**
7732 * Handler for client's MONITOR request.
7733 *
7734 * @param cls Closure (unused).
7735 * @param client Identification of the client.
7736 * @param message The actual message.
7737 */
7738static void
7739handle_local_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
7740 const struct GNUNET_MessageHeader *message)
7741{
7742 struct MeshClient *c;
7743
7744 /* Sanity check for client registration */
7745 if (NULL == (c = client_get (client)))
7746 {
7747 GNUNET_break (0);
7748 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
7749 return;
7750 }
7751
7752 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7753 "Received get tunnels request from client %u\n",
7754 c->id);
7755 GNUNET_CONTAINER_multihashmap_iterate (tunnels,
7756 monitor_all_tunnels_iterator,
7757 client);
7758 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7759 "Get tunnels request from client %u completed\n",
7760 c->id);
7761 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7762}
7763
7764
7765/**
7766 * Data needed to build a Monitor_Tunnel message.
7767 */
7768struct MeshMonitorTunnelContext
7769{
7770 /**
7771 * Partial message, including peer count.
7772 */
7773 struct GNUNET_MESH_LocalMonitor *msg;
7774
7775 /**
7776 * Hashmap with positions: peer->position.
7777 */
7778 struct GNUNET_CONTAINER_MultiHashMap *lookup;
7779
7780 /**
7781 * Index of the parent of each peer in the message, realtive to the absolute
7782 * order in the array (can be in a previous message).
7783 */
7784 uint32_t parents[1024];
7785
7786 /**
7787 * Peers visited so far in the tree, aka position of the current peer.
7788 */
7789 unsigned int npeers;
7790
7791 /**
7792 * Client requesting the info.
7793 */
7794 struct MeshClient *c;
7795};
7796
7797
7798/**
7799 * Send a client a message about the structure of a tunnel.
7800 *
7801 * @param ctx Context of the tunnel iteration, with info regarding the state
7802 * of the execution and the number of peers visited for this message.
7803 */
7804static void
7805send_client_tunnel_info (struct MeshMonitorTunnelContext *ctx)
7806{
7807 struct GNUNET_MESH_LocalMonitor *resp = ctx->msg;
7808 struct GNUNET_PeerIdentity *pid;
7809 unsigned int *parent;
7810 size_t size;
7811
7812 size = sizeof (struct GNUNET_MESH_LocalMonitor);
7813 size += (sizeof (struct GNUNET_PeerIdentity) + sizeof (int)) * resp->npeers;
7814 resp->header.size = htons (size);
7815 pid = (struct GNUNET_PeerIdentity *) &resp[1];
7816 parent = (unsigned int *) &pid[resp->npeers];
7817 memcpy (parent, ctx->parents, sizeof(uint32_t) * resp->npeers);
7818 GNUNET_SERVER_notification_context_unicast (nc, ctx->c->handle,
7819 &resp->header, GNUNET_NO);
7820}
7821
7822/**
7823 * Iterator over a tunnel tree to build a message containing all peers
7824 * the in the tunnel, including relay nodes.
7825 *
7826 * @param cls Closure (pointer to pointer of message being built).
7827 * @param peer Short ID of a peer.
7828 * @param parent Short ID of the @c peer 's parent.
7829 */
7830static void
7831tunnel_tree_iterator (void *cls,
7832 GNUNET_PEER_Id peer,
7833 GNUNET_PEER_Id parent)
7834{
7835 struct MeshMonitorTunnelContext *ctx = cls;
7836 struct GNUNET_MESH_LocalMonitor *msg;
7837 struct GNUNET_PeerIdentity *pid;
7838 struct GNUNET_PeerIdentity ppid;
7839
7840 msg = ctx->msg;
7841 pid = (struct GNUNET_PeerIdentity *) &msg[1];
7842 GNUNET_PEER_resolve (peer, &pid[msg->npeers]);
7843 GNUNET_CONTAINER_multihashmap_put (ctx->lookup,
7844 &pid[msg->npeers].hashPubKey,
7845 (void *) (long) ctx->npeers,
7846 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
7847 GNUNET_PEER_resolve (parent, &ppid);
7848 ctx->parents[msg->npeers] =
7849 htonl ((long) GNUNET_CONTAINER_multihashmap_get (ctx->lookup,
7850 &ppid.hashPubKey));
7851
7852 ctx->npeers++;
7853 msg->npeers++;
7854
7855 if (sizeof (struct GNUNET_MESH_LocalMonitor) +
7856 (msg->npeers + 1) *
7857 (sizeof (struct GNUNET_PeerIdentity) + sizeof (uint32_t))
7858 > USHRT_MAX)
7859 {
7860 send_client_tunnel_info (ctx);
7861 msg->npeers = 0;
7862 }
7863}
7864
7865
7866/**
7867 * Handler for client's MONITOR_TUNNEL request.
7868 *
7869 * @param cls Closure (unused).
7870 * @param client Identification of the client.
7871 * @param message The actual message.
7872 */
7873static void
7874handle_local_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
7875 const struct GNUNET_MessageHeader *message)
7876{
7877 const struct GNUNET_MESH_LocalMonitor *msg;
7878 struct GNUNET_MESH_LocalMonitor *resp;
7879 struct MeshMonitorTunnelContext ctx;
7880 struct MeshClient *c;
7881 struct MeshTunnel *t;
7882
7883 /* Sanity check for client registration */
7884 if (NULL == (c = client_get (client)))
7885 {
7886 GNUNET_break (0);
7887 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
7888 return;
7889 }
7890
7891 msg = (struct GNUNET_MESH_LocalMonitor *) message;
7892 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7893 "Received tunnel info request from client %u for tunnel %s[%X]\n",
7894 c->id,
7895 &msg->owner,
7896 ntohl (msg->tunnel_id));
7897 t = tunnel_get (&msg->owner, ntohl (msg->tunnel_id));
7898 if (NULL == t)
7899 {
7900 /* We don't know the tunnel */
7901 struct GNUNET_MESH_LocalMonitor warn;
7902
7903 warn = *msg;
7904 warn.npeers = htonl (UINT_MAX);
7905 GNUNET_SERVER_notification_context_unicast (nc, client,
7906 &warn.header,
7907 GNUNET_NO);
7908 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7909 return;
7910 }
7911
7912 /* Initialize context */
7913 resp = GNUNET_malloc (USHRT_MAX); /* avoid realloc'ing on each step */
7914 *resp = *msg;
7915 resp->npeers = 0;
7916 ctx.msg = resp;
7917 ctx.lookup = GNUNET_CONTAINER_multihashmap_create (4 * t->peers_total,
7918 GNUNET_YES);
7919 ctx.c = c;
7920
7921 /* Collect and send information */
7922 tree_iterate_all (t->tree, &tunnel_tree_iterator, &ctx);
7923 send_client_tunnel_info (&ctx);
7924
7925 /* Free context */
7926 GNUNET_CONTAINER_multihashmap_destroy (ctx.lookup);
7927 GNUNET_free (resp);
7928
7929 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7930 "Monitor tunnel request from client %u completed\n",
7931 c->id);
7932 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7933}
7934
7935
7936/**
7926 * Functions to handle messages from clients 7937 * Functions to handle messages from clients
7927 */ 7938 */
7928static struct GNUNET_SERVER_MessageHandler client_handlers[] = { 7939static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
@@ -7974,6 +7985,12 @@ static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
7974 {&handle_local_ack, NULL, 7985 {&handle_local_ack, NULL,
7975 GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK, 7986 GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK,
7976 sizeof (struct GNUNET_MESH_LocalAck)}, 7987 sizeof (struct GNUNET_MESH_LocalAck)},
7988 {&handle_local_get_tunnels, NULL,
7989 GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS,
7990 sizeof (struct GNUNET_MessageHeader)},
7991 {&handle_local_show_tunnel, NULL,
7992 GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL,
7993 sizeof (struct GNUNET_MESH_LocalMonitor)},
7977 {NULL, NULL, 0, 0} 7994 {NULL, NULL, 0, 0}
7978}; 7995};
7979 7996
@@ -7996,6 +8013,12 @@ core_init (void *cls, struct GNUNET_CORE_Handle *server,
7996 NULL == server) 8013 NULL == server)
7997 { 8014 {
7998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); 8015 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
8016 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8017 " core id %s\n",
8018 GNUNET_i2s (identity));
8019 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8020 " my id %s\n",
8021 GNUNET_i2s (&my_full_id));
7999 GNUNET_SCHEDULER_shutdown (); // Try gracefully 8022 GNUNET_SCHEDULER_shutdown (); // Try gracefully
8000 if (10 < i++) 8023 if (10 < i++)
8001 GNUNET_abort(); // Try harder 8024 GNUNET_abort(); // Try harder
@@ -8155,7 +8178,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
8155 GNUNET_CORE_disconnect (core_handle); 8178 GNUNET_CORE_disconnect (core_handle);
8156 core_handle = NULL; 8179 core_handle = NULL;
8157 } 8180 }
8158 if (NULL != keygen) 8181 if (NULL != keygen)
8159 { 8182 {
8160 GNUNET_CRYPTO_rsa_key_create_stop (keygen); 8183 GNUNET_CRYPTO_rsa_key_create_stop (keygen);
8161 keygen = NULL; 8184 keygen = NULL;
@@ -8177,6 +8200,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
8177 GNUNET_SCHEDULER_cancel (announce_id_task); 8200 GNUNET_SCHEDULER_cancel (announce_id_task);
8178 announce_id_task = GNUNET_SCHEDULER_NO_TASK; 8201 announce_id_task = GNUNET_SCHEDULER_NO_TASK;
8179 } 8202 }
8203 if (GNUNET_SCHEDULER_NO_TASK != announce_applications_task)
8204 {
8205 GNUNET_SCHEDULER_cancel (announce_applications_task);
8206 announce_applications_task = GNUNET_SCHEDULER_NO_TASK;
8207 }
8180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n"); 8208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
8181} 8209}
8182 8210
@@ -8184,7 +8212,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
8184/** 8212/**
8185 * Callback for hostkey read/generation 8213 * Callback for hostkey read/generation
8186 * 8214 *
8187 * @param cls NULL 8215 * @param cls Closure (Configuration handle).
8188 * @param pk the private key 8216 * @param pk the private key
8189 * @param emsg error message 8217 * @param emsg error message
8190 */ 8218 */
@@ -8193,6 +8221,7 @@ key_generation_cb (void *cls,
8193 struct GNUNET_CRYPTO_RsaPrivateKey *pk, 8221 struct GNUNET_CRYPTO_RsaPrivateKey *pk,
8194 const char *emsg) 8222 const char *emsg)
8195{ 8223{
8224 const struct GNUNET_CONFIGURATION_Handle *c = cls;
8196 struct MeshPeerInfo *peer; 8225 struct MeshPeerInfo *peer;
8197 struct MeshPeerPath *p; 8226 struct MeshPeerPath *p;
8198 8227
@@ -8200,7 +8229,8 @@ key_generation_cb (void *cls,
8200 if (NULL == pk) 8229 if (NULL == pk)
8201 { 8230 {
8202 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 8231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8203 _("Mesh service could not access hostkey. Exiting.\n")); 8232 _("Mesh service could not access hostkey: %s. Exiting.\n"),
8233 emsg);
8204 GNUNET_SCHEDULER_shutdown (); 8234 GNUNET_SCHEDULER_shutdown ();
8205 return; 8235 return;
8206 } 8236 }
@@ -8220,7 +8250,23 @@ key_generation_cb (void *cls,
8220// NULL, 8250// NULL,
8221// NULL); 8251// NULL);
8222 8252
8223 8253 core_handle = GNUNET_CORE_connect (c, /* Main configuration */
8254 NULL, /* Closure passed to MESH functions */
8255 &core_init, /* Call core_init once connected */
8256 &core_connect, /* Handle connects */
8257 &core_disconnect, /* remove peers on disconnects */
8258 NULL, /* Don't notify about all incoming messages */
8259 GNUNET_NO, /* For header only in notification */
8260 NULL, /* Don't notify about all outbound messages */
8261 GNUNET_NO, /* For header-only out notification */
8262 core_handlers); /* Register these handlers */
8263
8264 if (core_handle == NULL)
8265 {
8266 GNUNET_break (0);
8267 GNUNET_SCHEDULER_shutdown ();
8268 return;
8269 }
8224 8270
8225 next_tid = 0; 8271 next_tid = 0;
8226 next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV; 8272 next_local_tid = GNUNET_MESH_LOCAL_TUNNEL_ID_SERV;
@@ -8265,23 +8311,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
8265 8311
8266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); 8312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
8267 server_handle = server; 8313 server_handle = server;
8268 core_handle = GNUNET_CORE_connect (c, /* Main configuration */
8269 NULL, /* Closure passed to MESH functions */
8270 &core_init, /* Call core_init once connected */
8271 &core_connect, /* Handle connects */
8272 &core_disconnect, /* remove peers on disconnects */
8273 NULL, /* Don't notify about all incoming messages */
8274 GNUNET_NO, /* For header only in notification */
8275 NULL, /* Don't notify about all outbound messages */
8276 GNUNET_NO, /* For header-only out notification */
8277 core_handlers); /* Register these handlers */
8278
8279 if (core_handle == NULL)
8280 {
8281 GNUNET_break (0);
8282 GNUNET_SCHEDULER_shutdown ();
8283 return;
8284 }
8285 8314
8286 if (GNUNET_OK != 8315 if (GNUNET_OK !=
8287 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY", 8316 GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
@@ -8318,8 +8347,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
8318 GNUNET_SCHEDULER_shutdown (); 8347 GNUNET_SCHEDULER_shutdown ();
8319 return; 8348 return;
8320 } 8349 }
8321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "APP_ANNOUNCE_TIME %llu ms\n", app_announce_time.rel_value); 8350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8322 8351 "APP_ANNOUNCE_TIME %llu ms\n",
8352 app_announce_time.rel_value);
8323 if (GNUNET_OK != 8353 if (GNUNET_OK !=
8324 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME", 8354 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "ID_ANNOUNCE_TIME",
8325 &id_announce_time)) 8355 &id_announce_time))
@@ -8331,9 +8361,6 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
8331 GNUNET_SCHEDULER_shutdown (); 8361 GNUNET_SCHEDULER_shutdown ();
8332 return; 8362 return;
8333 } 8363 }
8334 else
8335 {
8336 }
8337 8364
8338 if (GNUNET_OK != 8365 if (GNUNET_OK !=
8339 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "CONNECT_TIMEOUT", 8366 GNUNET_CONFIGURATION_get_value_time (c, "MESH", "CONNECT_TIMEOUT",
@@ -8383,14 +8410,24 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
8383 } 8410 }
8384 8411
8385 if (GNUNET_OK != 8412 if (GNUNET_OK !=
8413 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "MAX_PEERS",
8414 &max_peers))
8415 {
8416 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8417 _("%s service is lacking key configuration settings (%s). Using default (%u).\n"),
8418 "mesh", "max peers", 1000);
8419 max_peers = 1000;
8420 }
8421
8422 if (GNUNET_OK !=
8386 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL", 8423 GNUNET_CONFIGURATION_get_value_number (c, "MESH", "DHT_REPLICATION_LEVEL",
8387 &dht_replication_level)) 8424 &dht_replication_level))
8388 { 8425 {
8389 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 8426 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8390 _ 8427 _
8391 ("%s service is lacking key configuration settings (%s). Using default (%u).\n"), 8428 ("%s service is lacking key configuration settings (%s). Using default (%u).\n"),
8392 "mesh", "dht replication level", 10); 8429 "mesh", "dht replication level", 3);
8393 dht_replication_level = 10; 8430 dht_replication_level = 3;
8394 } 8431 }
8395 8432
8396 tunnels = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO); 8433 tunnels = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
@@ -8410,7 +8447,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
8410 /* Scheduled the task to clean up when shutdown is called */ 8447 /* Scheduled the task to clean up when shutdown is called */
8411 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, 8448 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
8412 NULL); 8449 NULL);
8413 keygen = GNUNET_CRYPTO_rsa_key_create_start (keyfile, &key_generation_cb, NULL); 8450 keygen = GNUNET_CRYPTO_rsa_key_create_start (keyfile,
8451 &key_generation_cb,
8452 (void *) c);
8414 GNUNET_free (keyfile); 8453 GNUNET_free (keyfile);
8415} 8454}
8416 8455
diff --git a/src/mesh/gnunet-service-mesh.c b/src/mesh/gnunet-service-mesh.c
index 7c9addeb6..e3b389ddb 100644
--- a/src/mesh/gnunet-service-mesh.c
+++ b/src/mesh/gnunet-service-mesh.c
@@ -50,7 +50,6 @@
50#include "mesh_protocol.h" 50#include "mesh_protocol.h"
51#include "mesh_tunnel_tree.h" 51#include "mesh_tunnel_tree.h"
52#include "block_mesh.h" 52#include "block_mesh.h"
53#include "mesh_block_lib.h"
54#include "gnunet_dht_service.h" 53#include "gnunet_dht_service.h"
55#include "gnunet_statistics_service.h" 54#include "gnunet_statistics_service.h"
56#include "gnunet_regex_lib.h" 55#include "gnunet_regex_lib.h"
@@ -184,17 +183,69 @@ struct MeshRegexDescriptor
184 */ 183 */
185 char *regex; 184 char *regex;
186 185
187 /**
188 * Cached DFA for regular expression 'regex'.
189 */
190 struct GNUNET_REGEX_Automaton *dfa;
191
192 /** 186 /**
193 * How many characters per edge can we squeeze? 187 * How many characters per edge can we squeeze?
194 */ 188 */
195 uint16_t compression; 189 uint16_t compression;
190
191 /**
192 * Handle to announce the regex.
193 */
194 struct GNUNET_REGEX_announce_handle *h;
196}; 195};
197 196
197
198/**
199 * Struct to keep information of searches of services described by a regex
200 * using a user-provided string service description.
201 */
202struct MeshRegexSearchInfo
203{
204 /**
205 * Which tunnel is this for
206 */
207 struct MeshTunnel *t;
208
209 /**
210 * User provided description of the searched service.
211 */
212 char *description;
213
214 /**
215 * Regex search handle.
216 */
217 struct GNUNET_REGEX_search_handle *search_handle;
218
219 /**
220 * Peer that is connecting via connect_by_string. When connected, free ctx.
221 */
222 GNUNET_PEER_Id peer;
223
224 /**
225 * Other peers that are found but not yet being connected to.
226 */
227 GNUNET_PEER_Id *peers;
228
229 /**
230 * Number of elements in peers.
231 */
232 unsigned int n_peers;
233
234 /**
235 * Next peer to try to connect to.
236 */
237 unsigned int i_peer;
238
239 /**
240 * Timeout for a connect attempt.
241 * When reached, try to connect to a different peer, if any. If not,
242 * try the same peer again.
243 */
244 GNUNET_SCHEDULER_TaskIdentifier timeout;
245
246};
247
248
198/** 249/**
199 * Struct containing all info possibly needed to build a package when called 250 * Struct containing all info possibly needed to build a package when called
200 * back by core. 251 * back by core.
@@ -495,9 +546,9 @@ struct MeshTunnel
495 struct GNUNET_DHT_GetHandle *dht_get_type; 546 struct GNUNET_DHT_GetHandle *dht_get_type;
496 547
497 /** 548 /**
498 * Initial context of the regex search for a connect_by_string 549 * Handle for the regex search for a connect_by_string
499 */ 550 */
500 struct MeshRegexSearchContext *regex_ctx; 551 struct MeshRegexSearchInfo *regex_search;
501 552
502 /** 553 /**
503 * Task to keep the used paths alive 554 * Task to keep the used paths alive
@@ -756,105 +807,6 @@ struct MeshClient
756}; 807};
757 808
758 809
759/**
760 * Struct to keep information of searches of services described by a regex
761 * using a user-provided string service description.
762 */
763struct MeshRegexSearchInfo
764{
765 /**
766 * Which tunnel is this for
767 */
768 struct MeshTunnel *t;
769
770 /**
771 * User provided description of the searched service.
772 */
773 char *description;
774
775 /**
776 * Part of the description already consumed by the search.
777 */
778 size_t position;
779
780 /**
781 * Running DHT GETs.
782 */
783 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
784
785 /**
786 * Results from running DHT GETs.
787 */
788 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
789
790 /**
791 * Contexts, for each running DHT GET. Free all on end of search.
792 */
793 struct MeshRegexSearchContext **contexts;
794
795 /**
796 * Number of contexts (branches/steps in search).
797 */
798 unsigned int n_contexts;
799
800 /**
801 * Peer that is connecting via connect_by_string. When connected, free ctx.
802 */
803 GNUNET_PEER_Id peer;
804
805 /**
806 * Other peers that are found but not yet being connected to.
807 */
808 GNUNET_PEER_Id *peers;
809
810 /**
811 * Number of elements in peers.
812 */
813 unsigned int n_peers;
814
815 /**
816 * Next peer to try to connect to.
817 */
818 unsigned int i_peer;
819
820 /**
821 * Timeout for a connect attempt.
822 * When reached, try to connect to a different peer, if any. If not,
823 * try the same peer again.
824 */
825 GNUNET_SCHEDULER_TaskIdentifier timeout;
826
827};
828
829/**
830 * Struct to keep state of running searches that have consumed a part of
831 * the inital string.
832 */
833struct MeshRegexSearchContext
834{
835 /**
836 * Part of the description already consumed by
837 * this particular search branch.
838 */
839 size_t position;
840
841 /**
842 * Information about the search.
843 */
844 struct MeshRegexSearchInfo *info;
845
846 /**
847 * We just want to look for one edge, the longer the better.
848 * Keep its length.
849 */
850 unsigned int longest_match;
851
852 /**
853 * Destination hash of the longest match.
854 */
855 struct GNUNET_HashCode hash;
856};
857
858/******************************************************************************/ 810/******************************************************************************/
859/************************ DEBUG FUNCTIONS ****************************/ 811/************************ DEBUG FUNCTIONS ****************************/
860/******************************************************************************/ 812/******************************************************************************/
@@ -1090,56 +1042,15 @@ dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
1090 1042
1091 1043
1092/** 1044/**
1093 * Function to process DHT string to regex matching. 1045 * Retrieve the MeshPeerInfo stucture associated with the peer, create one
1094 * Called on each result obtained for the DHT search. 1046 * and insert it in the appropiate structures if the peer is not known yet.
1095 *
1096 * @param cls closure (search context)
1097 * @param exp when will this value expire
1098 * @param key key of the result
1099 * @param get_path path of the get request (not used)
1100 * @param get_path_length lenght of get_path (not used)
1101 * @param put_path path of the put request (not used)
1102 * @param put_path_length length of the put_path (not used)
1103 * @param type type of the result
1104 * @param size number of bytes in data
1105 * @param data pointer to the result data
1106 * 1047 *
1107 * TODO: re-issue the request after certain time? cancel after X results? 1048 * @param peer Full identity of the peer.
1108 */
1109static void
1110dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
1111 const struct GNUNET_HashCode * key,
1112 const struct GNUNET_PeerIdentity *get_path,
1113 unsigned int get_path_length,
1114 const struct GNUNET_PeerIdentity *put_path,
1115 unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
1116 size_t size, const void *data);
1117
1118
1119/**
1120 * Function to process DHT string to regex matching.
1121 * Called on each result obtained for the DHT search.
1122 * 1049 *
1123 * @param cls closure (search context) 1050 * @return Existing or newly created peer info.
1124 * @param exp when will this value expire
1125 * @param key key of the result
1126 * @param get_path path of the get request (not used)
1127 * @param get_path_length lenght of get_path (not used)
1128 * @param put_path path of the put request (not used)
1129 * @param put_path_length length of the put_path (not used)
1130 * @param type type of the result
1131 * @param size number of bytes in data
1132 * @param data pointer to the result data
1133 */ 1051 */
1134static void 1052static struct MeshPeerInfo *
1135dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp, 1053peer_info_get (const struct GNUNET_PeerIdentity *peer);
1136 const struct GNUNET_HashCode * key,
1137 const struct GNUNET_PeerIdentity *get_path,
1138 unsigned int get_path_length,
1139 const struct GNUNET_PeerIdentity *put_path,
1140 unsigned int put_path_length,
1141 enum GNUNET_BLOCK_Type type,
1142 size_t size, const void *data);
1143 1054
1144 1055
1145/** 1056/**
@@ -1168,6 +1079,29 @@ peer_info_connect (struct MeshPeerInfo *peer, struct MeshTunnel *t);
1168 1079
1169 1080
1170/** 1081/**
1082 * Build a PeerPath from the paths returned from the DHT, reversing the paths
1083 * to obtain a local peer -> destination path and interning the peer ids.
1084 *
1085 * @return Newly allocated and created path
1086 */
1087static struct MeshPeerPath *
1088path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
1089 unsigned int get_path_length,
1090 const struct GNUNET_PeerIdentity *put_path,
1091 unsigned int put_path_length);
1092
1093
1094/**
1095 * Adds a path to the peer_infos of all the peers in the path
1096 *
1097 * @param p Path to process.
1098 * @param confirmed Whether we know if the path works or not.
1099 */
1100static void
1101path_add_to_peers (struct MeshPeerPath *p, int confirmed);
1102
1103
1104/**
1171 * Add a peer to a tunnel, accomodating paths accordingly and initializing all 1105 * Add a peer to a tunnel, accomodating paths accordingly and initializing all
1172 * needed rescources. 1106 * needed rescources.
1173 * If peer already exists, reevaluate shortest path and change if different. 1107 * If peer already exists, reevaluate shortest path and change if different.
@@ -1252,33 +1186,6 @@ tunnel_add_client (struct MeshTunnel *t, struct MeshClient *c);
1252 1186
1253 1187
1254/** 1188/**
1255 * Jump to the next edge, with the longest matching token.
1256 *
1257 * @param block Block found in the DHT.
1258 * @param size Size of the block.
1259 * @param ctx Context of the search.
1260 *
1261 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1262 */
1263static void
1264regex_next_edge (const struct MeshRegexBlock *block,
1265 size_t size,
1266 struct MeshRegexSearchContext *ctx);
1267
1268
1269/**
1270 * Find a path to a peer that offers a regex servcie compatible
1271 * with a given string.
1272 *
1273 * @param key The key of the accepting state.
1274 * @param ctx Context containing info about the string, tunnel, etc.
1275 */
1276static void
1277regex_find_path (const struct GNUNET_HashCode *key,
1278 struct MeshRegexSearchContext *ctx);
1279
1280
1281/**
1282 * @brief Queue and pass message to core when possible. 1189 * @brief Queue and pass message to core when possible.
1283 * 1190 *
1284 * If type is payload (UNICAST, TO_ORIGIN, MULTICAST) checks for queue status 1191 * If type is payload (UNICAST, TO_ORIGIN, MULTICAST) checks for queue status
@@ -1339,257 +1246,23 @@ static size_t
1339queue_send (void *cls, size_t size, void *buf); 1246queue_send (void *cls, size_t size, void *buf);
1340 1247
1341/******************************************************************************/ 1248/******************************************************************************/
1342/************************ ITERATORS ****************************/ 1249/************************ REGEX INTEGRATION ****************************/
1343/******************************************************************************/ 1250/******************************************************************************/
1344 1251
1345/** 1252/**
1346 * Iterator over found existing mesh regex blocks that match an ongoing search. 1253 * Cancel a mesh regex search and free resources.
1347 *
1348 * @param cls closure
1349 * @param key current key code
1350 * @param value value in the hash map
1351 * @return GNUNET_YES if we should continue to iterate,
1352 * GNUNET_NO if not.
1353 */
1354static int
1355regex_result_iterator (void *cls,
1356 const struct GNUNET_HashCode * key,
1357 void *value)
1358{
1359 struct MeshRegexBlock *block = value;
1360 struct MeshRegexSearchContext *ctx = cls;
1361
1362 if (GNUNET_YES == ntohl(block->accepting) &&
1363 ctx->position == strlen (ctx->info->description))
1364 {
1365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Found accepting known block\n");
1366 regex_find_path (key, ctx);
1367 return GNUNET_YES; // We found an accept state!
1368 }
1369 else
1370 {
1371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* %u, %u, [%u]\n",
1372 ctx->position, strlen(ctx->info->description),
1373 ntohl(block->accepting));
1374
1375 }
1376 regex_next_edge(block, SIZE_MAX, ctx);
1377
1378 GNUNET_STATISTICS_update (stats, "# regex mesh blocks iterated", 1, GNUNET_NO);
1379
1380 return GNUNET_YES;
1381}
1382
1383
1384/**
1385 * Iterator over edges in a regex block retrieved from the DHT.
1386 *
1387 * @param cls Closure (context of the search).
1388 * @param token Token that follows to next state.
1389 * @param len Lenght of token.
1390 * @param key Hash of next state.
1391 *
1392 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1393 */
1394static int
1395regex_edge_iterator (void *cls,
1396 const char *token,
1397 size_t len,
1398 const struct GNUNET_HashCode *key)
1399{
1400 struct MeshRegexSearchContext *ctx = cls;
1401 struct MeshRegexSearchInfo *info = ctx->info;
1402 char *current;
1403 size_t current_len;
1404
1405 GNUNET_STATISTICS_update (stats, "# regex edges iterated", 1, GNUNET_NO);
1406
1407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Start of regex edge iterator\n");
1408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* descr : %s\n", info->description);
1409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* posit : %u\n", ctx->position);
1410 current = &info->description[ctx->position];
1411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* currt : %s\n", current);
1412 current_len = strlen (info->description) - ctx->position;
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* ctlen : %u\n", current_len);
1414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* tklen : %u\n", len);
1415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* token : %.*s\n", len, token);
1416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* nextk : %s\n", GNUNET_h2s(key));
1417 if (len > current_len)
1418 {
1419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token too long, END\n");
1420 return GNUNET_YES; // Token too long, wont match
1421 }
1422 if (0 != strncmp (current, token, len))
1423 {
1424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token doesn't match, END\n");
1425 return GNUNET_YES; // Token doesn't match
1426 }
1427
1428 if (len > ctx->longest_match)
1429 {
1430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is longer, KEEP\n");
1431 ctx->longest_match = len;
1432 ctx->hash = *key;
1433 }
1434 else
1435 {
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is not longer, IGNORE\n");
1437 }
1438
1439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
1440 return GNUNET_YES;
1441}
1442
1443
1444/**
1445 * Jump to the next edge, with the longest matching token.
1446 *
1447 * @param block Block found in the DHT.
1448 * @param size Size of the block.
1449 * @param ctx Context of the search.
1450 *
1451 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
1452 */ 1254 */
1453static void 1255static void
1454regex_next_edge (const struct MeshRegexBlock *block, 1256regex_cancel_search (struct MeshRegexSearchInfo *regex_search)
1455 size_t size, 1257{
1456 struct MeshRegexSearchContext *ctx) 1258 GNUNET_REGEX_search_cancel (regex_search->search_handle);
1457{ 1259 if (0 < regex_search->n_peers)
1458 struct MeshRegexSearchContext *new_ctx; 1260 GNUNET_free (regex_search->peers);
1459 struct MeshRegexSearchInfo *info = ctx->info; 1261 if (GNUNET_SCHEDULER_NO_TASK != regex_search->timeout)
1460 struct GNUNET_DHT_GetHandle *get_h;
1461 const char *rest;
1462 int result;
1463
1464 /* Find the longest match for the current string position,
1465 * among tokens in the given block */
1466 ctx->longest_match = 0;
1467 result = GNUNET_MESH_regex_block_iterate (block, size,
1468 &regex_edge_iterator, ctx);
1469 GNUNET_break (GNUNET_OK == result);
1470
1471 /* Did anything match? */
1472 if (0 == ctx->longest_match)
1473 return;
1474
1475 new_ctx = GNUNET_malloc (sizeof (struct MeshRegexSearchContext));
1476 new_ctx->info = info;
1477 new_ctx->position = ctx->position + ctx->longest_match;
1478 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
1479
1480 /* Check whether we already have a DHT GET running for it */
1481 if (GNUNET_YES ==
1482 GNUNET_CONTAINER_multihashmap_contains(info->dht_get_handles, &ctx->hash))
1483 {
1484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* GET running, END\n");
1485 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
1486 &ctx->hash,
1487 &regex_result_iterator,
1488 new_ctx);
1489 // FIXME: "leaks" new_ctx? avoid keeping it around?
1490 return; // We are already looking for it
1491 }
1492
1493 GNUNET_STATISTICS_update (stats, "# regex nodes traversed", 1, GNUNET_NO);
1494
1495 /* Start search in DHT */
1496 rest = &new_ctx->info->description[new_ctx->position];
1497 get_h =
1498 GNUNET_DHT_get_start (dht_handle, /* handle */
1499 GNUNET_BLOCK_TYPE_MESH_REGEX, /* type */
1500 &ctx->hash, /* key to search */
1501 dht_replication_level, /* replication level */
1502 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1503 rest, /* xquery */
1504 // FIXME add BLOOMFILTER to exclude filtered peers
1505 strlen(rest) + 1, /* xquery bits */
1506 // FIXME add BLOOMFILTER SIZE
1507 &dht_get_string_handler, new_ctx);
1508 if (GNUNET_OK !=
1509 GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
1510 &ctx->hash,
1511 get_h,
1512 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
1513 { 1262 {
1514 GNUNET_break (0); 1263 GNUNET_SCHEDULER_cancel(regex_search->timeout);
1515 return;
1516 } 1264 }
1517} 1265 GNUNET_free (regex_search);
1518
1519
1520/**
1521 * Iterator over hash map entries to cancel DHT GET requests after a
1522 * successful connect_by_string.
1523 *
1524 * @param cls Closure (unused).
1525 * @param key Current key code (unused).
1526 * @param value Value in the hash map (get handle).
1527 * @return GNUNET_YES if we should continue to iterate,
1528 * GNUNET_NO if not.
1529 */
1530static int
1531regex_cancel_dht_get (void *cls,
1532 const struct GNUNET_HashCode * key,
1533 void *value)
1534{
1535 struct GNUNET_DHT_GetHandle *h = value;
1536
1537 GNUNET_DHT_get_stop (h);
1538 return GNUNET_YES;
1539}
1540
1541
1542/**
1543 * Iterator over hash map entries to free MeshRegexBlocks stored during the
1544 * search for connect_by_string.
1545 *
1546 * @param cls Closure (unused).
1547 * @param key Current key code (unused).
1548 * @param value MeshRegexBlock in the hash map.
1549 * @return GNUNET_YES if we should continue to iterate,
1550 * GNUNET_NO if not.
1551 */
1552static int
1553regex_free_result (void *cls,
1554 const struct GNUNET_HashCode * key,
1555 void *value)
1556{
1557
1558 GNUNET_free (value);
1559 return GNUNET_YES;
1560}
1561
1562
1563/**
1564 * Find a path to a peer that offers a regex servcie compatible
1565 * with a given string.
1566 *
1567 * @param key The key of the accepting state.
1568 * @param ctx Context containing info about the string, tunnel, etc.
1569 */
1570static void
1571regex_find_path (const struct GNUNET_HashCode *key,
1572 struct MeshRegexSearchContext *ctx)
1573{
1574 struct GNUNET_DHT_GetHandle *get_h;
1575
1576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found peer by service\n");
1577 get_h = GNUNET_DHT_get_start (dht_handle, /* handle */
1578 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT, /* type */
1579 key, /* key to search */
1580 dht_replication_level, /* replication level */
1581 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE/* |
1582 GNUNET_DHT_RO_RECORD_ROUTE*/,
1583 NULL, /* xquery */
1584 // FIXME add BLOOMFILTER to exclude filtered peers
1585 0, /* xquery bits */
1586 // FIXME add BLOOMFILTER SIZE
1587 &dht_get_string_accept_handler, ctx);
1588 GNUNET_break (GNUNET_OK ==
1589 GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles,
1590 key,
1591 get_h,
1592 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
1593} 1266}
1594 1267
1595 1268
@@ -1613,6 +1286,7 @@ regex_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1613 info->timeout = GNUNET_SCHEDULER_NO_TASK; 1286 info->timeout = GNUNET_SCHEDULER_NO_TASK;
1614 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 1287 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1615 { 1288 {
1289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " due to shutdown\n");
1616 return; 1290 return;
1617 } 1291 }
1618 1292
@@ -1646,37 +1320,109 @@ regex_connect_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1646 1320
1647 1321
1648/** 1322/**
1649 * Cancel an ongoing regex search in the DHT and free all resources. 1323 * Function to process DHT string to regex matching.
1324 * Called on each result obtained for the DHT search.
1650 * 1325 *
1651 * @param ctx The search context. 1326 * @param cls Closure provided in GNUNET_REGEX_search.
1327 * @param id Peer providing a regex that matches the string.
1328 * @param get_path Path of the get request.
1329 * @param get_path_length Lenght of get_path.
1330 * @param put_path Path of the put request.
1331 * @param put_path_length Length of the put_path.
1652 */ 1332 */
1653static void 1333static void
1654regex_cancel_search(struct MeshRegexSearchContext *ctx) 1334regex_found_handler (void *cls,
1335 const struct GNUNET_PeerIdentity *id,
1336 const struct GNUNET_PeerIdentity *get_path,
1337 unsigned int get_path_length,
1338 const struct GNUNET_PeerIdentity *put_path,
1339 unsigned int put_path_length)
1655{ 1340{
1656 struct MeshRegexSearchInfo *info = ctx->info; 1341 struct MeshRegexSearchInfo *info = cls;
1657 int i; 1342 struct MeshPeerPath *p;
1343 struct MeshPeerInfo *peer_info;
1344
1345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
1346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", info->description);
1658 1347
1659 GNUNET_free (info->description); 1348 peer_info = peer_info_get (id);
1660 GNUNET_CONTAINER_multihashmap_iterate (info->dht_get_handles, 1349 p = path_build_from_dht (get_path, get_path_length,
1661 &regex_cancel_dht_get, NULL); 1350 put_path, put_path_length);
1662 GNUNET_CONTAINER_multihashmap_iterate (info->dht_get_results, 1351 path_add_to_peers (p, GNUNET_NO);
1663 &regex_free_result, NULL); 1352 path_destroy(p);
1664 GNUNET_CONTAINER_multihashmap_destroy (info->dht_get_results); 1353
1665 GNUNET_CONTAINER_multihashmap_destroy (info->dht_get_handles); 1354 tunnel_add_peer (info->t, peer_info);
1666 info->t->regex_ctx = NULL; 1355 peer_info_connect (peer_info, info->t);
1667 for (i = 0; i < info->n_contexts; i++) 1356 if (0 == info->peer)
1668 { 1357 {
1669 GNUNET_free (info->contexts[i]); 1358 info->peer = peer_info->id;
1670 } 1359 }
1671 if (0 < info->n_contexts) 1360 else
1672 GNUNET_free (info->contexts); 1361 {
1673 if (0 < info->n_peers) 1362 GNUNET_array_append (info->peers, info->n_peers, peer_info->id);
1674 GNUNET_free (info->peers); 1363 }
1364
1675 if (GNUNET_SCHEDULER_NO_TASK != info->timeout) 1365 if (GNUNET_SCHEDULER_NO_TASK != info->timeout)
1366 return;
1367
1368 info->timeout = GNUNET_SCHEDULER_add_delayed (connect_timeout,
1369 &regex_connect_timeout,
1370 info);
1371
1372 return;
1373}
1374
1375
1376/**
1377 * Store the regular expression describing a local service into the DHT.
1378 *
1379 * @param regex The regular expresion.
1380 */
1381static void
1382regex_put (struct MeshRegexDescriptor *regex)
1383{
1384 DEBUG_DHT (" regex_put (%s) start\n", regex->regex);
1385 if (NULL == regex->h)
1676 { 1386 {
1677 GNUNET_SCHEDULER_cancel(info->timeout); 1387 DEBUG_DHT (" first put, creating DFA\n");
1388 regex->h = GNUNET_REGEX_announce (dht_handle,
1389 &my_full_id,
1390 regex->regex,
1391 regex->compression,
1392 stats);
1678 } 1393 }
1679 GNUNET_free (info); 1394 else
1395 {
1396 DEBUG_DHT (" not first put, using cached data\n");
1397 GNUNET_REGEX_reannounce (regex->h);
1398 }
1399 DEBUG_DHT (" regex_put (%s) end\n", regex->regex);
1400}
1401
1402
1403/**
1404 * Periodically announce what applications are provided by local clients
1405 * (by regex)
1406 *
1407 * @param cls closure
1408 * @param tc task context
1409 */
1410static void
1411regex_announce (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1412{
1413 struct MeshClient *c = cls;
1414 unsigned int i;
1415
1416 c->regex_announce_task = GNUNET_SCHEDULER_NO_TASK;
1417 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1418 return;
1419 DEBUG_DHT ("Starting PUT for regex\n");
1420 for (i = 0; i < c->n_regex; i++)
1421 regex_put (&c->regexes[i]);
1422 c->regex_announce_task = GNUNET_SCHEDULER_add_delayed (app_announce_time,
1423 &regex_announce,
1424 cls);
1425 DEBUG_DHT ("Finished PUT for regex\n");
1680} 1426}
1681 1427
1682 1428
@@ -1725,193 +1471,6 @@ announce_application (void *cls, const struct GNUNET_HashCode * key, void *value
1725} 1471}
1726 1472
1727 1473
1728#if 0
1729/**
1730 * Function called when the DHT regex put is complete.
1731 *
1732 * @param the 'struct MeshClient' for which we were PUTting
1733 * @param success GNUNET_OK if the PUT was transmitted,
1734 * GNUNET_NO on timeout,
1735 * GNUNET_SYSERR on disconnect from service
1736 * after the PUT message was transmitted
1737 * (so we don't know if it was received or not)
1738 */
1739static void
1740announce_regex_done (void *cls,
1741 int success)
1742{
1743 struct MeshClient *c = cls;
1744
1745}
1746#endif
1747
1748
1749/**
1750 * Regex callback iterator to store own service description in the DHT.
1751 *
1752 * @param cls closure.
1753 * @param key hash for current state.
1754 * @param proof proof for current state.
1755 * @param accepting GNUNET_YES if this is an accepting state, GNUNET_NO if not.
1756 * @param num_edges number of edges leaving current state.
1757 * @param edges edges leaving current state.
1758 */
1759static void
1760regex_iterator (void *cls,
1761 const struct GNUNET_HashCode *key,
1762 const char *proof,
1763 int accepting,
1764 unsigned int num_edges,
1765 const struct GNUNET_REGEX_Edge *edges)
1766{
1767 struct MeshRegexBlock *block;
1768 struct MeshRegexEdge *block_edge;
1769 enum GNUNET_DHT_RouteOption opt;
1770 size_t size;
1771 size_t len;
1772 unsigned int i;
1773 unsigned int offset;
1774 char *aux;
1775
1776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1777 " regex dht put for state %s\n",
1778 GNUNET_h2s(key));
1779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1780 " proof: %s\n",
1781 proof);
1782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783 " num edges: %u\n",
1784 num_edges);
1785
1786 opt = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
1787 if (GNUNET_YES == accepting)
1788 {
1789 struct MeshRegexAccept block;
1790
1791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1792 " state %s is accepting, putting own id\n",
1793 GNUNET_h2s(key));
1794 size = sizeof (block);
1795 block.key = *key;
1796 block.id = my_full_id;
1797 GNUNET_STATISTICS_update (stats, "# regex accepting blocks stored",
1798 1, GNUNET_NO);
1799 GNUNET_STATISTICS_update (stats, "# regex accepting block bytes stored",
1800 sizeof (block), GNUNET_NO);
1801 (void)
1802 GNUNET_DHT_put(dht_handle, key,
1803 dht_replication_level,
1804 opt/* | GNUNET_DHT_RO_RECORD_ROUTE*/,
1805 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT,
1806 size,
1807 (char *) &block,
1808 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), /* FIXME: expiration time should be option */
1809 app_announce_time,
1810 NULL, NULL);
1811 }
1812 len = strlen(proof);
1813 size = sizeof (struct MeshRegexBlock) + len;
1814 block = GNUNET_malloc (size);
1815
1816 block->key = *key;
1817 block->n_proof = htonl (len);
1818 block->n_edges = htonl (num_edges);
1819 block->accepting = htonl (accepting);
1820
1821 /* Store the proof at the end of the block. */
1822 aux = (char *) &block[1];
1823 memcpy (aux, proof, len);
1824 aux = &aux[len];
1825
1826 /* Store each edge in a variable length MeshEdge struct at the
1827 * very end of the MeshRegexBlock structure.
1828 */
1829 for (i = 0; i < num_edges; i++)
1830 {
1831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1832 " edge %s towards %s\n",
1833 edges[i].label,
1834 GNUNET_h2s(&edges[i].destination));
1835
1836 /* aux points at the end of the last block */
1837 len = strlen (edges[i].label);
1838 size += sizeof (struct MeshRegexEdge) + len;
1839 // Calculate offset FIXME is this ok? use size instead?
1840 offset = aux - (char *) block;
1841 block = GNUNET_realloc (block, size);
1842 aux = &((char *) block)[offset];
1843 block_edge = (struct MeshRegexEdge *) aux;
1844 block_edge->key = edges[i].destination;
1845 block_edge->n_token = htonl (len);
1846 aux = (char *) &block_edge[1];
1847 memcpy (aux, edges[i].label, len);
1848 aux = &aux[len];
1849 }
1850 (void)
1851 GNUNET_DHT_put(dht_handle, key,
1852 dht_replication_level,
1853 opt,
1854 GNUNET_BLOCK_TYPE_MESH_REGEX, size,
1855 (char *) block,
1856 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), /* FIXME: this should be an option */
1857 app_announce_time,
1858 NULL, NULL);
1859 GNUNET_STATISTICS_update (stats, "# regex blocks stored",
1860 1, GNUNET_NO);
1861 GNUNET_STATISTICS_update (stats, "# regex block bytes stored",
1862 size, GNUNET_NO);
1863
1864 GNUNET_free (block);
1865}
1866
1867
1868/**
1869 * Store the regular expression describing a local service into the DHT.
1870 *
1871 * @param regex The regular expresion.
1872 */
1873static void
1874regex_put (struct MeshRegexDescriptor *regex)
1875{
1876 if (NULL == regex->dfa)
1877 {
1878 regex->dfa = GNUNET_REGEX_construct_dfa (regex->regex,
1879 strlen (regex->regex),
1880 regex->compression);
1881 }
1882
1883 DEBUG_DHT (" regex_put (%s) start\n", regex->regex);
1884 GNUNET_REGEX_iterate_all_edges (regex->dfa, &regex_iterator, NULL);
1885 DEBUG_DHT (" regex_put (%s) end\n", regex->regex);
1886}
1887
1888
1889/**
1890 * Periodically announce what applications are provided by local clients
1891 * (by regex)
1892 *
1893 * @param cls closure
1894 * @param tc task context
1895 */
1896static void
1897announce_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1898{
1899 struct MeshClient *c = cls;
1900 unsigned int i;
1901
1902 c->regex_announce_task = GNUNET_SCHEDULER_NO_TASK;
1903 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1904 return;
1905 DEBUG_DHT ("Starting PUT for regex\n");
1906 for (i = 0; i < c->n_regex; i++)
1907 regex_put (&c->regexes[i]);
1908 c->regex_announce_task = GNUNET_SCHEDULER_add_delayed (app_announce_time,
1909 &announce_regex,
1910 cls);
1911 DEBUG_DHT ("Finished PUT for regex\n");
1912}
1913
1914
1915/** 1474/**
1916 * Periodically announce what applications are provided by local clients 1475 * Periodically announce what applications are provided by local clients
1917 * (by type) 1476 * (by type)
@@ -4559,8 +4118,8 @@ tunnel_destroy (struct MeshTunnel *t)
4559 tree_iterate_children (t->tree, &tunnel_cancel_queues, t); 4118 tree_iterate_children (t->tree, &tunnel_cancel_queues, t);
4560 tree_destroy (t->tree); 4119 tree_destroy (t->tree);
4561 4120
4562 if (NULL != t->regex_ctx) 4121 if (NULL != t->regex_search)
4563 regex_cancel_search (t->regex_ctx); 4122 GNUNET_REGEX_search_cancel (t->regex_search->search_handle);
4564 if (NULL != t->dht_get_type) 4123 if (NULL != t->dht_get_type)
4565 GNUNET_DHT_get_stop (t->dht_get_type); 4124 GNUNET_DHT_get_stop (t->dht_get_type);
4566 if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task) 4125 if (GNUNET_SCHEDULER_NO_TASK != t->timeout_task)
@@ -6338,7 +5897,6 @@ handle_mesh_poll (void *cls, const struct GNUNET_PeerIdentity *peer,
6338 return GNUNET_OK; 5897 return GNUNET_OK;
6339} 5898}
6340 5899
6341
6342/** 5900/**
6343 * Core handler for path ACKs 5901 * Core handler for path ACKs
6344 * 5902 *
@@ -6384,12 +5942,12 @@ handle_mesh_path_ack (void *cls, const struct GNUNET_PeerIdentity *peer,
6384 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", 5942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n",
6385 GNUNET_i2s (peer)); 5943 GNUNET_i2s (peer));
6386 5944
6387 if (NULL != t->regex_ctx && t->regex_ctx->info->peer == peer_info->id) 5945 if (NULL != t->regex_search && t->regex_search->peer == peer_info->id)
6388 { 5946 {
6389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 5947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6390 "connect_by_string completed, stopping search\n"); 5948 "connect_by_string completed, stopping search\n");
6391 regex_cancel_search (t->regex_ctx); 5949 regex_cancel_search (t->regex_search);
6392 t->regex_ctx = NULL; 5950 t->regex_search = NULL;
6393 } 5951 }
6394 5952
6395 /* Add paths to peers? */ 5953 /* Add paths to peers? */
@@ -6717,152 +6275,6 @@ dht_get_type_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6717} 6275}
6718 6276
6719 6277
6720/**
6721 * Function to process DHT string to regex matching.
6722 * Called on each result obtained for the DHT search.
6723 *
6724 * @param cls closure (search context)
6725 * @param exp when will this value expire
6726 * @param key key of the result
6727 * @param get_path path of the get request (not used)
6728 * @param get_path_length lenght of get_path (not used)
6729 * @param put_path path of the put request (not used)
6730 * @param put_path_length length of the put_path (not used)
6731 * @param type type of the result
6732 * @param size number of bytes in data
6733 * @param data pointer to the result data
6734 */
6735static void
6736dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6737 const struct GNUNET_HashCode * key,
6738 const struct GNUNET_PeerIdentity *get_path,
6739 unsigned int get_path_length,
6740 const struct GNUNET_PeerIdentity *put_path,
6741 unsigned int put_path_length,
6742 enum GNUNET_BLOCK_Type type,
6743 size_t size, const void *data)
6744{
6745 const struct MeshRegexAccept *block = data;
6746 struct MeshRegexSearchContext *ctx = cls;
6747 struct MeshRegexSearchInfo *info = ctx->info;
6748// struct MeshPeerPath *p;
6749 struct MeshPeerInfo *peer_info;
6750
6751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
6752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", info->description);
6753 GNUNET_STATISTICS_update (stats, "# regex accepting blocks found",
6754 1, GNUNET_NO);
6755 GNUNET_STATISTICS_update (stats, "# regex accepting block bytes found",
6756 size, GNUNET_NO);
6757
6758 peer_info = peer_info_get(&block->id);
6759// p = path_build_from_dht (get_path, get_path_length, put_path,
6760// put_path_length);
6761// path_add_to_peers (p, GNUNET_NO);
6762// path_destroy(p);
6763
6764 tunnel_add_peer (info->t, peer_info);
6765 peer_info_connect (peer_info, info->t);
6766 if (0 == info->peer)
6767 {
6768 info->peer = peer_info->id;
6769 }
6770 else
6771 {
6772 GNUNET_array_append (info->peers, info->n_peers, peer_info->id);
6773 }
6774
6775 if (GNUNET_SCHEDULER_NO_TASK != info->timeout)
6776 return;
6777
6778 info->timeout = GNUNET_SCHEDULER_add_delayed (connect_timeout,
6779 &regex_connect_timeout,
6780 info);
6781
6782 return;
6783}
6784
6785
6786/**
6787 * Function to process DHT string to regex matching.
6788 * Called on each result obtained for the DHT search.
6789 *
6790 * @param cls closure (search context)
6791 * @param exp when will this value expire
6792 * @param key key of the result
6793 * @param get_path path of the get request (not used)
6794 * @param get_path_length lenght of get_path (not used)
6795 * @param put_path path of the put request (not used)
6796 * @param put_path_length length of the put_path (not used)
6797 * @param type type of the result
6798 * @param size number of bytes in data
6799 * @param data pointer to the result data
6800 *
6801 * TODO: re-issue the request after certain time? cancel after X results?
6802 */
6803static void
6804dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
6805 const struct GNUNET_HashCode * key,
6806 const struct GNUNET_PeerIdentity *get_path,
6807 unsigned int get_path_length,
6808 const struct GNUNET_PeerIdentity *put_path,
6809 unsigned int put_path_length,
6810 enum GNUNET_BLOCK_Type type,
6811 size_t size, const void *data)
6812{
6813 const struct MeshRegexBlock *block = data;
6814 struct MeshRegexSearchContext *ctx = cls;
6815 struct MeshRegexSearchInfo *info = ctx->info;
6816 void *copy;
6817 size_t len;
6818
6819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6820 "DHT GET STRING RETURNED RESULTS\n");
6821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6822 " key: %s\n", GNUNET_h2s (key));
6823
6824 GNUNET_STATISTICS_update (stats, "# regex blocks found",
6825 1, GNUNET_NO);
6826 GNUNET_STATISTICS_update (stats, "# regex block bytes found",
6827 size, GNUNET_NO);
6828
6829 copy = GNUNET_malloc (size);
6830 memcpy (copy, data, size);
6831 GNUNET_break (GNUNET_OK ==
6832 GNUNET_CONTAINER_multihashmap_put(info->dht_get_results, key, copy,
6833 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
6834 len = ntohl (block->n_proof);
6835 {
6836 char proof[len + 1];
6837
6838 memcpy (proof, &block[1], len);
6839 proof[len] = '\0';
6840 if (GNUNET_OK != GNUNET_REGEX_check_proof (proof, key))
6841 {
6842 GNUNET_break_op (0);
6843 return;
6844 }
6845 }
6846 len = strlen (info->description);
6847 if (len == ctx->position) // String processed
6848 {
6849 if (GNUNET_YES == ntohl (block->accepting))
6850 {
6851 regex_find_path(key, ctx);
6852 }
6853 else
6854 {
6855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " block not accepting!\n");
6856 // FIXME REGEX this block not successful, wait for more? start timeout?
6857 }
6858 return;
6859 }
6860
6861 regex_next_edge (block, size, ctx);
6862
6863 return;
6864}
6865
6866/******************************************************************************/ 6278/******************************************************************************/
6867/********************* MESH LOCAL HANDLES **************************/ 6279/********************* MESH LOCAL HANDLES **************************/
6868/******************************************************************************/ 6280/******************************************************************************/
@@ -6931,8 +6343,8 @@ handle_local_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
6931 for (i = 0; i < c->n_regex; i++) 6343 for (i = 0; i < c->n_regex; i++)
6932 { 6344 {
6933 GNUNET_free (c->regexes[i].regex); 6345 GNUNET_free (c->regexes[i].regex);
6934 if (NULL != c->regexes[i].dfa) 6346 if (NULL != c->regexes[i].h)
6935 GNUNET_REGEX_automaton_destroy (c->regexes[i].dfa); 6347 GNUNET_REGEX_announce_cancel (c->regexes[i].h);
6936 } 6348 }
6937 GNUNET_free_non_null (c->regexes); 6349 GNUNET_free_non_null (c->regexes);
6938 if (GNUNET_SCHEDULER_NO_TASK != c->regex_announce_task) 6350 if (GNUNET_SCHEDULER_NO_TASK != c->regex_announce_task)
@@ -7109,7 +6521,7 @@ handle_local_announce_regex (void *cls, struct GNUNET_SERVER_Client *client,
7109 } 6521 }
7110 rd.regex = regex; 6522 rd.regex = regex;
7111 rd.compression = ntohs (msg->compression_characters); 6523 rd.compression = ntohs (msg->compression_characters);
7112 rd.dfa = NULL; 6524 rd.h = NULL;
7113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " length %u\n", len); 6525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " length %u\n", len);
7114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regex %s\n", regex); 6526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " regex %s\n", regex);
7115 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " cm %u\n", ntohs(rd.compression)); 6527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " cm %u\n", ntohs(rd.compression));
@@ -7117,7 +6529,7 @@ handle_local_announce_regex (void *cls, struct GNUNET_SERVER_Client *client,
7117 c->partial_regex = NULL; 6529 c->partial_regex = NULL;
7118 if (GNUNET_SCHEDULER_NO_TASK == c->regex_announce_task) 6530 if (GNUNET_SCHEDULER_NO_TASK == c->regex_announce_task)
7119 { 6531 {
7120 c->regex_announce_task = GNUNET_SCHEDULER_add_now(&announce_regex, c); 6532 c->regex_announce_task = GNUNET_SCHEDULER_add_now(&regex_announce, c);
7121 } 6533 }
7122 else 6534 else
7123 { 6535 {
@@ -7774,9 +7186,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7774 const struct GNUNET_MessageHeader *message) 7186 const struct GNUNET_MessageHeader *message)
7775{ 7187{
7776 struct GNUNET_MESH_ConnectPeerByString *msg; 7188 struct GNUNET_MESH_ConnectPeerByString *msg;
7777 struct MeshRegexSearchContext *ctx;
7778 struct MeshRegexSearchInfo *info; 7189 struct MeshRegexSearchInfo *info;
7779 struct GNUNET_DHT_GetHandle *get_h;
7780 struct GNUNET_HashCode key; 7190 struct GNUNET_HashCode key;
7781 struct MeshTunnel *t; 7191 struct MeshTunnel *t;
7782 struct MeshClient *c; 7192 struct MeshClient *c;
@@ -7832,7 +7242,7 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7832 7242
7833 /* Only one connect_by_string allowed at the same time! */ 7243 /* Only one connect_by_string allowed at the same time! */
7834 /* FIXME: allow more, return handle at api level to cancel, document */ 7244 /* FIXME: allow more, return handle at api level to cancel, document */
7835 if (NULL != t->regex_ctx) 7245 if (NULL != t->regex_search)
7836 { 7246 {
7837 GNUNET_break (0); 7247 GNUNET_break (0);
7838 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); 7248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
@@ -7853,34 +7263,14 @@ handle_local_connect_by_string (void *cls, struct GNUNET_SERVER_Client *client,
7853 info = GNUNET_malloc (sizeof (struct MeshRegexSearchInfo)); 7263 info = GNUNET_malloc (sizeof (struct MeshRegexSearchInfo));
7854 info->t = t; 7264 info->t = t;
7855 info->description = GNUNET_strndup (string, len); 7265 info->description = GNUNET_strndup (string, len);
7856 info->dht_get_handles = GNUNET_CONTAINER_multihashmap_create(32, GNUNET_NO);
7857 info->dht_get_results = GNUNET_CONTAINER_multihashmap_create(32, GNUNET_NO);
7858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " string: %s\n", info->description); 7266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " string: %s\n", info->description);
7859 7267
7860 ctx = GNUNET_malloc (sizeof (struct MeshRegexSearchContext)); 7268 t->regex_search = info;
7861 ctx->position = size; 7269
7862 ctx->info = info; 7270 info->search_handle = GNUNET_REGEX_search (dht_handle,
7863 t->regex_ctx = ctx; 7271 info->description,
7864 7272 &regex_found_handler, info,
7865 GNUNET_array_append (info->contexts, info->n_contexts, ctx); 7273 stats);
7866
7867 /* Start search in DHT */
7868 get_h = GNUNET_DHT_get_start (dht_handle, /* handle */
7869 GNUNET_BLOCK_TYPE_MESH_REGEX, /* type */
7870 &key, /* key to search */
7871 dht_replication_level, /* replication level */
7872 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
7873 &info->description[size], /* xquery */
7874 // FIXME add BLOOMFILTER to exclude filtered peers
7875 len + 1 - size, /* xquery bits */
7876 // FIXME add BLOOMFILTER SIZE
7877 &dht_get_string_handler, ctx);
7878
7879 GNUNET_break (GNUNET_OK ==
7880 GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
7881 &key,
7882 get_h,
7883 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
7884 7274
7885 GNUNET_SERVER_receive_done (client, GNUNET_OK); 7275 GNUNET_SERVER_receive_done (client, GNUNET_OK);
7886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connect by string processed\n"); 7276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "connect by string processed\n");
diff --git a/src/mesh/plugin_block_mesh.c b/src/mesh/plugin_block_mesh.c
index b8a034da2..58faaa538 100644
--- a/src/mesh/plugin_block_mesh.c
+++ b/src/mesh/plugin_block_mesh.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet 2 This file is part of GNUnet
3 (C) 2012 Christian Grothoff (and other contributing authors) 3 (C) 2012,2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -27,7 +27,6 @@
27#include "platform.h" 27#include "platform.h"
28#include "gnunet_block_plugin.h" 28#include "gnunet_block_plugin.h"
29#include "block_mesh.h" 29#include "block_mesh.h"
30#include "mesh_block_lib.h"
31 30
32/** 31/**
33 * Number of bits we set per entry in the bloomfilter. 32 * Number of bits we set per entry in the bloomfilter.
@@ -127,92 +126,6 @@ block_plugin_mesh_evaluate (void *cls, enum GNUNET_BLOCK_Type type,
127 } 126 }
128 return GNUNET_BLOCK_EVALUATION_OK_MORE; 127 return GNUNET_BLOCK_EVALUATION_OK_MORE;
129 128
130
131 case GNUNET_BLOCK_TYPE_MESH_REGEX:
132 if (NULL == reply_block)
133 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
134 if (0 != xquery_size)
135 {
136 const char *query;
137
138 query = (const char *) xquery;
139 if ('\0' != query[xquery_size - 1]) /* must be valid string */
140 {
141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
142 "Block xquery not a valid string\n");
143 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
144 }
145 }
146 else
147 {
148 GNUNET_break_op (0);
149 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
150 }
151 switch (GNUNET_MESH_regex_block_check (reply_block,
152 reply_block_size,
153 xquery))
154 {
155 case GNUNET_SYSERR:
156 GNUNET_break_op(0);
157 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
158 case GNUNET_NO:
159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160 "BLOCK XQUERY %s not accepted\n", xquery);
161 return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
162 default:
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "BLOCK XQUERY %s accepted\n", xquery);
165 break;
166 }
167 if (NULL != bf)
168 {
169 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
170 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
171 if (NULL != *bf)
172 {
173 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
174 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
175 }
176 else
177 {
178 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
179 }
180 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
181 }
182 return GNUNET_BLOCK_EVALUATION_OK_MORE;
183
184
185 case GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT:
186 if (0 != xquery_size)
187 {
188 GNUNET_break_op (0);
189 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
190 }
191 if (NULL == reply_block)
192 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
193 if (sizeof (struct MeshRegexAccept) != reply_block_size)
194 {
195 GNUNET_break_op(0);
196 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
197 }
198 if (NULL != bf)
199 {
200 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
201 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
202 if (NULL != *bf)
203 {
204 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
205 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
206 }
207 else
208 {
209 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
210 }
211 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
212 }
213 return GNUNET_BLOCK_EVALUATION_OK_MORE;
214
215
216 default: 129 default:
217 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED; 130 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
218 } 131 }
@@ -264,8 +177,6 @@ libgnunet_plugin_block_mesh_init (void *cls)
264 { 177 {
265 GNUNET_BLOCK_TYPE_MESH_PEER, 178 GNUNET_BLOCK_TYPE_MESH_PEER,
266 GNUNET_BLOCK_TYPE_MESH_PEER_BY_TYPE, 179 GNUNET_BLOCK_TYPE_MESH_PEER_BY_TYPE,
267 GNUNET_BLOCK_TYPE_MESH_REGEX,
268 GNUNET_BLOCK_TYPE_MESH_REGEX_ACCEPT,
269 GNUNET_BLOCK_TYPE_ANY /* end of list */ 180 GNUNET_BLOCK_TYPE_ANY /* end of list */
270 }; 181 };
271 struct GNUNET_BLOCK_PluginFunctions *api; 182 struct GNUNET_BLOCK_PluginFunctions *api;
diff --git a/src/regex/Makefile.am b/src/regex/Makefile.am
index f6ab33abf..7d7c84dfe 100644
--- a/src/regex/Makefile.am
+++ b/src/regex/Makefile.am
@@ -8,17 +8,53 @@ if USE_COVERAGE
8 AM_CFLAGS = --coverage 8 AM_CFLAGS = --coverage
9endif 9endif
10 10
11lib_LTLIBRARIES = libgnunetregex.la 11lib_LTLIBRARIES = libgnunetregexblock.la \
12 libgnunetregex.la
13
14
15libgnunetregexblock_la_SOURCES = \
16 regex_block_lib.c regex_block_lib.h
17libgnunetregexblock_la_LIBADD = \
18 $(top_builddir)/src/util/libgnunetutil.la \
19 $(XLIB) \
20 $(LTLIBINTL)
21libgnunetregexblock_la_LDFLAGS = \
22 $(GN_LIB_LDFLAGS) $(WINFLAGS) \
23 -version-info 1:0:0
12 24
13libgnunetregex_la_SOURCES = \ 25libgnunetregex_la_SOURCES = \
14 regex_internal.h regex.c \ 26 regex_internal.h regex.c \
15 regex_graph.c regex_random.c 27 regex_graph.c regex_random.c \
28 regex_dht.c
16libgnunetregex_la_LIBADD = -lm \ 29libgnunetregex_la_LIBADD = -lm \
17 $(top_builddir)/src/util/libgnunetutil.la 30 $(top_builddir)/src/util/libgnunetutil.la \
31 $(top_builddir)/src/dht/libgnunetdht.la \
32 $(top_builddir)/src/statistics/libgnunetstatistics.la \
33 $(top_builddir)/src/regex/libgnunetregexblock.la
18libgnunetregex_la_LDFLAGS = \ 34libgnunetregex_la_LDFLAGS = \
19 $(GN_LIB_LDFLAGS) \ 35 $(GN_LIB_LDFLAGS) \
20 -version-info 1:1:0 36 -version-info 1:1:0
21 37
38
39plugindir = $(libdir)/gnunet
40
41plugin_LTLIBRARIES = \
42 libgnunet_plugin_block_regex.la
43
44libgnunet_plugin_block_regex_la_SOURCES = \
45 plugin_block_regex.c
46libgnunet_plugin_block_regex_la_LIBADD = \
47 $(top_builddir)/src/regex/libgnunetregexblock.la \
48 $(top_builddir)/src/block/libgnunetblock.la \
49 $(top_builddir)/src/util/libgnunetutil.la
50libgnunet_plugin_block_regex_la_LDFLAGS = \
51 $(GN_PLUGIN_LDFLAGS)
52libgnunet_plugin_block_regex_la_DEPENDENCIES = \
53 $(top_builddir)/src/regex/libgnunetregexblock.la \
54 $(top_builddir)/src/block/libgnunetblock.la \
55 $(top_builddir)/src/util/libgnunetutil.la
56
57
22if HAVE_MYSQL 58if HAVE_MYSQL
23noinst_mysql_progs = \ 59noinst_mysql_progs = \
24gnunet-regex-simulation-profiler 60gnunet-regex-simulation-profiler
diff --git a/src/regex/plugin_block_regex.c b/src/regex/plugin_block_regex.c
new file mode 100644
index 000000000..9a5ab33ec
--- /dev/null
+++ b/src/regex/plugin_block_regex.c
@@ -0,0 +1,221 @@
1/*
2 This file is part of GNUnet
3 (C) 2013 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 regex/plugin_block_regex.c
23 * @brief blocks used for regex storage and search
24 * @author Bartlomiej Polot
25 */
26
27#include "platform.h"
28#include "gnunet_block_plugin.h"
29#include "block_regex.h"
30#include "regex_block_lib.h"
31
32/**
33 * Number of bits we set per entry in the bloomfilter.
34 * Do not change!
35 */
36#define BLOOMFILTER_K 16
37
38
39/**
40 * Function called to validate a reply or a request. For
41 * request evaluation, simply pass "NULL" for the reply_block.
42 * Note that it is assumed that the reply has already been
43 * matched to the key (and signatures checked) as it would
44 * be done with the "get_key" function.
45 *
46 * @param cls closure
47 * @param type block type
48 * @param query original query (hash)
49 * @param bf pointer to bloom filter associated with query; possibly updated (!)
50 * @param bf_mutator mutation value for bf
51 * @param xquery extrended query data (can be NULL, depending on type)
52 * @param xquery_size number of bytes in xquery
53 * @param reply_block response to validate
54 * @param reply_block_size number of bytes in reply block
55 * @return characterization of result
56 */
57static enum GNUNET_BLOCK_EvaluationResult
58block_plugin_regex_evaluate (void *cls, enum GNUNET_BLOCK_Type type,
59 const struct GNUNET_HashCode * query,
60 struct GNUNET_CONTAINER_BloomFilter **bf,
61 int32_t bf_mutator, const void *xquery,
62 size_t xquery_size, const void *reply_block,
63 size_t reply_block_size)
64{
65 struct GNUNET_HashCode chash;
66 struct GNUNET_HashCode mhash;
67
68 switch (type)
69 {
70 case GNUNET_BLOCK_TYPE_REGEX:
71 if (NULL == reply_block)
72 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
73 if (0 != xquery_size)
74 {
75 const char *query;
76
77 query = (const char *) xquery;
78 if ('\0' != query[xquery_size - 1]) /* must be valid string */
79 {
80 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
81 "Block xquery not a valid string\n");
82 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
83 }
84 }
85 else
86 {
87 GNUNET_break_op (0);
88 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
89 }
90 switch (GNUNET_REGEX_block_check (reply_block,
91 reply_block_size,
92 xquery))
93 {
94 case GNUNET_SYSERR:
95 GNUNET_break_op(0);
96 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
97 case GNUNET_NO:
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 "BLOCK XQUERY %s not accepted\n", xquery);
100 return GNUNET_BLOCK_EVALUATION_RESULT_IRRELEVANT;
101 default:
102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103 "BLOCK XQUERY %s accepted\n", xquery);
104 break;
105 }
106 if (NULL != bf)
107 {
108 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
109 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
110 if (NULL != *bf)
111 {
112 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
113 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
114 }
115 else
116 {
117 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
118 }
119 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
120 }
121 return GNUNET_BLOCK_EVALUATION_OK_MORE;
122
123
124 case GNUNET_BLOCK_TYPE_REGEX_ACCEPT:
125 if (0 != xquery_size)
126 {
127 GNUNET_break_op (0);
128 return GNUNET_BLOCK_EVALUATION_REQUEST_INVALID;
129 }
130 if (NULL == reply_block)
131 return GNUNET_BLOCK_EVALUATION_REQUEST_VALID;
132 if (sizeof (struct RegexAccept) != reply_block_size)
133 {
134 GNUNET_break_op(0);
135 return GNUNET_BLOCK_EVALUATION_RESULT_INVALID;
136 }
137 if (NULL != bf)
138 {
139 GNUNET_CRYPTO_hash (reply_block, reply_block_size, &chash);
140 GNUNET_BLOCK_mingle_hash (&chash, bf_mutator, &mhash);
141 if (NULL != *bf)
142 {
143 if (GNUNET_YES == GNUNET_CONTAINER_bloomfilter_test (*bf, &mhash))
144 return GNUNET_BLOCK_EVALUATION_OK_DUPLICATE;
145 }
146 else
147 {
148 *bf = GNUNET_CONTAINER_bloomfilter_init (NULL, 8, BLOOMFILTER_K);
149 }
150 GNUNET_CONTAINER_bloomfilter_add (*bf, &mhash);
151 }
152 return GNUNET_BLOCK_EVALUATION_OK_MORE;
153
154
155 default:
156 return GNUNET_BLOCK_EVALUATION_TYPE_NOT_SUPPORTED;
157 }
158}
159
160
161/**
162 * Function called to obtain the key for a block.
163 *
164 * @param cls closure
165 * @param type block type
166 * @param block block to get the key for
167 * @param block_size number of bytes in block
168 * @param key set to the key (query) for the given block
169 * @return GNUNET_OK on success, GNUNET_SYSERR if type not supported
170 * (or if extracting a key from a block of this type does not work)
171 */
172static int
173block_plugin_regex_get_key (void *cls, enum GNUNET_BLOCK_Type type,
174 const void *block, size_t block_size,
175 struct GNUNET_HashCode * key)
176{
177 switch (type)
178 {
179 default:
180 /* FIXME */
181 GNUNET_break (0);
182 return GNUNET_SYSERR;
183 }
184}
185
186
187/**
188 * Entry point for the plugin.
189 */
190void *
191libgnunet_plugin_block_regex_init (void *cls)
192{
193 static enum GNUNET_BLOCK_Type types[] =
194 {
195 GNUNET_BLOCK_TYPE_REGEX,
196 GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
197 GNUNET_BLOCK_TYPE_ANY /* end of list */
198 };
199 struct GNUNET_BLOCK_PluginFunctions *api;
200
201 api = GNUNET_malloc (sizeof (struct GNUNET_BLOCK_PluginFunctions));
202 api->evaluate = &block_plugin_regex_evaluate;
203 api->get_key = &block_plugin_regex_get_key;
204 api->types = types;
205 return api;
206}
207
208
209/**
210 * Exit point from the plugin.
211 */
212void *
213libgnunet_plugin_block_regex_done (void *cls)
214{
215 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
216
217 GNUNET_free (api);
218 return NULL;
219}
220
221/* end of plugin_block_regex.c */
diff --git a/src/regex/regex.c b/src/regex/regex.c
index 92943391a..ad8e56b97 100644
--- a/src/regex/regex.c
+++ b/src/regex/regex.c
@@ -20,8 +20,7 @@
20/** 20/**
21 * @file src/regex/regex.c 21 * @file src/regex/regex.c
22 * @brief library to create Deterministic Finite Automatons (DFAs) from regular 22 * @brief library to create Deterministic Finite Automatons (DFAs) from regular
23 * expressions (regexes). Used by mesh for announcing regexes in the network and 23 * expressions (regexes).
24 * matching strings against published regexes.
25 * @author Maximilian Szengel 24 * @author Maximilian Szengel
26 */ 25 */
27#include "platform.h" 26#include "platform.h"
diff --git a/src/mesh/mesh_block_lib.c b/src/regex/regex_block_lib.c
index d414a5d81..95361ca95 100644
--- a/src/mesh/mesh_block_lib.c
+++ b/src/regex/regex_block_lib.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors) 3 (C) 2012,2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -19,16 +19,16 @@
19*/ 19*/
20/** 20/**
21 * @author Bartlomiej Polot 21 * @author Bartlomiej Polot
22 * @file mesh/mesh_block_lib.c 22 * @file regex/regex_block_lib.c
23 */ 23 */
24#include "platform.h" 24#include "platform.h"
25#include "mesh_block_lib.h" 25#include "regex_block_lib.h"
26 26
27 27
28/** 28/**
29 * Struct to keep track of the xquery while iterating all the edges in a block. 29 * Struct to keep track of the xquery while iterating all the edges in a block.
30 */ 30 */
31struct mesh_block_xquery_ctx 31struct regex_block_xquery_ctx
32{ 32{
33 /** 33 /**
34 * Xquery: string we are looking for. 34 * Xquery: string we are looking for.
@@ -58,7 +58,7 @@ check_edge (void *cls,
58 size_t len, 58 size_t len,
59 const struct GNUNET_HashCode *key) 59 const struct GNUNET_HashCode *key)
60{ 60{
61 struct mesh_block_xquery_ctx *ctx = cls; 61 struct regex_block_xquery_ctx *ctx = cls;
62 62
63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " edge %.*s [%u]\n", 63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " edge %.*s [%u]\n",
64 (int) len, token, len); 64 (int) len, token, len);
@@ -93,12 +93,12 @@ check_edge (void *cls,
93 * GNUNET_SYSERR if the block is invalid. 93 * GNUNET_SYSERR if the block is invalid.
94 */ 94 */
95int 95int
96GNUNET_MESH_regex_block_check (const struct MeshRegexBlock *block, 96GNUNET_REGEX_block_check (const struct RegexBlock *block,
97 size_t size, 97 size_t size,
98 const char *xquery) 98 const char *xquery)
99{ 99{
100 int res; 100 int res;
101 struct mesh_block_xquery_ctx ctx; 101 struct regex_block_xquery_ctx ctx;
102 102
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "* Checking block with xquery \"%s\"\n", 104 "* Checking block with xquery \"%s\"\n",
@@ -107,7 +107,7 @@ GNUNET_MESH_regex_block_check (const struct MeshRegexBlock *block,
107 return GNUNET_OK; 107 return GNUNET_OK;
108 ctx.xquery = xquery; 108 ctx.xquery = xquery;
109 ctx.found = GNUNET_NO; 109 ctx.found = GNUNET_NO;
110 res = GNUNET_MESH_regex_block_iterate (block, size, &check_edge, &ctx); 110 res = GNUNET_REGEX_block_iterate (block, size, &check_edge, &ctx);
111 if (GNUNET_SYSERR == res) 111 if (GNUNET_SYSERR == res)
112 return GNUNET_SYSERR; 112 return GNUNET_SYSERR;
113 return ctx.found; 113 return ctx.found;
@@ -125,26 +125,26 @@ GNUNET_MESH_regex_block_check (const struct MeshRegexBlock *block,
125 * @return How many bytes of block have been processed 125 * @return How many bytes of block have been processed
126 */ 126 */
127int 127int
128GNUNET_MESH_regex_block_iterate (const struct MeshRegexBlock *block, 128GNUNET_REGEX_block_iterate (const struct RegexBlock *block,
129 size_t size, 129 size_t size,
130 GNUNET_MESH_EgdeIterator iterator, 130 GNUNET_REGEX_EgdeIterator iterator,
131 void *iter_cls) 131 void *iter_cls)
132{ 132{
133 struct MeshRegexEdge *edge; 133 struct RegexEdge *edge;
134 unsigned int n; 134 unsigned int n;
135 unsigned int n_token; 135 unsigned int n_token;
136 unsigned int i; 136 unsigned int i;
137 size_t offset; 137 size_t offset;
138 char *aux; 138 char *aux;
139 139
140 offset = sizeof (struct MeshRegexBlock); 140 offset = sizeof (struct RegexBlock);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "* Start iterating block of size %u, off %u\n", 142 "* Start iterating block of size %u, off %u\n",
143 size, offset); 143 size, offset);
144 if (offset > size) // Is it safe to access the regex block? 144 if (offset > size) // Is it safe to access the regex block?
145 { 145 {
146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
147 "* Block is smaller than struct MeshRegexBlock, END\n"); 147 "* Block is smaller than struct RegexBlock, END\n");
148 GNUNET_break_op (0); 148 GNUNET_break_op (0);
149 return GNUNET_SYSERR; 149 return GNUNET_SYSERR;
150 } 150 }
@@ -165,16 +165,16 @@ GNUNET_MESH_regex_block_iterate (const struct MeshRegexBlock *block,
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Edges: %u\n", n); 165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Edges: %u\n", n);
166 for (i = 0; i < n; i++) // aux always points at the end of the previous block 166 for (i = 0; i < n; i++) // aux always points at the end of the previous block
167 { 167 {
168 offset += sizeof (struct MeshRegexEdge); 168 offset += sizeof (struct RegexEdge);
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Edge %u, off %u\n", i, offset); 169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Edge %u, off %u\n", i, offset);
170 if (offset > size) // Is it safe to access the next edge block? 170 if (offset > size) // Is it safe to access the next edge block?
171 { 171 {
172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 172 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
173 "* Size not enough for MeshRegexEdge, END\n"); 173 "* Size not enough for RegexEdge, END\n");
174 GNUNET_break_op (0); 174 GNUNET_break_op (0);
175 return GNUNET_SYSERR; 175 return GNUNET_SYSERR;
176 } 176 }
177 edge = (struct MeshRegexEdge *) aux; 177 edge = (struct RegexEdge *) aux;
178 n_token = ntohl (edge->n_token); 178 n_token = ntohl (edge->n_token);
179 offset += n_token; 179 offset += n_token;
180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -207,4 +207,4 @@ GNUNET_MESH_regex_block_iterate (const struct MeshRegexBlock *block,
207 return GNUNET_SYSERR; 207 return GNUNET_SYSERR;
208} 208}
209 209
210/* end of mesh_block_lib.c */ 210/* end of regex_block_lib.c */
diff --git a/src/mesh/mesh_block_lib.h b/src/regex/regex_block_lib.h
index 6ec268c6e..f591f5f61 100644
--- a/src/mesh/mesh_block_lib.h
+++ b/src/regex/regex_block_lib.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors) 3 (C) 2012,2013 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -20,11 +20,11 @@
20 20
21/** 21/**
22 * @author Bartlomiej Polot 22 * @author Bartlomiej Polot
23 * @file mesh/mesh_block_lib.h 23 * @file regex/regex_block_lib.h
24 */ 24 */
25 25
26#ifndef MESH_BLOCK_LIB_H_ 26#ifndef REGEX_BLOCK_LIB_H_
27#define MESH_BLOCK_LIB_H_ 27#define REGEX_BLOCK_LIB_H_
28 28
29#ifdef __cplusplus 29#ifdef __cplusplus
30extern "C" 30extern "C"
@@ -36,7 +36,7 @@ extern "C"
36#endif 36#endif
37 37
38#include "platform.h" 38#include "platform.h"
39#include "block_mesh.h" 39#include "block_regex.h"
40 40
41/** 41/**
42 * Check if the regex block is well formed, including all edges 42 * Check if the regex block is well formed, including all edges
@@ -50,9 +50,9 @@ extern "C"
50 * GNUNET_SYSERR if the block is invalid. 50 * GNUNET_SYSERR if the block is invalid.
51 */ 51 */
52int 52int
53GNUNET_MESH_regex_block_check (const struct MeshRegexBlock *block, 53GNUNET_REGEX_block_check (const struct RegexBlock *block,
54 size_t size, 54 size_t size,
55 const char *xquery); 55 const char *xquery);
56 56
57/** 57/**
58 * Iterator over edges in a block. 58 * Iterator over edges in a block.
@@ -64,10 +64,10 @@ GNUNET_MESH_regex_block_check (const struct MeshRegexBlock *block,
64 * 64 *
65 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise. 65 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
66 */ 66 */
67typedef int (*GNUNET_MESH_EgdeIterator)(void *cls, 67typedef int (*GNUNET_REGEX_EgdeIterator)(void *cls,
68 const char *token, 68 const char *token,
69 size_t len, 69 size_t len,
70 const struct GNUNET_HashCode *key); 70 const struct GNUNET_HashCode *key);
71 71
72 72
73/** 73/**
@@ -81,10 +81,10 @@ typedef int (*GNUNET_MESH_EgdeIterator)(void *cls,
81 * @return GNUNET_SYSERR if an error has been encountered, GNUNET_OK otherwise 81 * @return GNUNET_SYSERR if an error has been encountered, GNUNET_OK otherwise
82 */ 82 */
83int 83int
84GNUNET_MESH_regex_block_iterate (const struct MeshRegexBlock *block, 84GNUNET_REGEX_block_iterate (const struct RegexBlock *block,
85 size_t size, 85 size_t size,
86 GNUNET_MESH_EgdeIterator iterator, 86 GNUNET_REGEX_EgdeIterator iterator,
87 void *iter_cls); 87 void *iter_cls);
88 88
89#if 0 /* keep Emacsens' auto-indent happy */ 89#if 0 /* keep Emacsens' auto-indent happy */
90{ 90{
@@ -93,6 +93,6 @@ GNUNET_MESH_regex_block_iterate (const struct MeshRegexBlock *block,
93} 93}
94#endif 94#endif
95 95
96/* ifndef MESH_BLOCK_LIB_H */ 96/* ifndef REGEX_BLOCK_LIB_H */
97#endif 97#endif
98/* end of mesh_block_lib.h */ 98/* end of regex_block_lib.h */
diff --git a/src/regex/regex_dht.c b/src/regex/regex_dht.c
new file mode 100644
index 000000000..ce9d4e2a1
--- /dev/null
+++ b/src/regex/regex_dht.c
@@ -0,0 +1,754 @@
1/*
2 This file is part of GNUnet
3 (C) 2012 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 * @file src/regex/regex_dht.c
22 * @brief library to announce regexes in the network and match strings
23 * against published regexes.
24 * @author Bartlomiej Polot
25 */
26#include "platform.h"
27#include "gnunet_regex_lib.h"
28#include "regex_block_lib.h"
29#include "gnunet_dht_service.h"
30#include "gnunet_statistics_service.h"
31
32#define DHT_REPLICATION 5
33#define DHT_TTL GNUNET_TIME_UNIT_HOURS
34
35struct GNUNET_REGEX_announce_handle
36{
37 /**
38 * DHT handle to use, must be initialized externally.
39 */
40 struct GNUNET_DHT_Handle *dht;
41
42 /**
43 * Regular expression.
44 */
45 const char *regex;
46
47 /**
48 * Automaton representation of the regex (expensive to build).
49 */
50 struct GNUNET_REGEX_Automaton* dfa;
51
52 /**
53 * Identity under which to announce the regex.
54 */
55 struct GNUNET_PeerIdentity *id;
56
57 /**
58 * Optional statistics handle to report usage. Can be NULL.
59 */
60 struct GNUNET_STATISTICS_Handle *stats;
61};
62
63
64/**
65 * Regex callback iterator to store own service description in the DHT.
66 *
67 * @param cls closure.
68 * @param key hash for current state.
69 * @param proof proof for current state.
70 * @param accepting GNUNET_YES if this is an accepting state, GNUNET_NO if not.
71 * @param num_edges number of edges leaving current state.
72 * @param edges edges leaving current state.
73 */
74static void
75regex_iterator (void *cls,
76 const struct GNUNET_HashCode *key,
77 const char *proof,
78 int accepting,
79 unsigned int num_edges,
80 const struct GNUNET_REGEX_Edge *edges)
81{
82 struct GNUNET_REGEX_announce_handle *h = cls;
83 struct RegexBlock *block;
84 struct RegexEdge *block_edge;
85 enum GNUNET_DHT_RouteOption opt;
86 size_t size;
87 size_t len;
88 unsigned int i;
89 unsigned int offset;
90 char *aux;
91
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 " regex dht put for state %s\n",
94 GNUNET_h2s (key));
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 " proof: %s\n",
97 proof);
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
99 " num edges: %u\n",
100 num_edges);
101
102 opt = GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE;
103 if (GNUNET_YES == accepting)
104 {
105 struct RegexAccept block;
106
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
108 " state %s is accepting, putting own id\n",
109 GNUNET_h2s(key));
110 size = sizeof (block);
111 block.key = *key;
112 block.id = *(h->id);
113 GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored",
114 1, GNUNET_NO);
115 GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored",
116 sizeof (block), GNUNET_NO);
117 (void)
118 GNUNET_DHT_put (h->dht, key,
119 2, /* FIXME option */
120 opt /* | GNUNET_DHT_RO_RECORD_ROUTE*/,
121 GNUNET_BLOCK_TYPE_REGEX_ACCEPT,
122 size,
123 (char *) &block,
124 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS), /* FIXME: expiration time should be option */
125 GNUNET_TIME_UNIT_HOURS, /* FIXME option */
126 NULL, NULL);
127 }
128 len = strlen(proof);
129 size = sizeof (struct RegexBlock) + len;
130 block = GNUNET_malloc (size);
131
132 block->key = *key;
133 block->n_proof = htonl (len);
134 block->n_edges = htonl (num_edges);
135 block->accepting = htonl (accepting);
136
137 /* Store the proof at the end of the block. */
138 aux = (char *) &block[1];
139 memcpy (aux, proof, len);
140 aux = &aux[len];
141
142 /* Store each edge in a variable length MeshEdge struct at the
143 * very end of the MeshRegexBlock structure.
144 */
145 for (i = 0; i < num_edges; i++)
146 {
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 " edge %s towards %s\n",
149 edges[i].label,
150 GNUNET_h2s(&edges[i].destination));
151
152 /* aux points at the end of the last block */
153 len = strlen (edges[i].label);
154 size += sizeof (struct RegexEdge) + len;
155 // Calculate offset FIXME is this ok? use size instead?
156 offset = aux - (char *) block;
157 block = GNUNET_realloc (block, size);
158 aux = &((char *) block)[offset];
159 block_edge = (struct RegexEdge *) aux;
160 block_edge->key = edges[i].destination;
161 block_edge->n_token = htonl (len);
162 aux = (char *) &block_edge[1];
163 memcpy (aux, edges[i].label, len);
164 aux = &aux[len];
165 }
166 (void)
167 GNUNET_DHT_put(h->dht, key,
168 DHT_REPLICATION, /* FIXME OPTION */
169 opt,
170 GNUNET_BLOCK_TYPE_REGEX, size,
171 (char *) block,
172 GNUNET_TIME_relative_to_absolute (DHT_TTL), /* FIXME: this should be an option */
173 DHT_TTL,
174 NULL, NULL);
175 GNUNET_STATISTICS_update (h->stats, "# regex blocks stored",
176 1, GNUNET_NO);
177 GNUNET_STATISTICS_update (h->stats, "# regex block bytes stored",
178 size, GNUNET_NO);
179
180 GNUNET_free (block);
181}
182
183
184struct GNUNET_REGEX_announce_handle *
185GNUNET_REGEX_announce (struct GNUNET_DHT_Handle *dht,
186 struct GNUNET_PeerIdentity *id,
187 const char *regex,
188 uint16_t compression,
189 struct GNUNET_STATISTICS_Handle *stats)
190{
191 struct GNUNET_REGEX_announce_handle *h;
192
193 GNUNET_assert (NULL == dht);
194 h = GNUNET_malloc (sizeof (struct GNUNET_REGEX_announce_handle));
195 h->regex = regex;
196 h->dht = dht;
197 h->stats = stats;
198 h->id = id;
199 h->dfa = GNUNET_REGEX_construct_dfa (regex,
200 strlen (regex),
201 compression);
202 GNUNET_REGEX_reannounce (h);
203 return h;
204}
205
206void
207GNUNET_REGEX_reannounce (struct GNUNET_REGEX_announce_handle *h)
208{
209 GNUNET_REGEX_iterate_all_edges (h->dfa, &regex_iterator, h);
210}
211
212void
213GNUNET_REGEX_announce_cancel (struct GNUNET_REGEX_announce_handle *h)
214{
215 GNUNET_REGEX_automaton_destroy (h->dfa);
216 GNUNET_free (h);
217}
218
219
220/******************************************************************************/
221
222
223/**
224 * Struct to keep state of running searches that have consumed a part of
225 * the inital string.
226 */
227struct RegexSearchContext
228{
229 /**
230 * Part of the description already consumed by
231 * this particular search branch.
232 */
233 size_t position;
234
235 /**
236 * Information about the search.
237 */
238 struct GNUNET_REGEX_search_handle *info;
239
240 /**
241 * We just want to look for one edge, the longer the better.
242 * Keep its length.
243 */
244 unsigned int longest_match;
245
246 /**
247 * Destination hash of the longest match.
248 */
249 struct GNUNET_HashCode hash;
250};
251
252
253/**
254 * Struct to keep information of searches of services described by a regex
255 * using a user-provided string service description.
256 */
257struct GNUNET_REGEX_search_handle
258{
259 /**
260 * DHT handle to use, must be initialized externally.
261 */
262 struct GNUNET_DHT_Handle *dht;
263
264 /**
265 * Optional statistics handle to report usage. Can be NULL.
266 */
267 struct GNUNET_STATISTICS_Handle *stats;
268
269 /**
270 * User provided description of the searched service.
271 */
272 char *description;
273
274 /**
275 * Running DHT GETs.
276 */
277 struct GNUNET_CONTAINER_MultiHashMap *dht_get_handles;
278
279 /**
280 * Results from running DHT GETs.
281 */
282 struct GNUNET_CONTAINER_MultiHashMap *dht_get_results;
283
284 /**
285 * Contexts, for each running DHT GET. Free all on end of search.
286 */
287 struct RegexSearchContext **contexts;
288
289 /**
290 * Number of contexts (branches/steps in search).
291 */
292 unsigned int n_contexts;
293
294 /**
295 * @param callback Callback for found peers.
296 */
297 GNUNET_REGEX_Found callback;
298
299 /**
300 * @param callback_cls Closure for @c callback.
301 */
302 void *callback_cls;
303};
304
305
306
307/**
308 * Jump to the next edge, with the longest matching token.
309 *
310 * @param block Block found in the DHT.
311 * @param size Size of the block.
312 * @param ctx Context of the search.
313 *
314 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
315 */
316static void
317regex_next_edge (const struct RegexBlock *block,
318 size_t size,
319 struct RegexSearchContext *ctx);
320
321
322/**
323 * Function to process DHT string to regex matching.
324 * Called on each result obtained for the DHT search.
325 *
326 * @param cls Closure (search context).
327 * @param exp When will this value expire.
328 * @param key Key of the result.
329 * @param get_path Path of the get request.
330 * @param get_path_length Lenght of get_path.
331 * @param put_path Path of the put request.
332 * @param put_path_length Length of the put_path.
333 * @param type Type of the result.
334 * @param size Number of bytes in data.
335 * @param data Pointer to the result data.
336 */
337static void
338dht_get_string_accept_handler (void *cls, struct GNUNET_TIME_Absolute exp,
339 const struct GNUNET_HashCode * key,
340 const struct GNUNET_PeerIdentity *get_path,
341 unsigned int get_path_length,
342 const struct GNUNET_PeerIdentity *put_path,
343 unsigned int put_path_length,
344 enum GNUNET_BLOCK_Type type,
345 size_t size, const void *data)
346{
347 const struct RegexAccept *block = data;
348 struct RegexSearchContext *ctx = cls;
349 struct GNUNET_REGEX_search_handle *info = ctx->info;
350
351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got regex results from DHT!\n");
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " for %s\n", info->description);
353
354 GNUNET_STATISTICS_update (info->stats, "# regex accepting blocks found",
355 1, GNUNET_NO);
356 GNUNET_STATISTICS_update (info->stats, "# regex accepting block bytes found",
357 size, GNUNET_NO);
358
359 info->callback (info->callback_cls,
360 &block->id,
361 get_path, get_path_length,
362 put_path, put_path_length);
363
364 return;
365}
366
367/**
368 * Find a path to a peer that offers a regex servcie compatible
369 * with a given string.
370 *
371 * @param key The key of the accepting state.
372 * @param ctx Context containing info about the string, tunnel, etc.
373 */
374static void
375regex_find_path (const struct GNUNET_HashCode *key,
376 struct RegexSearchContext *ctx)
377{
378 struct GNUNET_DHT_GetHandle *get_h;
379
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found peer by service\n");
381 get_h = GNUNET_DHT_get_start (ctx->info->dht, /* handle */
382 GNUNET_BLOCK_TYPE_REGEX_ACCEPT, /* type */
383 key, /* key to search */
384 DHT_REPLICATION, /* replication level */
385 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE |
386 GNUNET_DHT_RO_RECORD_ROUTE,
387 NULL, /* xquery */ // FIXME BLOOMFILTER
388 0, /* xquery bits */ // FIXME BLOOMFILTER SIZE
389 &dht_get_string_accept_handler, ctx);
390 GNUNET_break (GNUNET_OK ==
391 GNUNET_CONTAINER_multihashmap_put(ctx->info->dht_get_handles,
392 key,
393 get_h,
394 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
395}
396
397
398/**
399 * Function to process DHT string to regex matching.
400 * Called on each result obtained for the DHT search.
401 *
402 * @param cls closure (search context)
403 * @param exp when will this value expire
404 * @param key key of the result
405 * @param get_path path of the get request (not used)
406 * @param get_path_length lenght of get_path (not used)
407 * @param put_path path of the put request (not used)
408 * @param put_path_length length of the put_path (not used)
409 * @param type type of the result
410 * @param size number of bytes in data
411 * @param data pointer to the result data
412 *
413 * TODO: re-issue the request after certain time? cancel after X results?
414 */
415static void
416dht_get_string_handler (void *cls, struct GNUNET_TIME_Absolute exp,
417 const struct GNUNET_HashCode * key,
418 const struct GNUNET_PeerIdentity *get_path,
419 unsigned int get_path_length,
420 const struct GNUNET_PeerIdentity *put_path,
421 unsigned int put_path_length,
422 enum GNUNET_BLOCK_Type type,
423 size_t size, const void *data)
424{
425 const struct RegexBlock *block = data;
426 struct RegexSearchContext *ctx = cls;
427 struct GNUNET_REGEX_search_handle *info = ctx->info;
428 void *copy;
429 size_t len;
430
431 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
432 "DHT GET STRING RETURNED RESULTS\n");
433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
434 " key: %s\n", GNUNET_h2s (key));
435
436 copy = GNUNET_malloc (size);
437 memcpy (copy, data, size);
438 GNUNET_break (GNUNET_OK ==
439 GNUNET_CONTAINER_multihashmap_put(info->dht_get_results, key, copy,
440 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
441 len = ntohl (block->n_proof);
442 {
443 char proof[len + 1];
444
445 memcpy (proof, &block[1], len);
446 proof[len] = '\0';
447 if (GNUNET_OK != GNUNET_REGEX_check_proof (proof, key))
448 {
449 GNUNET_break_op (0);
450 return;
451 }
452 }
453 len = strlen (info->description);
454 if (len == ctx->position) // String processed
455 {
456 if (GNUNET_YES == ntohl (block->accepting))
457 {
458 regex_find_path(key, ctx);
459 }
460 else
461 {
462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " block not accepting!\n");
463 // FIXME REGEX this block not successful, wait for more? start timeout?
464 }
465 return;
466 }
467
468 regex_next_edge (block, size, ctx);
469
470 return;
471}
472
473
474/**
475 * Iterator over found existing mesh regex blocks that match an ongoing search.
476 *
477 * @param cls closure
478 * @param key current key code
479 * @param value value in the hash map
480 * @return GNUNET_YES if we should continue to iterate,
481 * GNUNET_NO if not.
482 */
483static int
484regex_result_iterator (void *cls,
485 const struct GNUNET_HashCode * key,
486 void *value)
487{
488 struct RegexBlock *block = value;
489 struct RegexSearchContext *ctx = cls;
490
491 if (GNUNET_YES == ntohl(block->accepting) &&
492 ctx->position == strlen (ctx->info->description))
493 {
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Found accepting known block\n");
495 regex_find_path (key, ctx);
496 return GNUNET_YES; // We found an accept state!
497 }
498 else
499 {
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* %u, %u, [%u]\n",
501 ctx->position, strlen(ctx->info->description),
502 ntohl(block->accepting));
503
504 }
505 regex_next_edge(block, SIZE_MAX, ctx);
506
507 GNUNET_STATISTICS_update (ctx->info->stats, "# regex mesh blocks iterated",
508 1, GNUNET_NO);
509
510 return GNUNET_YES;
511}
512
513
514/**
515 * Iterator over edges in a regex block retrieved from the DHT.
516 *
517 * @param cls Closure (context of the search).
518 * @param token Token that follows to next state.
519 * @param len Lenght of token.
520 * @param key Hash of next state.
521 *
522 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
523 */
524static int
525regex_edge_iterator (void *cls,
526 const char *token,
527 size_t len,
528 const struct GNUNET_HashCode *key)
529{
530 struct RegexSearchContext *ctx = cls;
531 struct GNUNET_REGEX_search_handle *info = ctx->info;
532 const char *current;
533 size_t current_len;
534
535 GNUNET_STATISTICS_update (info->stats, "# regex edges iterated",
536 1, GNUNET_NO);
537
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Start of regex edge iterator\n");
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* descr : %s\n", info->description);
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* posit : %u\n", ctx->position);
541 current = &info->description[ctx->position];
542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* currt : %s\n", current);
543 current_len = strlen (info->description) - ctx->position;
544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* ctlen : %u\n", current_len);
545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* tklen : %u\n", len);
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* token : %.*s\n", len, token);
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* nextk : %s\n", GNUNET_h2s(key));
548 if (len > current_len)
549 {
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token too long, END\n");
551 return GNUNET_YES; // Token too long, wont match
552 }
553 if (0 != strncmp (current, token, len))
554 {
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token doesn't match, END\n");
556 return GNUNET_YES; // Token doesn't match
557 }
558
559 if (len > ctx->longest_match)
560 {
561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is longer, KEEP\n");
562 ctx->longest_match = len;
563 ctx->hash = *key;
564 }
565 else
566 {
567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* Token is not longer, IGNORE\n");
568 }
569
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* End of regex edge iterator\n");
571 return GNUNET_YES;
572}
573
574
575/**
576 * Jump to the next edge, with the longest matching token.
577 *
578 * @param block Block found in the DHT.
579 * @param size Size of the block.
580 * @param ctx Context of the search.
581 *
582 * @return GNUNET_YES if should keep iterating, GNUNET_NO otherwise.
583 */
584static void
585regex_next_edge (const struct RegexBlock *block,
586 size_t size,
587 struct RegexSearchContext *ctx)
588{
589 struct RegexSearchContext *new_ctx;
590 struct GNUNET_REGEX_search_handle *info = ctx->info;
591 struct GNUNET_DHT_GetHandle *get_h;
592 const char *rest;
593 int result;
594
595 /* Find the longest match for the current string position,
596 * among tokens in the given block */
597 ctx->longest_match = 0;
598 result = GNUNET_REGEX_block_iterate (block, size,
599 &regex_edge_iterator, ctx);
600 GNUNET_break (GNUNET_OK == result);
601
602 /* Did anything match? */
603 if (0 == ctx->longest_match)
604 return;
605
606 new_ctx = GNUNET_malloc (sizeof (struct RegexSearchContext));
607 new_ctx->info = info;
608 new_ctx->position = ctx->position + ctx->longest_match;
609 GNUNET_array_append (info->contexts, info->n_contexts, new_ctx);
610
611 /* Check whether we already have a DHT GET running for it */
612 if (GNUNET_YES ==
613 GNUNET_CONTAINER_multihashmap_contains(info->dht_get_handles, &ctx->hash))
614 {
615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "* GET running, END\n");
616 GNUNET_CONTAINER_multihashmap_get_multiple (info->dht_get_results,
617 &ctx->hash,
618 &regex_result_iterator,
619 new_ctx);
620 // FIXME: "leaks" new_ctx? avoid keeping it around?
621 return; // We are already looking for it
622 }
623
624 GNUNET_STATISTICS_update (info->stats, "# regex nodes traversed",
625 1, GNUNET_NO);
626
627 /* Start search in DHT */
628 rest = &new_ctx->info->description[new_ctx->position];
629 get_h =
630 GNUNET_DHT_get_start (info->dht, /* handle */
631 GNUNET_BLOCK_TYPE_REGEX, /* type */
632 &ctx->hash, /* key to search */
633 DHT_REPLICATION, /* replication level */
634 GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
635 rest, /* xquery */
636 // FIXME add BLOOMFILTER to exclude filtered peers
637 strlen(rest) + 1, /* xquery bits */
638 // FIXME add BLOOMFILTER SIZE
639 &dht_get_string_handler, new_ctx);
640 if (GNUNET_OK !=
641 GNUNET_CONTAINER_multihashmap_put(info->dht_get_handles,
642 &ctx->hash,
643 get_h,
644 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
645 {
646 GNUNET_break (0);
647 return;
648 }
649}
650
651
652struct GNUNET_REGEX_search_handle *
653GNUNET_REGEX_search (struct GNUNET_DHT_Handle *dht,
654 const char *string,
655 GNUNET_REGEX_Found callback,
656 void *callback_cls,
657 struct GNUNET_STATISTICS_Handle *stats)
658{
659 struct GNUNET_REGEX_search_handle *h;
660
661 GNUNET_assert (NULL == dht);
662 h = GNUNET_malloc (sizeof (struct GNUNET_REGEX_search_handle));
663 h->dht = dht;
664 h->description = GNUNET_strdup (string);
665 h->callback = callback;
666 h->callback_cls = callback_cls;
667 h->stats = stats;
668
669 h->dht_get_handles = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
670 h->dht_get_results = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
671 return h;
672}
673
674
675/**
676 * Iterator over hash map entries to cancel DHT GET requests after a
677 * successful connect_by_string.
678 *
679 * @param cls Closure (unused).
680 * @param key Current key code (unused).
681 * @param value Value in the hash map (get handle).
682 * @return GNUNET_YES if we should continue to iterate,
683 * GNUNET_NO if not.
684 */
685static int
686regex_cancel_dht_get (void *cls,
687 const struct GNUNET_HashCode * key,
688 void *value)
689{
690 struct GNUNET_DHT_GetHandle *h = value;
691
692 GNUNET_DHT_get_stop (h);
693 return GNUNET_YES;
694}
695
696
697/**
698 * Iterator over hash map entries to free MeshRegexBlocks stored during the
699 * search for connect_by_string.
700 *
701 * @param cls Closure (unused).
702 * @param key Current key code (unused).
703 * @param value MeshRegexBlock in the hash map.
704 * @return GNUNET_YES if we should continue to iterate,
705 * GNUNET_NO if not.
706 */
707static int
708regex_free_result (void *cls,
709 const struct GNUNET_HashCode * key,
710 void *value)
711{
712
713 GNUNET_free (value);
714 return GNUNET_YES;
715}
716
717
718/**
719 * Cancel an ongoing regex search in the DHT and free all resources.
720 *
721 * @param ctx The search context.
722 */
723static void
724regex_cancel_search (struct GNUNET_REGEX_search_handle *ctx)
725{
726 GNUNET_free (ctx->description);
727 GNUNET_CONTAINER_multihashmap_iterate (ctx->dht_get_handles,
728 &regex_cancel_dht_get, NULL);
729 GNUNET_CONTAINER_multihashmap_iterate (ctx->dht_get_results,
730 &regex_free_result, NULL);
731 GNUNET_CONTAINER_multihashmap_destroy (ctx->dht_get_results);
732 GNUNET_CONTAINER_multihashmap_destroy (ctx->dht_get_handles);
733 if (0 < ctx->n_contexts)
734 {
735 int i;
736
737 for (i = 0; i < ctx->n_contexts; i++)
738 {
739 GNUNET_free (ctx->contexts[i]);
740 }
741 GNUNET_free (ctx->contexts);
742 }
743}
744
745void
746GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_search_handle *h)
747{
748 regex_cancel_search (h);
749 GNUNET_free (h);
750}
751
752
753
754/* end of regex_dht.c */ \ No newline at end of file