migrate first half of regex API to MQ lib
[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
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
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_CLIENT_Connection *client;
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 message to transmit to the service.
63    */
64   struct RegexSearchMessage *msg;
65 };
66
67
68 /**
69  * We got a response or disconnect after asking regex
70  * to do the search.  Handle it.
71  *
72  * @param cls the `struct GNUNET_REGEX_Search` to retry
73  * @param msg NULL on disconnect
74  */
75 static void
76 handle_search_response (void *cls,
77                         const struct GNUNET_MessageHeader *msg);
78
79
80 /**
81  * Try sending the search request to regex.  On
82  * errors (i.e. regex died), try again.
83  *
84  * @param s the search to retry
85  */
86 static void
87 retry_search (struct GNUNET_REGEX_Search *s)
88 {
89   GNUNET_assert (NULL != s->client);
90   GNUNET_assert (GNUNET_OK ==
91                  GNUNET_CLIENT_transmit_and_get_response (s->client,
92                                                           &s->msg->header,
93                                                           GNUNET_TIME_UNIT_FOREVER_REL,
94                                                           GNUNET_YES,
95                                                           &handle_search_response,
96                                                           s));
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 msg NULL on disconnect, otherwise presumably a response
106  */
107 static void
108 handle_search_response (void *cls,
109                         const struct GNUNET_MessageHeader *msg)
110 {
111   struct GNUNET_REGEX_Search *s = cls;
112   const struct ResultMessage *result;
113   uint16_t size;
114   uint16_t gpl;
115   uint16_t ppl;
116
117   if (NULL == msg)
118   {
119     GNUNET_CLIENT_disconnect (s->client);
120     s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
121     retry_search (s);
122     return;
123   }
124   size = ntohs (msg->size);
125   if ( (GNUNET_MESSAGE_TYPE_REGEX_RESULT == ntohs (msg->type)) &&
126        (size >= sizeof (struct ResultMessage)) )
127   {
128     result = (const struct ResultMessage *) msg;
129     gpl = ntohs (result->get_path_length);
130     ppl = ntohs (result->put_path_length);
131     if (size == (sizeof (struct ResultMessage) +
132                  (gpl + ppl) * sizeof (struct GNUNET_PeerIdentity)))
133     {
134       const struct GNUNET_PeerIdentity *pid;
135
136       GNUNET_CLIENT_receive (s->client,
137                              &handle_search_response, s,
138                              GNUNET_TIME_UNIT_FOREVER_REL);
139       pid = &result->id;
140       LOG (GNUNET_ERROR_TYPE_DEBUG,
141            "Got regex result %s\n",
142            GNUNET_i2s (pid));
143       s->callback (s->callback_cls,
144                    pid,
145                    &pid[1], gpl,
146                    &pid[1 + gpl], ppl);
147       return;
148     }
149   }
150   GNUNET_break (0);
151   GNUNET_CLIENT_disconnect (s->client);
152   s->client = GNUNET_CLIENT_connect ("regex", s->cfg);
153   retry_search (s);
154 }
155
156
157 /**
158  * Search for a peer offering a regex matching certain string in the DHT.
159  * The search runs until #GNUNET_REGEX_search_cancel() is called, even if results
160  * are returned.
161  *
162  * @param cfg configuration to use
163  * @param string String to match against the regexes in the DHT.
164  * @param callback Callback for found peers.
165  * @param callback_cls Closure for @c callback.
166  * @return Handle to stop search and free resources.
167  *         Must be freed by calling #GNUNET_REGEX_search_cancel().
168  */
169 struct GNUNET_REGEX_Search *
170 GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
171                      const char *string,
172                      GNUNET_REGEX_Found callback,
173                      void *callback_cls)
174 {
175   struct GNUNET_REGEX_Search *s;
176   size_t slen;
177
178   LOG (GNUNET_ERROR_TYPE_DEBUG,
179        "Starting regex search for %s\n",
180        string);
181   slen = strlen (string) + 1;
182   s = GNUNET_new (struct GNUNET_REGEX_Search);
183   s->cfg = cfg;
184   s->client = GNUNET_CLIENT_connect ("regex", cfg);
185   if (NULL == s->client)
186   {
187     GNUNET_free (s);
188     return NULL;
189   }
190   s->callback = callback;
191   s->callback_cls = callback_cls;
192   s->msg = GNUNET_malloc (sizeof (struct RegexSearchMessage) + slen);
193   s->msg->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_SEARCH);
194   s->msg->header.size = htons (sizeof (struct RegexSearchMessage) + slen);
195   memcpy (&s->msg[1], string, slen);
196   retry_search (s);
197   return s;
198 }
199
200
201 /**
202  * Stop search and free all data used by a #GNUNET_REGEX_search() call.
203  *
204  * @param s Handle returned by a previous #GNUNET_REGEX_search() call.
205  */
206 void
207 GNUNET_REGEX_search_cancel (struct GNUNET_REGEX_Search *s)
208 {
209   GNUNET_CLIENT_disconnect (s->client);
210   GNUNET_free (s->msg);
211   GNUNET_free (s);
212 }
213
214
215 /* end of regex_api.c */