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