error handling
[oweals/gnunet.git] / src / nat-auto / nat_auto_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2007-2017 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 /**
22  * @author Christian Grothoff
23  * @author Milan Bouchet-Valat
24  *
25  * @file nat-auto/nat_auto_api.c
26  * Routines for NAT auto configuration.
27  */
28 #include "platform.h"
29 #include "gnunet_nat_service.h"
30 #include "gnunet_nat_auto_service.h"
31 #include "nat-auto.h"
32
33
34 /**
35  * Handle to auto-configuration in progress.
36  */
37 struct GNUNET_NAT_AUTO_AutoHandle
38 {
39   /**
40    * Configuration we use.
41    */
42   const struct GNUNET_CONFIGURATION_Handle *cfg;
43
44   /**
45    * Message queue for communicating with the NAT service.
46    */
47   struct GNUNET_MQ_Handle *mq;
48
49   /**
50    * Function called with the result from the autoconfiguration.
51    */
52   GNUNET_NAT_AUTO_AutoResultCallback arc;
53
54   /**
55    * Closure for @e arc.
56    */
57   void *arc_cls;
58 };
59
60
61 /**
62  * Converts `enum GNUNET_NAT_StatusCode` to string
63  *
64  * @param err error code to resolve to a string
65  * @return point to a static string containing the error code
66  */
67 const char *
68 GNUNET_NAT_AUTO_status2string (enum GNUNET_NAT_StatusCode err)
69 {
70   switch (err)
71   {
72   case GNUNET_NAT_ERROR_SUCCESS:
73     return _ ("Operation Successful");
74
75   case GNUNET_NAT_ERROR_IPC_FAILURE:
76     return _ ("IPC failure");
77
78   case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
79     return _ ("Failure in network subsystem, check permissions.");
80
81   case GNUNET_NAT_ERROR_TIMEOUT:
82     return _ ("Encountered timeout while performing operation");
83
84   case GNUNET_NAT_ERROR_NOT_ONLINE:
85     return _ ("detected that we are offline");
86
87   case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
88     return _ ("`upnpc` command not found");
89
90   case GNUNET_NAT_ERROR_UPNPC_FAILED:
91     return _ ("Failed to run `upnpc` command");
92
93   case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
94     return _ ("`upnpc' command took too long, process killed");
95
96   case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
97     return _ ("`upnpc' command failed to establish port mapping");
98
99   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
100     return _ ("`external-ip' command not found");
101
102   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
103     return _ ("Failed to run `external-ip` command");
104
105   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
106     return _ ("`external-ip' command output invalid");
107
108   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
109     return _ ("no valid address was returned by `external-ip'");
110
111   case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
112     return _ (
113       "Could not determine interface with internal/local network address");
114
115   case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
116     return _ ("No functioning gnunet-helper-nat-server installation found");
117
118   case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
119     return _ ("NAT test could not be initialized");
120
121   case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
122     return _ ("NAT test timeout reached");
123
124   case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
125     return _ ("could not register NAT");
126
127   case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
128     return _ ("No working gnunet-helper-nat-client installation found");
129
130   default:
131     return "unknown status code";
132   }
133 }
134
135
136 /**
137  * Check result from autoconfiguration attempt.
138  *
139  * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle`
140  * @param res the result
141  * @return #GNUNET_OK if @a res is well-formed (always for now)
142  */
143 static int
144 check_auto_result (void *cls,
145                    const struct GNUNET_NAT_AUTO_AutoconfigResultMessage *res)
146 {
147   return GNUNET_OK;
148 }
149
150
151 /**
152  * Handle result from autoconfiguration attempt.
153  *
154  * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle`
155  * @param res the result
156  */
157 static void
158 handle_auto_result (void *cls,
159                     const struct GNUNET_NAT_AUTO_AutoconfigResultMessage *res)
160 {
161   struct GNUNET_NAT_AUTO_AutoHandle *ah = cls;
162   size_t left;
163   struct GNUNET_CONFIGURATION_Handle *cfg;
164   enum GNUNET_NAT_Type type
165     = (enum GNUNET_NAT_Type) ntohl (res->type);
166   enum GNUNET_NAT_StatusCode status
167     = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code);
168
169   left = ntohs (res->header.size) - sizeof(*res);
170   cfg = GNUNET_CONFIGURATION_create ();
171   if (GNUNET_OK !=
172       GNUNET_CONFIGURATION_deserialize (cfg,
173                                         (const char *) &res[1],
174                                         left,
175                                         NULL))
176   {
177     GNUNET_break (0);
178     ah->arc (ah->arc_cls,
179              NULL,
180              GNUNET_NAT_ERROR_IPC_FAILURE,
181              type);
182   }
183   else
184   {
185     ah->arc (ah->arc_cls,
186              cfg,
187              status,
188              type);
189   }
190   GNUNET_CONFIGURATION_destroy (cfg);
191   GNUNET_NAT_AUTO_autoconfig_cancel (ah);
192 }
193
194
195 /**
196  * Handle queue errors by reporting autoconfiguration failure.
197  *
198  * @param cls the `struct GNUNET_NAT_AUTO_AutoHandle *`
199  * @param error details about the error
200  */
201 static void
202 ah_error_handler (void *cls,
203                   enum GNUNET_MQ_Error error)
204 {
205   struct GNUNET_NAT_AUTO_AutoHandle *ah = cls;
206
207   ah->arc (ah->arc_cls,
208            NULL,
209            GNUNET_NAT_ERROR_IPC_FAILURE,
210            GNUNET_NAT_TYPE_UNKNOWN);
211   GNUNET_NAT_AUTO_autoconfig_cancel (ah);
212 }
213
214
215 /**
216  * Start auto-configuration routine.  The transport adapters should
217  * be stopped while this function is called.
218  *
219  * @param cfg initial configuration
220  * @param cb function to call with autoconfiguration result
221  * @param cb_cls closure for @a cb
222  * @return handle to cancel operation
223  */
224 struct GNUNET_NAT_AUTO_AutoHandle *
225 GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
226                                   GNUNET_NAT_AUTO_AutoResultCallback cb,
227                                   void *cb_cls)
228 {
229   struct GNUNET_NAT_AUTO_AutoHandle *ah = GNUNET_new (struct
230                                                       GNUNET_NAT_AUTO_AutoHandle);
231   struct GNUNET_MQ_MessageHandler handlers[] = {
232     GNUNET_MQ_hd_var_size (auto_result,
233                            GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT,
234                            struct GNUNET_NAT_AUTO_AutoconfigResultMessage,
235                            ah),
236     GNUNET_MQ_handler_end ()
237   };
238   struct GNUNET_MQ_Envelope *env;
239   struct GNUNET_NAT_AUTO_AutoconfigRequestMessage *req;
240   char *buf;
241   size_t size;
242
243   buf = GNUNET_CONFIGURATION_serialize (cfg,
244                                         &size);
245   if (size > GNUNET_MAX_MESSAGE_SIZE - sizeof(*req))
246   {
247     GNUNET_break (0);
248     GNUNET_free (buf);
249     GNUNET_free (ah);
250     return NULL;
251   }
252   ah->arc = cb;
253   ah->arc_cls = cb_cls;
254   ah->mq = GNUNET_CLIENT_connect (cfg,
255                                   "nat",
256                                   handlers,
257                                   &ah_error_handler,
258                                   ah);
259   if (NULL == ah->mq)
260   {
261     GNUNET_break (0);
262     GNUNET_free (buf);
263     GNUNET_free (ah);
264     return NULL;
265   }
266   env = GNUNET_MQ_msg_extra (req,
267                              size,
268                              GNUNET_MESSAGE_TYPE_NAT_AUTO_REQUEST_CFG);
269   GNUNET_memcpy (&req[1],
270                  buf,
271                  size);
272   GNUNET_free (buf);
273   GNUNET_MQ_send (ah->mq,
274                   env);
275   return ah;
276 }
277
278
279 /**
280  * Abort autoconfiguration.
281  *
282  * @param ah handle for operation to abort
283  */
284 void
285 GNUNET_NAT_AUTO_autoconfig_cancel (struct GNUNET_NAT_AUTO_AutoHandle *ah)
286 {
287   GNUNET_MQ_destroy (ah->mq);
288   GNUNET_free (ah);
289 }
290
291
292 /* end of nat_api_auto.c */