Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "P_DNS.h"
00031 #include "P_DNSConnection.h"
00032 #include "P_DNSProcessor.h"
00033
00034 #define SET_TCP_NO_DELAY
00035 #define SET_NO_LINGER
00036
00037
00038
00039 #define FIRST_RANDOM_PORT (16000)
00040 #define LAST_RANDOM_PORT (60000)
00041
00042 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
00043
00044 DNSConnection::Options const DNSConnection::DEFAULT_OPTIONS;
00045
00046
00047
00048
00049
00050 DNSConnection::DNSConnection():
00051 fd(NO_FD), num(0), generator((uint32_t)((uintptr_t)time(NULL) ^ (uintptr_t) this)), handler(NULL)
00052 {
00053 memset(&ip, 0, sizeof(ip));
00054 }
00055
00056 DNSConnection::~DNSConnection()
00057 {
00058 close();
00059 }
00060
00061 int
00062 DNSConnection::close()
00063 {
00064
00065 if (fd >= 2) {
00066 int fd_save = fd;
00067 fd = NO_FD;
00068 return socketManager.close(fd_save);
00069 } else {
00070 fd = NO_FD;
00071 return -EBADF;
00072 }
00073 }
00074
00075 void
00076 DNSConnection::trigger()
00077 {
00078 handler->triggered.enqueue(this);
00079 }
00080
00081 int
00082 DNSConnection::connect(sockaddr const* addr, Options const& opt)
00083
00084 {
00085 ink_assert(fd == NO_FD);
00086 ink_assert(ats_is_ip(addr));
00087
00088 int res = 0;
00089 short Proto;
00090 uint8_t af = addr->sa_family;
00091 IpEndpoint bind_addr;
00092 size_t bind_size = 0;
00093
00094 if (opt._use_tcp) {
00095 Proto = IPPROTO_TCP;
00096 if ((res = socketManager.socket(af, SOCK_STREAM, 0)) < 0)
00097 goto Lerror;
00098 } else {
00099 Proto = IPPROTO_UDP;
00100 if ((res = socketManager.socket(af, SOCK_DGRAM, 0)) < 0)
00101 goto Lerror;
00102 }
00103
00104 fd = res;
00105
00106 memset(&bind_addr, 0, sizeof bind_addr);
00107 bind_addr.sa.sa_family = af;
00108
00109 if (AF_INET6 == af) {
00110 if (ats_is_ip6(opt._local_ipv6)) {
00111 ats_ip_copy(&bind_addr.sa, opt._local_ipv6);
00112 } else {
00113 bind_addr.sin6.sin6_addr = in6addr_any;
00114 }
00115 bind_size = sizeof(sockaddr_in6);
00116 } else if (AF_INET == af) {
00117 if (ats_is_ip4(opt._local_ipv4))
00118 ats_ip_copy(&bind_addr.sa, opt._local_ipv4);
00119 else
00120 bind_addr.sin.sin_addr.s_addr = INADDR_ANY;
00121 bind_size = sizeof(sockaddr_in);
00122 } else {
00123 ink_assert(!"Target DNS address must be IP.");
00124 }
00125
00126 if (opt._bind_random_port) {
00127 int retries = 0;
00128 IpEndpoint bind_addr;
00129 size_t bind_size = 0;
00130 memset(&bind_addr, 0, sizeof bind_addr);
00131 bind_addr.sa.sa_family = af;
00132 if (AF_INET6 == af) {
00133 bind_addr.sin6.sin6_addr = in6addr_any;
00134 bind_size = sizeof bind_addr.sin6;
00135 } else {
00136 bind_addr.sin.sin_addr.s_addr = INADDR_ANY;
00137 bind_size = sizeof bind_addr.sin;
00138 }
00139 while (retries++ < 10000) {
00140 ip_port_text_buffer b;
00141 uint32_t p = generator.random();
00142 p = static_cast<uint16_t>((p % (LAST_RANDOM_PORT - FIRST_RANDOM_PORT)) + FIRST_RANDOM_PORT);
00143 ats_ip_port_cast(&bind_addr.sa) = htons(p);
00144 Debug("dns", "random port = %s\n", ats_ip_nptop(&bind_addr.sa, b, sizeof b));
00145 if ((res = socketManager.ink_bind(fd, &bind_addr.sa, bind_size, Proto)) < 0) {
00146 continue;
00147 }
00148 goto Lok;
00149 }
00150 Warning("unable to bind random DNS port");
00151 Lok:;
00152 } else if (ats_is_ip(&bind_addr.sa)) {
00153 ip_text_buffer b;
00154 res = socketManager.ink_bind(fd, &bind_addr.sa, bind_size, Proto);
00155 if (res < 0) Warning("Unable to bind local address to %s.",
00156 ats_ip_ntop(&bind_addr.sa, b, sizeof b));
00157 }
00158
00159 if (opt._non_blocking_connect)
00160 if ((res = safe_nonblocking(fd)) < 0)
00161 goto Lerror;
00162
00163
00164 #ifdef SET_TCP_NO_DELAY
00165 if (opt._use_tcp)
00166 if ((res = safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, SOCKOPT_ON, sizeof(int))) < 0)
00167 goto Lerror;
00168 #endif
00169 #ifdef RECV_BUF_SIZE
00170 socketManager.set_rcvbuf_size(fd, RECV_BUF_SIZE);
00171 #endif
00172 #ifdef SET_SO_KEEPALIVE
00173
00174 if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, SOCKOPT_ON, sizeof(int))) < 0)
00175 goto Lerror;
00176 #endif
00177
00178 ats_ip_copy(&ip.sa, addr);
00179 res =::connect(fd, addr, ats_ip_size(addr));
00180
00181 if (!res || ((res < 0) && (errno == EINPROGRESS || errno == EWOULDBLOCK))) {
00182 if (!opt._non_blocking_connect && opt._non_blocking_io)
00183 if ((res = safe_nonblocking(fd)) < 0)
00184 goto Lerror;
00185
00186
00187 } else
00188 goto Lerror;
00189
00190 return 0;
00191
00192 Lerror:
00193 if (fd != NO_FD)
00194 close();
00195 return res;
00196 }