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 }