REST/NAMESTORE: rework API
[oweals/gnunet.git] / src / transport / transport_api_address_to_string.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2014, 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 transport/transport_api_address_to_string.c
22  * @author Christian Grothoff
23  * @brief enable clients to convert addresses to human readable strings
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_arm_service.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_transport_service.h"
31 #include "transport.h"
32
33 /**
34  * Context for the address lookup.
35  */
36 struct GNUNET_TRANSPORT_AddressToStringContext
37 {
38   /**
39    * Function to call with the human-readable address.
40    */
41   GNUNET_TRANSPORT_AddressToStringCallback cb;
42
43   /**
44    * Closure for @e cb.
45    */
46   void *cb_cls;
47
48   /**
49    * Connection to the service.
50    */
51   struct GNUNET_MQ_Handle *mq;
52
53 };
54
55
56 /**
57  * Function called with responses from the service.
58  *
59  * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
60  * @param msg message with the human-readable address
61  * @return #GNUNET_OK if message is well-formed
62  */
63 static int
64 check_reply (void *cls,
65              const struct AddressToStringResultMessage *atsm)
66 {
67   uint16_t size = ntohs (atsm->header.size) - sizeof (*atsm);
68   const char *address;
69   int result;
70   uint32_t addr_len;
71
72   result = (int) ntohl (atsm->res);
73   addr_len = ntohl (atsm->addr_len);
74   if (GNUNET_SYSERR == result)
75     return GNUNET_OK;
76   if (0 == size)
77   {
78     if (GNUNET_OK != result)
79     {
80       GNUNET_break (0);
81       return GNUNET_SYSERR;
82     }
83     return GNUNET_OK;
84   }
85   address = (const char *) &atsm[1];
86   if ( (addr_len > size) ||
87        (address[addr_len -1] != '\0') )
88   {
89     /* invalid reply */
90     GNUNET_break (0);
91     return GNUNET_SYSERR;
92   }
93   return GNUNET_OK;
94 }
95
96
97 /**
98  * Function called with responses from the service.
99  *
100  * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
101  * @param msg message with the human-readable address
102  */
103 static void
104 handle_reply (void *cls,
105               const struct AddressToStringResultMessage *atsm)
106 {
107   struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
108   uint16_t size = ntohs (atsm->header.size) - sizeof (*atsm);
109   const char *address;
110   int result;
111
112   result = (int) ntohl (atsm->res);
113   if (GNUNET_SYSERR == result)
114   {
115     /* expect more replies; as this is not the last
116        call, we must pass the empty string for the address */
117     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118                 "Address resolution failed\n");
119     alucb->cb (alucb->cb_cls,
120                "",
121                GNUNET_NO);
122     return;
123   }
124   if (0 == size)
125   {
126     /* we are done (successfully, without communication errors) */
127     alucb->cb (alucb->cb_cls,
128                NULL,
129                GNUNET_OK);
130     GNUNET_TRANSPORT_address_to_string_cancel (alucb);
131     return;
132   }
133   address = (const char *) &atsm[1];
134   /* return normal reply to caller, also expect more replies */
135   alucb->cb (alucb->cb_cls,
136              address,
137              GNUNET_OK);
138 }
139
140
141 /**
142  * Generic error handler, called with the appropriate
143  * error code and the same closure specified at the creation of
144  * the message queue.
145  * Not every message queue implementation supports an error handler.
146  *
147  * @param cls the `struct GNUNET_TRANSPORT_AddressToStringContext *`
148  * @param error error code
149  */
150 static void
151 mq_error_handler (void *cls,
152                   enum GNUNET_MQ_Error error)
153 {
154   struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
155
156   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157               "Disconnected from transport, address resolution failed\n");
158   alucb->cb (alucb->cb_cls,
159              NULL,
160              GNUNET_SYSERR);
161   GNUNET_TRANSPORT_address_to_string_cancel (alucb);
162 }
163
164
165 /**
166  * Convert a binary address into a human readable address.
167  *
168  * @param cfg configuration to use
169  * @param address address to convert (binary format)
170  * @param numeric should (IP) addresses be displayed in numeric form
171  *                (otherwise do reverse DNS lookup)
172  * @param timeout how long is the lookup allowed to take at most
173  * @param aluc function to call with the results
174  * @param aluc_cls closure for @a aluc
175  * @return handle to cancel the operation, NULL on error
176  */
177 struct GNUNET_TRANSPORT_AddressToStringContext *
178 GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cfg,
179                                     const struct GNUNET_HELLO_Address *address,
180                                     int numeric,
181                                     struct GNUNET_TIME_Relative timeout,
182                                     GNUNET_TRANSPORT_AddressToStringCallback aluc,
183                                     void *aluc_cls)
184 {
185   struct GNUNET_TRANSPORT_AddressToStringContext *alc
186     = GNUNET_new (struct GNUNET_TRANSPORT_AddressToStringContext);
187   struct GNUNET_MQ_MessageHandler handlers[] = {
188     GNUNET_MQ_hd_var_size (reply,
189                            GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY,
190                            struct AddressToStringResultMessage,
191                            alc),
192     GNUNET_MQ_handler_end ()
193   };
194   size_t alen;
195   size_t slen;
196   struct AddressLookupMessage *msg;
197   struct GNUNET_MQ_Envelope *env;
198   char *addrbuf;
199
200   alen = address->address_length;
201   slen = strlen (address->transport_name) + 1;
202   if ( (alen + slen >= GNUNET_MAX_MESSAGE_SIZE
203         - sizeof (struct AddressLookupMessage)) ||
204        (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
205        (slen >= GNUNET_MAX_MESSAGE_SIZE) )
206   {
207     GNUNET_break (0);
208     GNUNET_free (alc);
209     return NULL;
210   }
211   alc->cb = aluc;
212   alc->cb_cls = aluc_cls;
213   alc->mq = GNUNET_CLIENT_connect (cfg,
214                                    "transport",
215                                    handlers,
216                                    &mq_error_handler,
217                                    alc);
218   if (NULL == alc->mq)
219   {
220     GNUNET_break (0);
221     GNUNET_free (alc);
222     return NULL;
223   }
224   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
225               "Client tries to resolve for peer `%s' address plugin %s len %u\n",
226               GNUNET_i2s (&address->peer),
227               address->transport_name,
228               (unsigned int) address->address_length);
229   env = GNUNET_MQ_msg_extra (msg,
230                              alen + slen,
231                              GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
232   msg->numeric_only = htons ((int16_t) numeric);
233   msg->addrlen = htons ((uint16_t) alen);
234   msg->timeout = GNUNET_TIME_relative_hton (timeout);
235   addrbuf = (char *) &msg[1];
236   GNUNET_memcpy (addrbuf,
237           address->address,
238           alen);
239   GNUNET_memcpy (&addrbuf[alen],
240           address->transport_name,
241           slen);
242   GNUNET_MQ_send (alc->mq,
243                   env);
244   return alc;
245 }
246
247
248 /**
249  * Cancel request for address conversion.
250  *
251  * @param alc the context handle
252  */
253 void
254 GNUNET_TRANSPORT_address_to_string_cancel (struct GNUNET_TRANSPORT_AddressToStringContext *alc)
255 {
256   GNUNET_MQ_destroy (alc->mq);
257   GNUNET_free (alc);
258 }
259
260
261 /* end of transport_api_address_to_string.c */