$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/NetworkUtilities/TCPSocket.h" 00002 #include "artdaq-core/Utilities/TimeUtils.hh" 00003 #include "otsdaq-core/Macros/CoutMacros.h" 00004 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00005 00006 #include <cassert> 00007 #include <iostream> 00008 #include <sstream> 00009 00010 #include <arpa/inet.h> 00011 #include <unistd.h> 00012 //#include <sys/TCPSocket.h> 00013 #include <netdb.h> 00014 //#include <ifaddrs.h> 00015 //#include <sys/ioctl.h> 00016 //#if defined(SIOCGIFHWADDR) 00017 //#include <net/if.h> 00018 //#else 00019 //#include <net/if_dl.h> 00020 //#endif 00021 //#include <cstdlib> 00022 #include <cstring> 00023 //#include <cstdio> 00024 #include "trace.h" 00025 00026 using namespace ots; 00027 00028 //======================================================================================================================== 00029 TCPSocket::TCPSocket(const std::string& senderHost, 00030 unsigned int senderPort, 00031 int receiveBufferSize) 00032 : host_(senderHost) 00033 , port_(senderPort) 00034 , TCPSocketNumber_(-1) 00035 , SendSocket_(-1) 00036 , isSender_(false) 00037 , bufferSize_(receiveBufferSize) 00038 , chunkSize_(65000) 00039 { 00040 } 00041 00042 //======================================================================================================================== 00043 TCPSocket::TCPSocket(unsigned int listenPort, int sendBufferSize) 00044 : port_(listenPort) 00045 , TCPSocketNumber_(-1) 00046 , SendSocket_(-1) 00047 , isSender_(true) 00048 , bufferSize_(sendBufferSize) 00049 , chunkSize_(65000) 00050 { 00051 TCPSocketNumber_ = TCP_listen_fd(listenPort, bufferSize_); 00052 } 00053 00054 //======================================================================================================================== 00055 // protected constructor 00056 TCPSocket::TCPSocket(void) 00057 { 00058 __SS__ << "ERROR: This method should never be called. This is the protected " 00059 "constructor. There is something wrong in your inheritance scheme!" 00060 << std::endl; 00061 __COUT__ << "\n" << ss.str(); 00062 00063 __SS_THROW__; 00064 } 00065 00066 //======================================================================================================================== 00067 TCPSocket::~TCPSocket(void) 00068 { 00069 __COUT__ << "CLOSING THE TCPSocket #" << TCPSocketNumber_ << " IP: " << host_ 00070 << " port: " << port_ << std::endl; 00071 if(TCPSocketNumber_ != -1) 00072 close(TCPSocketNumber_); 00073 if(SendSocket_ != -1) 00074 close(SendSocket_); 00075 } 00076 00077 //======================================================================================================================== 00078 void TCPSocket::connect(double tmo_s) 00079 { 00080 auto start = std::chrono::steady_clock::now(); 00081 if(isSender_) 00082 { 00083 while(SendSocket_ == -1 && artdaq::TimeUtils::GetElapsedTime(start) < tmo_s) 00084 { 00085 sockaddr_in addr; 00086 socklen_t arglen = sizeof(addr); 00087 SendSocket_ = accept(TCPSocketNumber_, (struct sockaddr*)&addr, &arglen); 00088 00089 if(SendSocket_ == -1) 00090 { 00091 perror("accept"); 00092 continue; 00093 } 00094 00095 MagicPacket m; 00096 auto sts = read(SendSocket_, &m, sizeof(MagicPacket)); 00097 if(!checkMagicPacket(m) || sts != sizeof(MagicPacket)) 00098 { 00099 perror("magic"); 00100 close(SendSocket_); 00101 SendSocket_ = -1; 00102 } 00103 } 00104 } 00105 else 00106 { 00107 while(TCPSocketNumber_ == -1 && artdaq::TimeUtils::GetElapsedTime(start) < tmo_s) 00108 { 00109 TCPSocketNumber_ = TCPConnect(host_.c_str(), port_, 0, O_NONBLOCK); 00110 if(TCPSocketNumber_ == -1) 00111 { 00112 usleep(10000); 00113 continue; 00114 } 00115 00116 auto m = makeMagicPacket(port_); 00117 auto sts = ::send(TCPSocketNumber_, &m, sizeof(MagicPacket), 0); 00118 if(sts != sizeof(MagicPacket)) 00119 { 00120 perror("connect"); 00121 close(TCPSocketNumber_); 00122 TCPSocketNumber_ = -1; 00123 } 00124 } 00125 } 00126 } 00127 00128 //======================================================================================================================== 00129 int TCPSocket::send(const uint8_t* data, size_t size) 00130 { 00131 std::unique_lock<std::mutex> lk(socketMutex_); 00132 if(SendSocket_ == -1) 00133 { 00134 connect(); 00135 00136 if(SendSocket_ == -1) 00137 return -1; 00138 } 00139 00140 size_t offset = 0; 00141 int sts = 1; 00142 00143 while(offset < size && sts > 0) 00144 { 00145 auto thisSize = size - offset > chunkSize_ ? chunkSize_ : size - offset; 00146 00147 sts = ::send(SendSocket_, data + offset, thisSize, 0); 00148 00149 // Dynamically resize chunk size to match send calls 00150 if(static_cast<size_t>(sts) != size - offset && 00151 static_cast<size_t>(sts) < chunkSize_) 00152 { 00153 chunkSize_ = sts; 00154 } 00155 offset += sts; 00156 } 00157 00158 if(sts <= 0) 00159 { 00160 __COUT__ << "Error writing buffer for port " << port_ << ": " << strerror(errno) 00161 << std::endl; 00162 return -1; 00163 } 00164 return 0; 00165 } 00166 00167 //======================================================================================================================== 00168 int TCPSocket::send(const std::string& buffer) 00169 { 00170 return send(reinterpret_cast<const uint8_t*>(buffer.c_str()), buffer.size()); 00171 } 00172 00173 //======================================================================================================================== 00174 int TCPSocket::send(const std::vector<uint16_t>& buffer) 00175 { 00176 return send(reinterpret_cast<const uint8_t*>(&buffer[0]), 00177 buffer.size() * sizeof(uint16_t)); 00178 } 00179 00180 //======================================================================================================================== 00181 int TCPSocket::send(const std::vector<uint32_t>& buffer) 00182 { 00183 return send(reinterpret_cast<const uint8_t*>(&buffer[0]), 00184 buffer.size() * sizeof(uint32_t)); 00185 } 00186 00187 //======================================================================================================================== 00188 // receive ~~ 00189 // returns 0 on success, -1 on failure 00190 // NOTE: must call Socket::initialize before receiving! 00191 int TCPSocket::receive(uint8_t* buffer, 00192 unsigned int timeoutSeconds, 00193 unsigned int timeoutUSeconds) 00194 { 00195 // lockout other receivers for the remainder of the scope 00196 std::unique_lock<std::mutex> lk(socketMutex_); 00197 00198 if(TCPSocketNumber_ == -1) 00199 { 00200 connect(); 00201 if(TCPSocketNumber_ == -1) 00202 return -1; 00203 } 00204 00205 // set timeout period for select() 00206 struct timeval timeout; 00207 timeout.tv_sec = timeoutSeconds; 00208 timeout.tv_usec = timeoutUSeconds; 00209 00210 fd_set fdSet; 00211 FD_ZERO(&fdSet); 00212 FD_SET(TCPSocketNumber_, &fdSet); 00213 select(TCPSocketNumber_ + 1, &fdSet, 0, 0, &timeout); 00214 00215 if(FD_ISSET(TCPSocketNumber_, &fdSet)) 00216 { 00217 auto sts = -1; 00218 if((sts = read(TCPSocketNumber_, buffer, chunkSize_)) == -1) 00219 { 00220 __COUT__ << "Error reading buffer from: " << host_ << ":" << port_ 00221 << std::endl; 00222 return -1; 00223 } 00224 00225 // NOTE: this is inexpensive according to Lorenzo/documentation in C++11 (only 00226 // increases size once and doesn't decrease size) 00227 return sts; 00228 } 00229 00230 return -1; 00231 } 00232 00233 //======================================================================================================================== 00234 // receive ~~ 00235 // returns 0 on success, -1 on failure 00236 // NOTE: must call Socket::initialize before receiving! 00237 int TCPSocket::receive(std::string& buffer, 00238 unsigned int timeoutSeconds, 00239 unsigned int timeoutUSeconds) 00240 { 00241 buffer.resize(chunkSize_); 00242 auto sts = 00243 receive(reinterpret_cast<uint8_t*>(&buffer[0]), timeoutSeconds, timeoutUSeconds); 00244 if(sts > 0) 00245 { 00246 buffer.resize(sts); 00247 return 0; 00248 } 00249 return -1; 00250 } 00251 00252 //======================================================================================================================== 00253 // receive ~~ 00254 // returns 0 on success, -1 on failure 00255 // NOTE: must call Socket::initialize before receiving! 00256 int TCPSocket::receive(std::vector<uint32_t>& buffer, 00257 unsigned int timeoutSeconds, 00258 unsigned int timeoutUSeconds) 00259 { 00260 buffer.resize(chunkSize_ / sizeof(uint32_t)); 00261 auto sts = 00262 receive(reinterpret_cast<uint8_t*>(&buffer[0]), timeoutSeconds, timeoutUSeconds); 00263 if(sts > 0) 00264 { 00265 buffer.resize(sts); 00266 return 0; 00267 } 00268 return -1; 00269 }