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