#include "sock_channel.hpp" #include #include #include #include #include #include #include namespace udpsocket { std::string Channel::getRemoteAddress() const { char tmp[INET_ADDRSTRLEN] = {0}; inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp)); return std::string(tmp); } std::tuple Channel::read() { int rc = 0; int readSize = 0; ssize_t readDataLen = 0; buffer outBuffer(0); if (ioctl(sockfd, FIONREAD, &readSize) < 0) { std::cerr << "Channel::Read : ioctl failed with errno = " << errno; rc = -errno; return std::make_tuple(rc, std::move(outBuffer)); } outBuffer.resize(readSize); auto bufferSize = outBuffer.size(); auto outputPtr = outBuffer.data(); address.addrSize = static_cast(sizeof(address.inAddr)); do { readDataLen = recvfrom(sockfd, // File Descriptor outputPtr, // Buffer bufferSize, // Bytes requested 0, // Flags &address.sockAddr, // Address &address.addrSize); // Address Length if (readDataLen == 0) // Peer has performed an orderly shutdown { outBuffer.resize(0); rc = -1; } else if (readDataLen < 0) // Error { rc = -errno; std::cerr << "Channel::Read : Receive Error Fd[" << sockfd << "]" << "errno = " << rc << "\n"; outBuffer.resize(0); } } while ((readDataLen < 0) && (-(rc) == EINTR)); // Resize the vector to the actual data read from the socket outBuffer.resize(readDataLen); return std::make_tuple(rc, std::move(outBuffer)); } int Channel::write(buffer& inBuffer) { int rc = 0; auto outputPtr = inBuffer.data(); auto bufferSize = inBuffer.size(); auto spuriousWakeup = false; ssize_t writeDataLen = 0; timeval varTimeout = timeout; fd_set writeSet; FD_ZERO(&writeSet); FD_SET(sockfd, &writeSet); do { spuriousWakeup = false; rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout); if (rc > 0) { if (FD_ISSET(sockfd, &writeSet)) { address.addrSize = static_cast(sizeof(address.inAddr)); do { writeDataLen = sendto(sockfd, // File Descriptor outputPtr, // Message bufferSize, // Length MSG_NOSIGNAL, // Flags &address.sockAddr, // Destination Address address.addrSize); // Address Length if (writeDataLen < 0) { rc = -errno; std::cerr << "Channel::Write: Write failed with errno:" << rc << "\n"; } else if (static_cast(writeDataLen) < bufferSize) { rc = -1; std::cerr << "Channel::Write: Complete data not written" " to the socket\n"; } } while ((writeDataLen < 0) && (-(rc) == EINTR)); } else { // Spurious wake up std::cerr << "Spurious wake up on select (writeset)\n"; spuriousWakeup = true; } } else { if (rc == 0) { // Timed out rc = -1; std::cerr << "We timed out on select call (writeset)\n"; } else { // Error rc = -errno; std::cerr << "select call (writeset) had an error : " << rc << "\n"; } } } while (spuriousWakeup); return rc; } } // namespace udpsocket