| 208 /* We found the default route. Now get the destination address and netmask. */ |
208 /* We found the default route. Now get the destination address and netmask. */ |
| 209 struct sockaddr *rti_info[RTAX_MAX]; |
209 struct sockaddr *rti_info[RTAX_MAX]; |
| 210 struct sockaddr addr, mask; |
210 struct sockaddr addr, mask; |
| 211 |
211 |
| 212 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); |
212 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); |
| 213 bzero(&addr, sizeof(addr)); |
213 memset(&addr, 0, sizeof(addr)); |
| 214 |
214 |
| 215 if (rtm->rtm_addrs & RTA_DST) |
215 if (rtm->rtm_addrs & RTA_DST) |
| 216 bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len); |
216 memcpy(&addr, rti_info[RTAX_DST], sizeof(addr)); |
| 217 |
217 |
| 218 bzero(&mask, sizeof(mask)); |
218 memset(&mask, 0, sizeof(mask)); |
| 219 |
219 |
| 220 if (rtm->rtm_addrs & RTA_NETMASK) |
220 if (rtm->rtm_addrs & RTA_NETMASK) |
| 221 bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len); |
221 memcpy(&mask, rti_info[RTAX_NETMASK], sizeof(mask)); |
| 222 |
222 |
| 223 if (rtm->rtm_addrs & RTA_GATEWAY && |
223 if (rtm->rtm_addrs & RTA_GATEWAY && |
| 224 is_default_route(&addr, &mask)) |
224 is_default_route(&addr, &mask)) |
| 225 { |
225 { |
| 226 if (rti_info[RTAX_GATEWAY]) { |
226 if (rti_info[RTAX_GATEWAY]) { |
| 227 struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY]; |
227 struct sockaddr_in *rti_sin = (struct sockaddr_in *)rti_info[RTAX_GATEWAY]; |
| 228 sin = g_new0(struct sockaddr_in, 1); |
228 sin = g_new0(struct sockaddr_in, 1); |
| 229 sin->sin_family = rti_sin->sin_family; |
229 sin->sin_family = rti_sin->sin_family; |
| 230 sin->sin_port = rti_sin->sin_port; |
230 sin->sin_port = rti_sin->sin_port; |
| 289 req_timeout.tv_usec = PMP_TIMEOUT; |
289 req_timeout.tv_usec = PMP_TIMEOUT; |
| 290 |
290 |
| 291 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
291 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| 292 |
292 |
| 293 /* Clean out both req and resp structures */ |
293 /* Clean out both req and resp structures */ |
| 294 bzero(&req, sizeof(PurplePmpIpRequest)); |
294 memset(&req, 0, sizeof(PurplePmpIpRequest)); |
| 295 bzero(&resp, sizeof(PurplePmpIpResponse)); |
295 memset(&resp, 0, sizeof(PurplePmpIpResponse)); |
| 296 req.version = 0; |
296 req.version = 0; |
| 297 req.opcode = 0; |
297 req.opcode = 0; |
| 298 |
298 |
| 299 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
299 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
| 300 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds. |
300 * Even starting with a timeout of 0.1 seconds, that means that we have a total waiting of 204.6 seconds. |
| 301 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes). |
301 * With the recommended timeout of 0.25 seconds, we're talking 511.5 seconds (8.5 minutes). |
| 302 * |
302 * |
| 321 { |
321 { |
| 322 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); |
322 purple_debug_info("nat-pmp", "There was an error setting the socket's options! (%s)\n", strerror(errno)); |
| 323 g_free(gateway); |
323 g_free(gateway); |
| 324 pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; |
324 pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; |
| 325 return NULL; |
325 return NULL; |
| 326 } |
326 } |
| 327 |
327 |
| 328 /* TODO: Non-blocking! */ |
328 /* TODO: Non-blocking! */ |
| 329 len = sizeof(struct sockaddr_in); |
329 len = sizeof(struct sockaddr_in); |
| 330 if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0) |
330 if (recvfrom(sendfd, &resp, sizeof(PurplePmpIpResponse), 0, (struct sockaddr *)(&addr), &len) < 0) |
| 331 { |
331 { |
| 332 if (errno != EAGAIN) |
332 if (errno != EAGAIN) |
| 333 { |
333 { |
| 334 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); |
334 purple_debug_info("nat-pmp", "There was an error receiving the response from the NAT-PMP device! (%s)\n", strerror(errno)); |
| 335 g_free(gateway); |
335 g_free(gateway); |
| 336 pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; |
336 pmp_info.status = PURPLE_PMP_STATUS_UNABLE_TO_DISCOVER; |
| 363 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp.resultcode)); |
363 purple_debug_info("nat-pmp", "resultcode: %d\n", ntohs(resp.resultcode)); |
| 364 purple_debug_info("nat-pmp", "epoch: %d\n", ntohl(resp.epoch)); |
364 purple_debug_info("nat-pmp", "epoch: %d\n", ntohl(resp.epoch)); |
| 365 struct in_addr in; |
365 struct in_addr in; |
| 366 in.s_addr = resp.address; |
366 in.s_addr = resp.address; |
| 367 purple_debug_info("nat-pmp", "address: %s\n", inet_ntoa(in)); |
367 purple_debug_info("nat-pmp", "address: %s\n", inet_ntoa(in)); |
| 368 #endif |
368 #endif |
| 369 |
369 |
| 370 publicsockaddr->sin_addr.s_addr = resp.address; |
370 publicsockaddr->sin_addr.s_addr = resp.address; |
| 371 |
371 |
| 372 g_free(gateway); |
372 g_free(gateway); |
| 373 |
373 |
| 406 req_timeout.tv_usec = PMP_TIMEOUT; |
406 req_timeout.tv_usec = PMP_TIMEOUT; |
| 407 |
407 |
| 408 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
408 sendfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| 409 |
409 |
| 410 /* Set up the req */ |
410 /* Set up the req */ |
| 411 bzero(&req, sizeof(PurplePmpMapRequest)); |
411 memset(&req, 0, sizeof(PurplePmpMapRequest)); |
| 412 req.version = 0; |
412 req.version = 0; |
| 413 req.opcode = ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP); |
413 req.opcode = ((type == PURPLE_PMP_TYPE_UDP) ? PMP_MAP_OPCODE_UDP : PMP_MAP_OPCODE_TCP); |
| 414 req.privateport = htons(privateport); /* What a difference byte ordering makes...d'oh! */ |
414 req.privateport = htons(privateport); /* What a difference byte ordering makes...d'oh! */ |
| 415 req.publicport = htons(publicport); |
415 req.publicport = htons(publicport); |
| 416 req.lifetime = htonl(lifetime); |
416 req.lifetime = htonl(lifetime); |
| 417 |
417 |
| 418 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
418 /* The NAT-PMP spec says we should attempt to contact the gateway 9 times, doubling the time we wait each time. |
| 507 static void* |
507 static void* |
| 508 purple_pmp_get_handle(void) |
508 purple_pmp_get_handle(void) |
| 509 { |
509 { |
| 510 static int handle; |
510 static int handle; |
| 511 |
511 |
| 512 return &handle; |
512 return &handle; |
| 513 } |
513 } |
| 514 |
514 |
| 515 void |
515 void |
| 516 purple_pmp_init() |
516 purple_pmp_init() |
| 517 { |
517 { |
| 518 purple_signal_connect(purple_network_get_handle(), "network-configuration-changed", |
518 purple_signal_connect(purple_network_get_handle(), "network-configuration-changed", |
| 519 purple_pmp_get_handle(), PURPLE_CALLBACK(purple_pmp_network_config_changed_cb), |
519 purple_pmp_get_handle(), PURPLE_CALLBACK(purple_pmp_network_config_changed_cb), |
| 520 GINT_TO_POINTER(0)); |
520 GINT_TO_POINTER(0)); |
| 521 } |
521 } |
| 522 #else /* #ifdef NET_RT_DUMP */ |
522 #else /* #ifdef NET_RT_DUMP */ |
| 523 char * |
523 char * |
| 524 purple_pmp_get_public_ip() |
524 purple_pmp_get_public_ip() |
| 525 { |
525 { |