xref: /openbmc/slpd-lite/sock_channel.cpp (revision 537ff140)
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 
getRemoteAddress() const15 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 
read()22 std::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 << "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 
write(buffer & inBuffer)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