00001 #include "otsdaq-core/NetworkUtilities/TCPSocket.h"
00002 #include "otsdaq-core/MessageFacility/MessageFacility.h"
00003 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
00004
00005 #include <iostream>
00006 #include <cassert>
00007 #include <sstream>
00008
00009 #include <unistd.h>
00010 #include <arpa/inet.h>
00011
00012 #include <netdb.h>
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <cstring>
00022
00023 #include "trace.h"
00024
00025 using namespace ots;
00026
00027
00028 TCPSocket::TCPSocket(const std::string &senderHost, unsigned int senderPort, int receiveBufferSize)
00029 : host_(senderHost)
00030 , port_(senderPort)
00031 , TCPSocketNumber_(-1)
00032 , SendSocket_(-1)
00033 , isSender_(false)
00034 , bufferSize_(receiveBufferSize)
00035 , chunkSize_(65000)
00036 {}
00037
00038 TCPSocket::TCPSocket(unsigned int listenPort, int sendBufferSize)
00039 : port_(listenPort)
00040 , TCPSocketNumber_(-1)
00041 , SendSocket_(-1)
00042 , isSender_(true)
00043 , bufferSize_(sendBufferSize)
00044 , chunkSize_(65000)
00045 {
00046 TCPSocketNumber_ = TCP_listen_fd(listenPort, 0);
00047 if (bufferSize_ > 0)
00048 {
00049 int len;
00050 socklen_t lenlen = sizeof(len);
00051 len = 0;
00052 auto sts = getsockopt(TCPSocketNumber_, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
00053 TRACE(3, "TCPConnect SNDBUF initial: %d sts/errno=%d/%d lenlen=%d", len, sts, errno, lenlen);
00054 len = bufferSize_;
00055 sts = setsockopt(TCPSocketNumber_, SOL_SOCKET, SO_SNDBUF, &len, lenlen);
00056 if (sts == -1)
00057 TRACE(0, "Error with setsockopt SNDBUF %d", errno);
00058 len = 0;
00059 sts = getsockopt(TCPSocketNumber_, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
00060 if (len < (bufferSize_ * 2))
00061 TRACE(1, "SNDBUF %d not expected (%d) sts/errno=%d/%d"
00062 , len, bufferSize_, sts, errno);
00063 else
00064 TRACE(3, "SNDBUF %d sts/errno=%d/%d", len, sts, errno);
00065 }
00066 }
00067
00068
00069
00070 TCPSocket::TCPSocket(void)
00071 {
00072 __SS__ << "ERROR: This method should never be called. This is the protected constructor. There is something wrong in your inheritance scheme!" << std::endl;
00073 __COUT__ << "\n" << ss.str();
00074
00075 throw std::runtime_error(ss.str());
00076 }
00077
00078
00079 TCPSocket::~TCPSocket(void)
00080 {
00081 __COUT__ << "CLOSING THE TCPSocket #" << TCPSocketNumber_ << " IP: " << host_ << " port: " << port_ << std::endl;
00082 if (TCPSocketNumber_ != -1)
00083 close(TCPSocketNumber_);
00084 if (SendSocket_ != -1)
00085 close(SendSocket_);
00086 }
00087
00088 void TCPSocket::connect()
00089 {
00090 if (isSender_)
00091 {
00092 sockaddr_in addr;
00093 socklen_t arglen = sizeof(addr);
00094 SendSocket_ = accept(TCPSocketNumber_, (struct sockaddr *)&addr, &arglen);
00095
00096 if (SendSocket_ == -1)
00097 {
00098 perror("accept");
00099 exit(EXIT_FAILURE);
00100 }
00101
00102 MagicPacket m;
00103 auto sts = read(SendSocket_, &m, sizeof(MagicPacket));
00104 if (!checkMagicPacket(m) || sts != sizeof(MagicPacket))
00105 {
00106 perror("magic");
00107 exit(EXIT_FAILURE);
00108 }
00109 }
00110 else
00111 {
00112 TCPSocketNumber_ = TCPConnect(host_.c_str(), port_, 0, O_NONBLOCK);
00113 auto m = makeMagicPacket(port_);
00114 auto sts = ::send(TCPSocketNumber_, &m, sizeof(MagicPacket), 0);
00115 if (sts != sizeof(MagicPacket))
00116 {
00117 perror("connect");
00118 exit(EXIT_FAILURE);
00119 }
00120 }
00121 }
00122
00123
00124 int TCPSocket::send(const uint8_t* data, size_t size)
00125 {
00126 std::unique_lock<std::mutex> lk(socketMutex_);
00127 if (SendSocket_ == -1)
00128 {
00129 connect();
00130 }
00131
00132 size_t offset = 0;
00133 int sts = 1;
00134
00135 while (offset < size && sts > 0)
00136 {
00137 auto thisSize = size - offset > chunkSize_ ? chunkSize_ : size - offset;
00138
00139 sts = ::send(SendSocket_, data + offset, thisSize, 0);
00140
00141
00142 if (static_cast<size_t>(sts) != size - offset && static_cast<size_t>(sts) < chunkSize_)
00143 {
00144 chunkSize_ = sts;
00145 }
00146 offset += sts;
00147 }
00148
00149 if (sts <= 0)
00150 {
00151 __COUT__ << "Error writing buffer for port " << port_ << ": " << strerror(errno) << std::endl;
00152 return -1;
00153 }
00154 return 0;
00155 }
00156
00157
00158 int TCPSocket::send(const std::string& buffer)
00159 {
00160 return send(reinterpret_cast<const uint8_t*>(buffer.c_str()), buffer.size());
00161 }
00162
00163
00164 int TCPSocket::send(const std::vector<uint16_t>& buffer)
00165 {
00166 return send(reinterpret_cast<const uint8_t*>(&buffer[0]), buffer.size() * sizeof(uint16_t));
00167 }
00168
00169
00170 int TCPSocket::send(const std::vector<uint32_t>& buffer)
00171 {
00172 return send(reinterpret_cast<const uint8_t*>(&buffer[0]), buffer.size() * sizeof(uint32_t));
00173 }
00174
00175
00176
00177
00178
00179 int TCPSocket::receive(uint8_t* buffer, unsigned int timeoutSeconds, unsigned int timeoutUSeconds)
00180 {
00181
00182 std::unique_lock<std::mutex> lk(socketMutex_);
00183
00184 if (TCPSocketNumber_ == -1)
00185 {
00186 connect();
00187 }
00188
00189
00190 struct timeval timeout;
00191 timeout.tv_sec = timeoutSeconds;
00192 timeout.tv_usec = timeoutUSeconds;
00193
00194 fd_set fdSet;
00195 FD_ZERO(&fdSet);
00196 FD_SET(TCPSocketNumber_, &fdSet);
00197 select(TCPSocketNumber_ + 1, &fdSet, 0, 0, &timeout);
00198
00199 if (FD_ISSET(TCPSocketNumber_, &fdSet))
00200 {
00201 auto sts = -1;
00202 if ((sts = read(TCPSocketNumber_, buffer, chunkSize_)) == -1)
00203 {
00204 __COUT__ << "Error reading buffer from: " << host_ << ":" << port_ << std::endl;
00205 return -1;
00206 }
00207
00208
00209 return sts;
00210 }
00211
00212 return -1;
00213 }
00214
00215
00216
00217
00218
00219 int TCPSocket::receive(std::string& buffer, unsigned int timeoutSeconds, unsigned int timeoutUSeconds)
00220 {
00221 buffer.resize(chunkSize_);
00222 auto sts = receive(reinterpret_cast<uint8_t*>(&buffer[0]), timeoutSeconds, timeoutUSeconds);
00223 if (sts > 0)
00224 {
00225 buffer.resize(sts);
00226 return 0;
00227 }
00228 return -1;
00229 }
00230
00231
00232
00233
00234
00235 int TCPSocket::receive(std::vector<uint32_t>& buffer, unsigned int timeoutSeconds, unsigned int timeoutUSeconds)
00236 {
00237 buffer.resize(chunkSize_ / sizeof(uint32_t));
00238 auto sts = receive(reinterpret_cast<uint8_t*>(&buffer[0]), timeoutSeconds, timeoutUSeconds);
00239 if (sts > 0)
00240 {
00241 buffer.resize(sts);
00242 return 0;
00243 }
00244 return -1;
00245 }
00246