revert
[oweals/gnunet.git] / src / regex / regex_api_search.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2012, 2013, 2016 GNUnet e.V.
4
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.
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      Affero General Public License for more details.
14     
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/>.
17 */
18 /**
19  * @file regex/regex_api_search.c
20  * @brief access regex service to discover
21  *        peers using matching strings
22  * @author Maximilian Szengel
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include "gnunet_protocols.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_regex_service.h"
29 #include "regex_ipc.h"
30
31 #define LOG(kind,...) GNUNET_log_from (kind, "regex-api",__VA_ARGS__)
32
33
34 /**
35  * Handle to store data about a regex search.
36  */
37 struct GNUNET_REGEX_Search
38 {
39   /**
40    * Connection to the regex service.
41    */
42   struct GNUNET_MQ_Handle *mq;
43
44   /**
45    * Our configuration.
46    */
47   const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49   /**
50    * Function to call with results.
51    */
52   GNUNET_REGEX_Found callback;
53
54   /**
55    * Closure for @e callback.
56    */
57   void *callback_cls;
58
59   /**
60    * Search string to transmit to the service.
61    */
62   char *string;
63 };
64
65
66 /**
67  * (Re)connect to the REGEX service for the given search @a s.
68  *
69  * @param s context for the search search for
70  */
71 static void
72 search_reconnect (struct GNUNET_REGEX_Search *s);
73
74
75 /**
76  * We got a response or disconnect after asking regex
77  * to do the search.  Check it is well-formed.
78  *
79  * @param cls the `struct GNUNET_REGEX_Search` to handle reply for
80  * @param result the message
81  * @return #GNUNET_SYSERR if @a rm is not well-formed.
82  */
83 static int
84 check_search_response (void *cls,
85                        const struct ResultMessage *result)
86 {
87   uint16_t size = ntohs (result->header.size) - sizeof (*result);
88   uint16_t gpl = ntohs (result->get_path_length);
89   uint16_t ppl = ntohs (result->put_path_length);
90
91   if (size != (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity))
92   {
93     GNUNET_break (0);
94     return GNUNET_SYSERR;
95   }
96   return GNUNET_OK;
97 }
98
99
100 /**
101  * We got a response or disconnect after asking regex
102  * to do the search.  Handle it.
103  *
104  * @param cls the `struct GNUNET_REGEX_Search` to handle reply for
105  * @param result the message
106  */
107 static void
108 handle_search_response (void *cls,
109                         const struct ResultMessage *result)
110 {
111   struct GNUNET_REGEX_Search *s = cls;
112   uint16_t gpl = ntohs (result->get_path_length);
113   uint16_t ppl = ntohs (result->put_path_length);
114   const struct GNUNET_PeerIdentity *pid;
115
116   pid = &result->id;
117   LOG (GNUNET_ERROR_TYPE_DEBUG,
118        "Got regex result %s\n",
119        GNUNET_i2s (pid));
120   s->callback (s->callback_cls,
121                pid,
122                &pid[1],
123                gpl,
124                &pid[1 + gpl],
125                ppl);
126 }
127
128
129 /**
130  * We got a disconnect after asking regex to do the announcement.
131  * Retry.
132  *
133  * @param cls the `struct GNUNET_REGEX_Search` to retry
134  * @param error error code
135  */
136 static void
137 mq_error_handler (void *cls,
138                   enum GNUNET_MQ_Error error)
139 {
140   struct GNUNET_REGEX_Search *s = cls;
141
142   GNUNET_MQ_destroy (s->mq);
143   s->mq = NULL;
144   search_reconnect (s);
145 }
146
147
148 /**
149  * (Re)connect to the REGEX service for the given search @a s.
150  *
151  * @param s context for the search search for
152  */
153 static void
154 search_reconnect (struct GNUNET_REGEX_Search *s)
155 {
156   struct GNUNET_MQ_MessageHandler handlers[] = {
157     GNUNET_MQ_hd_var_size (search_response,
158                            GNUNET_MESSAGE_TYPE_REGEX_RESULT,
159                            struct ResultMessage,
160                            s),
161     GNUNET_MQ_handler_end ()
162   };
163   size_t slen = strlen (s->string) + 1;
164   struct GNUNET_MQ_Envelope *env;
165   struct RegexSearchMessage *rsm;
166
167   GNUNET_assert (NULL == s->mq);
168   s->mq = GNUNET_CLIENT_connect (s->cfg,
169                                  "regex",
170                                  handlers,
171                                  &mq_error_handler,
172                                  s);
173   if (NULL == s->mq)
174     return;
175   env = GNUNET_MQ_msg_extra (rsm,
176                              slen,
177                              GNUNET_MESSAGE_TYPE_REGEX_SEARCH);
178   GNUNET_memcpy (&rsm[1],
179           s->string,
180           slen);
181   GNUNET_MQ_send (s->mq,
182                   env);
183 }
184
185
186 /**
187  * Search for a peer offering a regex matching certain string in the DHT.
188  * The search runs until #GNUNET_REGEX_search_cancel() is called, even if results
189  * are returned.
190  *
191  * @param cfg configuration to use
192  * @param string String to match against the regexes in the DHT.
193  * @param callback Callback for found peers.
194  * @param callback_cls Closure for @c callback.
195  * @return Handle to stop search and free resources.
196  *         Must be freed by calling #GNUNET_REGEX_search_cancel().
197  */
198 struct GNUNET_REGEX_Search *
199 GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
200                      const char *string,
201                      GNUNET_REGEX_Found callback,
202                      void *callback_cls)
203 {
204   struct GNUNET_REGEX_Search *s;
205   size_t slen = strlen (string) + 1;
206
207   if (slen + sizeof (struct RegexSearchMessage) >= GNUNET_MAX_MESSAGE_SIZE)
208   {
209     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
210                 _("Search string `%s' is too long!\n"),
211                 string);
212     GNUNET_break (0);
213     return NULL;
214   }
215   LOG (GNUNET_ERROR_TYPE_DEBUG,
216        "Starting regex search for %s\n",
217        string);
218   s = GNUNET_new (struct GNUNET_REGEX_Search);
219   s->cfg = cfg;
220   s->string = GNUNET_strdup (string);
221   s->callback = callback;
222   s->callback_cls = callback_cls;
223   search_reconnect (s);
224   if (NULL == s->mq)
225   {
226     GNUNET_free (s->string);
227     GNUNET_free (s);
228     return NULL;
229   }
230   return s;
231 }
232
233
234 /**
235  * Stop search and free all data used by a #GNUNET_REGEX_search() call.
236  *
237  * @param s Handle returned by a previous #GNUNET_REGEX_search() call.
238  */
239 void
240 GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_Search *s)
241 {
242   GNUNET_MQ_destroy (s->mq);
243   GNUNET_free (s->string);
244   GNUNET_free (s);
245 }
246
247
248 /* end of regex_api_search.c */