IPSocket.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "IPSocket.h"
00019 #include "NetUtils.h"
00020 #include "debug/Log.h"
00021 #include "debug/DebugUtils.h"
00022 
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <fcntl.h>
00026 #include <errno.h>
00027 #include <sys/ioctl.h>
00028 #include <sys/types.h>
00029 #include <sys/socket.h>
00030 #include <sys/uio.h>
00031 #include <sys/poll.h>
00032 #include <netinet/in.h>
00033 #include <netinet/tcp.h>
00034 #include <arpa/inet.h>
00035 
00036 namespace oasys {
00037 
00038 IPSocket::IPSocket(int socktype, const char* logbase)
00039     : Logger("IPSocket", logbase)
00040 {
00041     state_       = INIT;
00042     local_addr_  = INADDR_ANY;
00043     local_port_  = 0;
00044     remote_addr_ = INADDR_NONE;
00045     remote_port_ = 0;
00046     fd_          = -1;
00047     socktype_    = socktype;
00048     logfd_       = true;
00049 }
00050 
00051 IPSocket::IPSocket(int socktype, int sock,
00052                    in_addr_t remote_addr, u_int16_t remote_port,
00053                    const char* logbase)
00054     : Logger("IPSocket", "%s/%d", logbase, sock)
00055 {
00056     fd_       = sock;
00057     socktype_ = socktype;
00058     
00059     state_       = ESTABLISHED;
00060     local_addr_  = INADDR_NONE;
00061     local_port_  = 0;
00062     remote_addr_ = remote_addr;
00063     remote_port_ = remote_port;
00064     
00065     configure();
00066 }
00067 
00068 IPSocket::~IPSocket()
00069 {
00070     close();
00071 }
00072 
00073 void
00074 IPSocket::init_socket()
00075 {
00076     // should only be called at real init time or after a call to close()
00077     ASSERT(state_ == INIT || state_ == FINI);
00078     ASSERT(fd_ == -1);
00079     state_ = INIT;
00080     
00081     fd_ = socket(PF_INET, socktype_, 0);
00082     if (fd_ == -1) {
00083         logf(LOG_ERR, "error creating socket: %s", strerror(errno));
00084         return;
00085     }
00086 
00087     if (logfd_)
00088         Logger::logpath_appendf("/%d", fd_);
00089     
00090     logf(LOG_DEBUG, "created socket %d", fd_);
00091     
00092     configure();
00093 }
00094 
00095 const char*
00096 IPSocket::statetoa(state_t state)
00097 {
00098     switch (state) {
00099     case INIT:          return "INIT";
00100     case LISTENING:     return "LISTENING";
00101     case CONNECTING:    return "CONNECTING";
00102     case ESTABLISHED:   return "ESTABLISHED";
00103     case RDCLOSED:      return "RDCLOSED";
00104     case WRCLOSED:      return "WRCLOSED";
00105     case CLOSED:        return "CLOSED";
00106     case FINI:          return "FINI";
00107     }
00108     ASSERT(0);
00109     return NULL;
00110 }
00111 
00112 void
00113 IPSocket::set_state(state_t state)
00114 {
00115     logf(LOG_DEBUG, "state %s -> %s", statetoa(state_), statetoa(state));
00116     state_ = state;
00117 }
00118 
00119 int
00120 IPSocket::bind(in_addr_t local_addr, u_int16_t local_port)
00121 {
00122     struct sockaddr_in sa;
00123 
00124     if (fd_ == -1) init_socket();
00125 
00126     local_addr_ = local_addr;
00127     local_port_ = local_port;
00128 
00129     logf(LOG_DEBUG, "binding to %s:%d", intoa(local_addr), local_port);
00130 
00131     memset(&sa, 0, sizeof(sa));
00132     sa.sin_family = AF_INET;
00133     sa.sin_addr.s_addr = local_addr_;
00134     sa.sin_port = htons(local_port_);
00135     if (::bind(fd_, (struct sockaddr*) &sa, sizeof(sa)) != 0) {
00136         int err = errno;
00137         logf(LOG_ERR, "error binding to %s:%d: %s",
00138              intoa(local_addr_), local_port_, strerror(err));
00139         return -1;
00140     }
00141 
00142     return 0;
00143 }
00144 
00145 int
00146 IPSocket::connect()
00147 {
00148     struct sockaddr_in sa;
00149 
00150     if (ESTABLISHED == state_)
00151         return 0;
00152 
00153     if (fd_ == -1) init_socket();
00154 
00155     log_debug("connecting to %s:%d", intoa(remote_addr_), remote_port_);
00156 
00157     memset(&sa, 0, sizeof(sa));
00158     sa.sin_family = AF_INET;
00159     sa.sin_addr.s_addr = remote_addr_;
00160     sa.sin_port = htons(remote_port_);
00161 
00162     set_state(CONNECTING);
00163 
00164     if (::connect(fd_, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
00165         if (errno == EISCONN)
00166             log_debug("already connected to %s:%d",
00167                       intoa(remote_addr_), remote_port_);
00168         else if (errno == EINPROGRESS) {
00169             log_debug("delayed connect to %s:%d (EINPROGRESS)",
00170                       intoa(remote_addr_), remote_port_);
00171         } else {
00172             log_debug("error connecting to %s:%d: %s",
00173                       intoa(remote_addr_), remote_port_, strerror(errno));
00174         }
00175         
00176         return -1;
00177     }
00178 
00179     set_state(ESTABLISHED);
00180 
00181     return 0;
00182 }
00183 
00184 int
00185 IPSocket::async_connect_result()
00186 {
00187     ASSERT(state_ == CONNECTING);
00188 
00189     int result;
00190     socklen_t len = sizeof(result);
00191     logf(LOG_DEBUG, "getting connect result");
00192     if (::getsockopt(fd_, SOL_SOCKET, SO_ERROR, &result, &len) != 0) {
00193         logf(LOG_ERR, "error getting connect result: %s", strerror(errno));
00194         return errno;
00195     }
00196 
00197     if (result == 0) {
00198         set_state(ESTABLISHED);
00199     }
00200 
00201     return result;
00202 }
00203 
00204 int
00205 IPSocket::connect(in_addr_t remote_addr, u_int16_t remote_port)
00206 {
00207     remote_addr_ = remote_addr;
00208     remote_port_ = remote_port;
00209 
00210     return connect();
00211 }
00212 
00213 void
00214 IPSocket::configure()
00215 {
00216     if (params_.reuseaddr_) {
00217         int y = 1;
00218         logf(LOG_DEBUG, "setting SO_REUSEADDR");
00219         if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &y, sizeof y) != 0) {
00220             logf(LOG_WARN, "error setting SO_REUSEADDR: %s",
00221                  strerror(errno));
00222         }
00223     }
00224 
00225     if (params_.reuseport_) {
00226 #ifdef SO_REUSEPORT
00227         int y = 1;
00228         logf(LOG_DEBUG, "setting SO_REUSEPORT");
00229         if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEPORT, &y, sizeof y) != 0) {
00230             logf(LOG_WARN, "error setting SO_REUSEPORT: %s",
00231                  strerror(errno));
00232         }
00233 #else
00234         logf(LOG_WARN, "error setting SO_REUSEPORT: not implemented");
00235 #endif
00236     }
00237     
00238     if (socktype_ == SOCK_STREAM && params_.tcp_nodelay_) {
00239         int y = 1;
00240         logf(LOG_DEBUG, "setting TCP_NODELAY");
00241         if (::setsockopt(fd_, IPPROTO_IP, TCP_NODELAY, &y, sizeof y) != 0) {
00242             logf(LOG_WARN, "error setting TCP_NODELAY: %s",
00243                  strerror(errno));
00244         }
00245     }
00246 
00247     if (socktype_ == SOCK_DGRAM && params_.broadcast_) {
00248         int y = 1;
00249         logf(LOG_DEBUG, "setting SO_BROADCAST");
00250 
00251         if (::setsockopt(fd_, SOL_SOCKET, SO_BROADCAST, &y, sizeof(y)) != 0) {
00252             logf(LOG_WARN, "error setting SO_BROADCAST: %s",
00253                  strerror(errno));
00254         }
00255     }
00256     
00257     if (socktype_ == SOCK_DGRAM && params_.multicast_) {
00258 
00259         // set up receiver to join in on multicast tree
00260         struct ip_mreq mcast_request;
00261         memset(&mcast_request,0,sizeof(struct ip_mreq));
00262 
00263         // Force remote addr to match multicast (class D)
00264         // 224.0.0.0 - 239.255.255.255
00265         in_addr_t mcast_addr = inet_addr("224.0.0.0");
00266         if (mcast_addr & remote_addr_ != mcast_addr) {
00267             logf(LOG_WARN, "multicast option set on non-multicast address: "
00268                            "%s",intoa(remote_addr_));
00269             return;
00270         }
00271 
00272         // set up remote address for multicast options struct
00273         mcast_request.imr_multiaddr.s_addr = remote_addr_;
00274         mcast_request.imr_interface.s_addr = INADDR_ANY;
00275 
00276         // pass struct into setsockopt
00277         if (::setsockopt(fd_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
00278                          (void*) &mcast_request, sizeof (struct ip_mreq)) < 0)
00279         {
00280             logf(LOG_WARN, "error setting multicast options: %s",
00281                            strerror(errno));
00282         }
00283 
00284         // set TTL on outbound packets
00285         u_char ttl = (u_char) params_.mcast_ttl_ & 0xff;
00286         if (::setsockopt(fd_, IPPROTO_IP, IP_MULTICAST_TTL, (void*) &ttl, 1)
00287                 < 0) {
00288             logf(LOG_WARN, "error setting multicast ttl: %s",
00289                            strerror(errno));
00290         }
00291     }
00292 
00293     if (params_.recv_bufsize_ > 0) {
00294         logf(LOG_DEBUG, "setting SO_RCVBUF to %d",
00295              params_.recv_bufsize_);
00296         
00297         if (::setsockopt(fd_, SOL_SOCKET, SO_RCVBUF,
00298                          &params_.recv_bufsize_,
00299                          sizeof (params_.recv_bufsize_)) < 0)
00300         {
00301             logf(LOG_WARN, "error setting SO_RCVBUF to %d: %s",
00302                  params_.recv_bufsize_, strerror(errno));
00303         }
00304     }
00305     
00306     if (params_.send_bufsize_ > 0) {
00307         logf(LOG_WARN, "setting SO_SNDBUF to %d",
00308              params_.send_bufsize_);
00309         
00310         if (::setsockopt(fd_, SOL_SOCKET, SO_SNDBUF,
00311                          &params_.send_bufsize_,
00312                          sizeof params_.send_bufsize_) < 0)
00313         {
00314             logf(LOG_WARN, "error setting SO_SNDBUF to %d: %s",
00315                  params_.send_bufsize_, strerror(errno));
00316         }
00317     }
00318 }
00319     
00320 int
00321 IPSocket::close()
00322 {
00323     logf(LOG_DEBUG, "closing socket in state %s", statetoa(state_));
00324 
00325     if (fd_ == -1) {
00326         ASSERT(state_ == INIT || state_ == FINI);
00327         return 0;
00328     }
00329     
00330     if (::close(fd_) != 0) {
00331         logf(LOG_ERR, "error closing socket in state %s: %s",
00332              statetoa(state_), strerror(errno));
00333         return -1;
00334     }
00335     
00336     set_state(FINI);
00337     fd_ = -1;
00338     return 0;
00339 }
00340 
00341 int
00342 IPSocket::shutdown(int how)
00343 {
00344     const char* howstr;
00345 
00346     switch (how) {
00347     case SHUT_RD:   howstr = "R";  break;
00348     case SHUT_WR:   howstr = "W";  break;
00349     case SHUT_RDWR: howstr = "RW"; break;
00350         
00351     default:
00352         logf(LOG_ERR, "shutdown invalid mode %d", how);
00353         return -1;
00354     }
00355       
00356     logf(LOG_DEBUG, "shutdown(%s) state %s", howstr, statetoa(state_));
00357     
00358     if (state_ == INIT || state_ == FINI) {
00359         ASSERT(fd_ == -1);
00360         return 0;
00361     }
00362     
00363     if (::shutdown(fd_, how) != 0) {
00364         logf(LOG_ERR, "error in shutdown(%s) state %s: %s",
00365              howstr, statetoa(state_), strerror(errno));
00366     }
00367     
00368     if (state_ == ESTABLISHED) {
00369         if (how == SHUT_RD)     { set_state(RDCLOSED); }
00370         if (how == SHUT_WR)     { set_state(WRCLOSED); }
00371         if (how == SHUT_RDWR)   { set_state(CLOSED); }
00372         
00373     } else if (state_ == RDCLOSED && how == SHUT_WR) {
00374         set_state(CLOSED);
00375         
00376     } else if (state_ == WRCLOSED && how == SHUT_RD) {
00377         set_state(CLOSED);
00378 
00379     } else {
00380         logf(LOG_ERR, "invalid state %s for shutdown(%s)",
00381              statetoa(state_), howstr);
00382         return -1;
00383     }
00384 
00385     return 0;
00386 }
00387 
00388 int
00389 IPSocket::send(const char* bp, size_t len, int flags)
00390 {
00391     return IO::send(fd_, bp, len, flags, get_notifier(), logpath_);
00392 }
00393 
00394 int
00395 IPSocket::sendto(char* bp, size_t len, int flags,
00396                  in_addr_t addr, u_int16_t port)
00397 {
00398     struct sockaddr_in sa;
00399     memset(&sa, 0, sizeof(sa));
00400     sa.sin_family = AF_INET;
00401     sa.sin_addr.s_addr = addr;
00402     sa.sin_port = htons(port);
00403 
00404     return IO::sendto(fd_, bp, len, flags, (sockaddr*)&sa, 
00405                       sizeof(sa), get_notifier(), logpath_);
00406 }
00407 
00408 int
00409 IPSocket::sendmsg(const struct msghdr* msg, int flags)
00410 {
00411     return IO::sendmsg(fd_, msg, flags, get_notifier(), logpath_);
00412 }
00413 
00414 int
00415 IPSocket::recv(char* bp, size_t len, int flags)
00416 {
00417     return IO::recv(fd_, bp, len, flags, 
00418                     get_notifier(), logpath_);
00419 }
00420 
00421 int
00422 IPSocket::recvfrom(char* bp, size_t len, int flags,
00423                    in_addr_t *addr, u_int16_t *port)
00424 {
00425     struct sockaddr_in sa;
00426     socklen_t sl = sizeof(sa);
00427     memset(&sa, 0, sizeof(sa));
00428     
00429     int cc = IO::recvfrom(fd_, bp, len, flags, (sockaddr*)&sa, &sl, 
00430                           get_notifier(), logpath_);
00431     
00432     if (cc < 0) {
00433         if (cc != IOINTR)
00434             logf(LOG_ERR, "error in recvfrom(): %s", strerror(errno));
00435         return cc;
00436     }
00437 
00438     if (addr)
00439         *addr = sa.sin_addr.s_addr;
00440 
00441     if (port)
00442         *port = htons(sa.sin_port);
00443 
00444     return cc;
00445 }
00446 
00447 int
00448 IPSocket::recvmsg(struct msghdr* msg, int flags)
00449 {
00450     return IO::recvmsg(fd_, msg, flags, get_notifier(), logpath_);
00451 }
00452 
00453 int
00454 IPSocket::poll_sockfd(int events, int* revents, int timeout_ms)
00455 {
00456     short s_events = events;
00457     short s_revents;
00458     
00459     int cc = IO::poll_single(fd_, s_events, &s_revents, timeout_ms, 
00460                              get_notifier(), logpath_);
00461     
00462     if (revents != 0) {
00463         *revents = s_revents;
00464     }
00465 
00466     return cc;
00467 }
00468 
00469 } // namespace oasys

Generated on Sat Sep 8 08:36:17 2007 for DTN Reference Implementation by  doxygen 1.5.3