• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

DNSConnection.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /**************************************************************************
00025   Connections
00026 
00027   Commonality across all platforms -- move out as required.
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 // set in the OS
00037 // #define RECV_BUF_SIZE            (1024*64)
00038 // #define SEND_BUF_SIZE            (1024*64)
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 // Functions
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   // don't close any of the standards
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 //                       bool non_blocking_connect, bool use_tcp, bool non_blocking, bool bind_random_port)
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); // stuff port in sockaddr.
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   // cannot do this after connection on non-blocking connect
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   // enables 2 hour inactivity probes, also may fix IRIX FIN_WAIT_2 leak
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     // Shouldn't we turn off non-blocking when it's a non-blocking connect
00186     // and blocking IO?
00187   } else
00188     goto Lerror;
00189 
00190   return 0;
00191 
00192 Lerror:
00193   if (fd != NO_FD)
00194     close();
00195   return res;
00196 }

Generated by  doxygen 1.7.1