comparison src/proxy.c @ 14163:c3167a1dd817

[gaim-migrate @ 16811] Split the DNS query stuff out into it's own file. Eventually we should move the dnssrv code into this same file. Maybe even share some code? Also the first steps toward cancelable DNS queries. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Thu, 17 Aug 2006 07:44:52 +0000
parents 7a205b430d19
children 879bb47cff8e
comparison
equal deleted inserted replaced
14162:cef7f6a93592 14163:c3167a1dd817
29 , 2nd provide an easy way to add socks support 29 , 2nd provide an easy way to add socks support
30 , 3rd draw women to it like flies to honey */ 30 , 3rd draw women to it like flies to honey */
31 31
32 #include "internal.h" 32 #include "internal.h"
33 #include "cipher.h" 33 #include "cipher.h"
34 #include "dnsquery.h"
34 #include "debug.h" 35 #include "debug.h"
35 #include "notify.h" 36 #include "notify.h"
36 #include "ntlm.h" 37 #include "ntlm.h"
37 #include "prefs.h" 38 #include "prefs.h"
38 #include "proxy.h" 39 #include "proxy.h"
44 char *host; 45 char *host;
45 int port; 46 int port;
46 int fd; 47 int fd;
47 guint inpa; 48 guint inpa;
48 GaimProxyInfo *gpi; 49 GaimProxyInfo *gpi;
50 GaimDnsqueryData *query_data;
49 51
50 /** 52 /**
51 * This contains alternating length/char* values. The char* 53 * This contains alternating length/char* values. The char*
52 * values need to be freed when removed from the linked list. 54 * values need to be freed when removed from the linked list.
53 */ 55 */
305 { 307 {
306 gaim_proxy_connect_info_disconnect(connect_info); 308 gaim_proxy_connect_info_disconnect(connect_info);
307 309
308 connect_infos = g_slist_remove(connect_infos, connect_info); 310 connect_infos = g_slist_remove(connect_infos, connect_info);
309 311
312 /*
313 if (connect_info->query_data != NULL)
314 gaim_dnsquery_destroy(connect_info->query_data);
315 */
316
310 while (connect_info->hosts != NULL) 317 while (connect_info->hosts != NULL)
311 { 318 {
312 /* Discard the length... */ 319 /* Discard the length... */
313 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data); 320 connect_info->hosts = g_slist_remove(connect_info->hosts, connect_info->hosts->data);
314 /* Free the address... */ 321 /* Free the address... */
348 gaim_proxy_connect_info_error(GaimProxyConnectInfo *connect_info, const gchar *error_message) 355 gaim_proxy_connect_info_error(GaimProxyConnectInfo *connect_info, const gchar *error_message)
349 { 356 {
350 connect_info->connect_cb(connect_info->data, -1, error_message); 357 connect_info->connect_cb(connect_info->data, -1, error_message);
351 gaim_proxy_connect_info_destroy(connect_info); 358 gaim_proxy_connect_info_destroy(connect_info);
352 } 359 }
353
354 #if defined(__unix__) || defined(__APPLE__)
355
356 /*
357 * This structure represents both a pending DNS request and
358 * a free child process.
359 */
360 typedef struct {
361 char *host;
362 int port;
363 GaimProxyDnsConnectFunction callback;
364 gpointer data;
365 guint inpa;
366 int fd_in, fd_out;
367 pid_t dns_pid;
368 } pending_dns_request_t;
369
370 static GSList *free_dns_children = NULL;
371 static GQueue *queued_requests = NULL;
372
373 static int number_of_dns_children = 0;
374
375 static const int MAX_DNS_CHILDREN = 2;
376
377 typedef struct {
378 char hostname[512];
379 int port;
380 } dns_params_t;
381
382 typedef struct {
383 dns_params_t params;
384 GaimProxyDnsConnectFunction callback;
385 gpointer data;
386 } queued_dns_request_t;
387
388 /*
389 * Begin the DNS resolver child process functions.
390 */
391 #ifdef HAVE_SIGNAL_H
392 static void
393 trap_gdb_bug()
394 {
395 const char *message =
396 "Gaim's DNS child got a SIGTRAP signal.\n"
397 "This can be caused by trying to run gaim inside gdb.\n"
398 "There is a known gdb bug which prevents this. Supposedly gaim\n"
399 "should have detected you were using gdb and used an ugly hack,\n"
400 "check cope_with_gdb_brokenness() in proxy.c.\n\n"
401 "For more info about this bug, see http://sources.redhat.com/ml/gdb/2001-07/msg00349.html\n";
402 fputs("\n* * *\n",stderr);
403 fputs(message,stderr);
404 fputs("* * *\n\n",stderr);
405 execlp("xmessage","xmessage","-center", message, NULL);
406 _exit(1);
407 }
408 #endif
409
410 static void
411 cope_with_gdb_brokenness()
412 {
413 #ifdef __linux__
414 static gboolean already_done = FALSE;
415 char s[256], e[512];
416 int n;
417 pid_t ppid;
418
419 if(already_done)
420 return;
421 already_done = TRUE;
422 ppid = getppid();
423 snprintf(s, sizeof(s), "/proc/%d/exe", ppid);
424 n = readlink(s, e, sizeof(e));
425 if(n < 0)
426 return;
427
428 e[MIN(n,sizeof(e)-1)] = '\0';
429
430 if(strstr(e,"gdb")) {
431 gaim_debug_info("dns",
432 "Debugger detected, performing useless query...\n");
433 gethostbyname("x.x.x.x.x");
434 }
435 #endif
436 }
437
438 static void
439 gaim_dns_resolverthread(int child_out, int child_in, gboolean show_debug)
440 {
441 dns_params_t dns_params;
442 const size_t zero = 0;
443 int rc;
444 #ifdef HAVE_GETADDRINFO
445 struct addrinfo hints, *res, *tmp;
446 char servname[20];
447 #else
448 struct sockaddr_in sin;
449 const size_t addrlen = sizeof(sin);
450 #endif
451
452 #ifdef HAVE_SIGNAL_H
453 signal(SIGHUP, SIG_DFL);
454 signal(SIGINT, SIG_DFL);
455 signal(SIGQUIT, SIG_DFL);
456 signal(SIGCHLD, SIG_DFL);
457 signal(SIGTERM, SIG_DFL);
458 signal(SIGTRAP, trap_gdb_bug);
459 #endif
460
461 /*
462 * We resolve 1 host name for each iteration of this
463 * while loop.
464 *
465 * The top half of this reads in the hostname and port
466 * number from the socket with our parent. The bottom
467 * half of this resolves the IP (blocking) and sends
468 * the result back to our parent, when finished.
469 */
470 while (1) {
471 const char ch = 'Y';
472 fd_set fds;
473 struct timeval tv = { .tv_sec = 40 , .tv_usec = 0 };
474 FD_ZERO(&fds);
475 FD_SET(child_in, &fds);
476 rc = select(child_in + 1, &fds, NULL, NULL, &tv);
477 if (!rc) {
478 if (show_debug)
479 printf("dns[%d]: nobody needs me... =(\n", getpid());
480 break;
481 }
482 rc = read(child_in, &dns_params, sizeof(dns_params_t));
483 if (rc < 0) {
484 perror("read()");
485 break;
486 }
487 if (rc == 0) {
488 if (show_debug)
489 printf("dns[%d]: Oops, father has gone, wait for me, wait...!\n", getpid());
490 _exit(0);
491 }
492 if (dns_params.hostname[0] == '\0') {
493 printf("dns[%d]: hostname = \"\" (port = %d)!!!\n", getpid(), dns_params.port);
494 _exit(1);
495 }
496 /* Tell our parent that we read the data successfully */
497 write(child_out, &ch, sizeof(ch));
498
499 /* We have the hostname and port, now resolve the IP */
500
501 #ifdef HAVE_GETADDRINFO
502 g_snprintf(servname, sizeof(servname), "%d", dns_params.port);
503 memset(&hints, 0, sizeof(hints));
504
505 /* This is only used to convert a service
506 * name to a port number. As we know we are
507 * passing a number already, we know this
508 * value will not be really used by the C
509 * library.
510 */
511 hints.ai_socktype = SOCK_STREAM;
512 rc = getaddrinfo(dns_params.hostname, servname, &hints, &res);
513 write(child_out, &rc, sizeof(rc));
514 if (rc != 0) {
515 close(child_out);
516 if (show_debug)
517 printf("dns[%d] Error: getaddrinfo returned %d\n",
518 getpid(), rc);
519 dns_params.hostname[0] = '\0';
520 continue;
521 }
522 tmp = res;
523 while (res) {
524 size_t ai_addrlen = res->ai_addrlen;
525 write(child_out, &ai_addrlen, sizeof(ai_addrlen));
526 write(child_out, res->ai_addr, res->ai_addrlen);
527 res = res->ai_next;
528 }
529 freeaddrinfo(tmp);
530 write(child_out, &zero, sizeof(zero));
531 #else
532 if (!inet_aton(dns_params.hostname, &sin.sin_addr)) {
533 struct hostent *hp;
534 if (!(hp = gethostbyname(dns_params.hostname))) {
535 write(child_out, &h_errno, sizeof(int));
536 close(child_out);
537 if (show_debug)
538 printf("DNS Error: %d\n", h_errno);
539 _exit(0);
540 }
541 memset(&sin, 0, sizeof(struct sockaddr_in));
542 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
543 sin.sin_family = hp->h_addrtype;
544 } else
545 sin.sin_family = AF_INET;
546
547 sin.sin_port = htons(dns_params.port);
548 write(child_out, &addrlen, sizeof(addrlen));
549 write(child_out, &sin, addrlen);
550 write(child_out, &zero, sizeof(zero));
551 #endif
552 dns_params.hostname[0] = '\0';
553 }
554
555 close(child_out);
556 close(child_in);
557
558 _exit(0);
559 }
560
561 static pending_dns_request_t *
562 gaim_dns_new_resolverthread(gboolean show_debug)
563 {
564 pending_dns_request_t *req;
565 int child_out[2], child_in[2];
566
567 /* Create pipes for communicating with the child process */
568 if (pipe(child_out) || pipe(child_in)) {
569 gaim_debug_error("dns",
570 "Could not create pipes: %s\n", strerror(errno));
571 return NULL;
572 }
573
574 req = g_new(pending_dns_request_t, 1);
575
576 cope_with_gdb_brokenness();
577
578 /* Fork! */
579 req->dns_pid = fork();
580
581 /* If we are the child process... */
582 if (req->dns_pid == 0) {
583 /* We should not access the parent's side of the pipes, so close them */
584 close(child_out[0]);
585 close(child_in[1]);
586
587 gaim_dns_resolverthread(child_out[1], child_in[0], show_debug);
588 /* The thread calls _exit() rather than returning, so we never get here */
589 }
590
591 /* We should not access the child's side of the pipes, so close them */
592 close(child_out[1]);
593 close(child_in[0]);
594 if (req->dns_pid == -1) {
595 gaim_debug_error("dns",
596 "Could not create child process for DNS: %s\n",
597 strerror(errno));
598 g_free(req);
599 return NULL;
600 }
601
602 req->fd_out = child_out[0];
603 req->fd_in = child_in[1];
604 number_of_dns_children++;
605 gaim_debug_info("dns",
606 "Created new DNS child %d, there are now %d children.\n",
607 req->dns_pid, number_of_dns_children);
608
609 return req;
610 }
611 /*
612 * End the DNS resolver child process functions.
613 */
614
615 /*
616 * Begin the functions for dealing with the DNS child processes.
617 */
618 static void
619 req_free(pending_dns_request_t *req)
620 {
621 g_return_if_fail(req != NULL);
622
623 close(req->fd_in);
624 close(req->fd_out);
625
626 g_free(req->host);
627 g_free(req);
628
629 number_of_dns_children--;
630 }
631
632 static int
633 send_dns_request_to_child(pending_dns_request_t *req, dns_params_t *dns_params)
634 {
635 char ch;
636 int rc;
637 pid_t pid;
638
639 /* This waitpid might return the child's PID if it has recently
640 * exited, or it might return an error if it exited "long
641 * enough" ago that it has already been reaped; in either
642 * instance, we can't use it. */
643 if ((pid = waitpid (req->dns_pid, NULL, WNOHANG)) > 0) {
644 gaim_debug_warning("dns",
645 "DNS child %d no longer exists\n", req->dns_pid);
646 return -1;
647 } else if (pid < 0) {
648 gaim_debug_warning("dns",
649 "Wait for DNS child %d failed: %s\n",
650 req->dns_pid, strerror(errno));
651 return -1;
652 }
653
654 /* Let's contact this lost child! */
655 rc = write(req->fd_in, dns_params, sizeof(*dns_params));
656 if (rc < 0) {
657 gaim_debug_error("dns",
658 "Unable to write to DNS child %d: %d\n",
659 req->dns_pid, strerror(errno));
660 close(req->fd_in);
661 return -1;
662 }
663
664 g_return_val_if_fail(rc == sizeof(*dns_params), -1);
665
666 /* Did you hear me? (This avoids some race conditions) */
667 rc = read(req->fd_out, &ch, sizeof(ch));
668 if (rc != 1 || ch != 'Y')
669 {
670 gaim_debug_warning("dns",
671 "DNS child %d not responding. Killing it!\n",
672 req->dns_pid);
673 kill(req->dns_pid, SIGKILL);
674 return -1;
675 }
676
677 gaim_debug_info("dns",
678 "Successfully sent DNS request to child %d\n", req->dns_pid);
679
680 return 0;
681 }
682
683 static void
684 host_resolved(gpointer data, gint source, GaimInputCondition cond);
685
686 static void
687 release_dns_child(pending_dns_request_t *req)
688 {
689 g_free(req->host);
690 req->host = NULL;
691
692 if (queued_requests && !g_queue_is_empty(queued_requests)) {
693 queued_dns_request_t *r = g_queue_pop_head(queued_requests);
694 req->host = g_strdup(r->params.hostname);
695 req->port = r->params.port;
696 req->callback = r->callback;
697 req->data = r->data;
698
699 gaim_debug_info("dns",
700 "Processing queued DNS query for '%s' with child %d\n",
701 req->host, req->dns_pid);
702
703 if (send_dns_request_to_child(req, &(r->params)) != 0) {
704 req_free(req);
705 req = NULL;
706
707 gaim_debug_warning("dns",
708 "Intent of process queued query of '%s' failed, "
709 "requeueing...\n", r->params.hostname);
710 g_queue_push_head(queued_requests, r);
711 } else {
712 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req);
713 g_free(r);
714 }
715
716 } else {
717 req->host = NULL;
718 req->callback = NULL;
719 req->data = NULL;
720 free_dns_children = g_slist_append(free_dns_children, req);
721 }
722 }
723
724 static void
725 host_resolved(gpointer data, gint source, GaimInputCondition cond)
726 {
727 pending_dns_request_t *req = (pending_dns_request_t*)data;
728 int rc, err;
729 GSList *hosts = NULL;
730 struct sockaddr *addr = NULL;
731 size_t addrlen;
732
733 gaim_debug_info("dns", "Got response for '%s'\n", req->host);
734 gaim_input_remove(req->inpa);
735
736 rc = read(req->fd_out, &err, sizeof(err));
737 if ((rc == 4) && (err != 0))
738 {
739 char message[1024];
740 #ifdef HAVE_GETADDRINFO
741 g_snprintf(message, sizeof(message), "DNS error: %s (pid=%d)",
742 gai_strerror(err), req->dns_pid);
743 #else
744 g_snprintf(message, sizeof(message), "DNS error: %d (pid=%d)",
745 err, req->dns_pid);
746 #endif
747 gaim_debug_error("dns", "%s\n", message);
748 req->callback(NULL, req->data, message);
749 release_dns_child(req);
750 return;
751 }
752 if (rc > 0)
753 {
754 while (rc > 0) {
755 rc = read(req->fd_out, &addrlen, sizeof(addrlen));
756 if (rc > 0 && addrlen > 0) {
757 addr = g_malloc(addrlen);
758 rc = read(req->fd_out, addr, addrlen);
759 hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen));
760 hosts = g_slist_append(hosts, addr);
761 } else {
762 break;
763 }
764 }
765 } else if (rc == -1) {
766 char message[1024];
767 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno));
768 gaim_debug_error("dns", "%s\n", message);
769 req->callback(NULL, req->data, message);
770 req_free(req);
771 return;
772 } else if (rc == 0) {
773 char message[1024];
774 g_snprintf(message, sizeof(message), "EOF reading from DNS child");
775 close(req->fd_out);
776 gaim_debug_error("dns", "%s\n", message);
777 req->callback(NULL, req->data, message);
778 req_free(req);
779 return;
780 }
781
782 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */
783
784 req->callback(hosts, req->data, NULL);
785
786 release_dns_child(req);
787 }
788 /*
789 * End the functions for dealing with the DNS child processes.
790 */
791
792 int
793 gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data)
794 {
795 pending_dns_request_t *req = NULL;
796 dns_params_t dns_params;
797 gchar *host_temp;
798 gboolean show_debug;
799
800 show_debug = gaim_debug_is_enabled();
801
802 host_temp = g_strstrip(g_strdup(hostname));
803 strncpy(dns_params.hostname, host_temp, sizeof(dns_params.hostname) - 1);
804 g_free(host_temp);
805 dns_params.hostname[sizeof(dns_params.hostname) - 1] = '\0';
806 dns_params.port = port;
807
808 /*
809 * If we have any children, attempt to have them perform the DNS
810 * query. If we're able to send the query to a child, then req
811 * will be set to the pending_dns_request_t. Otherwise, req will
812 * be NULL and we'll need to create a new DNS request child.
813 */
814 while (free_dns_children != NULL) {
815 req = free_dns_children->data;
816 free_dns_children = g_slist_remove(free_dns_children, req);
817
818 if (send_dns_request_to_child(req, &dns_params) == 0)
819 /* We found an acceptable child, yay */
820 break;
821
822 req_free(req);
823 req = NULL;
824 }
825
826 /* We need to create a new DNS request child */
827 if (req == NULL) {
828 if (number_of_dns_children >= MAX_DNS_CHILDREN) {
829 queued_dns_request_t *r = g_new(queued_dns_request_t, 1);
830 memcpy(&(r->params), &dns_params, sizeof(dns_params));
831 r->callback = callback;
832 r->data = data;
833 if (!queued_requests)
834 queued_requests = g_queue_new();
835 g_queue_push_tail(queued_requests, r);
836
837 gaim_debug_info("dns",
838 "DNS query for '%s' queued\n", dns_params.hostname);
839
840 return 0;
841 }
842
843 req = gaim_dns_new_resolverthread(show_debug);
844 if (req == NULL)
845 {
846 gaim_debug_error("proxy", "oh dear, this is going to explode, I give up\n");
847 return -1;
848 }
849 send_dns_request_to_child(req, &dns_params);
850 }
851
852 req->host = g_strdup(hostname);
853 req->port = port;
854 req->callback = callback;
855 req->data = data;
856 req->inpa = gaim_input_add(req->fd_out, GAIM_INPUT_READ, host_resolved, req);
857
858 return 0;
859 }
860
861 #elif defined _WIN32 /* end __unix__ || __APPLE__ */
862
863 typedef struct _dns_tdata {
864 char *hostname;
865 int port;
866 GaimProxyDnsConnectFunction callback;
867 gpointer data;
868 GSList *hosts;
869 char *errmsg;
870 } dns_tdata;
871
872 static gboolean dns_main_thread_cb(gpointer data) {
873 dns_tdata *td = (dns_tdata*)data;
874 if (td->errmsg != NULL) {
875 gaim_debug_info("dns", "%s\n", td->errmsg);
876 }
877 td->callback(td->hosts, td->data, td->errmsg);
878 g_free(td->hostname);
879 g_free(td->errmsg);
880 g_free(td);
881 return FALSE;
882 }
883
884 static gpointer dns_thread(gpointer data) {
885
886 #ifdef HAVE_GETADDRINFO
887 int rc;
888 struct addrinfo hints, *res, *tmp;
889 char servname[20];
890 #else
891 struct sockaddr_in sin;
892 struct hostent *hp;
893 #endif
894 dns_tdata *td = (dns_tdata*)data;
895
896 #ifdef HAVE_GETADDRINFO
897 g_snprintf(servname, sizeof(servname), "%d", td->port);
898 memset(&hints,0,sizeof(hints));
899
900 /* This is only used to convert a service
901 * name to a port number. As we know we are
902 * passing a number already, we know this
903 * value will not be really used by the C
904 * library.
905 */
906 hints.ai_socktype = SOCK_STREAM;
907 if ((rc = getaddrinfo(td->hostname, servname, &hints, &res)) == 0) {
908 tmp = res;
909 while(res) {
910 td->hosts = g_slist_append(td->hosts,
911 GSIZE_TO_POINTER(res->ai_addrlen));
912 td->hosts = g_slist_append(td->hosts,
913 g_memdup(res->ai_addr, res->ai_addrlen));
914 res = res->ai_next;
915 }
916 freeaddrinfo(tmp);
917 } else {
918 td->errmsg = g_strdup_printf("DNS getaddrinfo(\"%s\", \"%s\") error: %d", td->hostname, servname, rc);
919 }
920 #else
921 if ((hp = gethostbyname(td->hostname))) {
922 memset(&sin, 0, sizeof(struct sockaddr_in));
923 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
924 sin.sin_family = hp->h_addrtype;
925 sin.sin_port = htons(td->port);
926
927 td->hosts = g_slist_append(td->hosts,
928 GSIZE_TO_POINTER(sizeof(sin)));
929 td->hosts = g_slist_append(td->hosts,
930 g_memdup(&sin, sizeof(sin)));
931 } else {
932 td->errmsg = g_strdup_printf("DNS gethostbyname(\"%s\") error: %d", td->hostname, h_errno);
933 }
934 #endif
935 /* back to main thread */
936 g_idle_add(dns_main_thread_cb, td);
937 return 0;
938 }
939
940 int
941 gaim_gethostbyname_async(const char *hostname, int port,
942 GaimProxyDnsConnectFunction callback, gpointer data)
943 {
944 dns_tdata *td;
945 struct sockaddr_in sin;
946 GError* err = NULL;
947
948 if(inet_aton(hostname, &sin.sin_addr)) {
949 GSList *hosts = NULL;
950 sin.sin_family = AF_INET;
951 sin.sin_port = htons(port);
952 hosts = g_slist_append(hosts, GINT_TO_POINTER(sizeof(sin)));
953 hosts = g_slist_append(hosts, g_memdup(&sin, sizeof(sin)));
954 callback(hosts, data, NULL);
955 return 0;
956 }
957
958 gaim_debug_info("dns", "DNS Lookup for: %s\n", hostname);
959 td = g_new0(dns_tdata, 1);
960 td->hostname = g_strdup(hostname);
961 td->port = port;
962 td->callback = callback;
963 td->data = data;
964
965 if(!g_thread_create(dns_thread, td, FALSE, &err)) {
966 gaim_debug_error("dns", "DNS thread create failure: %s\n", err?err->message:"");
967 g_error_free(err);
968 g_free(td->hostname);
969 g_free(td);
970 return -1;
971 }
972 return 0;
973 }
974
975 #else /* not __unix__ or __APPLE__ or _WIN32 */
976
977 typedef struct {
978 gpointer data;
979 size_t addrlen;
980 struct sockaddr *addr;
981 GaimProxyDnsConnectFunction callback;
982 } pending_dns_request_t;
983
984 static gboolean host_resolved(gpointer data)
985 {
986 pending_dns_request_t *req = (pending_dns_request_t*)data;
987 GSList *hosts = NULL;
988 hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen));
989 hosts = g_slist_append(hosts, req->addr);
990 req->callback(hosts, req->data, NULL);
991 g_free(req);
992 return FALSE;
993 }
994
995 int
996 gaim_gethostbyname_async(const char *hostname, int port,
997 GaimProxyDnsConnectFunction callback, gpointer data)
998 {
999 struct sockaddr_in sin;
1000 pending_dns_request_t *req;
1001
1002 if (!inet_aton(hostname, &sin.sin_addr)) {
1003 struct hostent *hp;
1004 if(!(hp = gethostbyname(hostname))) {
1005 gaim_debug_error("dns",
1006 "gaim_gethostbyname(\"%s\", %d) failed: %d\n",
1007 hostname, port, h_errno);
1008 return -1;
1009 }
1010 memset(&sin, 0, sizeof(struct sockaddr_in));
1011 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
1012 sin.sin_family = hp->h_addrtype;
1013 } else
1014 sin.sin_family = AF_INET;
1015 sin.sin_port = htons(port);
1016
1017 req = g_new(pending_dns_request_t, 1);
1018 req->addr = (struct sockaddr*) g_memdup(&sin, sizeof(sin));
1019 req->addrlen = sizeof(sin);
1020 req->data = data;
1021 req->callback = callback;
1022 gaim_timeout_add(10, host_resolved, req);
1023 return 0;
1024 }
1025
1026 #endif /* not __unix__ or __APPLE__ or _WIN32 */
1027 360
1028 static void 361 static void
1029 no_one_calls(gpointer data, gint source, GaimInputCondition cond) 362 no_one_calls(gpointer data, gint source, GaimInputCondition cond)
1030 { 363 {
1031 GaimProxyConnectInfo *connect_info = data; 364 GaimProxyConnectInfo *connect_info = data;
2366 default: 1699 default:
2367 gaim_proxy_connect_info_destroy(connect_info); 1700 gaim_proxy_connect_info_destroy(connect_info);
2368 return NULL; 1701 return NULL;
2369 } 1702 }
2370 1703
2371 if (gaim_gethostbyname_async(connecthost, 1704 connect_info->query_data = gaim_dnsquery_a(connecthost,
2372 connectport, connection_host_resolved, connect_info) != 0) 1705 connectport, connection_host_resolved, connect_info);
1706 if (connect_info->query_data == NULL)
2373 { 1707 {
2374 gaim_proxy_connect_info_destroy(connect_info); 1708 gaim_proxy_connect_info_destroy(connect_info);
2375 return NULL; 1709 return NULL;
2376 } 1710 }
2377 1711
2399 connect_info->data = data; 1733 connect_info->data = data;
2400 connect_info->host = g_strdup(host); 1734 connect_info->host = g_strdup(host);
2401 connect_info->port = port; 1735 connect_info->port = port;
2402 connect_info->gpi = gpi; 1736 connect_info->gpi = gpi;
2403 1737
2404 if (gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi), 1738 connect_info->query_data = gaim_dnsquery_a(gaim_proxy_info_get_host(gpi),
2405 gaim_proxy_info_get_port(gpi), connection_host_resolved, connect_info) != 0) 1739 gaim_proxy_info_get_port(gpi), connection_host_resolved, connect_info);
1740 if (connect_info->query_data == NULL)
2406 { 1741 {
2407 gaim_proxy_connect_info_destroy(connect_info); 1742 gaim_proxy_connect_info_destroy(connect_info);
2408 return NULL; 1743 return NULL;
2409 } 1744 }
2410 1745