misc fixes to gnunet-gns-proxy, in particular avoiding MHD-busy waiting
[oweals/gnunet.git] / src / gns / gns_tld_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2013, 2016, 2018 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 gns/gns_tld_api.c
22  * @brief library to access the GNS service, including TLD lookup
23  * @author Martin Schanzenbach
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_hello_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_dht_service.h"
34 #include "gns.h"
35 #include "gns_api.h"
36
37
38 #define LOG(kind,...) GNUNET_log_from (kind, "gns-tld-api",__VA_ARGS__)
39
40
41
42 /**
43  * Handle to a lookup request
44  */
45 struct GNUNET_GNS_LookupWithTldRequest
46 {
47
48   /**
49    * handle to gns
50    */
51   struct GNUNET_GNS_Handle *gns_handle;
52
53   /**
54    * processor to call on lookup result
55    */
56   GNUNET_GNS_LookupResultProcessor2 lookup_proc;
57
58   /**
59    * Domain name we are resolving.
60    */
61   char *name;
62
63   /**
64    * @e lookup_proc closure
65    */
66   void *lookup_proc_cls;
67
68   /**
69    * Underlying GNS lookup.
70    */
71   struct GNUNET_GNS_LookupRequest *lr;
72
73   /**
74    * Lookup an ego with the identity service.
75    */
76   struct GNUNET_IDENTITY_EgoLookup *id_op;
77
78   /**
79    * Desired result record type.
80    */
81   uint32_t type;
82
83   /**
84    * Lookup options.
85    */
86   enum GNUNET_GNS_LocalOptions options;
87 };
88
89
90 /**
91  * Obtain the TLD of the given @a name.
92  *
93  * @param name a name
94  * @return the part of @a name after the last ".",
95  *         or @a name if @a name does not contain a "."
96  */
97 static const char *
98 get_tld (const char *name)
99 {
100   const char *tld;
101
102   tld = strrchr (name,
103                  (unsigned char) '.');
104   if (NULL == tld)
105     tld = name;
106   else
107     tld++; /* skip the '.' */
108   return tld;
109 }
110
111
112 /**
113  * Eat the TLD of the given @a name.
114  *
115  * @param name a name
116  */
117 static void
118 eat_tld (char *name)
119 {
120   char *tld;
121
122   GNUNET_assert (0 < strlen (name));
123   tld = strrchr (name,
124                  (unsigned char) '.');
125   if (NULL == tld)
126     strcpy (name,
127             GNUNET_GNS_MASTERZONE_STR);
128   else
129     *tld = '\0';
130 }
131
132
133 /**
134  * Function called with the result of a GNS lookup.
135  *
136  * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
137  * @param rd_count number of records returned
138  * @param rd array of @a rd_count records with the results
139  */
140 static void
141 process_lookup_result (void *cls,
142                        uint32_t rd_count,
143                        const struct GNUNET_GNSRECORD_Data *rd)
144 {
145   struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
146
147   ltr->lr = NULL;
148   ltr->lookup_proc (ltr->lookup_proc_cls,
149                     GNUNET_YES,
150                     rd_count,
151                     rd);
152   GNUNET_GNS_lookup_with_tld_cancel (ltr);
153 }
154
155
156 /**
157  * Perform the actual resolution, starting with the zone
158  * identified by the given public key.
159  *
160  * @param pkey public key to use for the zone, can be NULL
161  */
162 static void
163 lookup_with_public_key (struct GNUNET_GNS_LookupWithTldRequest *ltr,
164                         const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
165 {
166   ltr->lr = GNUNET_GNS_lookup (ltr->gns_handle,
167                                ltr->name,
168                                pkey,
169                                ltr->type,
170                                ltr->options,
171                                &process_lookup_result,
172                                ltr);
173 }
174
175
176 /**
177  * Method called to with the ego we are to use for the lookup,
178  * when the ego is determined by a name.
179  *
180  * @param cls a `struct GNUNET_GNS_LookupWithTldRequest *`
181  * @param ego ego handle, NULL if not found
182  */
183 static void
184 identity_zone_cb (void *cls,
185                   const struct GNUNET_IDENTITY_Ego *ego)
186 {
187   struct GNUNET_GNS_LookupWithTldRequest *ltr = cls;
188   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
189
190   ltr->id_op = NULL;
191   if (NULL == ego)
192   {
193     ltr->lookup_proc (ltr->lookup_proc_cls,
194                       GNUNET_NO,
195                       0,
196                       NULL);
197     GNUNET_GNS_lookup_with_tld_cancel (ltr);
198     return;
199   }
200   else
201   {
202     GNUNET_IDENTITY_ego_get_public_key (ego,
203                                         &pkey);
204     lookup_with_public_key (ltr,
205                             &pkey);
206   }
207 }
208
209
210 /**
211  * Perform an asynchronous lookup operation on the GNS,
212  * determining the zone using the TLD of the given name
213  * and the current configuration to resolve TLDs to zones.
214  *
215  * @param handle handle to the GNS service
216  * @param name the name to look up, including TLD
217  * @param type the record type to look up
218  * @param options local options for the lookup
219  * @param proc processor to call on result
220  * @param proc_cls closure for @a proc
221  * @return handle to the get request, NULL on error (i.e. bad configuration)
222  */
223 struct GNUNET_GNS_LookupWithTldRequest *
224 GNUNET_GNS_lookup_with_tld (struct GNUNET_GNS_Handle *handle,
225                             const char *name,
226                             uint32_t type,
227                             enum GNUNET_GNS_LocalOptions options,
228                             GNUNET_GNS_LookupResultProcessor2 proc,
229                             void *proc_cls)
230 {
231   struct GNUNET_GNS_LookupWithTldRequest *ltr;
232   const char *tld;
233   char *dot_tld;
234   char *zonestr;
235   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
236
237   ltr = GNUNET_new (struct GNUNET_GNS_LookupWithTldRequest);
238   ltr->gns_handle = handle;
239   ltr->name = GNUNET_strdup (name);
240   ltr->type = type;
241   ltr->options = options;
242   ltr->lookup_proc = proc;
243   ltr->lookup_proc_cls = proc_cls;
244   /* start with trivial case: TLD is zkey */
245   tld = get_tld (ltr->name);
246   if (GNUNET_OK ==
247       GNUNET_CRYPTO_ecdsa_public_key_from_string (tld,
248                                                   strlen (tld),
249                                                   &pkey))
250   {
251     eat_tld (ltr->name);
252     lookup_with_public_key (ltr,
253                             &pkey);
254     return ltr;
255   }
256
257   /* second case: TLD is mapped in our configuration file */
258   GNUNET_asprintf (&dot_tld,
259                    ".%s",
260                    tld);
261   if (GNUNET_OK ==
262       GNUNET_CONFIGURATION_get_value_string (handle->cfg,
263                                              "gns",
264                                              dot_tld,
265                                              &zonestr))
266   {
267     if (GNUNET_OK !=
268         GNUNET_CRYPTO_ecdsa_public_key_from_string (zonestr,
269                                                     strlen (zonestr),
270                                                     &pkey))
271     {
272       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
273                                  "gns",
274                                  dot_tld,
275                                  _("Expected a base32-encoded public zone key\n"));
276       GNUNET_free (zonestr);
277       GNUNET_free (dot_tld);
278       GNUNET_free (ltr->name);
279       GNUNET_free (ltr);
280       return NULL;
281     }
282     GNUNET_free (dot_tld);
283     GNUNET_free (zonestr);
284     eat_tld (ltr->name);
285     lookup_with_public_key (ltr,
286                             &pkey);
287     return ltr;
288   }
289   GNUNET_free (dot_tld);
290
291   /* Final case: TLD matches one of our egos */
292   eat_tld (ltr->name);
293
294   /* if the name is of the form 'label' (and not 'label.SUBDOMAIN'), never go to the DHT */
295   if (NULL == strchr (ltr->name,
296                       (unsigned char) '.'))
297     ltr->options = GNUNET_GNS_LO_NO_DHT;
298   else
299     ltr->options = GNUNET_GNS_LO_LOCAL_MASTER;
300   ltr->id_op = GNUNET_IDENTITY_ego_lookup (ltr->gns_handle->cfg,
301                                            tld,
302                                            &identity_zone_cb,
303                                            ltr);
304   if (NULL == ltr->id_op)
305   {
306     GNUNET_free (ltr->name);
307     GNUNET_free (ltr);
308     return NULL;
309   }
310   return ltr;
311 }
312
313
314 /**
315  * Cancel pending lookup request
316  *
317  * @param ltr the lookup request to cancel
318  */
319 void
320 GNUNET_GNS_lookup_with_tld_cancel (struct GNUNET_GNS_LookupWithTldRequest *ltr)
321 {
322   if (NULL != ltr->id_op)
323   {
324     GNUNET_IDENTITY_ego_lookup_cancel (ltr->id_op);
325     ltr->id_op = NULL;
326   }
327   if (NULL != ltr->lr)
328   {
329     GNUNET_GNS_lookup_cancel (ltr->lr);
330     ltr->lr = NULL;
331   }
332   GNUNET_free (ltr->name);
333   GNUNET_free (ltr);
334 }
335
336 /* end of gns_tld_api.c */