diff options
Diffstat (limited to 'socket_channel.cpp')
-rw-r--r-- | socket_channel.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/socket_channel.cpp b/socket_channel.cpp new file mode 100644 index 0000000..4a6d827 --- /dev/null +++ b/socket_channel.cpp @@ -0,0 +1,156 @@ +#include "socket_channel.hpp" + +#include <errno.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <iostream> +#include <string> + +namespace udpsocket +{ + +std::string Channel::getRemoteAddress() const +{ + char tmp[INET_ADDRSTRLEN] = { 0 }; + inet_ntop(AF_INET, &address.inAddr.sin_addr, tmp, sizeof(tmp)); + return std::string(tmp); +} + +std::tuple<int, buffer> Channel::read() +{ + int rc = 0; + int readSize = 0; + ssize_t readDataLen = 0; + buffer outBuffer(0); + + if (ioctl(sockfd, FIONREAD, &readSize) < 0) + { + std::cerr << "E> 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 = 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) // Data read from the socket + { + std::cout << "I> Channel::Read : DataIn Fd[" << sockfd << "] Req[" + << bufferSize << "] Recv[" << readDataLen << "]\n"; + } + else if (readDataLen == 0) // Peer has performed an orderly shutdown + { + std::cerr << "E> Channel::Read : Connection Closed Fd[" << sockfd + << "]\n"; + outBuffer.resize(0); + rc = -1; + } + else if (readDataLen < 0) // Error + { + rc = -errno; + std::cerr << "E> 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 = 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<size_t>(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 << "E> Spurious wake up on select (writeset)\n"; + spuriousWakeup = true; + } + } + else + { + if (rc == 0) + { + // Timed out + rc = -1; + std::cerr << "E> We timed out on select call (writeset)\n"; + } + else + { + // Error + rc = -errno; + std::cerr << "E> select call (writeset) had an error : " + << rc << "\n"; + } + + } + } + while (spuriousWakeup); + + return rc; +} + +} // namespace udpsocket |