psyc/social: local join flag; social service: leave place, save _file
[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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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 #define LOG(kind,...) GNUNET_log_from (kind, "regex-api",__VA_ARGS__)
34
35 /**
36  * Handle to store cached data about a regex announce.
37  */
38 struct GNUNET_REGEX_Announcement
39 {
40   /**
41    * Connection to the regex service.
42    */
43   struct GNUNET_CLIENT_Connection *client;
44
45   /**
46    * Our configuration.
47    */
48   const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50   /**
51    * Message we're sending to the service.
52    */
53   struct AnnounceMessage msg;
54 };
55
56
57 /**
58  * We got a response (!?) or disconnect after asking regex
59  * to do the announcement.  Retry.
60  *
61  * @param cls the 'struct GNUNET_REGEX_Announcement' to retry
62  * @param msg NULL on disconnect
63  */
64 static void
65 handle_a_reconnect (void *cls,
66                     const struct GNUNET_MessageHeader *msg);
67
68
69 /**
70  * Try sending the announcement request to regex.  On
71  * errors (i.e. regex died), try again.
72  *
73  * @param a the announcement to retry
74  */
75 static void
76 retry_announcement (struct GNUNET_REGEX_Announcement *a)
77 {
78   GNUNET_assert (NULL != a->client);
79   GNUNET_assert (GNUNET_OK ==
80                  GNUNET_CLIENT_transmit_and_get_response (a->client,
81                                                           &a->msg.header,
82                                                           GNUNET_TIME_UNIT_FOREVER_REL,
83                                                           GNUNET_YES,
84                                                           &handle_a_reconnect,
85                                                           a));
86 }
87
88
89 /**
90  * We got a response (!?) or disconnect after asking regex
91  * to do the announcement.  Retry.
92  *
93  * @param cls the 'struct GNUNET_REGEX_Announcement' to retry
94  * @param msg NULL on disconnect
95  */
96 static void
97 handle_a_reconnect (void *cls,
98                     const struct GNUNET_MessageHeader *msg)
99 {
100   struct GNUNET_REGEX_Announcement *a = cls;
101
102   GNUNET_CLIENT_disconnect (a->client);
103   a->client = GNUNET_CLIENT_connect ("regex", a->cfg);
104   retry_announcement (a);
105 }
106
107
108 /**
109  * Announce the given peer under the given regular expression.
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   LOG (GNUNET_ERROR_TYPE_DEBUG,
137        "Starting REGEX announcement %s\n",
138        regex);
139   a = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Announcement) + slen);
140   a->cfg = cfg;
141   a->client = GNUNET_CLIENT_connect ("regex", cfg);
142   if (NULL == a->client)
143   {
144     GNUNET_free (a);
145     return NULL;
146   }
147   a->msg.header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE);
148   a->msg.header.size = htons (slen + sizeof (struct AnnounceMessage));
149   a->msg.compression = htons (compression);
150   a->msg.reserved = htons (0);
151   a->msg.refresh_delay = GNUNET_TIME_relative_hton (refresh_delay);
152   memcpy (&a[1], regex, slen);
153   retry_announcement (a);
154   return a;
155 }
156
157
158 /**
159  * Stop announcing the regex specified by the given handle.
160  *
161  * @param a handle returned by a previous GNUNET_REGEX_announce call.
162  */
163 void
164 GNUNET_REGEX_announce_cancel (struct GNUNET_REGEX_Announcement *a)
165 {
166   GNUNET_CLIENT_disconnect (a->client);
167   GNUNET_free (a);
168 }
169
170
171 /**
172  * Handle to store data about a regex search.
173  */
174 struct GNUNET_REGEX_Search
175 {
176   /**
177    * Connection to the regex service.
178    */
179   struct GNUNET_CLIENT_Connection *client;
180
181   /**
182    * Our configuration.
183    */
184   const struct GNUNET_CONFIGURATION_Handle *cfg;
185
186   /**
187    * Function to call with results.
188    */
189   GNUNET_REGEX_Found callback;
190
191   /**
192    * Closure for @e callback.
193    */
194   void *callback_cls;
195
196   /**
197    * Search message to transmit to the service.
198    */
199   struct RegexSearchMessage *msg;
200 };
201
202
203 /**
204  * We got a response or disconnect after asking regex
205  * to do the search.  Handle it.
206  *
207  * @param cls the `struct GNUNET_REGEX_Search` to retry
208  * @param msg NULL on disconnect
209  */
210 static void
211 handle_search_response (void *cls,
212                         const struct GNUNET_MessageHeader *msg);
213
214
215 /**
216  * Try sending the search request to regex.  On
217  * errors (i.e. regex died), try again.
218  *
219  * @param s the search to retry
220  */
221 static void
222 retry_search (struct GNUNET_REGEX_Search *s)
223 {
224   GNUNET_assert (NULL != s->client);
225   GNUNET_assert (GNUNET_OK ==
226                  GNUNET_CLIENT_transmit_and_get_response (s->client,
227                                                           &s->msg->header,
228                                                           GNUNET_TIME_UNIT_FOREVER_REL,
229                                                           GNUNET_YES,
230                                                           &handle_search_response,
231                                                           s));
232 }
233
234
235 /**
236  * We got a response or disconnect after asking regex
237  * to do the search.  Handle it.
238  *
239  * @param cls the `struct GNUNET_REGEX_Search` to handle reply for
240  * @param msg NULL on disconnect, otherwise presumably a response
241  */
242 static void
243 handle_search_response (void *cls,
244                         const struct GNUNET_MessageHeader *msg)
245 {
246   struct GNUNET_REGEX_Search *s = cls;
247   const struct ResultMessage *result;
248   uint16_t size;
249   uint16_t gpl;
250   uint16_t ppl;
251
252   if (NULL == msg)
253   {
254     GNUNET_CLIENT_disconnect (s->client);
255     s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
256     retry_search (s);
257     return;
258   }
259   size = ntohs (msg->size);
260   if ( (GNUNET_MESSAGE_TYPE_REGEX_RESULT == ntohs (msg->type)) &&
261        (size >= sizeof (struct ResultMessage)) )
262   {
263     result = (const struct ResultMessage *) msg;
264     gpl = ntohs (result->get_path_length);
265     ppl = ntohs (result->put_path_length);
266     if (size == (sizeof (struct ResultMessage) +
267                  (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity)))
268     {
269       const struct GNUNET_PeerIdentity *pid;
270
271       GNUNET_CLIENT_receive (s->client,
272                              &handle_search_response, s,
273                              GNUNET_TIME_UNIT_FOREVER_REL);
274       pid = &result->id;
275       LOG (GNUNET_ERROR_TYPE_DEBUG,
276            "Got regex result %s\n",
277            GNUNET_i2s (pid));
278       s->callback (s->callback_cls,
279                    pid,
280                    &pid[1], gpl,
281                    &pid[1 + gpl], ppl);
282       return;
283     }
284   }
285   GNUNET_break (0);
286   GNUNET_CLIENT_disconnect (s->client);
287   s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
288   retry_search (s);
289 }
290
291
292 /**
293  * Search for a peer offering a regex matching certain string in the DHT.
294  * The search runs until #GNUNET_REGEX_search_cancel() is called, even if results
295  * are returned.
296  *
297  * @param cfg configuration to use
298  * @param string String to match against the regexes in the DHT.
299  * @param callback Callback for found peers.
300  * @param callback_cls Closure for @c callback.
301  * @return Handle to stop search and free resources.
302  *         Must be freed by calling #GNUNET_REGEX_search_cancel().
303  */
304 struct GNUNET_REGEX_Search *
305 GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
306                      const char *string,
307                      GNUNET_REGEX_Found callback,
308                      void *callback_cls)
309 {
310   struct GNUNET_REGEX_Search *s;
311   size_t slen;
312
313   LOG (GNUNET_ERROR_TYPE_DEBUG,
314        "Starting regex search for %s\n",
315        string);
316   slen = strlen (string) + 1;
317   s = GNUNET_new (struct GNUNET_REGEX_Search);
318   s->cfg = cfg;
319   s->client = GNUNET_CLIENT_connect ("regex", cfg);
320   if (NULL == s->client)
321   {
322     GNUNET_free (s);
323     return NULL;
324   }
325   s->callback = callback;
326   s->callback_cls = callback_cls;
327   s->msg = GNUNET_malloc (sizeof (struct RegexSearchMessage) + slen);
328   s->msg->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_SEARCH);
329   s->msg->header.size = htons (sizeof (struct RegexSearchMessage) + slen);
330   memcpy (&s->msg[1], string, slen);
331   retry_search (s);
332   return s;
333 }
334
335
336 /**
337  * Stop search and free all data used by a #GNUNET_REGEX_search() call.
338  *
339  * @param s Handle returned by a previous #GNUNET_REGEX_search() call.
340  */
341 void
342 GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_Search *s)
343 {
344   GNUNET_CLIENT_disconnect (s->client);
345   GNUNET_free (s->msg);
346   GNUNET_free (s);
347 }
348
349
350 /* end of regex_api.c */