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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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
28 #include "gnunet_util_lib.h"
29 #include "regex_internal_lib.h"
30 #include "regex_ipc.h"
34 * Information about one of our clients.
39 * Queue for transmissions to @e client.
41 struct GNUNET_MQ_Handle *mq;
44 * Handle identifying the client.
46 struct GNUNET_SERVICE_Client *client;
49 * Search handle (if this client is searching).
51 struct REGEX_INTERNAL_Search *sh;
54 * Announcement handle (if this client is announcing).
56 struct REGEX_INTERNAL_Announcement *ah;
59 * Refresh frequency for announcements.
61 struct GNUNET_TIME_Relative frequency;
64 * Task for re-announcing.
66 struct GNUNET_SCHEDULER_Task *refresh_task;
71 * Connection to the DHT.
73 static struct GNUNET_DHT_Handle *dht;
76 * Handle for doing statistics.
78 static struct GNUNET_STATISTICS_Handle *stats;
81 * Private key for this peer.
83 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
87 * Task run during shutdown.
92 cleanup_task (void *cls)
94 GNUNET_DHT_disconnect (dht);
96 GNUNET_STATISTICS_destroy (stats,
99 GNUNET_free (my_private_key);
100 my_private_key = NULL;
105 * Periodic task to refresh our announcement of the regex.
107 * @param cls the `struct ClientEntry *` of the client that triggered the
111 reannounce (void *cls)
113 struct ClientEntry *ce = cls;
115 REGEX_INTERNAL_reannounce (ce->ah);
116 ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
123 * Check ANNOUNCE message.
125 * @param cls identification of the client
126 * @param am the actual message
127 * @return #GNUNET_OK if @am is well-formed
130 check_announce (void *cls,
131 const struct AnnounceMessage *am)
133 struct ClientEntry *ce = cls;
135 GNUNET_MQ_check_zero_termination (am);
138 /* only one announcement per client allowed */
140 return GNUNET_SYSERR;
147 * Handle ANNOUNCE message.
149 * @param cls identification of the client
150 * @param am the actual message
153 handle_announce (void *cls,
154 const struct AnnounceMessage *am)
156 struct ClientEntry *ce = cls;
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,
164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
165 "Starting to announce regex `%s' every %s\n",
167 GNUNET_STRINGS_relative_time_to_string (ce->frequency,
169 ce->ah = REGEX_INTERNAL_announce (dht,
172 ntohs (am->compression),
177 GNUNET_SCHEDULER_cancel (ce->refresh_task);
178 ce->refresh_task = NULL;
179 GNUNET_SERVICE_client_drop (ce->client);
182 GNUNET_SERVICE_client_continue (ce->client);
187 * Handle result, pass it back to the client.
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 Lenght of @a get_path.
193 * @param put_path Path of the put request.
194 * @param put_path_length Length of the @a put_path.
197 handle_search_result (void *cls,
198 const struct GNUNET_PeerIdentity *id,
199 const struct GNUNET_PeerIdentity *get_path,
200 unsigned int get_path_length,
201 const struct GNUNET_PeerIdentity *put_path,
202 unsigned int put_path_length)
204 struct ClientEntry *ce = cls;
205 struct GNUNET_MQ_Envelope *env;
206 struct ResultMessage *result;
207 struct GNUNET_PeerIdentity *gp;
210 if ((get_path_length >= 65536) ||
211 (put_path_length >= 65536) ||
212 ( ((get_path_length + put_path_length) * sizeof(struct
213 GNUNET_PeerIdentity))
214 + sizeof(struct ResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) )
219 size = (get_path_length + put_path_length) * sizeof(struct
220 GNUNET_PeerIdentity);
221 env = GNUNET_MQ_msg_extra (result,
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);
228 GNUNET_memcpy (&gp[1],
230 get_path_length * sizeof(struct GNUNET_PeerIdentity));
231 GNUNET_memcpy (&gp[1 + get_path_length],
233 put_path_length * sizeof(struct GNUNET_PeerIdentity));
234 GNUNET_MQ_send (ce->mq,
240 * Check SEARCH message.
242 * @param cls identification of the client
243 * @param message the actual message
246 check_search (void *cls,
247 const struct RegexSearchMessage *sm)
249 struct ClientEntry *ce = cls;
253 size = ntohs (sm->header.size) - sizeof(*sm);
254 string = (const char *) &sm[1];
255 if ('\0' != string[size - 1])
258 return GNUNET_SYSERR;
262 /* only one search allowed per client */
264 return GNUNET_SYSERR;
271 * Handle SEARCH message.
273 * @param cls identification of the client
274 * @param message the actual message
277 handle_search (void *cls,
278 const struct RegexSearchMessage *sm)
280 struct ClientEntry *ce = cls;
283 string = (const char *) &sm[1];
284 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
285 "Starting to search for `%s'\n",
287 ce->sh = REGEX_INTERNAL_search (dht,
289 &handle_search_result,
295 GNUNET_SERVICE_client_drop (ce->client);
298 GNUNET_SERVICE_client_continue (ce->client);
303 * Process regex requests.
306 * @param cfg configuration to use
307 * @param service the initialized service
311 const struct GNUNET_CONFIGURATION_Handle *cfg,
312 struct GNUNET_SERVICE_Handle *service)
314 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
315 if (NULL == my_private_key)
317 GNUNET_SCHEDULER_shutdown ();
320 dht = GNUNET_DHT_connect (cfg, 1024);
323 GNUNET_free (my_private_key);
324 my_private_key = NULL;
325 GNUNET_SCHEDULER_shutdown ();
328 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
330 stats = GNUNET_STATISTICS_create ("regex", cfg);
335 * Callback called when a client connects to the service.
337 * @param cls closure for the service
338 * @param c the new client that connected to the service
339 * @param mq the message queue used to send messages to the client
343 client_connect_cb (void *cls,
344 struct GNUNET_SERVICE_Client *c,
345 struct GNUNET_MQ_Handle *mq)
347 struct ClientEntry *ce;
349 ce = GNUNET_new (struct ClientEntry);
357 * Callback called when a client disconnected from the service
359 * @param cls closure for the service
360 * @param c the client that disconnected
361 * @param internal_cls should be equal to @a c
364 client_disconnect_cb (void *cls,
365 struct GNUNET_SERVICE_Client *c,
368 struct ClientEntry *ce = internal_cls;
370 if (NULL != ce->refresh_task)
372 GNUNET_SCHEDULER_cancel (ce->refresh_task);
373 ce->refresh_task = NULL;
377 REGEX_INTERNAL_announce_cancel (ce->ah);
382 REGEX_INTERNAL_search_cancel (ce->sh);
390 * Define "main" method using service macro.
394 GNUNET_SERVICE_OPTION_NONE,
397 &client_disconnect_cb,
399 GNUNET_MQ_hd_var_size (announce,
400 GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE,
401 struct AnnounceMessage,
403 GNUNET_MQ_hd_var_size (search,
404 GNUNET_MESSAGE_TYPE_REGEX_SEARCH,
405 struct RegexSearchMessage,
407 GNUNET_MQ_handler_end ());
410 /* end of gnunet-service-regex.c */