blob: a3e1301964dc8e82002803e650461e5192a574c1 [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
Vernon Maueryfc37e592018-12-19 14:55:15 -08009#include <phosphor-logging/log.hpp>
Tom Josephaaeb29e2016-08-10 06:36:33 -050010#include <string>
11
Vernon Maueryfc37e592018-12-19 14:55:15 -080012using namespace phosphor::logging;
13
Tom Josephaaeb29e2016-08-10 06:36:33 -050014namespace udpsocket
15{
16
17std::string Channel::getRemoteAddress() const
18{
Vernon Mauery9e801a22018-10-12 13:20:49 -070019 char tmp[INET_ADDRSTRLEN] = {0};
Tom Josephc35524e2016-08-29 08:17:59 -050020 inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp));
Tom Josephaaeb29e2016-08-10 06:36:33 -050021 return std::string(tmp);
22}
23
Vernon Mauery70fd29c2017-11-30 13:11:43 -080024std::tuple<int, std::vector<uint8_t>> Channel::read()
Tom Josephaaeb29e2016-08-10 06:36:33 -050025{
26 int rc = 0;
27 int readSize = 0;
28 ssize_t readDataLen = 0;
Vernon Mauery70fd29c2017-11-30 13:11:43 -080029 std::vector<uint8_t> outBuffer(0);
Tom Josephaaeb29e2016-08-10 06:36:33 -050030
31 if (ioctl(sockfd, FIONREAD, &readSize) < 0)
32 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080033 log<level::ERR>("Channel::Read: ioctl failed",
34 entry("ERRNO=%d", errno));
Tom Josephaaeb29e2016-08-10 06:36:33 -050035 rc = -errno;
36 return std::make_tuple(rc, std::move(outBuffer));
37 }
38
39 outBuffer.resize(readSize);
40 auto bufferSize = outBuffer.size();
41 auto outputPtr = outBuffer.data();
42
Tom Josephc0f5b5d2017-02-09 17:47:50 +053043 address.addrSize = static_cast<socklen_t>(sizeof(address.inAddr));
Tom Josephaaeb29e2016-08-10 06:36:33 -050044
45 do
46 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070047 readDataLen = recvfrom(sockfd, // File Descriptor
48 outputPtr, // Buffer
49 bufferSize, // Bytes requested
50 0, // Flags
51 &address.sockAddr, // Address
52 &address.addrSize); // Address Length
Tom Josephaaeb29e2016-08-10 06:36:33 -050053
Tom Joseph092f3262017-03-31 10:25:16 +053054 if (readDataLen == 0) // Peer has performed an orderly shutdown
Tom Josephaaeb29e2016-08-10 06:36:33 -050055 {
Vernon Maueryfc37e592018-12-19 14:55:15 -080056 log<level::ERR>("Channel::Read: Connection Closed");
Tom Josephaaeb29e2016-08-10 06:36:33 -050057 outBuffer.resize(0);
58 rc = -1;
59 }
60 else if (readDataLen < 0) // Error
61 {
62 rc = -errno;
Vernon Maueryfc37e592018-12-19 14:55:15 -080063 log<level::ERR>("Channel::Read: Receive Error",
64 entry("ERRNO=%d", rc));
Tom Josephaaeb29e2016-08-10 06:36:33 -050065 outBuffer.resize(0);
66 }
Vernon Mauery9e801a22018-10-12 13:20:49 -070067 } while ((readDataLen < 0) && (-(rc) == EINTR));
Tom Josephaaeb29e2016-08-10 06:36:33 -050068
69 // Resize the vector to the actual data read from the socket
70 outBuffer.resize(readDataLen);
71 return std::make_tuple(rc, std::move(outBuffer));
72}
73
Vernon Mauery70fd29c2017-11-30 13:11:43 -080074int Channel::write(const std::vector<uint8_t>& inBuffer)
Tom Josephaaeb29e2016-08-10 06:36:33 -050075{
76 int rc = 0;
77 auto outputPtr = inBuffer.data();
78 auto bufferSize = inBuffer.size();
79 auto spuriousWakeup = false;
80 ssize_t writeDataLen = 0;
81 timeval varTimeout = timeout;
82
83 fd_set writeSet;
84 FD_ZERO(&writeSet);
85 FD_SET(sockfd, &writeSet);
86
87 do
88 {
89 spuriousWakeup = false;
90
91 rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout);
92
93 if (rc > 0)
94 {
95 if (FD_ISSET(sockfd, &writeSet))
96 {
Tom Josephc0f5b5d2017-02-09 17:47:50 +053097 address.addrSize =
Vernon Mauery9e801a22018-10-12 13:20:49 -070098 static_cast<socklen_t>(sizeof(address.inAddr));
Tom Josephaaeb29e2016-08-10 06:36:33 -050099 do
100 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700101 writeDataLen =
102 sendto(sockfd, // File Descriptor
103 outputPtr, // Message
104 bufferSize, // Length
105 MSG_NOSIGNAL, // Flags
106 &address.sockAddr, // Destination Address
107 address.addrSize); // Address Length
Tom Josephaaeb29e2016-08-10 06:36:33 -0500108
109 if (writeDataLen < 0)
110 {
111 rc = -errno;
Vernon Maueryfc37e592018-12-19 14:55:15 -0800112 log<level::ERR>("Channel::Write: Write failed",
113 entry("ERRNO=%d", rc));
Tom Josephaaeb29e2016-08-10 06:36:33 -0500114 }
115 else if (static_cast<size_t>(writeDataLen) < bufferSize)
116 {
117 rc = -1;
Vernon Maueryfc37e592018-12-19 14:55:15 -0800118 log<level::ERR>(
119 "Channel::Write: Complete data not written"
120 " to the socket");
Tom Josephaaeb29e2016-08-10 06:36:33 -0500121 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700122 } while ((writeDataLen < 0) && (-(rc) == EINTR));
Tom Josephaaeb29e2016-08-10 06:36:33 -0500123 }
124 else
125 {
126 // Spurious wake up
Vernon Maueryfc37e592018-12-19 14:55:15 -0800127 log<level::ERR>("Spurious wake up on select (writeset)");
Tom Josephaaeb29e2016-08-10 06:36:33 -0500128 spuriousWakeup = true;
129 }
130 }
131 else
132 {
133 if (rc == 0)
134 {
135 // Timed out
136 rc = -1;
Vernon Maueryfc37e592018-12-19 14:55:15 -0800137 log<level::ERR>("We timed out on select call (writeset)");
Tom Josephaaeb29e2016-08-10 06:36:33 -0500138 }
139 else
140 {
141 // Error
Vernon Mauery9e801a22018-10-12 13:20:49 -0700142 rc = -errno;
Vernon Maueryfc37e592018-12-19 14:55:15 -0800143 log<level::ERR>("select call (writeset) error",
144 entry("ERRNO=%d", rc));
Tom Josephaaeb29e2016-08-10 06:36:33 -0500145 }
Tom Josephaaeb29e2016-08-10 06:36:33 -0500146 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700147 } while (spuriousWakeup);
Tom Josephaaeb29e2016-08-10 06:36:33 -0500148
149 return rc;
150}
151
152} // namespace udpsocket