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