IPSocket.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include "IPSocket.h"
00040 #include "NetUtils.h"
00041 #include "debug/Log.h"
00042 #include "debug/DebugUtils.h"
00043 
00044 #include <string.h>
00045 #include <unistd.h>
00046 #include <fcntl.h>
00047 #include <errno.h>
00048 #include <sys/ioctl.h>
00049 #include <sys/types.h>
00050 #include <sys/socket.h>
00051 #include <sys/uio.h>
00052 #include <sys/poll.h>
00053 #include <netinet/in.h>
00054 #include <netinet/tcp.h>
00055 #include <arpa/inet.h>
00056 
00057 namespace oasys {
00058 
00059 IPSocket::IPSocket(int socktype, const char* logbase)
00060     : Logger("IPSocket", logbase)
00061 {
00062     state_       = INIT;
00063     local_addr_  = INADDR_ANY;
00064     local_port_  = 0;
00065     remote_addr_ = INADDR_NONE;
00066     remote_port_ = 0;
00067     fd_          = -1;
00068     socktype_    = socktype;
00069     logfd_       = true;
00070 }
00071 
00072 IPSocket::IPSocket(int socktype, int sock,
00073                    in_addr_t remote_addr, u_int16_t remote_port,
00074                    const char* logbase)
00075     : Logger("IPSocket", "%s/%d", logbase, sock)
00076 {
00077     fd_       = sock;
00078     socktype_ = socktype;
00079     
00080     state_       = ESTABLISHED;
00081     local_addr_  = INADDR_NONE;
00082     local_port_  = 0;
00083     remote_addr_ = remote_addr;
00084     remote_port_ = remote_port;
00085     
00086     configure();
00087 }
00088 
00089 IPSocket::~IPSocket()
00090 {
00091     close();
00092 }
00093 
00094 void
00095 IPSocket::init_socket()
00096 {
00097     // should only be called at real init time or after a call to close()
00098     ASSERT(state_ == INIT || state_ == FINI);
00099     ASSERT(fd_ == -1);
00100     state_ = INIT;
00101     
00102     fd_ = socket(PF_INET, socktype_, 0);
00103     if (fd_ == -1) {
00104         logf(LOG_ERR, "error creating socket: %s", strerror(errno));
00105         return;
00106     }
00107 
00108     if (logfd_)
00109         Logger::logpath_appendf("/%d", fd_);
00110     
00111     logf(LOG_DEBUG, "created socket %d", fd_);
00112     
00113     configure();
00114 }
00115 
00116 const char*
00117 IPSocket::statetoa(state_t state)
00118 {
00119     switch (state) {
00120     case INIT:          return "INIT";
00121     case LISTENING:     return "LISTENING";
00122     case CONNECTING:    return "CONNECTING";
00123     case ESTABLISHED:   return "ESTABLISHED";
00124     case RDCLOSED:      return "RDCLOSED";
00125     case WRCLOSED:      return "WRCLOSED";
00126     case CLOSED:        return "CLOSED";
00127     case FINI:          return "FINI";
00128     }
00129     ASSERT(0);
00130     return NULL;
00131 }
00132 
00133 void
00134 IPSocket::set_state(state_t state)
00135 {
00136     logf(LOG_DEBUG, "state %s -> %s", statetoa(state_), statetoa(state));
00137     state_ = state;
00138 }
00139 
00140 int
00141 IPSocket::bind(in_addr_t local_addr, u_int16_t local_port)
00142 {
00143     struct sockaddr_in sa;
00144 
00145     if (fd_ == -1) init_socket();
00146 
00147     local_addr_ = local_addr;
00148     local_port_ = local_port;
00149 
00150     logf(LOG_DEBUG, "binding to %s:%d", intoa(local_addr), local_port);
00151 
00152     memset(&sa, 0, sizeof(sa));
00153     sa.sin_family = AF_INET;
00154     sa.sin_addr.s_addr = local_addr_;
00155     sa.sin_port = htons(local_port_);
00156     if (::bind(fd_, (struct sockaddr*) &sa, sizeof(sa)) != 0) {
00157         int err = errno;
00158         logf(LOG_ERR, "error binding to %s:%d: %s",
00159              intoa(local_addr_), local_port_, strerror(err));
00160         return -1;
00161     }
00162 
00163     return 0;
00164 }
00165 
00166 int
00167 IPSocket::connect()
00168 {
00169     struct sockaddr_in sa;
00170 
00171     if (ESTABLISHED == state_)
00172         return 0;
00173 
00174     if (fd_ == -1) init_socket();
00175 
00176     log_debug("connecting to %s:%d", intoa(remote_addr_), remote_port_);
00177 
00178     memset(&sa, 0, sizeof(sa));
00179     sa.sin_family = AF_INET;
00180     sa.sin_addr.s_addr = remote_addr_;
00181     sa.sin_port = htons(remote_port_);
00182 
00183     set_state(CONNECTING);
00184 
00185     if (::connect(fd_, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
00186         if (errno == EISCONN)
00187             log_debug("already connected to %s:%d",
00188                       intoa(remote_addr_), remote_port_);
00189         else if (errno == EINPROGRESS) {
00190             log_debug("delayed connect to %s:%d (EINPROGRESS)",
00191                       intoa(remote_addr_), remote_port_);
00192         } else {
00193             log_debug("error connecting to %s:%d: %s",
00194                       intoa(remote_addr_), remote_port_, strerror(errno));
00195         }
00196         
00197         return -1;
00198     }
00199 
00200     set_state(ESTABLISHED);
00201 
00202     return 0;
00203 }
00204 
00205 int
00206 IPSocket::async_connect_result()
00207 {
00208     ASSERT(state_ == CONNECTING);
00209 
00210     int result;
00211     socklen_t len = sizeof(result);
00212     logf(LOG_DEBUG, "getting connect result");
00213     if (::getsockopt(fd_, SOL_SOCKET, SO_ERROR, &result, &len) != 0) {
00214         logf(LOG_ERR, "error getting connect result: %s", strerror(errno));
00215         return errno;
00216     }
00217 
00218     if (result == 0) {
00219         set_state(ESTABLISHED);
00220     }
00221 
00222     return result;
00223 }
00224 
00225 int
00226 IPSocket::connect(in_addr_t remote_addr, u_int16_t remote_port)
00227 {
00228     remote_addr_ = remote_addr;
00229     remote_port_ = remote_port;
00230 
00231     return connect();
00232 }
00233 
00234 void
00235 IPSocket::configure()
00236 {
00237     if (params_.reuseaddr_) {
00238         int y = 1;
00239         logf(LOG_DEBUG, "setting SO_REUSEADDR");
00240         if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &y, sizeof y) != 0) {
00241             logf(LOG_WARN, "error setting SO_REUSEADDR: %s",
00242                  strerror(errno));
00243         }
00244     }
00245 
00246     if (params_.reuseport_) {
00247 #ifdef SO_REUSEPORT
00248         int y = 1;
00249         logf(LOG_DEBUG, "setting SO_REUSEPORT");
00250         if (::setsockopt(fd_, SOL_SOCKET, SO_REUSEPORT, &y, sizeof y) != 0) {
00251             logf(LOG_WARN, "error setting SO_REUSEPORT: %s",
00252                  strerror(errno));
00253         }
00254 #else
00255         logf(LOG_WARN, "error setting SO_REUSEPORT: not implemented");
00256 #endif
00257     }
00258     
00259     if (socktype_ == SOCK_STREAM && params_.tcp_nodelay_) {
00260         int y = 1;
00261         logf(LOG_DEBUG, "setting TCP_NODELAY");
00262         if (::setsockopt(fd_, IPPROTO_IP, TCP_NODELAY, &y, sizeof y) != 0) {
00263             logf(LOG_WARN, "error setting TCP_NODELAY: %s",
00264                  strerror(errno));
00265         }
00266     }
00267     
00268     if (params_.recv_bufsize_ > 0) {
00269         logf(LOG_DEBUG, "setting SO_RCVBUF to %d",
00270              params_.recv_bufsize_);
00271         
00272         if (::setsockopt(fd_, SOL_SOCKET, SO_RCVBUF,
00273                          &params_.recv_bufsize_,
00274                          sizeof (params_.recv_bufsize_)) < 0)
00275         {
00276             logf(LOG_WARN, "error setting SO_RCVBUF to %d: %s",
00277                  params_.recv_bufsize_, strerror(errno));
00278         }
00279     }
00280     
00281     if (params_.send_bufsize_ > 0) {
00282         logf(LOG_WARN, "setting SO_SNDBUF to %d",
00283              params_.send_bufsize_);
00284         
00285         if (::setsockopt(fd_, SOL_SOCKET, SO_SNDBUF,
00286                          &params_.send_bufsize_,
00287                          sizeof params_.send_bufsize_) < 0)
00288         {
00289             logf(LOG_WARN, "error setting SO_SNDBUF to %d: %s",
00290                  params_.send_bufsize_, strerror(errno));
00291         }
00292     }
00293 }
00294     
00295 int
00296 IPSocket::close()
00297 {
00298     logf(LOG_DEBUG, "closing socket in state %s", statetoa(state_));
00299 
00300     if (fd_ == -1) {
00301         ASSERT(state_ == INIT || state_ == FINI);
00302         return 0;
00303     }
00304     
00305     if (::close(fd_) != 0) {
00306         logf(LOG_ERR, "error closing socket in state %s: %s",
00307              statetoa(state_), strerror(errno));
00308         return -1;
00309     }
00310     
00311     set_state(FINI);
00312     fd_ = -1;
00313     return 0;
00314 }
00315 
00316 int
00317 IPSocket::shutdown(int how)
00318 {
00319     const char* howstr;
00320 
00321     switch (how) {
00322     case SHUT_RD:   howstr = "R";  break;
00323     case SHUT_WR:   howstr = "W";  break;
00324     case SHUT_RDWR: howstr = "RW"; break;
00325         
00326     default:
00327         logf(LOG_ERR, "shutdown invalid mode %d", how);
00328         return -1;
00329     }
00330       
00331     logf(LOG_DEBUG, "shutdown(%s) state %s", howstr, statetoa(state_));
00332     
00333     if (state_ == INIT || state_ == FINI) {
00334         ASSERT(fd_ == -1);
00335         return 0;
00336     }
00337     
00338     if (::shutdown(fd_, how) != 0) {
00339         logf(LOG_ERR, "error in shutdown(%s) state %s: %s",
00340              howstr, statetoa(state_), strerror(errno));
00341     }
00342     
00343     if (state_ == ESTABLISHED) {
00344         if (how == SHUT_RD)     { set_state(RDCLOSED); }
00345         if (how == SHUT_WR)     { set_state(WRCLOSED); }
00346         if (how == SHUT_RDWR)   { set_state(CLOSED); }
00347         
00348     } else if (state_ == RDCLOSED && how == SHUT_WR) {
00349         set_state(CLOSED);
00350         
00351     } else if (state_ == WRCLOSED && how == SHUT_RD) {
00352         set_state(CLOSED);
00353 
00354     } else {
00355         logf(LOG_ERR, "invalid state %s for shutdown(%s)",
00356              statetoa(state_), howstr);
00357         return -1;
00358     }
00359 
00360     return 0;
00361 }
00362 
00363 int
00364 IPSocket::send(const char* bp, size_t len, int flags)
00365 {
00366     return IO::send(fd_, bp, len, flags, get_notifier(), logpath_);
00367 }
00368 
00369 int
00370 IPSocket::sendto(char* bp, size_t len, int flags,
00371                  in_addr_t addr, u_int16_t port)
00372 {
00373     struct sockaddr_in sa;
00374     memset(&sa, 0, sizeof(sa));
00375     sa.sin_family = AF_INET;
00376     sa.sin_addr.s_addr = addr;
00377     sa.sin_port = htons(port);
00378 
00379     return IO::sendto(fd_, bp, len, flags, (sockaddr*)&sa, 
00380                       sizeof(sa), get_notifier(), logpath_);
00381 }
00382 
00383 int
00384 IPSocket::sendmsg(const struct msghdr* msg, int flags)
00385 {
00386     return IO::sendmsg(fd_, msg, flags, get_notifier(), logpath_);
00387 }
00388 
00389 int
00390 IPSocket::recv(char* bp, size_t len, int flags)
00391 {
00392     return IO::recv(fd_, bp, len, flags, 
00393                     get_notifier(), logpath_);
00394 }
00395 
00396 int
00397 IPSocket::recvfrom(char* bp, size_t len, int flags,
00398                    in_addr_t *addr, u_int16_t *port)
00399 {
00400     struct sockaddr_in sa;
00401     socklen_t sl = sizeof(sa);
00402     memset(&sa, 0, sizeof(sa));
00403     
00404     int cc = IO::recvfrom(fd_, bp, len, flags, (sockaddr*)&sa, &sl, 
00405                           get_notifier(), logpath_);
00406     
00407     if (cc < 0) {
00408         if (cc != IOINTR)
00409             logf(LOG_ERR, "error in recvfrom(): %s", strerror(errno));
00410         return cc;
00411     }
00412 
00413     if (addr)
00414         *addr = sa.sin_addr.s_addr;
00415 
00416     if (port)
00417         *port = htons(sa.sin_port);
00418 
00419     return cc;
00420 }
00421 
00422 int
00423 IPSocket::recvmsg(struct msghdr* msg, int flags)
00424 {
00425     return IO::recvmsg(fd_, msg, flags, get_notifier(), logpath_);
00426 }
00427 
00428 int
00429 IPSocket::poll_sockfd(int events, int* revents, int timeout_ms)
00430 {
00431     short s_events = events;
00432     short s_revents;
00433     
00434     int cc = IO::poll_single(fd_, s_events, &s_revents, timeout_ms, 
00435                              get_notifier(), logpath_);
00436     
00437     if (revents != 0) {
00438         *revents = s_revents;
00439     }
00440 
00441     return cc;
00442 }
00443 
00444 } // namespace oasys

Generated on Fri Dec 22 14:47:59 2006 for DTN Reference Implementation by  doxygen 1.5.1