Go to the documentation of this file.00001
00002
00003
00004
00005
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
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
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
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
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
00103 if (::send(_socket, out_buf_, (iend - ibegin), MSG_NOSIGNAL) < 0)
00104 {
00105 switch (errno)
00106 {
00107 case EPIPE:
00108
00109 errmsg = ERROR_EPIPE;
00110 break;
00111
00112 case ECONNRESET:
00113
00114 errmsg = ERROR_RESET;
00115 break;
00116
00117 default:
00118 errmsg = ERROR_WRITE;
00119 }
00120
00121
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
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
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
00163
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
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
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 }