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