Mercurial > pidgin
comparison src/proxy.c @ 4678:9ce3c698ff5e
[gaim-migrate @ 4989]
Now we try all the results that getaddrinfo gives us, instead of just the
first one. This should fix the issues people have been having connecting
to certain jabber servers (like amessage.de) that have an IPv6 record as
well as an IPv4 record. It's also more correct and stuff.
committer: Tailor Script <tailor@pidgin.im>
| author | Nathan Walp <nwalp@pidgin.im> |
|---|---|
| date | Sat, 08 Mar 2003 17:54:36 +0000 |
| parents | 4bb99cdfd837 |
| children | 5b372a95b9a8 |
comparison
equal
deleted
inserted
replaced
| 4677:24657a33e9e5 | 4678:9ce3c698ff5e |
|---|---|
| 127 if (tag > 0) | 127 if (tag > 0) |
| 128 g_source_remove(tag); | 128 g_source_remove(tag); |
| 129 } | 129 } |
| 130 | 130 |
| 131 | 131 |
| 132 typedef void (*dns_callback_t)(struct sockaddr *addr, size_t addrlen, | 132 typedef void (*dns_callback_t)(GSList *hosts, gpointer data, |
| 133 gpointer data, const char *error_message); | 133 const char *error_message); |
| 134 | 134 |
| 135 #ifdef __unix__ | 135 #ifdef __unix__ |
| 136 | 136 |
| 137 /* This structure represents both a pending DNS request and | 137 /* This structure represents both a pending DNS request and |
| 138 * a free child process. | 138 * a free child process. |
| 246 | 246 |
| 247 static void host_resolved(gpointer data, gint source, GaimInputCondition cond) | 247 static void host_resolved(gpointer data, gint source, GaimInputCondition cond) |
| 248 { | 248 { |
| 249 pending_dns_request_t *req = (pending_dns_request_t*)data; | 249 pending_dns_request_t *req = (pending_dns_request_t*)data; |
| 250 int rc, err; | 250 int rc, err; |
| 251 GSList *hosts = NULL; | |
| 251 struct sockaddr *addr = NULL; | 252 struct sockaddr *addr = NULL; |
| 252 socklen_t addrlen; | 253 socklen_t addrlen; |
| 253 | 254 |
| 254 debug_printf("Host '%s' resolved\n", req->host); | 255 debug_printf("Host '%s' resolved\n", req->host); |
| 255 gaim_input_remove(req->inpa); | 256 gaim_input_remove(req->inpa); |
| 263 #else | 264 #else |
| 264 hstrerror(err), | 265 hstrerror(err), |
| 265 #endif | 266 #endif |
| 266 req->dns_pid); | 267 req->dns_pid); |
| 267 debug_printf("%s\n",message); | 268 debug_printf("%s\n",message); |
| 268 req->callback(NULL, 0, req->data, message); | 269 req->callback(NULL, req->data, message); |
| 269 release_dns_child(req); | 270 release_dns_child(req); |
| 270 return; | 271 return; |
| 271 } | 272 } |
| 272 if(rc>0) { | 273 if(rc>0) { |
| 273 rc=read(req->fd_out, &addrlen, sizeof(addrlen)); | 274 while(rc > 0) { |
| 274 if(rc>0) { | 275 rc=read(req->fd_out, &addrlen, sizeof(addrlen)); |
| 275 addr=g_malloc(addrlen); | 276 if(rc>0 && addrlen > 0) { |
| 276 rc=read(req->fd_out, addr, addrlen); | 277 addr=g_malloc(addrlen); |
| 277 } | 278 rc=read(req->fd_out, addr, addrlen); |
| 278 } | 279 hosts = g_slist_append(hosts, GINT_TO_POINTER(addrlen)); |
| 279 if(rc==-1) { | 280 hosts = g_slist_append(hosts, addr); |
| 281 } else { | |
| 282 break; | |
| 283 } | |
| 284 } | |
| 285 } else if(rc==-1) { | |
| 280 char message[1024]; | 286 char message[1024]; |
| 281 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); | 287 g_snprintf(message, sizeof(message), "Error reading from DNS child: %s",strerror(errno)); |
| 282 debug_printf("%s\n",message); | 288 debug_printf("%s\n",message); |
| 283 req->callback(NULL, 0, req->data, message); | 289 req->callback(NULL, req->data, message); |
| 284 req_free(req); | 290 req_free(req); |
| 285 return; | 291 return; |
| 286 } | 292 } else if(rc==0) { |
| 287 if(rc==0) { | |
| 288 char message[1024]; | 293 char message[1024]; |
| 289 g_snprintf(message, sizeof(message), "EOF reading from DNS child"); | 294 g_snprintf(message, sizeof(message), "EOF reading from DNS child"); |
| 290 close(req->fd_out); | 295 close(req->fd_out); |
| 291 debug_printf("%s\n",message); | 296 debug_printf("%s\n",message); |
| 292 req->callback(NULL, 0, req->data, message); | 297 req->callback(NULL, req->data, message); |
| 293 req_free(req); | 298 req_free(req); |
| 294 return; | 299 return; |
| 295 } | 300 } |
| 296 | 301 |
| 297 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ | 302 /* wait4(req->dns_pid, NULL, WNOHANG, NULL); */ |
| 298 | 303 |
| 299 req->callback(addr, addrlen, req->data, NULL); | 304 req->callback(hosts, req->data, NULL); |
| 300 | 305 |
| 301 g_free(addr); | 306 while(hosts) { |
| 302 | 307 hosts = g_slist_remove(hosts, hosts->data); |
| 303 release_dns_child(req); | 308 g_free(hosts->data); |
| 309 hosts = g_slist_remove(hosts, hosts->data); | |
| 310 } | |
| 311 | |
| 312 release_dns_child(req); | |
| 304 } | 313 } |
| 305 | 314 |
| 306 static void trap_gdb_bug() | 315 static void trap_gdb_bug() |
| 307 { | 316 { |
| 308 const char *message = | 317 const char *message = |
| 395 if(req->dns_pid==0) { | 404 if(req->dns_pid==0) { |
| 396 const int zero = 0; | 405 const int zero = 0; |
| 397 int rc; | 406 int rc; |
| 398 | 407 |
| 399 #ifdef HAVE_GETADDRINFO | 408 #ifdef HAVE_GETADDRINFO |
| 400 struct addrinfo hints, *res; | 409 struct addrinfo hints, *res, *tmp; |
| 401 char servname[20]; | 410 char servname[20]; |
| 402 #else | 411 #else |
| 403 struct sockaddr_in sin; | 412 struct sockaddr_in sin; |
| 404 const socklen_t addrlen = sizeof(sin); | 413 const socklen_t addrlen = sizeof(sin); |
| 405 #endif | 414 #endif |
| 466 getpid(), rc); | 475 getpid(), rc); |
| 467 dns_params.hostname[0] = '\0'; | 476 dns_params.hostname[0] = '\0'; |
| 468 continue; | 477 continue; |
| 469 } | 478 } |
| 470 write(child_out[1], &zero, sizeof(zero)); | 479 write(child_out[1], &zero, sizeof(zero)); |
| 471 write(child_out[1], &(res->ai_addrlen), sizeof(res->ai_addrlen)); | 480 while(res) { |
| 472 write(child_out[1], res->ai_addr, res->ai_addrlen); | 481 write(child_out[1], &(res->ai_addrlen), sizeof(res->ai_addrlen)); |
| 473 freeaddrinfo(res); | 482 write(child_out[1], res->ai_addr, res->ai_addrlen); |
| 483 tmp = res; | |
| 484 res = res->ai_next; | |
| 485 freeaddrinfo(tmp); | |
| 486 } | |
| 487 write(child_out[1], &zero, sizeof(zero)); | |
| 474 #else | 488 #else |
| 475 if (!inet_aton(hostname, &sin.sin_addr)) { | 489 if (!inet_aton(hostname, &sin.sin_addr)) { |
| 476 struct hostent *hp; | 490 struct hostent *hp; |
| 477 if(!(hp = gethostbyname(dns_params.hostname))) { | 491 if(!(hp = gethostbyname(dns_params.hostname))) { |
| 478 write(child_out[1], &h_errno, sizeof(int)); | 492 write(child_out[1], &h_errno, sizeof(int)); |
| 488 sin.sin_family = AF_INET; | 502 sin.sin_family = AF_INET; |
| 489 sin.sin_port = htons(dns_params.port); | 503 sin.sin_port = htons(dns_params.port); |
| 490 write(child_out[1], &zero, sizeof(zero)); | 504 write(child_out[1], &zero, sizeof(zero)); |
| 491 write(child_out[1], &addrlen, sizeof(addrlen)); | 505 write(child_out[1], &addrlen, sizeof(addrlen)); |
| 492 write(child_out[1], &sin, addrlen); | 506 write(child_out[1], &sin, addrlen); |
| 507 write(child_out[1], &zero, sizeof(zero)); | |
| 493 #endif | 508 #endif |
| 494 dns_params.hostname[0] = '\0'; | 509 dns_params.hostname[0] = '\0'; |
| 495 } | 510 } |
| 496 close(child_out[1]); | 511 close(child_out[1]); |
| 497 close(child_in[0]); | 512 close(child_in[0]); |
| 527 } pending_dns_request_t; | 542 } pending_dns_request_t; |
| 528 | 543 |
| 529 static gboolean host_resolved(gpointer data) | 544 static gboolean host_resolved(gpointer data) |
| 530 { | 545 { |
| 531 pending_dns_request_t *req = (pending_dns_request_t*)data; | 546 pending_dns_request_t *req = (pending_dns_request_t*)data; |
| 532 req->callback(req->addr, req->addrlen, req->data, NULL); | 547 GSList *hosts = NULL; |
| 548 hosts = g_slist_append(hosts, GINT_TO_POINTER(req->addrlen)); | |
| 549 hosts = g_slist_append(hosts, req->addr); | |
| 550 req->callback(hosts, req->data, NULL); | |
| 551 g_slist_free(hosts); | |
| 533 g_free(req->addr); | 552 g_free(req->addr); |
| 534 g_free(req); | 553 g_free(req); |
| 535 return FALSE; | 554 return FALSE; |
| 536 } | 555 } |
| 537 | 556 |
| 612 | 631 |
| 613 debug_printf("connecting to %s:%d with no proxy\n", phb->host, phb->port); | 632 debug_printf("connecting to %s:%d with no proxy\n", phb->host, phb->port); |
| 614 | 633 |
| 615 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 634 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 616 debug_printf("unable to create socket: %s\n", strerror(errno)); | 635 debug_printf("unable to create socket: %s\n", strerror(errno)); |
| 617 g_free(phb->host); | |
| 618 g_free(phb); | |
| 619 return -1; | 636 return -1; |
| 620 } | 637 } |
| 621 fcntl(fd, F_SETFL, O_NONBLOCK); | 638 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 622 | 639 |
| 623 if (connect(fd, (struct sockaddr *)addr, addrlen) < 0) { | 640 if (connect(fd, (struct sockaddr *)addr, addrlen) < 0) { |
| 625 debug_printf("Connect would have blocked\n"); | 642 debug_printf("Connect would have blocked\n"); |
| 626 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); | 643 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, no_one_calls, phb); |
| 627 } else { | 644 } else { |
| 628 debug_printf("connect failed (errno %d)\n", errno); | 645 debug_printf("connect failed (errno %d)\n", errno); |
| 629 close(fd); | 646 close(fd); |
| 630 g_free(phb->host); | |
| 631 g_free(phb); | |
| 632 return -1; | 647 return -1; |
| 633 } | 648 } |
| 634 } else { | 649 } else { |
| 635 unsigned int len; | 650 unsigned int len; |
| 636 int error = ETIMEDOUT; | 651 int error = ETIMEDOUT; |
| 637 debug_printf("Connect didn't block\n"); | 652 debug_printf("Connect didn't block\n"); |
| 638 len = sizeof(error); | 653 len = sizeof(error); |
| 639 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 654 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 640 debug_printf("getsockopt failed\n"); | 655 debug_printf("getsockopt failed\n"); |
| 641 close(fd); | 656 close(fd); |
| 642 g_free(phb->host); | |
| 643 g_free(phb); | |
| 644 return -1; | 657 return -1; |
| 645 } | 658 } |
| 646 fcntl(fd, F_SETFL, 0); | 659 fcntl(fd, F_SETFL, 0); |
| 647 phb->port = fd; /* bleh */ | 660 phb->port = fd; /* bleh */ |
| 648 g_timeout_add(50, clean_connect, phb); /* we do this because we never | 661 g_timeout_add(50, clean_connect, phb); /* we do this because we never |
| 759 int fd = -1; | 772 int fd = -1; |
| 760 | 773 |
| 761 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); | 774 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); |
| 762 | 775 |
| 763 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 776 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 764 g_free(phb->host); | |
| 765 g_free(phb); | |
| 766 return -1; | 777 return -1; |
| 767 } | 778 } |
| 768 | 779 |
| 769 fcntl(fd, F_SETFL, O_NONBLOCK); | 780 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 770 | 781 |
| 772 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 783 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 773 debug_printf("Connect would have blocked\n"); | 784 debug_printf("Connect would have blocked\n"); |
| 774 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); | 785 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); |
| 775 } else { | 786 } else { |
| 776 close(fd); | 787 close(fd); |
| 777 g_free(phb->host); | |
| 778 g_free(phb); | |
| 779 return -1; | 788 return -1; |
| 780 } | 789 } |
| 781 } else { | 790 } else { |
| 782 unsigned int len; | 791 unsigned int len; |
| 783 int error = ETIMEDOUT; | 792 int error = ETIMEDOUT; |
| 784 | 793 |
| 785 debug_printf("Connect didn't block\n"); | 794 debug_printf("Connect didn't block\n"); |
| 786 len = sizeof(error); | 795 len = sizeof(error); |
| 787 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 796 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 788 close(fd); | 797 close(fd); |
| 789 g_free(phb->host); | |
| 790 g_free(phb); | |
| 791 return -1; | 798 return -1; |
| 792 } | 799 } |
| 793 fcntl(fd, F_SETFL, 0); | 800 fcntl(fd, F_SETFL, 0); |
| 794 http_canwrite(phb, fd, GAIM_INPUT_WRITE); | 801 http_canwrite(phb, fd, GAIM_INPUT_WRITE); |
| 795 } | 802 } |
| 875 int fd = -1; | 882 int fd = -1; |
| 876 | 883 |
| 877 debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); | 884 debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); |
| 878 | 885 |
| 879 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 886 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 880 g_free(phb->host); | |
| 881 g_free(phb); | |
| 882 return -1; | 887 return -1; |
| 883 } | 888 } |
| 884 | 889 |
| 885 fcntl(fd, F_SETFL, O_NONBLOCK); | 890 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 886 if (connect(fd, addr, addrlen) < 0) { | 891 if (connect(fd, addr, addrlen) < 0) { |
| 887 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 892 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 888 debug_printf("Connect would have blocked\n"); | 893 debug_printf("Connect would have blocked\n"); |
| 889 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s4_canwrite, phb); | 894 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s4_canwrite, phb); |
| 890 } else { | 895 } else { |
| 891 close(fd); | 896 close(fd); |
| 892 g_free(phb->host); | |
| 893 g_free(phb); | |
| 894 return -1; | 897 return -1; |
| 895 } | 898 } |
| 896 } else { | 899 } else { |
| 897 unsigned int len; | 900 unsigned int len; |
| 898 int error = ETIMEDOUT; | 901 int error = ETIMEDOUT; |
| 899 | 902 |
| 900 debug_printf("Connect didn't block\n"); | 903 debug_printf("Connect didn't block\n"); |
| 901 len = sizeof(error); | 904 len = sizeof(error); |
| 902 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 905 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 903 close(fd); | 906 close(fd); |
| 904 g_free(phb->host); | |
| 905 g_free(phb); | |
| 906 return -1; | 907 return -1; |
| 907 } | 908 } |
| 908 fcntl(fd, F_SETFL, 0); | 909 fcntl(fd, F_SETFL, 0); |
| 909 s4_canwrite(phb, fd, GAIM_INPUT_WRITE); | 910 s4_canwrite(phb, fd, GAIM_INPUT_WRITE); |
| 910 } | 911 } |
| 1093 int fd = -1; | 1094 int fd = -1; |
| 1094 | 1095 |
| 1095 debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); | 1096 debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", phb->host, phb->port, phb->gpi->proxyhost, phb->gpi->proxyport); |
| 1096 | 1097 |
| 1097 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { | 1098 if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) { |
| 1098 g_free(phb->host); | |
| 1099 g_free(phb); | |
| 1100 return -1; | 1099 return -1; |
| 1101 } | 1100 } |
| 1102 | 1101 |
| 1103 fcntl(fd, F_SETFL, O_NONBLOCK); | 1102 fcntl(fd, F_SETFL, O_NONBLOCK); |
| 1104 if (connect(fd, addr, addrlen) < 0) { | 1103 if (connect(fd, addr, addrlen) < 0) { |
| 1105 if ((errno == EINPROGRESS) || (errno == EINTR)) { | 1104 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 1106 debug_printf("Connect would have blocked\n"); | 1105 debug_printf("Connect would have blocked\n"); |
| 1107 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s5_canwrite, phb); | 1106 phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, s5_canwrite, phb); |
| 1108 } else { | 1107 } else { |
| 1109 close(fd); | 1108 close(fd); |
| 1110 g_free(phb->host); | |
| 1111 g_free(phb); | |
| 1112 return -1; | 1109 return -1; |
| 1113 } | 1110 } |
| 1114 } else { | 1111 } else { |
| 1115 unsigned int len; | 1112 unsigned int len; |
| 1116 int error = ETIMEDOUT; | 1113 int error = ETIMEDOUT; |
| 1117 | 1114 |
| 1118 debug_printf("Connect didn't block\n"); | 1115 debug_printf("Connect didn't block\n"); |
| 1119 len = sizeof(error); | 1116 len = sizeof(error); |
| 1120 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | 1117 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 1121 close(fd); | 1118 close(fd); |
| 1122 g_free(phb->host); | |
| 1123 g_free(phb); | |
| 1124 return -1; | 1119 return -1; |
| 1125 } | 1120 } |
| 1126 fcntl(fd, F_SETFL, 0); | 1121 fcntl(fd, F_SETFL, 0); |
| 1127 s5_canwrite(phb, fd, GAIM_INPUT_WRITE); | 1122 s5_canwrite(phb, fd, GAIM_INPUT_WRITE); |
| 1128 } | 1123 } |
| 1129 | 1124 |
| 1130 return fd; | 1125 return fd; |
| 1131 } | 1126 } |
| 1132 | 1127 |
| 1133 static void connection_host_resolved(struct sockaddr *addr, size_t addrlen, gpointer data, const char *error_message) | 1128 static void connection_host_resolved(GSList *hosts, gpointer data, const char *error_message) |
| 1134 { | 1129 { |
| 1135 struct PHB *phb = (struct PHB*)data; | 1130 struct PHB *phb = (struct PHB*)data; |
| 1136 | 1131 size_t addrlen; |
| 1137 if(!addr) | 1132 struct sockaddr *addr; |
| 1138 { | 1133 int ret = -1; |
| 1139 phb->func(phb->data, -1, GAIM_INPUT_READ); | 1134 |
| 1140 return; | 1135 while(hosts) { |
| 1141 } | 1136 addrlen = GPOINTER_TO_INT(hosts->data); |
| 1142 | 1137 hosts = hosts->next; |
| 1143 switch(phb->gpi->proxytype) | 1138 addr = hosts->data; |
| 1144 { | 1139 hosts = hosts->next; |
| 1145 case PROXY_NONE: | 1140 |
| 1146 proxy_connect_none(phb, addr, addrlen); | 1141 switch(phb->gpi->proxytype) |
| 1142 { | |
| 1143 case PROXY_NONE: | |
| 1144 ret = proxy_connect_none(phb, addr, addrlen); | |
| 1145 break; | |
| 1146 case PROXY_HTTP: | |
| 1147 ret = proxy_connect_http(phb, addr, addrlen); | |
| 1148 break; | |
| 1149 case PROXY_SOCKS4: | |
| 1150 ret = proxy_connect_socks4(phb, addr, addrlen); | |
| 1151 break; | |
| 1152 case PROXY_SOCKS5: | |
| 1153 ret = proxy_connect_socks5(phb, addr, addrlen); | |
| 1154 break; | |
| 1155 } | |
| 1156 if (ret > 0) | |
| 1147 break; | 1157 break; |
| 1148 case PROXY_HTTP: | 1158 } |
| 1149 proxy_connect_http(phb, addr, addrlen); | 1159 if(ret < 0) { |
| 1150 break; | 1160 phb->func(phb->data, -1, GAIM_INPUT_READ); |
| 1151 case PROXY_SOCKS4: | 1161 g_free(phb->host); |
| 1152 proxy_connect_socks4(phb, addr, addrlen); | 1162 g_free(phb); |
| 1153 break; | |
| 1154 case PROXY_SOCKS5: | |
| 1155 proxy_connect_socks5(phb, addr, addrlen); | |
| 1156 break; | |
| 1157 } | 1163 } |
| 1158 } | 1164 } |
| 1159 | 1165 |
| 1160 int | 1166 int |
| 1161 proxy_connect(struct gaim_account *account, char *host, int port, GaimInputFunction func, gpointer data) | 1167 proxy_connect(struct gaim_account *account, char *host, int port, GaimInputFunction func, gpointer data) |
