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

UnixConnection.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 **************************************************************************/
00028 #include "P_Net.h"
00029 
00030 #define SET_NO_LINGER
00031 // set in the OS
00032 // #define RECV_BUF_SIZE            (1024*64)
00033 // #define SEND_BUF_SIZE            (1024*64)
00034 #define FIRST_RANDOM_PORT        16000
00035 #define LAST_RANDOM_PORT         32000
00036 
00037 #define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
00038 
00039 #if TS_USE_TPROXY
00040 #if !defined(IP_TRANSPARENT)
00041 unsigned int const IP_TRANSPARENT = 19;
00042 #endif
00043 #endif
00044 
00045 //
00046 // Functions
00047 //
00048 int
00049 Connection::setup_mc_send(
00050   sockaddr const* mc_addr,
00051   sockaddr const* my_addr,
00052   bool non_blocking, unsigned char mc_ttl, bool mc_loopback, Continuation * c
00053 ) {
00054   (void) c;
00055   ink_assert(fd == NO_FD);
00056   int res = 0;
00057   int enable_reuseaddr = 1;
00058   in_addr_t mc_if = ats_ip4_addr_cast(my_addr);
00059 
00060   if ((res = socketManager.mc_socket(my_addr->sa_family, SOCK_DGRAM, 0, non_blocking)) < 0)
00061     goto Lerror;
00062 
00063   fd = res;
00064 
00065   if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable_reuseaddr, sizeof(enable_reuseaddr)) < 0)) {
00066     goto Lerror;
00067   }
00068 
00069   if ((res = socketManager.ink_bind(fd, my_addr, ats_ip_size(my_addr), IPPROTO_UDP)) < 0) {
00070     goto Lerror;
00071   }
00072 
00073   ats_ip_copy(&addr, mc_addr);
00074 
00075 #ifdef SET_CLOSE_ON_EXEC
00076   if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
00077     goto Lerror;
00078 #endif
00079 
00080   if (non_blocking)
00081     if ((res = safe_nonblocking(fd)) < 0)
00082       goto Lerror;
00083 
00084   // Set MultiCast TTL to specified value
00085   if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &mc_ttl, sizeof(mc_ttl)) < 0))
00086     goto Lerror;
00087 
00088   // Set MultiCast Interface to specified value
00089   if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &mc_if, sizeof(mc_if)) < 0))
00090     goto Lerror;
00091 
00092   // Disable MultiCast loopback if requested
00093   if (!mc_loopback) {
00094     char loop = 0;
00095 
00096     if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) < 0))
00097       goto Lerror;
00098   }
00099   return 0;
00100 
00101 Lerror:
00102   if (fd != NO_FD)
00103     close();
00104   return res;
00105 }
00106 
00107 
00108 int
00109 Connection::setup_mc_receive(
00110   sockaddr const* mc_addr,
00111   sockaddr const* my_addr,
00112   bool non_blocking, Connection * sendChan, Continuation * c
00113 ) {
00114   ink_assert(fd == NO_FD);
00115   (void) sendChan;
00116   (void) c;
00117   int res = 0;
00118   int enable_reuseaddr = 1;
00119   IpAddr inaddr_any(INADDR_ANY);
00120 
00121   if ((res = socketManager.socket(mc_addr->sa_family, SOCK_DGRAM, 0)) < 0)
00122     goto Lerror;
00123 
00124   fd = res;
00125 
00126 #ifdef SET_CLOSE_ON_EXEC
00127   if ((res = safe_fcntl(fd, F_SETFD, 1)) < 0)
00128     goto Lerror;
00129 #endif
00130 
00131   if ((res = safe_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable_reuseaddr, sizeof(enable_reuseaddr)) < 0))
00132     goto Lerror;
00133 
00134   addr.assign(inaddr_any, ats_ip_port_cast(mc_addr));
00135 
00136   if ((res = socketManager.ink_bind(fd, &addr.sa, ats_ip_size(&addr.sa), IPPROTO_TCP)) < 0)
00137     goto Lerror;
00138 
00139   if (non_blocking)
00140     if ((res = safe_nonblocking(fd)) < 0)
00141       goto Lerror;
00142 
00143   if (ats_is_ip4(&addr)) {
00144     struct ip_mreq mc_request;
00145     // Add ourselves to the MultiCast group
00146     mc_request.imr_multiaddr.s_addr = ats_ip4_addr_cast(mc_addr);
00147     mc_request.imr_interface.s_addr = ats_ip4_addr_cast(my_addr);
00148 
00149     if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mc_request, sizeof(mc_request)) < 0))
00150       goto Lerror;
00151   }
00152   return 0;
00153 
00154 Lerror:
00155   if (fd != NO_FD)
00156     close();
00157   return res;
00158 }
00159 
00160 namespace {
00161   /** Struct to make cleaning up resources easier.
00162 
00163       By default, the @a method is invoked on the @a object when
00164       this object is destructed. This can be prevented by calling
00165       the @c reset method.
00166 
00167       This is not overly useful in the allocate, check, return case
00168       but very handy if there are
00169       - multiple resources (each can have its own cleaner)
00170       - multiple checks against the resource
00171       In such cases, rather than trying to track all the resources
00172       that might need cleaned up, you can set up a cleaner at allocation
00173       and only have to deal with them on success, which is generally
00174       singular.
00175 
00176       @code
00177       self::some_method (...) {
00178         /// allocate resource
00179         cleaner<self> clean_up(this, &self::cleanup);
00180         // modify or check the resource
00181         if (fail) return FAILURE; // cleanup() is called
00182         /// success!
00183         clean_up.reset(); // cleanup() not called after this
00184         return SUCCESS;
00185       @endcode
00186    */
00187   template <typename T> struct cleaner {
00188     T* obj; ///< Object instance.
00189     typedef void (T::*method)(); ///< Method signature.
00190     method m;
00191 
00192     cleaner(T* _obj, method  _method) : obj(_obj), m(_method) {}
00193     ~cleaner() { if (obj) (obj->*m)(); }
00194     void reset() { obj = 0; }
00195   };
00196 }
00197 
00198 /** Default options.
00199 
00200     @internal This structure is used to reduce the number of places in
00201     which the defaults are set. Originally the argument defaulted to
00202     @c NULL which meant that the defaults had to be encoded in any
00203     methods that used it as well as the @c NetVCOptions
00204     constructor. Now they are controlled only in the latter and not in
00205     any of the methods. This makes handling global default values
00206     (such as @c RECV_BUF_SIZE) more robust. It doesn't have to be
00207     checked in the method, only in the @c NetVCOptions constructor.
00208 
00209     The methods are simpler because they never have to check for the
00210     presence of the options, yet the clients aren't inconvenienced
00211     because a default value for the argument is provided. Further,
00212     clients can pass temporaries and not have to declare a variable in
00213     order to tweak options.
00214  */
00215 NetVCOptions const Connection::DEFAULT_OPTIONS;
00216 
00217 int
00218 Connection::open(NetVCOptions const& opt)
00219 {
00220   ink_assert(fd == NO_FD);
00221   int enable_reuseaddr = 1; // used for sockopt setting
00222   int res = 0; // temp result
00223   IpEndpoint local_addr;
00224   sock_type = NetVCOptions::USE_UDP == opt.ip_proto
00225     ? SOCK_DGRAM
00226     : SOCK_STREAM;
00227   int family;
00228 
00229   // Need to do address calculations first, so we can determine the
00230   // address family for socket creation.
00231   ink_zero(local_addr);
00232 
00233   bool is_any_address = false;
00234   if (NetVCOptions::FOREIGN_ADDR == opt.addr_binding ||
00235     NetVCOptions::INTF_ADDR == opt.addr_binding
00236   ) {
00237     // Same for now, transparency for foreign addresses must be handled
00238     // *after* the socket is created, and we need to do this calculation
00239     // before the socket to get the IP family correct.
00240     ink_release_assert(opt.local_ip.isValid());
00241     local_addr.assign(opt.local_ip, htons(opt.local_port));
00242     family = opt.local_ip.family();
00243   } else {
00244     // No local address specified, so use family option if possible.
00245     family = ats_is_ip(opt.ip_family) ? opt.ip_family : AF_INET;
00246     local_addr.setToAnyAddr(family);
00247     is_any_address = true;
00248     local_addr.port() = htons(opt.local_port);
00249   }
00250 
00251   res = socketManager.socket(family, sock_type, 0);
00252   if (-1 == res) return -errno;
00253 
00254   fd = res;
00255   // mark fd for close until we succeed.
00256   cleaner<Connection> cleanup(this, &Connection::_cleanup);
00257 
00258   // Try setting the various socket options, if requested.
00259 
00260   if (-1 == safe_setsockopt(fd,
00261                             SOL_SOCKET,
00262                             SO_REUSEADDR,
00263                             reinterpret_cast<char *>(&enable_reuseaddr),
00264                             sizeof(enable_reuseaddr)))
00265     return -errno;
00266 
00267   if (NetVCOptions::FOREIGN_ADDR == opt.addr_binding) {
00268     static char const * const DEBUG_TEXT = "::open setsockopt() IP_TRANSPARENT";
00269 #if TS_USE_TPROXY
00270     int value = 1;
00271     if (-1 == safe_setsockopt(fd, SOL_IP, TS_IP_TRANSPARENT,
00272                               reinterpret_cast<char*>(&value), sizeof(value)
00273                               )) {
00274       Debug("socket", "%s - fail %d:%s", DEBUG_TEXT, errno, strerror(errno));
00275       return -errno;
00276     } else {
00277       Debug("socket", "%s set", DEBUG_TEXT);
00278     }
00279 #else
00280     Debug("socket", "%s - requested but TPROXY not configured", DEBUG_TEXT);
00281 #endif
00282   }
00283 
00284   if (!opt.f_blocking_connect && -1 == safe_nonblocking(fd))
00285     return -errno;
00286 
00287   if (opt.socket_recv_bufsize > 0) {
00288     if (socketManager.set_rcvbuf_size(fd, opt.socket_recv_bufsize)) {
00289       // Round down until success
00290       int rbufsz = ROUNDUP(opt.socket_recv_bufsize, 1024);
00291       while (rbufsz && !socketManager.set_rcvbuf_size(fd, rbufsz))
00292         rbufsz -= 1024;
00293       Debug("socket", "::open: recv_bufsize = %d of %d\n", rbufsz, opt.socket_recv_bufsize);
00294     }
00295   }
00296   if (opt.socket_send_bufsize > 0) {
00297     if (socketManager.set_sndbuf_size(fd, opt.socket_send_bufsize)) {
00298       // Round down until success
00299       int sbufsz = ROUNDUP(opt.socket_send_bufsize, 1024);
00300       while (sbufsz && !socketManager.set_sndbuf_size(fd, sbufsz))
00301         sbufsz -= 1024;
00302       Debug("socket", "::open: send_bufsize = %d of %d\n", sbufsz, opt.socket_send_bufsize);
00303     }
00304   }
00305 
00306   // apply dynamic options
00307   apply_options(opt);
00308 
00309   if(local_addr.port() || !is_any_address) {
00310     if (-1 == socketManager.ink_bind(fd, &local_addr.sa, ats_ip_size(&local_addr.sa)))
00311       return -errno;
00312   }
00313 
00314   cleanup.reset();
00315   is_bound = true;
00316   return 0;
00317 }
00318 
00319 int
00320 Connection::connect(sockaddr const* target, NetVCOptions const& opt) {
00321   ink_assert(fd != NO_FD);
00322   ink_assert(is_bound);
00323   ink_assert(!is_connected);
00324 
00325   int res;
00326 
00327   this->setRemote(target);
00328 
00329   cleaner<Connection> cleanup(this, &Connection::_cleanup); // mark for close until we succeed.
00330 
00331   res = ::connect(fd, target, ats_ip_size(target));
00332 
00333   // It's only really an error if either the connect was blocking
00334   // or it wasn't blocking and the error was other than EINPROGRESS.
00335   // (Is EWOULDBLOCK ok? Does that start the connect?)
00336   // We also want to handle the cases where the connect blocking
00337   // and IO blocking differ, by turning it on or off as needed.
00338   if (-1 == res 
00339       && (opt.f_blocking_connect
00340           || ! (EINPROGRESS == errno || EWOULDBLOCK == errno))) {
00341     return -errno;
00342   } else if (opt.f_blocking_connect && !opt.f_blocking) {
00343     if (-1 == safe_nonblocking(fd)) return -errno;
00344   } else if (!opt.f_blocking_connect && opt.f_blocking) {
00345     if (-1 == safe_blocking(fd)) return -errno;
00346   }
00347 
00348   cleanup.reset();
00349   is_connected = true;
00350   return 0;
00351 }
00352 
00353 void
00354 Connection::_cleanup()
00355 {
00356   this->close();
00357 }
00358 
00359 void
00360 Connection::apply_options(NetVCOptions const& opt)
00361 {
00362   // Set options which can be changed after a connection is established
00363   // ignore other changes
00364   if (SOCK_STREAM == sock_type) {
00365     if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_NO_DELAY) {
00366       safe_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, SOCKOPT_ON, sizeof(int));
00367       Debug("socket", "::open: setsockopt() TCP_NODELAY on socket");
00368     }
00369     if (opt.sockopt_flags & NetVCOptions::SOCK_OPT_KEEP_ALIVE) {
00370       safe_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, SOCKOPT_ON, sizeof(int));
00371       Debug("socket", "::open: setsockopt() SO_KEEPALIVE on socket");
00372     }
00373   }
00374 
00375 #if TS_HAS_SO_MARK
00376   uint32_t mark = opt.packet_mark;
00377   safe_setsockopt(fd, SOL_SOCKET, SO_MARK, reinterpret_cast<char *>(&mark), sizeof(uint32_t));
00378 #endif
00379 
00380 #if TS_HAS_IP_TOS
00381   uint32_t tos = opt.packet_tos;
00382   safe_setsockopt(fd, IPPROTO_IP, IP_TOS, reinterpret_cast<char *>(&tos), sizeof(uint32_t));
00383 #endif
00384 
00385 }

Generated by  doxygen 1.7.1