Mercurial > pidgin
comparison libpurple/nat-pmp.c @ 15905:2cf21661f828
Cleanup and fixes for nat-pmp. We no longer do the whole 'try 10 times, doubling the delay in a blocking manner' ttempt from the original code; as I note in the comments above where the attempt is made a single time, this leads to about 8 minutes of nonresponsiveness if the router both doesn't support nat-pmp and doesn't send back a response to let the program know.
purple_pmp_create_map() and purple_pmp_destroy_map() now return a gboolean indicating success, as the internal data structures of nat-pmp are certainly not needed elsewhere.
The #includes are slightly reordered from the cleanup Mark did (thanks, Mark :) ), as with my OS X 10.3 cross-compiler, anyways, route.h needs to come after the sys includes to be properly handled.
author | Evan Schoenberg <evan.s@dreskin.net> |
---|---|
date | Sun, 25 Mar 2007 01:29:58 +0000 |
parents | 9cfe41743c65 |
children | 23c57ef2cf9f |
comparison
equal
deleted
inserted
replaced
15901:402236ee7981 | 15905:2cf21661f828 |
---|---|
30 | 30 |
31 #include "nat-pmp.h" | 31 #include "nat-pmp.h" |
32 #include "debug.h" | 32 #include "debug.h" |
33 | 33 |
34 #include <arpa/inet.h> | 34 #include <arpa/inet.h> |
35 #include <net/route.h> | |
36 #include <netinet/in.h> | 35 #include <netinet/in.h> |
36 #include <sys/types.h> | |
37 #include <sys/socket.h> | 37 #include <sys/socket.h> |
38 #include <sys/sysctl.h> | 38 #include <sys/sysctl.h> |
39 #include <sys/types.h> | 39 |
40 #include <net/route.h> | |
40 | 41 |
41 #include <netdb.h> | 42 #include <netdb.h> |
42 #include <stdio.h> | 43 #include <stdio.h> |
43 #include <stdlib.h> | 44 #include <stdlib.h> |
44 #include <string.h> | 45 #include <string.h> |
48 #include <sys/types.h> | 49 #include <sys/types.h> |
49 #include <net/if.h> | 50 #include <net/if.h> |
50 | 51 |
51 #ifdef NET_RT_DUMP2 | 52 #ifdef NET_RT_DUMP2 |
52 | 53 |
53 #define PMP_DEBUG 1 | 54 #define PMP_DEBUG 1 |
55 | |
56 typedef struct { | |
57 uint8_t version; | |
58 uint8_t opcode; | |
59 } PurplePmpIpRequest; | |
60 | |
61 typedef struct { | |
62 uint8_t version; | |
63 uint8_t opcode; // 128 + n | |
64 uint16_t resultcode; | |
65 uint32_t epoch; | |
66 uint32_t address; | |
67 } PurplePmpIpResponse; | |
68 | |
69 typedef struct { | |
70 uint8_t version; | |
71 uint8_t opcode; | |
72 char reserved[2]; | |
73 uint16_t privateport; | |
74 uint16_t publicport; | |
75 uint32_t lifetime; | |
76 } PurplePmpMapRequest; | |
77 | |
78 struct _PurplePmpMapResponse { | |
79 uint8_t version; | |
80 uint8_t opcode; | |
81 uint16_t resultcode; | |
82 uint32_t epoch; | |
83 uint16_t privateport; | |
84 uint16_t publicport; | |
85 uint32_t lifetime; | |
86 }; | |
87 | |
88 typedef struct _PurplePmpMapResponse PurplePmpMapResponse; | |
54 | 89 |
55 /* | 90 /* |
56 * Thanks to R. Matthew Emerson for the fixes on this | 91 * Thanks to R. Matthew Emerson for the fixes on this |
57 */ | 92 */ |
58 | 93 |
59 #define PMP_MAP_OPCODE_UDP 1 | 94 #define PMP_MAP_OPCODE_UDP 1 |
60 #define PMP_MAP_OPCODE_TCP 2 | 95 #define PMP_MAP_OPCODE_TCP 2 |
61 | 96 |
62 #define PMP_VERSION 0 | 97 #define PMP_VERSION 0 |
63 #define PMP_PORT 5351 | 98 #define PMP_PORT 5351 |
64 #define PMP_TIMEOUT 250000 // 250000 useconds | 99 #define PMP_TIMEOUT 250000 /* 250000 useconds */ |
65 | 100 |
66 /* alignment constraint for routing socket */ | 101 /* alignment constraint for routing socket */ |
67 #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | 102 #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
68 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) | 103 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |
69 | 104 |
195 | 230 |
196 return (found ? sin : NULL); | 231 return (found ? sin : NULL); |
197 } | 232 } |
198 | 233 |
199 /*! | 234 /*! |
200 * double_timeout(struct timeval *) will handle doubling a timeout for backoffs required by NAT-PMP | |
201 */ | |
202 static void | |
203 double_timeout(struct timeval *to) | |
204 { | |
205 int second = 1000000; // number of useconds | |
206 | |
207 to->tv_sec = (to->tv_sec * 2); | |
208 to->tv_usec = (to->tv_usec * 2); | |
209 | |
210 // Overflow useconds if necessary | |
211 if (to->tv_usec >= second) | |
212 { | |
213 int overflow = (to->tv_usec / second); | |
214 to->tv_usec = (to->tv_usec - (overflow * second)); | |
215 to->tv_sec = (to->tv_sec + overflow); | |
216 } | |
217 } | |
218 | |
219 /*! | |
220 * purple_pmp_get_public_ip() will return the publicly facing IP address of the | 235 * purple_pmp_get_public_ip() will return the publicly facing IP address of the |
221 * default NAT gateway. The function will return NULL if: | 236 * default NAT gateway. The function will return NULL if: |
222 * - The gateway doesn't support NAT-PMP | 237 * - The gateway doesn't support NAT-PMP |
223 * - The gateway errors in some other spectacular fashion | 238 * - The gateway errors in some other spectacular fashion |
224 */ | 239 */ |
225 char * | 240 char * |
226 purple_pmp_get_public_ip() | 241 purple_pmp_get_public_ip() |
227 { | 242 { |
228 struct sockaddr_in *gateway = default_gw(); | 243 struct sockaddr_in *gateway = default_gw(); |
229 | 244 |
230 if (gateway == NULL) | 245 if (!gateway) |
231 { | 246 { |
232 purple_debug_info("nat-pmp", "Cannot request public IP from a NULL gateway!\n"); | 247 purple_debug_info("nat-pmp", "Cannot request public IP from a NULL gateway!\n"); |
233 return NULL; | 248 return NULL; |
234 } | 249 } |
250 | |
251 /* Default port for NAT-PMP is 5351 */ | |
235 if (gateway->sin_port != PMP_PORT) | 252 if (gateway->sin_port != PMP_PORT) |
236 { | 253 gateway->sin_port = htons(PMP_PORT); |
237 gateway->sin_port = htons(PMP_PORT); // Default port for NAT-PMP is 5351 | |
238 } | |
239 | 254 |
240 int sendfd; | 255 int sendfd; |
241 int req_attempts = 1; | |
242 struct timeval req_timeout; | 256 struct timeval req_timeout; |
243 PurplePmpIpRequest req; | 257 PurplePmpIpRequest req; |
244 PurplePmpIpResponse resp; | 258 PurplePmpIpResponse resp; |
245 struct sockaddr_in *publicsockaddr = NULL; | 259 struct sockaddr_in *publicsockaddr = NULL; |
246 | 260 |
247 req_timeout.tv_sec = 0; | 261 req_timeout.tv_sec = 0; |
248 req_timeout.tv_usec = PMP_TIMEOUT; | 262 req_timeout.tv_usec = PMP_TIMEOUT; |
249 | 263 |
250 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | 264 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
251 | 265 |
252 // Clean out both req and resp structures | 266 /* Clean out both req and resp structures */ |
253 bzero(&req, sizeof(PurplePmpIpRequest)); | 267 bzero(&req, sizeof(PurplePmpIpRequest)); |
254 bzero(&resp, sizeof(PurplePmpIpResponse)); | 268 bzero(&resp, sizeof(PurplePmpIpResponse)); |
255 req.version = 0; | 269 req.version = 0; |
256 req.opcode = 0; | 270 req.opcode = 0; |
257 | 271 |
258 // Attempt to contact NAT-PMP device 9 times as per: draft-cheshire-nat-pmp-02.txt | 272 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
259 while (req_attempts < 10) | 273 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds. |
260 { | 274 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes). |
275 * | |
276 * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present. | |
277 * XXX Make this nonblocking. | |
278 */ | |
261 #ifdef PMP_DEBUG | 279 #ifdef PMP_DEBUG |
262 purple_debug_info("nat-pmp", "Attempting to retrieve the public ip address for the NAT device at: %s\n", inet_ntoa(gateway->sin_addr)); | 280 purple_debug_info("nat-pmp", "Attempting to retrieve the public ip address for the NAT device at: %s\n", inet_ntoa(gateway->sin_addr)); |
263 purple_debug_info("nat-pmp", "\tTimeout: %ds %dus, Request #: %d\n", req_timeout.tv_sec, req_timeout.tv_usec, req_attempts); | 281 purple_debug_info("nat-pmp", "\tTimeout: %ds %dus\n", req_timeout.tv_sec, req_timeout.tv_usec); |
264 #endif | 282 #endif |
265 struct sockaddr_in addr; | 283 struct sockaddr_in addr; |
266 socklen_t len = sizeof(struct sockaddr_in); | 284 socklen_t len = sizeof(struct sockaddr_in); |
267 | 285 |
268 /* TODO: Non-blocking! */ | 286 /* TODO: Non-blocking! */ |
269 if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0) | 287 if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0) |
288 { | |
289 purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", strerror(errno)); | |
290 g_free(gateway); | |
291 return NULL; | |
292 } | |
293 | |
294 if (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) < 0) | |
295 { | |
296 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); | |
297 g_free(gateway); | |
298 return NULL; | |
299 } | |
300 | |
301 /* TODO: Non-blocking! */ | |
302 if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0) | |
303 { | |
304 if (errno != EAGAIN) | |
270 { | 305 { |
271 purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP public IP request! (%s)\n", strerror(errno)); | 306 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); |
307 g_free(gateway); | |
272 return NULL; | 308 return NULL; |
273 } | 309 } |
274 | 310 } |
275 if (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) < 0) | 311 |
276 { | 312 if (addr.sin_addr.s_addr == gateway->sin_addr.s_addr) |
277 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); | 313 publicsockaddr = &addr; |
278 return NULL; | 314 else |
279 } | 315 { |
280 | 316 purple_debug_info("nat-pmp", "Response was not received from our gateway! Instead from: %s\n", inet_ntoa(addr.sin_addr)); |
281 /* TODO: Non-blocking! */ | |
282 if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0) | |
283 { | |
284 if ( (errno != EAGAIN) || (req_attempts == 9) ) | |
285 { | |
286 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); | |
287 return NULL; | |
288 } | |
289 else | |
290 { | |
291 goto iterate; | |
292 } | |
293 } | |
294 | |
295 if (addr.sin_addr.s_addr != gateway->sin_addr.s_addr) | |
296 { | |
297 purple_debug_info("nat-pmp", "Response was not received from our gateway! Instead from: %s\n", inet_ntoa(addr.sin_addr)); | |
298 goto iterate; | |
299 } | |
300 else | |
301 { | |
302 publicsockaddr = &addr; | |
303 break; | |
304 } | |
305 | |
306 iterate: | |
307 ++req_attempts; | |
308 double_timeout(&req_timeout); | |
309 } | |
310 | |
311 if (publicsockaddr == NULL) { | |
312 g_free(gateway); | 317 g_free(gateway); |
313 return NULL; | 318 return NULL; |
314 } | 319 } |
315 | 320 |
321 if (!publicsockaddr) { | |
322 g_free(gateway); | |
323 return NULL; | |
324 } | |
325 | |
316 #ifdef PMP_DEBUG | 326 #ifdef PMP_DEBUG |
317 purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n"); | 327 purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n"); |
318 purple_debug_info("nat-pmp", "version: %d\n", resp.version); | 328 purple_debug_info("nat-pmp", "version: %d\n", resp.version); |
319 purple_debug_info("nat-pmp", "opcode: %d\n", resp.opcode); | 329 purple_debug_info("nat-pmp", "opcode: %d\n", resp.opcode); |
320 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp.resultcode)); | 330 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp.resultcode)); |
329 g_free(gateway); | 339 g_free(gateway); |
330 | 340 |
331 return inet_ntoa(publicsockaddr->sin_addr); | 341 return inet_ntoa(publicsockaddr->sin_addr); |
332 } | 342 } |
333 | 343 |
334 /*! | 344 gboolean |
335 * will return NULL on error, or a pointer to the PurplePmpMapResponse type | 345 purple_pmp_create_map(PurplePmpType type, unsigned short privateport, unsigned short publicport, int lifetime) |
336 */ | 346 { |
337 PurplePmpMapResponse * | 347 struct sockaddr_in *gateway; |
338 purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime) | 348 gboolean success = TRUE; |
339 { | |
340 struct sockaddr_in *gateway = default_gw(); | |
341 | |
342 if (gateway == NULL) | |
343 { | |
344 purple_debug_info("nat-pmp", "Cannot create mapping on a NULL gateway!\n"); | |
345 return NULL; | |
346 } | |
347 if (gateway->sin_port != PMP_PORT) | |
348 { | |
349 gateway->sin_port = htons(PMP_PORT); // Default port for NAT-PMP is 5351 | |
350 } | |
351 | |
352 int sendfd; | 349 int sendfd; |
353 int req_attempts = 1; | |
354 struct timeval req_timeout; | 350 struct timeval req_timeout; |
355 PurplePmpMapRequest req; | 351 PurplePmpMapRequest req; |
356 PurplePmpMapResponse *resp = (PurplePmpMapResponse *)(malloc(sizeof(PurplePmpMapResponse))); | 352 PurplePmpMapResponse *resp; |
353 | |
354 gateway = default_gw(); | |
355 | |
356 if (!gateway) | |
357 { | |
358 purple_debug_info("nat-pmp", "Cannot create mapping on a NULL gateway!\n"); | |
359 return FALSE; | |
360 } | |
361 | |
362 /* Default port for NAT-PMP is 5351 */ | |
363 if (gateway->sin_port != PMP_PORT) | |
364 gateway->sin_port = htons(PMP_PORT); | |
365 | |
366 resp = g_new0(PurplePmpMapResponse, 1); | |
357 | 367 |
358 req_timeout.tv_sec = 0; | 368 req_timeout.tv_sec = 0; |
359 req_timeout.tv_usec = PMP_TIMEOUT; | 369 req_timeout.tv_usec = PMP_TIMEOUT; |
360 | 370 |
361 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | 371 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
362 | 372 |
363 // Clean out both req and resp structures | 373 /* Set up the req */ |
364 bzero(&req, sizeof(PurplePmpMapRequest)); | 374 bzero(&req, sizeof(PurplePmpMapRequest)); |
365 bzero(resp, sizeof(PurplePmpMapResponse)); | |
366 req.version = 0; | 375 req.version = 0; |
367 req.opcode = ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP); | 376 req.opcode = ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP); |
368 req.privateport = htons(privateport); // What a difference byte ordering makes...d'oh! | 377 req.privateport = htons(privateport); // What a difference byte ordering makes...d'oh! |
369 req.publicport = htons(publicport); | 378 req.publicport = htons(publicport); |
370 req.lifetime = htonl(lifetime); | 379 req.lifetime = htonl(lifetime); |
371 | 380 |
372 // Attempt to contact NAT-PMP device 9 times as per: draft-cheshire-nat-pmp-02.txt | 381 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
373 while (req_attempts < 10) | 382 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds. |
374 { | 383 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes). |
384 * | |
385 * This seems really silly... if this were nonblocking, a couple retries might be in order, but it's not at present. | |
386 * XXX Make this nonblocking. | |
387 * XXX This code looks like the pmp_get_public_ip() code. Can it be consolidated? | |
388 */ | |
375 #ifdef PMP_DEBUG | 389 #ifdef PMP_DEBUG |
376 purple_debug_info("nat-pmp", "Attempting to create a NAT-PMP mapping the private port %d, and the public port %d\n", privateport, publicport); | 390 purple_debug_info("nat-pmp", "Attempting to create a NAT-PMP mapping the private port %d, and the public port %d\n", privateport, publicport); |
377 purple_debug_info("nat-pmp", "\tTimeout: %ds %dus, Request #: %d\n", req_timeout.tv_sec, req_timeout.tv_usec, req_attempts); | 391 purple_debug_info("nat-pmp", "\tTimeout: %ds %dus\n", req_timeout.tv_sec, req_timeout.tv_usec); |
378 #endif | 392 #endif |
379 | 393 |
394 /* TODO: Non-blocking! */ | |
395 success = (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) >= 0); | |
396 if (!success) | |
397 purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP mapping request! (%s)\n", strerror(errno)); | |
398 | |
399 if (success) | |
400 { | |
401 success = (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) >= 0); | |
402 if (!success) | |
403 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); | |
404 } | |
405 | |
406 if (success) | |
407 { | |
408 /* The original code treats EAGAIN as a reason to iterate.. but I've removed iteration. This may be a problem */ | |
380 /* TODO: Non-blocking! */ | 409 /* TODO: Non-blocking! */ |
381 if (sendto(sendfd, &req, sizeof(req), 0, (struct sockaddr *)(gateway), sizeof(struct sockaddr)) < 0) | 410 success = ((recvfrom(sendfd, resp, sizeof(PurplePmpMapResponse), 0, NULL, NULL) >= 0) || |
382 { | 411 (errno == EAGAIN)); |
383 purple_debug_info("nat-pmp", "There was an error sending the NAT-PMP mapping request! (%s)\n", strerror(errno)); | 412 if (!success) |
384 return NULL; | 413 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); |
385 } | 414 } |
386 | 415 |
387 if (setsockopt(sendfd, SOL_SOCKET, SO_RCVTIMEO, &req_timeout, sizeof(req_timeout)) < 0) | 416 if (success) |
388 { | 417 { |
389 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); | 418 success = (resp->opcode == (req.opcode + 128)); |
390 return NULL; | 419 if (!success) |
391 } | |
392 | |
393 /* TODO: Non-blocking! */ | |
394 if (recvfrom(sendfd, resp, sizeof(PurplePmpMapResponse), 0, NULL, NULL) < 0) | |
395 { | |
396 if ( (errno != EAGAIN) || (req_attempts == 9) ) | |
397 { | |
398 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); | |
399 return NULL; | |
400 } | |
401 else | |
402 { | |
403 goto iterate; | |
404 } | |
405 } | |
406 | |
407 if (resp->opcode != (req.opcode + 128)) | |
408 { | |
409 purple_debug_info("nat-pmp", "The opcode for the response from the NAT device does not match the request opcode!\n"); | 420 purple_debug_info("nat-pmp", "The opcode for the response from the NAT device does not match the request opcode!\n"); |
410 goto iterate; | 421 } |
411 } | 422 |
412 | |
413 break; | |
414 | |
415 iterate: | |
416 ++req_attempts; | |
417 double_timeout(&req_timeout); | |
418 } | |
419 | |
420 #ifdef PMP_DEBUG | 423 #ifdef PMP_DEBUG |
421 purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n"); | 424 if (success) |
422 purple_debug_info("nat-pmp", "version: %d\n", resp->version); | 425 { |
423 purple_debug_info("nat-pmp", "opcode: %d\n", resp->opcode); | 426 purple_debug_info("nat-pmp", "Response received from NAT-PMP device:\n"); |
424 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp->resultcode)); | 427 purple_debug_info("nat-pmp", "version: %d\n", resp->version); |
425 purple_debug_info("nat-pmp", "epoch: %d\n", ntohl(resp->epoch)); | 428 purple_debug_info("nat-pmp", "opcode: %d\n", resp->opcode); |
426 purple_debug_info("nat-pmp", "privateport: %d\n", ntohs(resp->privateport)); | 429 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp->resultcode)); |
427 purple_debug_info("nat-pmp", "publicport: %d\n", ntohs(resp->publicport)); | 430 purple_debug_info("nat-pmp", "epoch: %d\n", ntohl(resp->epoch)); |
428 purple_debug_info("nat-pmp", "lifetime: %d\n", ntohl(resp->lifetime)); | 431 purple_debug_info("nat-pmp", "privateport: %d\n", ntohs(resp->privateport)); |
429 #endif | 432 purple_debug_info("nat-pmp", "publicport: %d\n", ntohs(resp->publicport)); |
430 | 433 purple_debug_info("nat-pmp", "lifetime: %d\n", ntohl(resp->lifetime)); |
434 } | |
435 #endif | |
436 | |
437 g_free(resp); | |
431 g_free(gateway); | 438 g_free(gateway); |
432 | 439 |
433 return resp; | 440 /* XXX The private port may actually differ from the one we requested, according to the spec. |
434 } | 441 * We don't handle that situation at present. |
435 | 442 * |
436 /*! | 443 * TODO: Look at the result and verify it matches what we wanted; either return a failure if it doesn't, |
437 * pmp_destroy_map(uint8_t,uint16_t) | 444 * or change network.c to know what to do if the desired private port shifts as a result of the nat-pmp operation. |
438 * will return NULL on error, or a pointer to the PurplePmpMapResponse type | 445 */ |
439 */ | 446 return success; |
440 PurplePmpMapResponse * | 447 } |
441 purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport) | 448 |
442 { | 449 gboolean |
443 PurplePmpMapResponse *response; | 450 purple_pmp_destroy_map(PurplePmpType type, unsigned short privateport) |
444 | 451 { |
445 response = purple_pmp_create_map(((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP), | 452 gboolean success; |
453 | |
454 success = purple_pmp_create_map(((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP), | |
446 privateport, 0, 0); | 455 privateport, 0, 0); |
447 if (!response) | 456 if (!success) |
448 { | 457 purple_debug_warning("nat-pmp", "Failed to properly destroy mapping for %d!\n", privateport); |
449 purple_debug_info("nat-pmp", "Failed to properly destroy mapping for %d!\n", privateport); | 458 |
450 return NULL; | 459 return success; |
451 } | |
452 else | |
453 { | |
454 return response; | |
455 } | |
456 } | 460 } |
457 #else /* #ifdef NET_RT_DUMP2 */ | 461 #else /* #ifdef NET_RT_DUMP2 */ |
458 char * | 462 char * |
459 purple_pmp_get_public_ip() | 463 purple_pmp_get_public_ip() |
460 { | 464 { |
461 return NULL; | 465 return NULL; |
462 } | 466 } |
463 | 467 |
464 PurplePmpMapResponse * | 468 gboolean |
465 purple_pmp_create_map(PurplePmpType type, uint16_t privateport, uint16_t publicport, uint32_t lifetime) | 469 purple_pmp_create_map(PurplePmpType type, unsigned short privateport, unsigned short publicport, int lifetime) |
466 { | 470 { |
467 return NULL; | 471 return NULL; |
468 } | 472 } |
469 | 473 |
470 PurplePmpMapResponse * | 474 gboolean |
471 purple_pmp_destroy_map(PurplePmpType type, uint16_t privateport) | 475 purple_pmp_destroy_map(PurplePmpType type, unsigned short privateport) |
472 { | 476 { |
473 return NULL; | 477 return NULL; |
474 } | 478 } |
475 #endif /* #ifndef NET_RT_DUMP2 */ | 479 #endif /* #ifndef NET_RT_DUMP2 */ |