-improve UDP logging
[oweals/gnunet.git] / src / regex / regex_api.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2012, 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  * @file regex/regex_api.c
22  * @brief access regex service to advertise capabilities via regex and discover
23  *        respective peers using matching strings
24  * @author Maximilian Szengel
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_regex_service.h"
31 #include "regex_ipc.h"
32
33 /**
34  * Handle to store cached data about a regex announce.
35  */
36 struct GNUNET_REGEX_Announcement
37 {
38   /**
39    * Connection to the regex service.
40    */
41   struct GNUNET_CLIENT_Connection *client;
42
43   /**
44    * Our configuration.
45    */
46   const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48   /**
49    * Message we're sending to the service.
50    */
51   struct AnnounceMessage msg;
52 };
53
54
55 /**
56  * We got a response (!?) or disconnect after asking regex
57  * to do the announcement.  Retry.
58  *
59  * @param cls the 'struct GNUNET_REGEX_Announcement' to retry
60  * @param msg NULL on disconnect
61  */
62 static void
63 handle_a_reconnect (void *cls,
64                     const struct GNUNET_MessageHeader *msg);
65
66
67 /**
68  * Try sending the announcement request to regex.  On
69  * errors (i.e. regex died), try again.
70  *
71  * @param a the announcement to retry
72  */
73 static void
74 retry_announcement (struct GNUNET_REGEX_Announcement *a)
75 {
76   GNUNET_assert (NULL != a->client);
77   GNUNET_assert (GNUNET_OK ==
78                  GNUNET_CLIENT_transmit_and_get_response (a->client,
79                                                           &a->msg.header,
80                                                           GNUNET_TIME_UNIT_FOREVER_REL,
81                                                           GNUNET_YES,
82                                                           &handle_a_reconnect,
83                                                           a));
84 }
85
86
87 /**
88  * We got a response (!?) or disconnect after asking regex
89  * to do the announcement.  Retry.
90  *
91  * @param cls the 'struct GNUNET_REGEX_Announcement' to retry
92  * @param msg NULL on disconnect
93  */
94 static void
95 handle_a_reconnect (void *cls,
96                     const struct GNUNET_MessageHeader *msg)
97 {
98   struct GNUNET_REGEX_Announcement *a = cls;
99
100   GNUNET_CLIENT_disconnect (a->client);
101   a->client = GNUNET_CLIENT_connect ("regex", a->cfg);
102   retry_announcement (a);
103 }
104
105
106 /**
107  * Announce the given peer under the given regular expression.  Does
108  * not free resources, must call #GNUNET_REGEX_announce_cancel for
109  * that.
110  *
111  * @param cfg configuration to use
112  * @param regex Regular expression to announce.
113  * @param refresh_delay after what delay should the announcement be repeated?
114  * @param compression How many characters per edge can we squeeze?
115  * @return Handle to reuse o free cached resources.
116  *         Must be freed by calling #GNUNET_REGEX_announce_cancel.
117  */
118 struct GNUNET_REGEX_Announcement *
119 GNUNET_REGEX_announce (const struct GNUNET_CONFIGURATION_Handle *cfg,
120                        const char *regex,
121                        struct GNUNET_TIME_Relative refresh_delay,
122                        uint16_t compression)
123 {
124   struct GNUNET_REGEX_Announcement *a;
125   size_t slen;
126
127   slen = strlen (regex) + 1;
128   if (slen + sizeof (struct AnnounceMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
129   {
130     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
131                 _("Regex `%s' is too long!\n"),
132                 regex);
133     GNUNET_break (0);
134     return NULL;
135   }
136   a = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Announcement) + slen);
137   a->cfg = cfg;
138   a->client = GNUNET_CLIENT_connect ("regex", cfg);
139   if (NULL == a->client)
140   {
141     GNUNET_free (a);
142     return NULL;
143   }
144   a->msg.header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE);
145   a->msg.header.size = htons (slen + sizeof (struct AnnounceMessage));
146   a->msg.compression = htons (compression);
147   a->msg.reserved = htons (0);
148   a->msg.refresh_delay = GNUNET_TIME_relative_hton (refresh_delay);
149   memcpy (&a[1], regex, slen);
150   retry_announcement (a);
151   return a;
152 }
153
154
155 /**
156  * Stop announcing the regex specified by the given handle.
157  *
158  * @param a handle returned by a previous GNUNET_REGEX_announce call.
159  */
160 void
161 GNUNET_REGEX_announce_cancel (struct GNUNET_REGEX_Announcement *a)
162 {
163   GNUNET_CLIENT_disconnect (a->client);
164   GNUNET_free (a);
165 }
166
167
168 /**
169  * Handle to store data about a regex search.
170  */
171 struct GNUNET_REGEX_Search
172 {
173   /**
174    * Connection to the regex service.
175    */
176   struct GNUNET_CLIENT_Connection *client;
177
178   /**
179    * Our configuration.
180    */
181   const struct GNUNET_CONFIGURATION_Handle *cfg;
182
183   /**
184    * Function to call with results.
185    */
186   GNUNET_REGEX_Found callback;
187
188   /**
189    * Closure for @e callback.
190    */
191   void *callback_cls;
192
193   /**
194    * Search message to transmit to the service.
195    */
196   struct RegexSearchMessage *msg;
197 };
198
199
200 /**
201  * We got a response or disconnect after asking regex
202  * to do the search.  Handle it.
203  *
204  * @param cls the `struct GNUNET_REGEX_Search` to retry
205  * @param msg NULL on disconnect
206  */
207 static void
208 handle_search_response (void *cls,
209                         const struct GNUNET_MessageHeader *msg);
210
211
212 /**
213  * Try sending the search request to regex.  On
214  * errors (i.e. regex died), try again.
215  *
216  * @param s the search to retry
217  */
218 static void
219 retry_search (struct GNUNET_REGEX_Search *s)
220 {
221   GNUNET_assert (NULL != s->client);
222   GNUNET_assert (GNUNET_OK ==
223                  GNUNET_CLIENT_transmit_and_get_response (s->client,
224                                                           &s->msg->header,
225                                                           GNUNET_TIME_UNIT_FOREVER_REL,
226                                                           GNUNET_YES,
227                                                           &handle_search_response,
228                                                           s));
229 }
230
231
232 /**
233  * We got a response or disconnect after asking regex
234  * to do the search.  Handle it.
235  *
236  * @param cls the 'struct GNUNET_REGEX_Search' to retry
237  * @param msg NULL on disconnect, otherwise presumably a response
238  */
239 static void
240 handle_search_response (void *cls,
241                         const struct GNUNET_MessageHeader *msg)
242 {
243   struct GNUNET_REGEX_Search *s = cls;
244   const struct ResultMessage *result;
245   uint16_t size;
246   uint16_t gpl;
247   uint16_t ppl;
248
249   if (NULL == msg)
250   {
251     GNUNET_CLIENT_disconnect (s->client);
252     s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
253     retry_search (s);
254     return;
255   }
256   size = ntohs (msg->size);
257   if ( (GNUNET_MESSAGE_TYPE_REGEX_RESULT == ntohs (msg->type)) &&
258        (size >= sizeof (struct ResultMessage)) )
259   {
260     result = (const struct ResultMessage *) msg;
261     gpl = ntohs (result->get_path_length);
262     ppl = ntohs (result->put_path_length);
263     if (size == (sizeof (struct ResultMessage) +
264                  (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity)))
265     {
266       const struct GNUNET_PeerIdentity *pid;
267
268       GNUNET_CLIENT_receive (s->client,
269                              &handle_search_response, s,
270                              GNUNET_TIME_UNIT_FOREVER_REL);
271       pid = &result->id;
272       s->callback (s->callback_cls,
273                    pid,
274                    &pid[1], gpl,
275                    &pid[1 + gpl], ppl);
276       return;
277     }
278   }
279   GNUNET_break (0);
280   GNUNET_CLIENT_disconnect (s->client);
281   s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
282   retry_search (s);
283 }
284
285
286 /**
287  * Search for a peer offering a regex matching certain string in the DHT.
288  * The search runs until GNUNET_REGEX_search_cancel is called, even if results
289  * are returned.
290  *
291  * @param cfg configuration to use
292  * @param string String to match against the regexes in the DHT.
293  * @param callback Callback for found peers.
294  * @param callback_cls Closure for @c callback.
295  * @return Handle to stop search and free resources.
296  *         Must be freed by calling GNUNET_REGEX_search_cancel.
297  */
298 struct GNUNET_REGEX_Search *
299 GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
300                      const char *string,
301                      GNUNET_REGEX_Found callback,
302                      void *callback_cls)
303 {
304   struct GNUNET_REGEX_Search *s;
305   size_t slen;
306
307   slen = strlen (string) + 1;
308   s = GNUNET_new (struct GNUNET_REGEX_Search);
309   s->cfg = cfg;
310   s->client = GNUNET_CLIENT_connect ("regex", cfg);
311   if (NULL == s->client)
312   {
313     GNUNET_free (s);
314     return NULL;
315   }
316   s->callback = callback;
317   s->callback_cls = callback_cls;
318   s->msg = GNUNET_malloc (sizeof (struct RegexSearchMessage) + slen);
319   s->msg->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_SEARCH);
320   s->msg->header.size = htons (sizeof (struct RegexSearchMessage) + slen);
321   memcpy (&s->msg[1], string, slen);
322   retry_search (s);
323   return s;
324 }
325
326
327 /**
328  * Stop search and free all data used by a GNUNET_REGEX_search call.
329  *
330  * @param s Handle returned by a previous GNUNET_REGEX_search call.
331  */
332 void
333 GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_Search *s)
334 {
335   GNUNET_CLIENT_disconnect (s->client);
336   GNUNET_free (s->msg);
337   GNUNET_free (s);
338 }
339
340
341 /* end of regex_api.c */