• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

ibrcommon/ibrcommon/net/tcpstream.cpp

Go to the documentation of this file.
00001 /*
00002  * tcpstream.cpp
00003  *
00004  *  Created on: 29.07.2009
00005  *      Author: morgenro
00006  */
00007 
00008 #include "ibrcommon/config.h"
00009 #include "ibrcommon/Logger.h"
00010 #include "ibrcommon/net/tcpstream.h"
00011 #include "ibrcommon/thread/MutexLock.h"
00012 #include <netinet/in.h>
00013 #include <sys/types.h>
00014 #include <sys/socket.h>
00015 #include <arpa/inet.h>
00016 #include <netinet/tcp.h>
00017 #include <errno.h>
00018 
00019 namespace ibrcommon
00020 {
00021         tcpstream::tcpstream(int socket) :
00022                 iostream(this), errmsg(ERROR_NONE), _socket(socket), in_buf_(new char[BUFF_SIZE]), out_buf_(new char[BUFF_SIZE])
00023         {
00024                 // Initialize get pointer.  This should be zero so that underflow is called upon first read.
00025                 setg(0, 0, 0);
00026                 setp(out_buf_, out_buf_ + BUFF_SIZE - 1);
00027         }
00028 
00029         tcpstream::~tcpstream()
00030         {
00031                 delete[] in_buf_;
00032                 delete[] out_buf_;
00033 
00034                 // finally, close the socket
00035                 close();
00036         }
00037 
00038         string tcpstream::getAddress() const
00039         {
00040                 struct ::sockaddr_in sa;
00041                 int iLen = sizeof(sa);
00042 
00043                 getpeername(_socket, (sockaddr*) &sa, (socklen_t*) &iLen);
00044                 return inet_ntoa(sa.sin_addr);
00045         }
00046 
00047         int tcpstream::getPort() const
00048         {
00049                 struct ::sockaddr_in sa;
00050                 int iLen = sizeof(sa);
00051 
00052                 getpeername(_socket, (sockaddr*) &sa, (socklen_t*) &iLen);
00053                 return ntohs(sa.sin_port);
00054         }
00055 
00056         void tcpstream::close(bool errorcheck)
00057         {
00058                 if (_socket == -1)
00059                 {
00060                         if (errorcheck) throw ConnectionClosedException();
00061                         return;
00062                 }
00063 
00064                 int sock = _socket;
00065                 _socket = -1;
00066 
00067                 if ((::close(sock) == -1) && errorcheck)
00068                 {
00069                         throw ConnectionClosedException();
00070                 }
00071         }
00072 
00073         int tcpstream::sync()
00074         {
00075                 int ret = std::char_traits<char>::eq_int_type(this->overflow(
00076                                 std::char_traits<char>::eof()), std::char_traits<char>::eof()) ? -1
00077                                 : 0;
00078 
00079                 return ret;
00080         }
00081 
00082         int tcpstream::overflow(int c)
00083         {
00084                 char *ibegin = out_buf_;
00085                 char *iend = pptr();
00086 
00087                 // mark the buffer as free
00088                 setp(out_buf_, out_buf_ + BUFF_SIZE - 1);
00089 
00090                 if (!std::char_traits<char>::eq_int_type(c, std::char_traits<char>::eof()))
00091                 {
00092                         *iend++ = std::char_traits<char>::to_char_type(c);
00093                 }
00094 
00095                 // if there is nothing to send, just return
00096                 if ((iend - ibegin) == 0)
00097                 {
00098                         IBRCOMMON_LOGGER_DEBUG(90) << "tcpstream::overflow() nothing to sent" << IBRCOMMON_LOGGER_ENDL;
00099                         return std::char_traits<char>::not_eof(c);
00100                 }
00101 
00102                 // send the data
00103                 if (::send(_socket, out_buf_, (iend - ibegin), MSG_NOSIGNAL) < 0)
00104                 {
00105                         switch (errno)
00106                         {
00107                         case EPIPE:
00108                                 // connection has been reset
00109                                 errmsg = ERROR_EPIPE;
00110                                 break;
00111 
00112                         case ECONNRESET:
00113                                 // Connection reset by peer
00114                                 errmsg = ERROR_RESET;
00115                                 break;
00116 
00117                         default:
00118                                 errmsg = ERROR_WRITE;
00119                         }
00120 
00121                         // failure
00122                         close();
00123                         std::stringstream ss; ss << "<tcpstream> send() in tcpstream failed: " << errno;
00124                         throw ConnectionClosedException(ss.str());
00125                 }
00126 
00127                 return std::char_traits<char>::not_eof(c);
00128         }
00129 
00130         int tcpstream::underflow()
00131         {
00132                 if (_socket == -1) return std::char_traits<char>::eof();
00133 
00134                 int bytes = ::recv(_socket, in_buf_, BUFF_SIZE, 0);
00135 
00136                 // end of stream
00137                 if (bytes == 0)
00138                 {
00139                         errmsg = ERROR_CLOSED;
00140                         close();
00141                         std::stringstream ss; ss << "<tcpstream> recv() returned zero: " << errno;
00142                         throw ConnectionClosedException(ss.str());
00143                 }
00144                 else if (bytes < 0)
00145                 {
00146                         switch (errno)
00147                         {
00148                         case EPIPE:
00149                                 // connection has been reset
00150                                 errmsg = ERROR_EPIPE;
00151                                 break;
00152 
00153                         default:
00154                                 errmsg = ERROR_READ;
00155                         }
00156 
00157                         close();
00158                         std::stringstream ss; ss << "<tcpstream> recv() failed: " << errno;
00159                         throw ConnectionClosedException(ss.str());
00160                 }
00161 
00162                 // Since the input buffer content is now valid (or is new)
00163                 // the get pointer should be initialized (or reset).
00164                 setg(in_buf_, in_buf_, in_buf_ + bytes);
00165 
00166                 return std::char_traits<char>::not_eof(in_buf_[0]);
00167         }
00168 
00169         void tcpstream::enableKeepalive()
00170         {
00171                 /* Set the option active */
00172                 int optval = 1;
00173                 if(setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) {
00174                         throw ibrcommon::vsocket_exception("<tcpstream> can not activate keepalives");
00175                 }
00176         }
00177 
00178         void tcpstream::enableLinger(int l)
00179         {
00180                 // set linger option to the socket
00181                 struct linger linger;
00182 
00183                 linger.l_onoff = 1;
00184                 linger.l_linger = l;
00185                 ::setsockopt(_socket, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
00186         }
00187 
00188         void tcpstream::enableNoDelay()
00189         {
00190                 int set = 1;
00191                 ::setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&set, sizeof(set));
00192         }
00193 
00194 }

Generated on Wed Mar 30 2011 11:11:49 for IBR-DTNSuite by  doxygen 1.7.1