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 #include "P_Net.h"
00029 
00030 #define SET_NO_LINGER
00031 
00032 
00033 
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 
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   
00085   if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &mc_ttl, sizeof(mc_ttl)) < 0))
00086     goto Lerror;
00087 
00088   
00089   if ((res = safe_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &mc_if, sizeof(mc_if)) < 0))
00090     goto Lerror;
00091 
00092   
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     
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 
00162 
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 
00172 
00173 
00174 
00175 
00176 
00177 
00178 
00179         cleaner<self> clean_up(this, &self::cleanup);
00180         // modify or check the resource
00181         if (fail) return FAILURE; // cleanup() is called
00182 
00183         clean_up.reset(); // cleanup() not called after this
00184         return SUCCESS;
00185       @endcode
00186    */
00187   template <typename T> struct cleaner {
00188     T* obj; 
00189     typedef void (T::*method)(); 
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 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206 
00207 
00208 
00209 
00210 
00211 
00212 
00213 
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; 
00222   int res = 0; 
00223   IpEndpoint local_addr;
00224   sock_type = NetVCOptions::USE_UDP == opt.ip_proto
00225     ? SOCK_DGRAM
00226     : SOCK_STREAM;
00227   int family;
00228 
00229   
00230   
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     
00238     
00239     
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     
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   
00256   cleaner<Connection> cleanup(this, &Connection::_cleanup);
00257 
00258   
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       
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       
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   
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); 
00330 
00331   res = ::connect(fd, target, ats_ip_size(target));
00332 
00333   
00334   
00335   
00336   
00337   
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   
00363   
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 }