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