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