1 #include "sock_channel.hpp" 2 3 #include <errno.h> 4 #include <netinet/in.h> 5 #include <sys/ioctl.h> 6 #include <sys/socket.h> 7 #include <unistd.h> 8 9 #include <iostream> 10 #include <string> 11 12 namespace udpsocket 13 { 14 15 std::string Channel::getRemoteAddress() const 16 { 17 char tmp[INET_ADDRSTRLEN] = {0}; 18 inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp)); 19 return std::string(tmp); 20 } 21 22 std::tuple<int, buffer> Channel::read() 23 { 24 int rc = 0; 25 int readSize = 0; 26 ssize_t readDataLen = 0; 27 buffer outBuffer; 28 29 if (ioctl(sockfd, FIONREAD, &readSize) < 0) 30 { 31 std::cerr << "Channel::Read : ioctl failed with errno = " << errno; 32 rc = -errno; 33 return std::make_tuple(rc, std::move(outBuffer)); 34 } 35 36 outBuffer.resize(readSize); 37 auto bufferSize = outBuffer.size(); 38 auto outputPtr = outBuffer.data(); 39 40 address.addrSize = static_cast<socklen_t>(sizeof(address.inAddr)); 41 42 do 43 { 44 readDataLen = recvfrom(sockfd, // File Descriptor 45 outputPtr, // Buffer 46 bufferSize, // Bytes requested 47 0, // Flags 48 &address.sockAddr, // Address 49 &address.addrSize); // Address Length 50 51 if (readDataLen == 0) // Peer has performed an orderly shutdown 52 { 53 outBuffer.resize(0); 54 rc = -1; 55 } 56 else if (readDataLen < 0) // Error 57 { 58 rc = -errno; 59 std::cerr << "Channel::Read : Receive Error Fd[" << sockfd << "]" 60 << "errno = " << rc << "\n"; 61 outBuffer.resize(0); 62 } 63 } while ((readDataLen < 0) && (-(rc) == EINTR)); 64 65 // Resize the vector to the actual data read from the socket 66 outBuffer.resize(readDataLen); 67 return std::make_tuple(rc, std::move(outBuffer)); 68 } 69 70 int Channel::write(buffer& inBuffer) 71 { 72 int rc = 0; 73 auto outputPtr = inBuffer.data(); 74 auto bufferSize = inBuffer.size(); 75 auto spuriousWakeup = false; 76 ssize_t writeDataLen = 0; 77 timeval varTimeout = timeout; 78 79 fd_set writeSet; 80 FD_ZERO(&writeSet); 81 FD_SET(sockfd, &writeSet); 82 83 do 84 { 85 spuriousWakeup = false; 86 87 rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout); 88 89 if (rc > 0) 90 { 91 if (FD_ISSET(sockfd, &writeSet)) 92 { 93 address.addrSize = 94 static_cast<socklen_t>(sizeof(address.inAddr)); 95 do 96 { 97 writeDataLen = 98 sendto(sockfd, // File Descriptor 99 outputPtr, // Message 100 bufferSize, // Length 101 MSG_NOSIGNAL, // Flags 102 &address.sockAddr, // Destination Address 103 address.addrSize); // Address Length 104 105 if (writeDataLen < 0) 106 { 107 rc = -errno; 108 std::cerr 109 << "Channel::Write: Write failed with errno:" << rc 110 << "\n"; 111 } 112 else if (static_cast<size_t>(writeDataLen) < bufferSize) 113 { 114 rc = -1; 115 std::cerr << "Channel::Write: Complete data not written" 116 " to the socket\n"; 117 } 118 } while ((writeDataLen < 0) && (-(rc) == EINTR)); 119 } 120 else 121 { 122 // Spurious wake up 123 std::cerr << "Spurious wake up on select (writeset)\n"; 124 spuriousWakeup = true; 125 } 126 } 127 else 128 { 129 if (rc == 0) 130 { 131 // Timed out 132 rc = -1; 133 std::cerr << "We timed out on select call (writeset)\n"; 134 } 135 else 136 { 137 // Error 138 rc = -errno; 139 std::cerr << "select call (writeset) had an error : " << rc 140 << "\n"; 141 } 142 } 143 } while (spuriousWakeup); 144 145 return rc; 146 } 147 148 } // namespace udpsocket 149