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 */