- tweaks for hex experiments
[oweals/gnunet.git] / src / regex / regex_api.c
1 /*
2      This file is part of GNUnet
3      (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_break (0);
131     return NULL;
132   }
133   a = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Announcement) + slen);
134   a->cfg = cfg;
135   a->client = GNUNET_CLIENT_connect ("regex", cfg);
136   if (NULL == a->client)
137   {
138     GNUNET_free (a);
139     return NULL;
140   }
141   a->msg.header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE);
142   a->msg.header.size = htons (slen + sizeof (struct AnnounceMessage));
143   a->msg.compression = htons (compression);
144   a->msg.reserved = htons (0);
145   a->msg.refresh_delay = GNUNET_TIME_relative_hton (refresh_delay);
146   memcpy (&a[1], regex, slen);
147   retry_announcement (a);
148   return a;
149 }
150
151
152 /**
153  * Stop announcing the regex specified by the given handle.
154  * 
155  * @param a handle returned by a previous GNUNET_REGEX_announce call.
156  */
157 void
158 GNUNET_REGEX_announce_cancel (struct GNUNET_REGEX_Announcement *a)
159 {
160   GNUNET_CLIENT_disconnect (a->client);
161   GNUNET_free (a);
162 }
163
164
165 /**
166  * Handle to store data about a regex search.
167  */
168 struct GNUNET_REGEX_Search
169 {
170   /**
171    * Connection to the regex service.
172    */
173   struct GNUNET_CLIENT_Connection *client;
174
175   /** 
176    * Our configuration.
177    */
178   const struct GNUNET_CONFIGURATION_Handle *cfg;
179   
180   /**
181    * Function to call with results.
182    */
183   GNUNET_REGEX_Found callback;
184
185   /**
186    * Closure for 'callback'.
187    */
188   void *callback_cls;
189   
190   /**
191    * Search message to transmit to the service.
192    */
193   struct SearchMessage *msg;
194 };
195
196
197 /**
198  * We got a response or disconnect after asking regex
199  * to do the search.  Handle it.
200  * 
201  * @param cls the 'struct GNUNET_REGEX_Search' to retry
202  * @param msg NULL on disconnect
203  */
204 static void
205 handle_search_response (void *cls,
206                         const struct GNUNET_MessageHeader *msg);
207
208
209 /**
210  * Try sending the search request to regex.  On 
211  * errors (i.e. regex died), try again.
212  *
213  * @param s the search to retry
214  */
215 static void
216 retry_search (struct GNUNET_REGEX_Search *s)
217 {
218   GNUNET_assert (NULL != s->client);
219   GNUNET_assert (GNUNET_OK ==
220                  GNUNET_CLIENT_transmit_and_get_response (s->client,
221                                                           &s->msg->header,
222                                                           GNUNET_TIME_UNIT_FOREVER_REL,
223                                                           GNUNET_YES,
224                                                           &handle_search_response,
225                                                           s));
226 }
227
228
229 /**
230  * We got a response or disconnect after asking regex
231  * to do the search.  Handle it.
232  * 
233  * @param cls the 'struct GNUNET_REGEX_Search' to retry
234  * @param msg NULL on disconnect, otherwise presumably a response
235  */
236 static void
237 handle_search_response (void *cls,
238                         const struct GNUNET_MessageHeader *msg)
239 {
240   struct GNUNET_REGEX_Search *s = cls;
241   const struct ResultMessage *result;
242   uint16_t size;
243   uint16_t gpl;
244   uint16_t ppl;
245
246   if (NULL == msg)
247   {
248     GNUNET_CLIENT_disconnect (s->client);
249     s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
250     retry_search (s);
251     return;
252   }
253   size = ntohs (msg->size);
254   if ( (GNUNET_MESSAGE_TYPE_REGEX_RESULT == ntohs (msg->type)) &&
255        (size >= sizeof (struct ResultMessage)) )
256   {
257     result = (const struct ResultMessage *) msg;
258     gpl = ntohs (result->get_path_length);
259     ppl = ntohs (result->put_path_length);
260     if (size == (sizeof (struct ResultMessage) + 
261                  (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity)))
262     {
263       const struct GNUNET_PeerIdentity *pid;
264
265       GNUNET_CLIENT_receive (s->client,
266                              &handle_search_response, s,
267                              GNUNET_TIME_UNIT_FOREVER_REL);
268       pid = &result->id;
269       s->callback (s->callback_cls,
270                    pid,
271                    &pid[1], gpl,
272                    &pid[1 + gpl], ppl);            
273       return;
274     }
275   }
276   GNUNET_break (0);
277   GNUNET_CLIENT_disconnect (s->client);
278   s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
279   retry_search (s);
280 }
281
282
283 /**
284  * Search for a peer offering a regex matching certain string in the DHT.
285  * The search runs until GNUNET_REGEX_search_cancel is called, even if results
286  * are returned.
287  *
288  * @param cfg configuration to use
289  * @param string String to match against the regexes in the DHT.
290  * @param callback Callback for found peers.
291  * @param callback_cls Closure for @c callback.
292  * @return Handle to stop search and free resources.
293  *         Must be freed by calling GNUNET_REGEX_search_cancel.
294  */
295 struct GNUNET_REGEX_Search *
296 GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
297                      const char *string,
298                      GNUNET_REGEX_Found callback,
299                      void *callback_cls)
300 {
301   struct GNUNET_REGEX_Search *s;
302   size_t slen;
303
304   slen = strlen (string) + 1;
305   s = GNUNET_new (struct GNUNET_REGEX_Search);
306   s->cfg = cfg;
307   s->client = GNUNET_CLIENT_connect ("regex", cfg);
308   if (NULL == s->client)
309   {
310     GNUNET_free (s);
311     return NULL;
312   }
313   s->callback = callback;
314   s->callback_cls = callback_cls;
315   s->msg = GNUNET_malloc (sizeof (struct SearchMessage) + slen);
316   s->msg->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_SEARCH);
317   s->msg->header.size = htons (sizeof (struct SearchMessage) + slen);
318   memcpy (&s->msg[1], string, slen);
319   retry_search (s);
320   return s;
321 }
322
323
324 /**
325  * Stop search and free all data used by a GNUNET_REGEX_search call.
326  * 
327  * @param s Handle returned by a previous GNUNET_REGEX_search call.
328  */
329 void
330 GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_Search *s)
331 {
332   GNUNET_CLIENT_disconnect (s->client);
333   GNUNET_free (s->msg);
334   GNUNET_free (s);
335 }
336
337
338 /* end of regex_api.c */