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