📄 connect.c
字号:
/* Sockets-o-matic *//* $Id: connect.c,v 1.114.2.6 2005/05/01 21:18:43 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <errno.h>#include <string.h>#include <sys/types.h>#ifdef HAVE_NETINET_IN_H#include <netinet/in.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_FCNTL_H#include <fcntl.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_GETIFADDRS#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_NET_IF_H#include <net/if.h>#endif#ifdef HAVE_IFADDRS_H#include <ifaddrs.h> /* getifaddrs() */#endif#endif /* HAVE_GETIFADDRS */#include "elinks.h"#include "config/options.h"#include "lowlevel/connect.h"#include "lowlevel/dns.h"#include "lowlevel/select.h"#include "osdep/osdep.h"#include "osdep/getifaddrs.h"#include "protocol/protocol.h"#include "protocol/uri.h"#include "sched/connection.h"#include "ssl/connect.h"#include "util/error.h"#include "util/memory.h"#include "util/string.h"/* To enable logging of tranfers, for debugging purposes. */#if 0#define DEBUG_TRANSFER_LOGFILE "/tmp/log"static voiddebug_transfer_log(unsigned char *data, int len){ int fd = open(DEBUG_TRANSFER_LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0622); if (fd == -1) return; set_bin(fd); write(fd, data, len < 0 ? strlen(data) : len); close(fd);}#undef DEBUG_TRANSFER_LOGFILE#else#define debug_transfer_log(data, len)#endifvoid dns_found(/* struct connection */ void *, int);static void connected(/* struct connection */ void *);voidclose_socket(struct connection *conn, struct connection_socket *socket){ if (socket->fd == -1) return;#ifdef CONFIG_SSL if (conn && socket->ssl) ssl_close(conn, socket);#endif close(socket->fd); clear_handlers(socket->fd); socket->fd = -1;}voiddns_exception(void *data){ struct connection *conn = data; set_connection_state(conn, S_EXCEPT); close_socket(NULL, conn->conn_info->socket); dns_found(conn, 0);}static voidexception(void *data){ retry_conn_with_state((struct connection *) data, S_EXCEPT);}struct conn_info *init_connection_info(struct uri *uri, struct connection_socket *socket, void (*done)(struct connection *)){ struct conn_info *conn_info = mem_calloc(1, sizeof(*conn_info)); if (!conn_info) return NULL; conn_info->done = done; conn_info->socket = socket; conn_info->port = get_uri_port(uri); conn_info->triedno = -1; conn_info->addr = NULL; return conn_info;}voiddone_connection_info(struct connection *conn){ struct conn_info *conn_info = conn->conn_info; conn->conn_info = NULL; if (conn_info->done) conn_info->done(conn); mem_free_if(conn_info->addr); mem_free(conn_info);}voidmake_connection(struct connection *conn, struct connection_socket *socket, void (*done)(struct connection *)){ unsigned char *host = get_uri_string(conn->uri, URI_DNS_HOST); struct conn_info *conn_info; int async; if (!host) { retry_conn_with_state(conn, S_OUT_OF_MEM); return; } conn_info = init_connection_info(conn->uri, socket, done); if (!conn_info) { mem_free(host); retry_conn_with_state(conn, S_OUT_OF_MEM); return; } conn->conn_info = conn_info; debug_transfer_log("\nCONNECTION: ", -1); debug_transfer_log(host, -1); debug_transfer_log("\n", -1); if (conn->cache_mode >= CACHE_MODE_FORCE_RELOAD) async = find_host_no_cache(host, &conn_info->addr, &conn_info->addrno, &conn->dnsquery, dns_found, conn); else async = find_host(host, &conn_info->addr, &conn_info->addrno, &conn->dnsquery, dns_found, conn); mem_free(host); if (async) set_connection_state(conn, S_DNS);}/* Returns negative if error, otherwise pasv socket's fd. */intget_pasv_socket(struct connection *conn, int ctrl_sock, unsigned char *port){ struct sockaddr_in sa, sb; int sock, len; memset(&sa, 0, sizeof(sa)); memset(&sb, 0, sizeof(sb)); /* Get our endpoint of the control socket */ len = sizeof(sa); if (getsockname(ctrl_sock, (struct sockaddr *) &sa, &len)) {sock_error: retry_conn_with_state(conn, -errno); return -1; } /* Get a passive socket */ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) goto sock_error; /* Set it non-blocking */ if (set_nonblocking_fd(sock) < 0) goto sock_error; /* Bind it to some port */ copy_struct(&sb, &sa); sb.sin_port = 0; if (bind(sock, (struct sockaddr *) &sb, sizeof(sb))) goto sock_error; /* Get our endpoint of the passive socket and save it to port */ len = sizeof(sa); if (getsockname(sock, (struct sockaddr *) &sa, &len)) goto sock_error; memcpy(port, &sa.sin_addr.s_addr, 4); memcpy(port + 4, &sa.sin_port, 2); /* Go listen */ if (listen(sock, 1)) goto sock_error; set_ip_tos_throughput(sock); return sock;}#ifdef CONFIG_IPV6intget_pasv6_socket(struct connection *conn, int ctrl_sock, struct sockaddr_storage *s6){ int sock; struct sockaddr_in6 s0; int len = sizeof(s0); memset(&s0, 0, sizeof(s0)); memset(s6, 0, sizeof(*s6)); /* Get our endpoint of the control socket */ if (getsockname(ctrl_sock, (struct sockaddr *) s6, &len)) {sock_error: retry_conn_with_state(conn, -errno); return -1; } /* Get a passive socket */ sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) goto sock_error; /* Set it non-blocking */ if (set_nonblocking_fd(sock) < 0) goto sock_error; /* Bind it to some port */ memcpy(&s0, s6, sizeof(s0)); s0.sin6_port = 0; if (bind(sock, (struct sockaddr *) &s0, sizeof(s0))) goto sock_error; /* Get our endpoint of the passive socket and save it to port */ len = sizeof(s0); if (getsockname(sock, (struct sockaddr *) s6, &len)) goto sock_error; /* Go listen */ if (listen(sock, 1)) goto sock_error; set_ip_tos_throughput(sock); return sock;}static inline intcheck_if_local_address6(struct sockaddr_in6 *addr){ struct ifaddrs *ifaddrs; int local = IN6_IS_ADDR_LOOPBACK(&(addr->sin6_addr)); if (!local && !getifaddrs(&ifaddrs)) { struct ifaddrs *ifa; for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family == AF_INET6 && !memcmp(&addr->sin6_addr.s6_addr, &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr.s6_addr, sizeof(addr->sin6_addr.s6_addr))) { local = 1; break; } if (ifa->ifa_addr->sa_family == AF_INET && !memcmp(&((struct sockaddr_in *) &addr)->sin_addr.s_addr, &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr, sizeof(((struct sockaddr_in *) &addr)->sin_addr.s_addr))) { local = 1; break; } } freeifaddrs(ifaddrs); } return local;}#endif /* CONFIG_IPV6 */static inline intcheck_if_local_address4(struct sockaddr_in *addr){ struct ifaddrs *ifaddrs; int local = (ntohl(addr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET; if (!local && !getifaddrs(&ifaddrs)) { struct ifaddrs *ifa; for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; if (!memcmp(&addr->sin_addr.s_addr, &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr))) { local = 1; break; } } freeifaddrs(ifaddrs); } return local;}voiddns_found(void *data, int state){ int sock = -1; struct connection *conn = (struct connection *) data; struct conn_info *conn_info = conn->conn_info; int i; int trno = conn_info->triedno; int only_local = get_cmd_opt_bool("localhost"); int saved_errno = 0; int at_least_one_remote_ip = 0; /* We tried something but we failed in such a way that we would rather * prefer the connection to retain the information about previous * failures. That is, we i.e. decided we are forbidden to even think * about such a connection attempt. * XXX: Unify with @local_only handling? --pasky */ int silent_fail = 0; if (state < 0) { abort_conn_with_state(conn, S_NO_DNS); return; } /* Clear handlers, the connection to the previous RR really timed * out and doesn't interest us anymore. */ if (conn_info->socket && conn_info->socket->fd >= 0) clear_handlers(conn_info->socket->fd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -