blob: a29ef8dd09ac2d644348e4c545461872b790a61c [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{
17 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
22std::tuple<int, buffer> Channel::read()
23{
24 int rc = 0;
25 int readSize = 0;
26 ssize_t readDataLen = 0;
27 buffer outBuffer(0);
28
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
40 address.addrSize = 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) // Data read from the socket
52 {
53 std::cout << "I> Channel::Read : DataIn Fd[" << sockfd << "] Req["
54 << bufferSize << "] Recv[" << readDataLen << "]\n";
55 }
56 else if (readDataLen == 0) // Peer has performed an orderly shutdown
57 {
58 std::cerr << "E> Channel::Read : Connection Closed Fd[" << sockfd
59 << "]\n";
60 outBuffer.resize(0);
61 rc = -1;
62 }
63 else if (readDataLen < 0) // Error
64 {
65 rc = -errno;
66 std::cerr << "E> Channel::Read : Receive Error Fd[" << sockfd << "]"
67 << "errno = " << rc << "\n";
68 outBuffer.resize(0);
69 }
70 }
71 while ((readDataLen < 0) && (-(rc) == EINTR));
72
73 // Resize the vector to the actual data read from the socket
74 outBuffer.resize(readDataLen);
75 return std::make_tuple(rc, std::move(outBuffer));
76}
77
78int Channel::write(buffer& inBuffer)
79{
80 int rc = 0;
81 auto outputPtr = inBuffer.data();
82 auto bufferSize = inBuffer.size();
83 auto spuriousWakeup = false;
84 ssize_t writeDataLen = 0;
85 timeval varTimeout = timeout;
86
87 fd_set writeSet;
88 FD_ZERO(&writeSet);
89 FD_SET(sockfd, &writeSet);
90
91 do
92 {
93 spuriousWakeup = false;
94
95 rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout);
96
97 if (rc > 0)
98 {
99 if (FD_ISSET(sockfd, &writeSet))
100 {
101 address.addrSize = sizeof(address.inAddr);
102 do
103 {
104 writeDataLen = sendto(sockfd, // File Descriptor
105 outputPtr, // Message
106 bufferSize, // Length
107 MSG_NOSIGNAL, // Flags
108 &address.sockAddr,// Destination Address
109 address.addrSize);// Address Length
110
111 if (writeDataLen < 0)
112 {
113 rc = -errno;
114 std::cerr << "Channel::Write: Write failed with errno:"
115 << rc << "\n";
116 }
117 else if (static_cast<size_t>(writeDataLen) < bufferSize)
118 {
119 rc = -1;
120 std::cerr << "Channel::Write: Complete data not written"
121 " to the socket\n";
122 }
123 }
124 while ((writeDataLen < 0) && (-(rc) == EINTR));
125 }
126 else
127 {
128 // Spurious wake up
129 std::cerr << "E> Spurious wake up on select (writeset)\n";
130 spuriousWakeup = true;
131 }
132 }
133 else
134 {
135 if (rc == 0)
136 {
137 // Timed out
138 rc = -1;
139 std::cerr << "E> We timed out on select call (writeset)\n";
140 }
141 else
142 {
143 // Error
144 rc = -errno;
145 std::cerr << "E> select call (writeset) had an error : "
146 << rc << "\n";
147 }
148
149 }
150 }
151 while (spuriousWakeup);
152
153 return rc;
154}
155
156} // namespace udpsocket