aboutsummaryrefslogtreecommitdiff
path: root/src/service/regex/gnunet-service-regex.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/regex/gnunet-service-regex.c')
-rw-r--r--src/service/regex/gnunet-service-regex.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/src/service/regex/gnunet-service-regex.c b/src/service/regex/gnunet-service-regex.c
new file mode 100644
index 000000000..c25ef9eda
--- /dev/null
+++ b/src/service/regex/gnunet-service-regex.c
@@ -0,0 +1,408 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file regex/gnunet-service-regex.c
23 * @brief service to advertise capabilities described as regex and to
24 * lookup capabilities by regex
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "regex_internal_lib.h"
30#include "regex_ipc.h"
31
32
33/**
34 * Information about one of our clients.
35 */
36struct ClientEntry
37{
38 /**
39 * Queue for transmissions to @e client.
40 */
41 struct GNUNET_MQ_Handle *mq;
42
43 /**
44 * Handle identifying the client.
45 */
46 struct GNUNET_SERVICE_Client *client;
47
48 /**
49 * Search handle (if this client is searching).
50 */
51 struct REGEX_INTERNAL_Search *sh;
52
53 /**
54 * Announcement handle (if this client is announcing).
55 */
56 struct REGEX_INTERNAL_Announcement *ah;
57
58 /**
59 * Refresh frequency for announcements.
60 */
61 struct GNUNET_TIME_Relative frequency;
62
63 /**
64 * Task for re-announcing.
65 */
66 struct GNUNET_SCHEDULER_Task *refresh_task;
67};
68
69
70/**
71 * Connection to the DHT.
72 */
73static struct GNUNET_DHT_Handle *dht;
74
75/**
76 * Handle for doing statistics.
77 */
78static struct GNUNET_STATISTICS_Handle *stats;
79
80/**
81 * Private key for this peer.
82 */
83static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
84
85
86/**
87 * Task run during shutdown.
88 *
89 * @param cls unused
90 */
91static void
92cleanup_task (void *cls)
93{
94 GNUNET_DHT_disconnect (dht);
95 dht = NULL;
96 GNUNET_STATISTICS_destroy (stats,
97 GNUNET_NO);
98 stats = NULL;
99 GNUNET_free (my_private_key);
100 my_private_key = NULL;
101}
102
103
104/**
105 * Periodic task to refresh our announcement of the regex.
106 *
107 * @param cls the `struct ClientEntry *` of the client that triggered the
108 * announcement
109 */
110static void
111reannounce (void *cls)
112{
113 struct ClientEntry *ce = cls;
114
115 REGEX_INTERNAL_reannounce (ce->ah);
116 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
117 &reannounce,
118 ce);
119}
120
121
122/**
123 * Check ANNOUNCE message.
124 *
125 * @param cls identification of the client
126 * @param am the actual message
127 * @return #GNUNET_OK if @a am is well-formed
128 */
129static int
130check_announce (void *cls,
131 const struct AnnounceMessage *am)
132{
133 struct ClientEntry *ce = cls;
134
135 GNUNET_MQ_check_zero_termination (am);
136 if (NULL != ce->ah)
137 {
138 /* only one announcement per client allowed */
139 GNUNET_break (0);
140 return GNUNET_SYSERR;
141 }
142 return GNUNET_OK;
143}
144
145
146/**
147 * Handle ANNOUNCE message.
148 *
149 * @param cls identification of the client
150 * @param am the actual message
151 */
152static void
153handle_announce (void *cls,
154 const struct AnnounceMessage *am)
155{
156 struct ClientEntry *ce = cls;
157 const char *regex;
158
159 regex = (const char *) &am[1];
160 ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay);
161 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
162 &reannounce,
163 ce);
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Starting to announce regex `%s' every %s\n",
166 regex,
167 GNUNET_STRINGS_relative_time_to_string (ce->frequency,
168 GNUNET_NO));
169 ce->ah = REGEX_INTERNAL_announce (dht,
170 my_private_key,
171 regex,
172 ntohs (am->compression),
173 stats);
174 if (NULL == ce->ah)
175 {
176 GNUNET_break (0);
177 GNUNET_SCHEDULER_cancel (ce->refresh_task);
178 ce->refresh_task = NULL;
179 GNUNET_SERVICE_client_drop (ce->client);
180 return;
181 }
182 GNUNET_SERVICE_client_continue (ce->client);
183}
184
185
186/**
187 * Handle result, pass it back to the client.
188 *
189 * @param cls the struct ClientEntry of the client searching
190 * @param id Peer providing a regex that matches the string.
191 * @param get_path Path of the get request.
192 * @param get_path_length Length of @a get_path.
193 * @param put_path Path of the put request.
194 * @param put_path_length Length of the @a put_path.
195 */
196static void
197handle_search_result (void *cls,
198 const struct GNUNET_PeerIdentity *id,
199 const struct GNUNET_DHT_PathElement *get_path,
200 unsigned int get_path_length,
201 const struct GNUNET_DHT_PathElement *put_path,
202 unsigned int put_path_length)
203{
204 struct ClientEntry *ce = cls;
205 struct GNUNET_MQ_Envelope *env;
206 struct ResultMessage *result;
207 struct GNUNET_PeerIdentity *gp;
208 uint16_t size;
209
210 if ((get_path_length >= 65536) ||
211 (put_path_length >= 65536) ||
212 ( ((get_path_length + put_path_length)
213 * sizeof(struct GNUNET_PeerIdentity))
214 + sizeof(struct ResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) )
215 {
216 GNUNET_break (0);
217 return;
218 }
219 size = (get_path_length + put_path_length)
220 * sizeof(struct GNUNET_PeerIdentity);
221 env = GNUNET_MQ_msg_extra (result,
222 size,
223 GNUNET_MESSAGE_TYPE_REGEX_RESULT);
224 result->get_path_length = htons ((uint16_t) get_path_length);
225 result->put_path_length = htons ((uint16_t) put_path_length);
226 result->id = *id;
227 gp = &result->id;
228 for (unsigned int i = 0; i<get_path_length; i++)
229 gp[i + 1] = get_path[i].pred;
230 for (unsigned int i = 0; i<put_path_length; i++)
231 gp[i + get_path_length + 1] = put_path[i].pred;
232 GNUNET_MQ_send (ce->mq,
233 env);
234}
235
236
237/**
238 * Check SEARCH message.
239 *
240 * @param cls identification of the client
241 * @param sm the actual message
242 */
243static int
244check_search (void *cls,
245 const struct RegexSearchMessage *sm)
246{
247 struct ClientEntry *ce = cls;
248 const char *string;
249 uint16_t size;
250
251 size = ntohs (sm->header.size) - sizeof(*sm);
252 string = (const char *) &sm[1];
253 if ('\0' != string[size - 1])
254 {
255 GNUNET_break (0);
256 return GNUNET_SYSERR;
257 }
258 if (NULL != ce->sh)
259 {
260 /* only one search allowed per client */
261 GNUNET_break (0);
262 return GNUNET_SYSERR;
263 }
264 return GNUNET_OK;
265}
266
267
268/**
269 * Handle SEARCH message.
270 *
271 * @param cls identification of the client
272 * @param sm the actual message
273 */
274static void
275handle_search (void *cls,
276 const struct RegexSearchMessage *sm)
277{
278 struct ClientEntry *ce = cls;
279 const char *string;
280
281 string = (const char *) &sm[1];
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Starting to search for `%s'\n",
284 string);
285 ce->sh = REGEX_INTERNAL_search (dht,
286 string,
287 &handle_search_result,
288 ce,
289 stats);
290 if (NULL == ce->sh)
291 {
292 GNUNET_break (0);
293 GNUNET_SERVICE_client_drop (ce->client);
294 return;
295 }
296 GNUNET_SERVICE_client_continue (ce->client);
297}
298
299
300/**
301 * Process regex requests.
302 *
303 * @param cls closure
304 * @param cfg configuration to use
305 * @param service the initialized service
306 */
307static void
308run (void *cls,
309 const struct GNUNET_CONFIGURATION_Handle *cfg,
310 struct GNUNET_SERVICE_Handle *service)
311{
312 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
313 if (NULL == my_private_key)
314 {
315 GNUNET_SCHEDULER_shutdown ();
316 return;
317 }
318 dht = GNUNET_DHT_connect (cfg, 1024);
319 if (NULL == dht)
320 {
321 GNUNET_free (my_private_key);
322 my_private_key = NULL;
323 GNUNET_SCHEDULER_shutdown ();
324 return;
325 }
326 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
327 NULL);
328 stats = GNUNET_STATISTICS_create ("regex", cfg);
329}
330
331
332/**
333 * Callback called when a client connects to the service.
334 *
335 * @param cls closure for the service
336 * @param c the new client that connected to the service
337 * @param mq the message queue used to send messages to the client
338 * @return @a c
339 */
340static void *
341client_connect_cb (void *cls,
342 struct GNUNET_SERVICE_Client *c,
343 struct GNUNET_MQ_Handle *mq)
344{
345 struct ClientEntry *ce;
346
347 ce = GNUNET_new (struct ClientEntry);
348 ce->client = c;
349 ce->mq = mq;
350 return ce;
351}
352
353
354/**
355 * Callback called when a client disconnected from the service
356 *
357 * @param cls closure for the service
358 * @param c the client that disconnected
359 * @param internal_cls should be equal to @a c
360 */
361static void
362client_disconnect_cb (void *cls,
363 struct GNUNET_SERVICE_Client *c,
364 void *internal_cls)
365{
366 struct ClientEntry *ce = internal_cls;
367
368 if (NULL != ce->refresh_task)
369 {
370 GNUNET_SCHEDULER_cancel (ce->refresh_task);
371 ce->refresh_task = NULL;
372 }
373 if (NULL != ce->ah)
374 {
375 REGEX_INTERNAL_announce_cancel (ce->ah);
376 ce->ah = NULL;
377 }
378 if (NULL != ce->sh)
379 {
380 REGEX_INTERNAL_search_cancel (ce->sh);
381 ce->sh = NULL;
382 }
383 GNUNET_free (ce);
384}
385
386
387/**
388 * Define "main" method using service macro.
389 */
390GNUNET_SERVICE_MAIN
391 ("regex",
392 GNUNET_SERVICE_OPTION_NONE,
393 &run,
394 &client_connect_cb,
395 &client_disconnect_cb,
396 NULL,
397 GNUNET_MQ_hd_var_size (announce,
398 GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE,
399 struct AnnounceMessage,
400 NULL),
401 GNUNET_MQ_hd_var_size (search,
402 GNUNET_MESSAGE_TYPE_REGEX_SEARCH,
403 struct RegexSearchMessage,
404 NULL),
405 GNUNET_MQ_handler_end ());
406
407
408/* end of gnunet-service-regex.c */