| #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_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp)); |
| return std::string(tmp); |
| } |
| |
| std::tuple<int, std::vector<uint8_t>> Channel::read() |
| { |
| int rc = 0; |
| int readSize = 0; |
| ssize_t readDataLen = 0; |
| std::vector<uint8_t> 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 = static_cast<socklen_t>(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 |
| { |
| 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(const std::vector<uint8_t>& 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<socklen_t>(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 |