2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
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.
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.
17 * @file regex/gnunet-service-regex.c
18 * @brief service to advertise capabilities described as regex and to
19 * lookup capabilities by regex
20 * @author Christian Grothoff
23 #include "gnunet_util_lib.h"
24 #include "regex_internal_lib.h"
25 #include "regex_ipc.h"
29 * Information about one of our clients.
35 * Queue for transmissions to @e client.
37 struct GNUNET_MQ_Handle *mq;
40 * Handle identifying the client.
42 struct GNUNET_SERVICE_Client *client;
45 * Search handle (if this client is searching).
47 struct REGEX_INTERNAL_Search *sh;
50 * Announcement handle (if this client is announcing).
52 struct REGEX_INTERNAL_Announcement *ah;
55 * Refresh frequency for announcements.
57 struct GNUNET_TIME_Relative frequency;
60 * Task for re-announcing.
62 struct GNUNET_SCHEDULER_Task *refresh_task;
68 * Connection to the DHT.
70 static struct GNUNET_DHT_Handle *dht;
73 * Handle for doing statistics.
75 static struct GNUNET_STATISTICS_Handle *stats;
78 * Private key for this peer.
80 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
84 * Task run during shutdown.
89 cleanup_task (void *cls)
91 GNUNET_DHT_disconnect (dht);
93 GNUNET_STATISTICS_destroy (stats,
96 GNUNET_free (my_private_key);
97 my_private_key = NULL;
102 * Periodic task to refresh our announcement of the regex.
104 * @param cls the `struct ClientEntry *` of the client that triggered the
108 reannounce (void *cls)
110 struct ClientEntry *ce = cls;
112 REGEX_INTERNAL_reannounce (ce->ah);
113 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
120 * Check ANNOUNCE message.
122 * @param cls identification of the client
123 * @param am the actual message
124 * @return #GNUNET_OK if @am is well-formed
127 check_announce (void *cls,
128 const struct AnnounceMessage *am)
130 struct ClientEntry *ce = cls;
134 size = ntohs (am->header.size) - sizeof (*am);
135 regex = (const char *) &am[1];
136 if ('\0' != regex[size - 1])
139 return GNUNET_SYSERR;
143 /* only one announcement per client allowed */
145 return GNUNET_SYSERR;
152 * Handle ANNOUNCE message.
154 * @param cls identification of the client
155 * @param am the actual message
158 handle_announce (void *cls,
159 const struct AnnounceMessage *am)
161 struct ClientEntry *ce = cls;
164 regex = (const char *) &am[1];
165 ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay);
166 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
170 "Starting to announce regex `%s' every %s\n",
172 GNUNET_STRINGS_relative_time_to_string (ce->frequency,
174 ce->ah = REGEX_INTERNAL_announce (dht,
177 ntohs (am->compression),
182 GNUNET_SCHEDULER_cancel (ce->refresh_task);
183 ce->refresh_task = NULL;
184 GNUNET_SERVICE_client_drop (ce->client);
187 GNUNET_SERVICE_client_continue (ce->client);
192 * Handle result, pass it back to the client.
194 * @param cls the struct ClientEntry of the client searching
195 * @param id Peer providing a regex that matches the string.
196 * @param get_path Path of the get request.
197 * @param get_path_length Lenght of @a get_path.
198 * @param put_path Path of the put request.
199 * @param put_path_length Length of the @a put_path.
202 handle_search_result (void *cls,
203 const struct GNUNET_PeerIdentity *id,
204 const struct GNUNET_PeerIdentity *get_path,
205 unsigned int get_path_length,
206 const struct GNUNET_PeerIdentity *put_path,
207 unsigned int put_path_length)
209 struct ClientEntry *ce = cls;
210 struct GNUNET_MQ_Envelope *env;
211 struct ResultMessage *result;
212 struct GNUNET_PeerIdentity *gp;
215 if ( (get_path_length >= 65536) ||
216 (put_path_length >= 65536) ||
217 ( (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity))
218 + sizeof (struct ResultMessage) >= GNUNET_MAX_MESSAGE_SIZE)
223 size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
224 env = GNUNET_MQ_msg_extra (result,
226 GNUNET_MESSAGE_TYPE_REGEX_RESULT);
227 result->get_path_length = htons ((uint16_t) get_path_length);
228 result->put_path_length = htons ((uint16_t) put_path_length);
231 GNUNET_memcpy (&gp[1],
233 get_path_length * sizeof (struct GNUNET_PeerIdentity));
234 GNUNET_memcpy (&gp[1 + get_path_length],
236 put_path_length * sizeof (struct GNUNET_PeerIdentity));
237 GNUNET_MQ_send (ce->mq,
243 * Check SEARCH message.
245 * @param cls identification of the client
246 * @param message the actual message
249 check_search (void *cls,
250 const struct RegexSearchMessage *sm)
252 struct ClientEntry *ce = cls;
256 size = ntohs (sm->header.size) - sizeof (*sm);
257 string = (const char *) &sm[1];
258 if ('\0' != string[size - 1])
261 return GNUNET_SYSERR;
265 /* only one search allowed per client */
267 return GNUNET_SYSERR;
274 * Handle SEARCH message.
276 * @param cls identification of the client
277 * @param message the actual message
280 handle_search (void *cls,
281 const struct RegexSearchMessage *sm)
283 struct ClientEntry *ce = cls;
286 string = (const char *) &sm[1];
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288 "Starting to search for `%s'\n",
290 ce->sh = REGEX_INTERNAL_search (dht,
292 &handle_search_result,
298 GNUNET_SERVICE_client_drop (ce->client);
301 GNUNET_SERVICE_client_continue (ce->client);
306 * Process regex requests.
309 * @param cfg configuration to use
310 * @param service the initialized service
314 const struct GNUNET_CONFIGURATION_Handle *cfg,
315 struct GNUNET_SERVICE_Handle *service)
317 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
318 if (NULL == my_private_key)
320 GNUNET_SCHEDULER_shutdown ();
323 dht = GNUNET_DHT_connect (cfg, 1024);
326 GNUNET_free (my_private_key);
327 my_private_key = NULL;
328 GNUNET_SCHEDULER_shutdown ();
331 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
333 stats = GNUNET_STATISTICS_create ("regex", cfg);
338 * Callback called when a client connects to the service.
340 * @param cls closure for the service
341 * @param c the new client that connected to the service
342 * @param mq the message queue used to send messages to the client
346 client_connect_cb (void *cls,
347 struct GNUNET_SERVICE_Client *c,
348 struct GNUNET_MQ_Handle *mq)
350 struct ClientEntry *ce;
352 ce = GNUNET_new (struct ClientEntry);
360 * Callback called when a client disconnected from the service
362 * @param cls closure for the service
363 * @param c the client that disconnected
364 * @param internal_cls should be equal to @a c
367 client_disconnect_cb (void *cls,
368 struct GNUNET_SERVICE_Client *c,
371 struct ClientEntry *ce = internal_cls;
373 if (NULL != ce->refresh_task)
375 GNUNET_SCHEDULER_cancel (ce->refresh_task);
376 ce->refresh_task = NULL;
380 REGEX_INTERNAL_announce_cancel (ce->ah);
385 REGEX_INTERNAL_search_cancel (ce->sh);
393 * Define "main" method using service macro.
397 GNUNET_SERVICE_OPTION_NONE,
400 &client_disconnect_cb,
402 GNUNET_MQ_hd_var_size (announce,
403 GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE,
404 struct AnnounceMessage,
406 GNUNET_MQ_hd_var_size (search,
407 GNUNET_MESSAGE_TYPE_REGEX_SEARCH,
408 struct RegexSearchMessage,
410 GNUNET_MQ_handler_end ());
413 /* end of gnunet-service-regex.c */