src/proxy.c

changeset 4678
4fe99bee3ecc
parent 4648
22f8080928e0
child 4679
fefa15b49bd0
equal deleted inserted replaced
4677:41896169d71a 4678:4fe99bee3ecc
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)

mercurial