Mercurial > pidgin
comparison src/proxy.c @ 9657:51464cbbdc1a
[gaim-migrate @ 10505]
I fixed my bug from an hour ago, cleaned up a few more things, and
separated the code for the dns lookup child into a function. You know,
functions? The things that make code suck less?
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Wed, 04 Aug 2004 01:51:22 +0000 |
| parents | 2ea77e275b85 |
| children | f44ae9331afc |
comparison
equal
deleted
inserted
replaced
| 9656:2ea77e275b85 | 9657:51464cbbdc1a |
|---|---|
| 415 gethostbyname("x.x.x.x.x"); | 415 gethostbyname("x.x.x.x.x"); |
| 416 } | 416 } |
| 417 #endif | 417 #endif |
| 418 } | 418 } |
| 419 | 419 |
| 420 static void | |
| 421 gaim_dns_childthread(int child_out, int child_in, dns_params_t *dns_params) | |
| 422 { | |
| 423 const int zero = 0; | |
| 424 int rc; | |
| 425 #if HAVE_GETADDRINFO | |
| 426 struct addrinfo hints, *res, *tmp; | |
| 427 char servname[20]; | |
| 428 #else | |
| 429 struct sockaddr_in sin; | |
| 430 const size_t addrlen = sizeof(sin); | |
| 431 #endif | |
| 432 | |
| 433 #ifdef HAVE_SIGNAL_H | |
| 434 signal(SIGHUP, SIG_DFL); | |
| 435 signal(SIGINT, SIG_DFL); | |
| 436 signal(SIGQUIT, SIG_DFL); | |
| 437 signal(SIGCHLD, SIG_DFL); | |
| 438 signal(SIGTERM, SIG_DFL); | |
| 439 signal(SIGTRAP, trap_gdb_bug); | |
| 440 #endif | |
| 441 | |
| 442 while (1) { | |
| 443 if (dns_params->hostname[0] == '\0') { | |
| 444 const char Y = 'Y'; | |
| 445 fd_set fds; | |
| 446 struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; | |
| 447 FD_ZERO(&fds); | |
| 448 FD_SET(child_in, &fds); | |
| 449 rc = select(child_in + 1, &fds, NULL, NULL, &tv); | |
| 450 if (!rc) { | |
| 451 if (opt_debug) | |
| 452 fprintf(stderr,"dns[%d]: nobody needs me... =(\n", getpid()); | |
| 453 break; | |
| 454 } | |
| 455 rc = read(child_in, dns_params, sizeof(dns_params_t)); | |
| 456 if (rc < 0) { | |
| 457 perror("read()"); | |
| 458 break; | |
| 459 } | |
| 460 if (rc==0) { | |
| 461 if(opt_debug) | |
| 462 fprintf(stderr,"dns[%d]: Ops, father has gone, wait for me, wait...!\n", getpid()); | |
| 463 _exit(0); | |
| 464 } | |
| 465 if (dns_params->hostname[0] == '\0') { | |
| 466 fprintf(stderr, "dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params->port); | |
| 467 _exit(1); | |
| 468 } | |
| 469 write(child_out, &Y, 1); | |
| 470 } | |
| 471 | |
| 472 #if HAVE_GETADDRINFO | |
| 473 g_snprintf(servname, sizeof(servname), "%d", dns_params->port); | |
| 474 memset(&hints,0,sizeof(hints)); | |
| 475 | |
| 476 /* This is only used to convert a service | |
| 477 * name to a port number. As we know we are | |
| 478 * passing a number already, we know this | |
| 479 * value will not be really used by the C | |
| 480 * library. | |
| 481 */ | |
| 482 hints.ai_socktype = SOCK_STREAM; | |
| 483 rc = getaddrinfo(dns_params->hostname, servname, &hints, &res); | |
| 484 if(rc) { | |
| 485 write(child_out, &rc, sizeof(int)); | |
| 486 close(child_out); | |
| 487 if(opt_debug) | |
| 488 fprintf(stderr,"dns[%d] Error: getaddrinfo returned %d\n", | |
| 489 getpid(), rc); | |
| 490 dns_params->hostname[0] = '\0'; | |
| 491 continue; | |
| 492 } | |
| 493 write(child_out, &zero, sizeof(zero)); | |
| 494 tmp = res; | |
| 495 while(res) { | |
| 496 size_t ai_addrlen = res->ai_addrlen; | |
| 497 write(child_out, &ai_addrlen, sizeof(ai_addrlen)); | |
| 498 write(child_out, res->ai_addr, res->ai_addrlen); | |
| 499 res = res->ai_next; | |
| 500 } | |
| 501 freeaddrinfo(tmp); | |
| 502 write(child_out, &zero, sizeof(zero)); | |
| 503 #else | |
| 504 if (!inet_aton(hostname, &sin.sin_addr)) { | |
| 505 struct hostent *hp; | |
| 506 if(!(hp = gethostbyname(dns_params->hostname))) { | |
| 507 write(child_out, &h_errno, sizeof(int)); | |
| 508 close(child_out); | |
| 509 if(opt_debug) | |
| 510 fprintf(stderr,"DNS Error: %d\n", h_errno); | |
| 511 _exit(0); | |
| 512 } | |
| 513 memset(&sin, 0, sizeof(struct sockaddr_in)); | |
| 514 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | |
| 515 sin.sin_family = hp->h_addrtype; | |
| 516 } else | |
| 517 sin.sin_family = AF_INET; | |
| 518 | |
| 519 sin.sin_port = htons(dns_params->port); | |
| 520 write(child_out, &zero, sizeof(zero)); | |
| 521 write(child_out, &addrlen, sizeof(addrlen)); | |
| 522 write(child_out, &sin, addrlen); | |
| 523 write(child_out, &zero, sizeof(zero)); | |
| 524 #endif | |
| 525 dns_params->hostname[0] = '\0'; | |
| 526 } | |
| 527 | |
| 528 close(child_out); | |
| 529 close(child_in); | |
| 530 | |
| 531 _exit(0); | |
| 532 } | |
| 533 | |
| 420 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) | 534 int gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) |
| 421 { | 535 { |
| 422 pending_dns_request_t *req = NULL; | 536 pending_dns_request_t *req = NULL; |
| 423 dns_params_t dns_params; | 537 dns_params_t dns_params; |
| 424 gchar *host_temp; | 538 gchar *host_temp; |
| 442 if (send_dns_request_to_child(req, &dns_params) == 0) | 556 if (send_dns_request_to_child(req, &dns_params) == 0) |
| 443 /* We found an acceptable child, yay */ | 557 /* We found an acceptable child, yay */ |
| 444 break; | 558 break; |
| 445 | 559 |
| 446 req_free(req); | 560 req_free(req); |
| 447 } | 561 req = NULL; |
| 448 | 562 } |
| 449 /* | 563 |
| 450 * We need to create a new DNS request child. | 564 /* We need to create a new DNS request child */ |
| 451 */ | |
| 452 if (req == NULL) { | 565 if (req == NULL) { |
| 453 int child_out[2], child_in[2]; | 566 int child_out[2], child_in[2]; |
| 454 | 567 |
| 455 if (number_of_dns_children >= MAX_DNS_CHILDREN) { | 568 if (number_of_dns_children >= MAX_DNS_CHILDREN) { |
| 456 queued_dns_request_t *r = g_new(queued_dns_request_t, 1); | 569 queued_dns_request_t *r = g_new(queued_dns_request_t, 1); |
| 465 "DNS query for '%s' queued\n", dns_params.hostname); | 578 "DNS query for '%s' queued\n", dns_params.hostname); |
| 466 | 579 |
| 467 return 0; | 580 return 0; |
| 468 } | 581 } |
| 469 | 582 |
| 583 /* Create pipes for communicating with the child process */ | |
| 470 if (pipe(child_out) || pipe(child_in)) { | 584 if (pipe(child_out) || pipe(child_in)) { |
| 471 gaim_debug(GAIM_DEBUG_ERROR, "dns", | 585 gaim_debug(GAIM_DEBUG_ERROR, "dns", |
| 472 "Could not create pipes: %s\n", strerror(errno)); | 586 "Could not create pipes: %s\n", strerror(errno)); |
| 473 return -1; | 587 return -1; |
| 474 } | 588 } |
| 475 | 589 |
| 476 /* We need to create a new child. */ | 590 req = g_new(pending_dns_request_t, 1); |
| 477 req = g_new(pending_dns_request_t,1); | |
| 478 | 591 |
| 479 cope_with_gdb_brokenness(); | 592 cope_with_gdb_brokenness(); |
| 480 | 593 |
| 594 /* Fork! */ | |
| 481 req->dns_pid = fork(); | 595 req->dns_pid = fork(); |
| 482 | 596 |
| 483 /* If we are a child... */ | 597 /* If we are the child process... */ |
| 484 if (req->dns_pid == 0) { | 598 if (req->dns_pid==0) { |
| 485 const int zero = 0; | |
| 486 int rc; | |
| 487 | |
| 488 #if HAVE_GETADDRINFO | |
| 489 struct addrinfo hints, *res, *tmp; | |
| 490 char servname[20]; | |
| 491 #else | |
| 492 struct sockaddr_in sin; | |
| 493 const size_t addrlen = sizeof(sin); | |
| 494 #endif | |
| 495 #ifdef HAVE_SIGNAL_H | |
| 496 signal(SIGHUP, SIG_DFL); | |
| 497 signal(SIGINT, SIG_DFL); | |
| 498 signal(SIGQUIT, SIG_DFL); | |
| 499 signal(SIGCHLD, SIG_DFL); | |
| 500 signal(SIGTERM, SIG_DFL); | |
| 501 signal(SIGTRAP, trap_gdb_bug); | |
| 502 #endif | |
| 503 | |
| 504 /* We should not access the parent's side of the pipe, so close them... */ | 599 /* We should not access the parent's side of the pipe, so close them... */ |
| 505 close(child_out[0]); | 600 close(child_out[0]); |
| 506 close(child_in[1]); | 601 close(child_in[1]); |
| 507 | 602 |
| 508 while (1) { | 603 gaim_dns_childthread(child_out[1], child_in[0], &dns_params); |
| 509 if (dns_params.hostname[0] == '\0') { | 604 /* The thread calls _exit() rather than returning, so we never get here */ |
| 510 const char Y = 'Y'; | 605 } |
| 511 fd_set fds; | |
| 512 struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 }; | |
| 513 FD_ZERO(&fds); | |
| 514 FD_SET(child_in[0], &fds); | |
| 515 rc = select(child_in[0]+1, &fds, NULL, NULL, &tv); | |
| 516 if (!rc) { | |
| 517 if (opt_debug) | |
| 518 fprintf(stderr,"dns[%d]: Nobody needs me... =(\n", getpid()); | |
| 519 break; | |
| 520 } | |
| 521 rc = read(child_in[0], &dns_params, sizeof(dns_params)); | |
| 522 if (rc < 0) { | |
| 523 perror("read()"); | |
| 524 break; | |
| 525 } | |
| 526 if (rc==0) { | |
| 527 if (opt_debug) | |
| 528 fprintf(stderr,"dns[%d]: Father has gone, wait for me, wait...!\n", getpid()); | |
| 529 _exit(0); | |
| 530 } | |
| 531 if (dns_params.hostname[0] == '\0') { | |
| 532 fprintf(stderr, "dns[%d]: Hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port); | |
| 533 _exit(1); | |
| 534 } | |
| 535 write(child_out[1], &Y, 1); | |
| 536 } | |
| 537 | |
| 538 #if HAVE_GETADDRINFO | |
| 539 g_snprintf(servname, sizeof(servname), "%d", dns_params.port); | |
| 540 memset(&hints,0,sizeof(hints)); | |
| 541 | |
| 542 /* This is only used to convert a service | |
| 543 * name to a port number. As we know we are | |
| 544 * passing a number already, we know this | |
| 545 * value will not be really used by the C | |
| 546 * library. | |
| 547 */ | |
| 548 hints.ai_socktype = SOCK_STREAM; | |
| 549 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res); | |
| 550 if (rc) { | |
| 551 write(child_out[1], &rc, sizeof(int)); | |
| 552 close(child_out[1]); | |
| 553 if (opt_debug) | |
| 554 fprintf(stderr,"dns[%d] Error: getaddrinfo returned %d\n", | |
| 555 getpid(), rc); | |
| 556 dns_params.hostname[0] = '\0'; | |
| 557 continue; | |
| 558 } | |
| 559 write(child_out[1], &zero, sizeof(zero)); | |
| 560 tmp = res; | |
| 561 while (res) { | |
| 562 size_t ai_addrlen = res->ai_addrlen; | |
| 563 write(child_out[1], &ai_addrlen, sizeof(ai_addrlen)); | |
| 564 write(child_out[1], res->ai_addr, res->ai_addrlen); | |
| 565 res = res->ai_next; | |
| 566 } | |
| 567 freeaddrinfo(tmp); | |
| 568 write(child_out[1], &zero, sizeof(zero)); | |
| 569 #else | |
| 570 /* XXX - Should hostname be changed to dns_params.hostname? */ | |
| 571 if (!inet_aton(hostname, &sin.sin_addr)) { | |
| 572 struct hostent *hp; | |
| 573 if (!(hp = gethostbyname(dns_params.hostname))) { | |
| 574 write(child_out[1], &h_errno, sizeof(int)); | |
| 575 close(child_out[1]); | |
| 576 if (opt_debug) | |
| 577 fprintf(stderr,"DNS Error: %d\n", h_errno); | |
| 578 _exit(0); | |
| 579 } | |
| 580 memset(&sin, 0, sizeof(struct sockaddr_in)); | |
| 581 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | |
| 582 sin.sin_family = hp->h_addrtype; | |
| 583 } else | |
| 584 sin.sin_family = AF_INET; | |
| 585 sin.sin_port = htons(dns_params.port); | |
| 586 write(child_out[1], &zero, sizeof(zero)); | |
| 587 write(child_out[1], &addrlen, sizeof(addrlen)); | |
| 588 write(child_out[1], &sin, addrlen); | |
| 589 write(child_out[1], &zero, sizeof(zero)); | |
| 590 #endif | |
| 591 dns_params.hostname[0] = '\0'; | |
| 592 } | |
| 593 close(child_out[1]); | |
| 594 close(child_in[0]); | |
| 595 _exit(0); | |
| 596 } /* End of child process */ | |
| 597 | 606 |
| 598 /* We should not access the child's side of the pipe, so close them... */ | 607 /* We should not access the child's side of the pipe, so close them... */ |
| 599 close(child_out[1]); | 608 close(child_out[1]); |
| 600 close(child_in[0]); | 609 close(child_in[0]); |
| 601 if (req->dns_pid==-1) { | 610 if (req->dns_pid == -1) { |
| 602 gaim_debug(GAIM_DEBUG_ERROR, "dns", | 611 gaim_debug(GAIM_DEBUG_ERROR, "dns", |
| 603 "Could not create child process for DNS: %s\n", | 612 "Could not create child process for DNS: %s\n", |
| 604 strerror(errno)); | 613 strerror(errno)); |
| 605 g_free(req); | 614 g_free(req); |
| 606 return -1; | 615 return -1; |
| 607 } | 616 } |
| 617 | |
| 608 req->fd_out = child_out[0]; | 618 req->fd_out = child_out[0]; |
| 609 req->fd_in = child_in[1]; | 619 req->fd_in = child_in[1]; |
| 610 number_of_dns_children++; | 620 number_of_dns_children++; |
| 611 gaim_debug(GAIM_DEBUG_INFO, "dns", | 621 gaim_debug(GAIM_DEBUG_INFO, "dns", |
| 612 "Created new DNS child %d, there are now %d children.\n", | 622 "Created new DNS child %d, there are now %d children.\n", |
| 613 req->dns_pid, number_of_dns_children); | 623 req->dns_pid, number_of_dns_children); |
| 614 } | 624 } |
| 615 | 625 |
| 616 req->host = g_strdup(dns_params.hostname); | 626 req->host = g_strdup(hostname); |
| 617 req->port = port; | 627 req->port = port; |
| 618 req->callback = callback; | 628 req->callback = callback; |
| 619 req->data = data; | 629 req->data = data; |
| 620 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); | 630 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req); |
| 621 | 631 |
