| #include "sock_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, buffer> 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<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) // Data read from the socket |
| { |
| std::cout << "Channel::Read : DataIn Fd[" << sockfd << "] Req[" |
| << bufferSize << "] Recv[" << readDataLen << "]\n"; |
| } |
| else if (readDataLen == 0) // Peer has performed an orderly shutdown |
| { |
| std::cerr << "Channel::Read : Connection Closed Fd[" << sockfd |
| << "]\n"; |
| 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<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 << "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 |
| |