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