blob: 2fa350a29e6a25e52753cebdb08ce23be6e5bd3a [file] [log] [blame]
Tom Josephaaeb29e2016-08-10 06:36:33 -05001#include "socket_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
12namespace udpsocket
13{
14
15std::string Channel::getRemoteAddress() const
16{
Vernon Mauery9e801a22018-10-12 13:20:49 -070017 char tmp[INET_ADDRSTRLEN] = {0};
Tom Josephc35524e2016-08-29 08:17:59 -050018 inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp));
Tom Josephaaeb29e2016-08-10 06:36:33 -050019 return std::string(tmp);
20}
21
Vernon Mauery70fd29c2017-11-30 13:11:43 -080022std::tuple<int, std::vector<uint8_t>> Channel::read()
Tom Josephaaeb29e2016-08-10 06:36:33 -050023{
24 int rc = 0;
25 int readSize = 0;
26 ssize_t readDataLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -080027 std::vector<uint8_t> outBuffer(0);
Tom Josephaaeb29e2016-08-10 06:36:33 -050028
29 if (ioctl(sockfd, FIONREAD, &readSize) < 0)
30 {
31 std::cerr << "E> 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
Tom Josephc0f5b5d2017-02-09 17:47:50 +053040 address.addrSize = static_cast<socklen_t>(sizeof(address.inAddr));
Tom Josephaaeb29e2016-08-10 06:36:33 -050041
42 do
43 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070044 readDataLen = recvfrom(sockfd, // File Descriptor
45 outputPtr, // Buffer
46 bufferSize, // Bytes requested
47 0, // Flags
48 &address.sockAddr, // Address
49 &address.addrSize); // Address Length
Tom Josephaaeb29e2016-08-10 06:36:33 -050050
Tom Joseph092f3262017-03-31 10:25:16 +053051 if (readDataLen == 0) // Peer has performed an orderly shutdown
Tom Josephaaeb29e2016-08-10 06:36:33 -050052 {
53 std::cerr << "E> Channel::Read : Connection Closed Fd[" << sockfd
54 << "]\n";
55 outBuffer.resize(0);
56 rc = -1;
57 }
58 else if (readDataLen < 0) // Error
59 {
60 rc = -errno;
61 std::cerr << "E> Channel::Read : Receive Error Fd[" << sockfd << "]"
62 << "errno = " << rc << "\n";
63 outBuffer.resize(0);
64 }
Vernon Mauery9e801a22018-10-12 13:20:49 -070065 } while ((readDataLen < 0) && (-(rc) == EINTR));
Tom Josephaaeb29e2016-08-10 06:36:33 -050066
67 // Resize the vector to the actual data read from the socket
68 outBuffer.resize(readDataLen);
69 return std::make_tuple(rc, std::move(outBuffer));
70}
71
Vernon Mauery70fd29c2017-11-30 13:11:43 -080072int Channel::write(const std::vector<uint8_t>& inBuffer)
Tom Josephaaeb29e2016-08-10 06:36:33 -050073{
74 int rc = 0;
75 auto outputPtr = inBuffer.data();
76 auto bufferSize = inBuffer.size();
77 auto spuriousWakeup = false;
78 ssize_t writeDataLen = 0;
79 timeval varTimeout = timeout;
80
81 fd_set writeSet;
82 FD_ZERO(&writeSet);
83 FD_SET(sockfd, &writeSet);
84
85 do
86 {
87 spuriousWakeup = false;
88
89 rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout);
90
91 if (rc > 0)
92 {
93 if (FD_ISSET(sockfd, &writeSet))
94 {
Tom Josephc0f5b5d2017-02-09 17:47:50 +053095 address.addrSize =
Vernon Mauery9e801a22018-10-12 13:20:49 -070096 static_cast<socklen_t>(sizeof(address.inAddr));
Tom Josephaaeb29e2016-08-10 06:36:33 -050097 do
98 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070099 writeDataLen =
100 sendto(sockfd, // File Descriptor
101 outputPtr, // Message
102 bufferSize, // Length
103 MSG_NOSIGNAL, // Flags
104 &address.sockAddr, // Destination Address
105 address.addrSize); // Address Length
Tom Josephaaeb29e2016-08-10 06:36:33 -0500106
107 if (writeDataLen < 0)
108 {
109 rc = -errno;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700110 std::cerr
111 << "Channel::Write: Write failed with errno:" << rc
112 << "\n";
Tom Josephaaeb29e2016-08-10 06:36:33 -0500113 }
114 else if (static_cast<size_t>(writeDataLen) < bufferSize)
115 {
116 rc = -1;
117 std::cerr << "Channel::Write: Complete data not written"
Vernon Mauery9e801a22018-10-12 13:20:49 -0700118 " to the socket\n";
Tom Josephaaeb29e2016-08-10 06:36:33 -0500119 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700120 } while ((writeDataLen < 0) && (-(rc) == EINTR));
Tom Josephaaeb29e2016-08-10 06:36:33 -0500121 }
122 else
123 {
124 // Spurious wake up
125 std::cerr << "E> Spurious wake up on select (writeset)\n";
126 spuriousWakeup = true;
127 }
128 }
129 else
130 {
131 if (rc == 0)
132 {
133 // Timed out
134 rc = -1;
135 std::cerr << "E> We timed out on select call (writeset)\n";
136 }
137 else
138 {
139 // Error
Vernon Mauery9e801a22018-10-12 13:20:49 -0700140 rc = -errno;
141 std::cerr << "E> select call (writeset) had an error : " << rc
142 << "\n";
Tom Josephaaeb29e2016-08-10 06:36:33 -0500143 }
Tom Josephaaeb29e2016-08-10 06:36:33 -0500144 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700145 } while (spuriousWakeup);
Tom Josephaaeb29e2016-08-10 06:36:33 -0500146
147 return rc;
148}
149
150} // namespace udpsocket