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