diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-07-08 11:30:01 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-07-08 11:30:01 +0000 |
commit | ceefc6de0ed40c33a644c571422d0b558aa851ca (patch) | |
tree | bb2da9ec2e03367377cf8d9da7a7e566716e01ea /src/nat/nat_mini.c | |
parent | f2e1a736377f59b2f7f12b0dcfc8c73e6e80e897 (diff) | |
download | gnunet-ceefc6de0ed40c33a644c571422d0b558aa851ca.tar.gz gnunet-ceefc6de0ed40c33a644c571422d0b558aa851ca.zip |
mini works
Diffstat (limited to 'src/nat/nat_mini.c')
-rw-r--r-- | src/nat/nat_mini.c | 140 |
1 files changed, 121 insertions, 19 deletions
diff --git a/src/nat/nat_mini.c b/src/nat/nat_mini.c index 2e4dd1a38..38dcfcd1f 100644 --- a/src/nat/nat_mini.c +++ b/src/nat/nat_mini.c | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file nat/nat_mini.c | 22 | * @file nat/nat_mini.c |
23 | * @brief functions for interaction with miniupnp | 23 | * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
@@ -33,7 +33,6 @@ | |||
33 | */ | 33 | */ |
34 | #define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | 34 | #define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) |
35 | 35 | ||
36 | |||
37 | /** | 36 | /** |
38 | * How long do we give upnpc to remove a mapping? | 37 | * How long do we give upnpc to remove a mapping? |
39 | */ | 38 | */ |
@@ -42,7 +41,7 @@ | |||
42 | /** | 41 | /** |
43 | * How often do we check for changes in the mapping? | 42 | * How often do we check for changes in the mapping? |
44 | */ | 43 | */ |
45 | #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | 44 | #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) |
46 | 45 | ||
47 | 46 | ||
48 | /** | 47 | /** |
@@ -158,6 +157,11 @@ struct GNUNET_NAT_MiniHandle | |||
158 | int did_map; | 157 | int did_map; |
159 | 158 | ||
160 | /** | 159 | /** |
160 | * Did we find our mapping during refresh scan? | ||
161 | */ | ||
162 | int found; | ||
163 | |||
164 | /** | ||
161 | * Which port are we mapping? | 165 | * Which port are we mapping? |
162 | */ | 166 | */ |
163 | uint16_t port; | 167 | uint16_t port; |
@@ -177,6 +181,17 @@ do_refresh (void *cls, | |||
177 | 181 | ||
178 | 182 | ||
179 | /** | 183 | /** |
184 | * Process the output from the 'upnpc -r' command. | ||
185 | * | ||
186 | * @param cls the 'struct GNUNET_NAT_MiniHandle' | ||
187 | * @param line line of output, NULL at the end | ||
188 | */ | ||
189 | static void | ||
190 | process_map_output (void *cls, | ||
191 | const char *line); | ||
192 | |||
193 | |||
194 | /** | ||
180 | * Process the output from 'upnpc -l' to see if our | 195 | * Process the output from 'upnpc -l' to see if our |
181 | * external mapping changed. If so, do the notifications. | 196 | * external mapping changed. If so, do the notifications. |
182 | * | 197 | * |
@@ -188,20 +203,105 @@ process_refresh_output (void *cls, | |||
188 | const char *line) | 203 | const char *line) |
189 | { | 204 | { |
190 | struct GNUNET_NAT_MiniHandle *mini = cls; | 205 | struct GNUNET_NAT_MiniHandle *mini = cls; |
206 | char pstr[9]; | ||
207 | const char *s; | ||
208 | unsigned int nport; | ||
209 | struct in_addr exip; | ||
191 | 210 | ||
192 | if (NULL == line) | 211 | if (NULL == line) |
193 | { | 212 | { |
194 | GNUNET_OS_command_stop (mini->refresh_cmd); | 213 | GNUNET_OS_command_stop (mini->refresh_cmd); |
195 | mini->refresh_cmd = NULL; | 214 | mini->refresh_cmd = NULL; |
215 | if (mini->found == GNUNET_NO) | ||
216 | { | ||
217 | /* mapping disappeared, try to re-create */ | ||
218 | if (mini->did_map) | ||
219 | { | ||
220 | mini->ac (mini->ac_cls, GNUNET_NO, | ||
221 | (const struct sockaddr*) &mini->current_addr, | ||
222 | sizeof (mini->current_addr)); | ||
223 | mini->did_map = GNUNET_NO; | ||
224 | } | ||
225 | GNUNET_snprintf (pstr, sizeof (pstr), | ||
226 | "%u", | ||
227 | (unsigned int) mini->port); | ||
228 | mini->map_cmd = GNUNET_OS_command_run (&process_map_output, | ||
229 | mini, | ||
230 | MAP_TIMEOUT, | ||
231 | "upnpc", | ||
232 | "upnpc", | ||
233 | "-r", pstr, | ||
234 | mini->is_tcp ? "tcp" : "udp", | ||
235 | NULL); | ||
236 | if (NULL != mini->map_cmd) | ||
237 | return; | ||
238 | } | ||
196 | mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | 239 | mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, |
197 | &do_refresh, | 240 | &do_refresh, |
198 | mini); | 241 | mini); |
199 | return; | 242 | return; |
200 | } | 243 | } |
201 | /* FIXME: parse 'line' */ | 244 | if (! mini->did_map) |
202 | fprintf (stderr, | 245 | return; /* never mapped, won't find our mapping anyway */ |
203 | "Refresh output: `%s'\n", | 246 | |
204 | line); | 247 | /* we're looking for output of the form: |
248 | "ExternalIPAddress = 12.134.41.124" */ | ||
249 | |||
250 | s = strstr (line, "ExternalIPAddress = "); | ||
251 | if (NULL != s) | ||
252 | { | ||
253 | s += strlen ("ExternalIPAddress = "); | ||
254 | if (1 != inet_pton (AF_INET, | ||
255 | s, &exip)) | ||
256 | return; /* skip */ | ||
257 | if (exip.s_addr == mini->current_addr.sin_addr.s_addr) | ||
258 | return; /* no change */ | ||
259 | /* update mapping */ | ||
260 | mini->ac (mini->ac_cls, GNUNET_NO, | ||
261 | (const struct sockaddr*) &mini->current_addr, | ||
262 | sizeof (mini->current_addr)); | ||
263 | mini->current_addr.sin_addr = exip; | ||
264 | mini->ac (mini->ac_cls, GNUNET_YES, | ||
265 | (const struct sockaddr*) &mini->current_addr, | ||
266 | sizeof (mini->current_addr)); | ||
267 | return; | ||
268 | } | ||
269 | /* | ||
270 | we're looking for output of the form: | ||
271 | |||
272 | "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''" | ||
273 | "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''" | ||
274 | |||
275 | the pattern we look for is: | ||
276 | |||
277 | "%s TCP PORT->STRING:OURPORT *" or | ||
278 | "%s UDP PORT->STRING:OURPORT *" | ||
279 | */ | ||
280 | GNUNET_snprintf (pstr, sizeof (pstr), | ||
281 | ":%u ", | ||
282 | mini->port); | ||
283 | if (NULL == (s = strstr (line, "->"))) | ||
284 | return; /* skip */ | ||
285 | if (NULL == (s = strstr (s, pstr))) | ||
286 | return; /* skip */ | ||
287 | if (1 != sscanf (line, | ||
288 | (mini->is_tcp) | ||
289 | ? "%*u TCP %u->%*s:%*u %*s" | ||
290 | : "%*u UDP %u->%*s:%*u %*s", | ||
291 | &nport)) | ||
292 | return; /* skip */ | ||
293 | mini->found = GNUNET_YES; | ||
294 | if (nport == ntohs (mini->current_addr.sin_port)) | ||
295 | return; /* no change */ | ||
296 | |||
297 | /* external port changed, update mapping */ | ||
298 | mini->ac (mini->ac_cls, GNUNET_NO, | ||
299 | (const struct sockaddr*) &mini->current_addr, | ||
300 | sizeof (mini->current_addr)); | ||
301 | mini->current_addr.sin_port = htons ((uint16_t) nport); | ||
302 | mini->ac (mini->ac_cls, GNUNET_YES, | ||
303 | (const struct sockaddr*) &mini->current_addr, | ||
304 | sizeof (mini->current_addr)); | ||
205 | } | 305 | } |
206 | 306 | ||
207 | 307 | ||
@@ -218,6 +318,7 @@ do_refresh (void *cls, | |||
218 | struct GNUNET_NAT_MiniHandle *mini = cls; | 318 | struct GNUNET_NAT_MiniHandle *mini = cls; |
219 | 319 | ||
220 | mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; | 320 | mini->refresh_task = GNUNET_SCHEDULER_NO_TASK; |
321 | mini->found = GNUNET_NO; | ||
221 | mini->refresh_cmd = GNUNET_OS_command_run (&process_refresh_output, | 322 | mini->refresh_cmd = GNUNET_OS_command_run (&process_refresh_output, |
222 | mini, | 323 | mini, |
223 | MAP_TIMEOUT, | 324 | MAP_TIMEOUT, |
@@ -248,10 +349,9 @@ process_map_output (void *cls, | |||
248 | { | 349 | { |
249 | GNUNET_OS_command_stop (mini->map_cmd); | 350 | GNUNET_OS_command_stop (mini->map_cmd); |
250 | mini->map_cmd = NULL; | 351 | mini->map_cmd = NULL; |
251 | if (mini->did_map == GNUNET_YES) | 352 | mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, |
252 | mini->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | 353 | &do_refresh, |
253 | &do_refresh, | 354 | mini); |
254 | mini); | ||
255 | return; | 355 | return; |
256 | } | 356 | } |
257 | /* | 357 | /* |
@@ -263,9 +363,6 @@ process_map_output (void *cls, | |||
263 | (NULL == (pstr = strstr (ipaddr, ":"))) || | 363 | (NULL == (pstr = strstr (ipaddr, ":"))) || |
264 | (1 != sscanf (pstr + 1, "%u", &port)) ) | 364 | (1 != sscanf (pstr + 1, "%u", &port)) ) |
265 | { | 365 | { |
266 | fprintf (stderr, | ||
267 | "Skipping output `%s'\n", | ||
268 | line); | ||
269 | return; /* skip line */ | 366 | return; /* skip line */ |
270 | } | 367 | } |
271 | ipa = GNUNET_strdup (ipaddr + 1); | 368 | ipa = GNUNET_strdup (ipaddr + 1); |
@@ -275,9 +372,6 @@ process_map_output (void *cls, | |||
275 | &mini->current_addr.sin_addr)) | 372 | &mini->current_addr.sin_addr)) |
276 | { | 373 | { |
277 | GNUNET_free (ipa); | 374 | GNUNET_free (ipa); |
278 | fprintf (stderr, | ||
279 | "Skipping output `%s'\n", | ||
280 | line); | ||
281 | return; /* skip line */ | 375 | return; /* skip line */ |
282 | } | 376 | } |
283 | GNUNET_free (ipa); | 377 | GNUNET_free (ipa); |
@@ -332,7 +426,12 @@ GNUNET_NAT_mini_map_start (uint16_t port, | |||
332 | "-r", pstr, | 426 | "-r", pstr, |
333 | is_tcp ? "tcp" : "udp", | 427 | is_tcp ? "tcp" : "udp", |
334 | NULL); | 428 | NULL); |
335 | 429 | if (NULL != ret->map_cmd) | |
430 | return ret; | ||
431 | ret->refresh_task = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | ||
432 | &do_refresh, | ||
433 | ret); | ||
434 | |||
336 | return ret; | 435 | return ret; |
337 | } | 436 | } |
338 | 437 | ||
@@ -396,9 +495,12 @@ GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini) | |||
396 | mini->ac (mini->ac_cls, GNUNET_NO, | 495 | mini->ac (mini->ac_cls, GNUNET_NO, |
397 | (const struct sockaddr*) &mini->current_addr, | 496 | (const struct sockaddr*) &mini->current_addr, |
398 | sizeof (mini->current_addr)); | 497 | sizeof (mini->current_addr)); |
498 | /* Note: oddly enough, deletion uses the external port whereas | ||
499 | addition uses the internal port; this rarely matters since they | ||
500 | often are the same, but it might... */ | ||
399 | GNUNET_snprintf (pstr, sizeof (pstr), | 501 | GNUNET_snprintf (pstr, sizeof (pstr), |
400 | "%u", | 502 | "%u", |
401 | (unsigned int) mini->port); | 503 | (unsigned int) mini->current_addr.sin_port); |
402 | mini->unmap_cmd = GNUNET_OS_command_run (&process_unmap_output, | 504 | mini->unmap_cmd = GNUNET_OS_command_run (&process_unmap_output, |
403 | mini, | 505 | mini, |
404 | UNMAP_TIMEOUT, | 506 | UNMAP_TIMEOUT, |