xref: /openbmc/slpd-lite/sock_channel.cpp (revision 40efe6724862a5fe493c1b672e43b81463343b45)
137a7a078SRatan Gupta #include "sock_channel.hpp"
237a7a078SRatan Gupta 
337a7a078SRatan Gupta #include <errno.h>
437a7a078SRatan Gupta #include <netinet/in.h>
537a7a078SRatan Gupta #include <sys/ioctl.h>
637a7a078SRatan Gupta #include <sys/socket.h>
737a7a078SRatan Gupta #include <unistd.h>
837a7a078SRatan Gupta 
937a7a078SRatan Gupta #include <iostream>
1037a7a078SRatan Gupta #include <string>
1137a7a078SRatan Gupta 
1237a7a078SRatan Gupta namespace udpsocket
1337a7a078SRatan Gupta {
1437a7a078SRatan Gupta 
getRemoteAddress() const1537a7a078SRatan Gupta std::string Channel::getRemoteAddress() const
1637a7a078SRatan Gupta {
1737a7a078SRatan Gupta     char tmp[INET_ADDRSTRLEN] = {0};
1870b85271SRatan Gupta     inet_ntop(AF_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp));
1937a7a078SRatan Gupta     return std::string(tmp);
2037a7a078SRatan Gupta }
2137a7a078SRatan Gupta 
read()2237a7a078SRatan Gupta std::tuple<int, buffer> Channel::read()
2337a7a078SRatan Gupta {
2437a7a078SRatan Gupta     int rc = 0;
2537a7a078SRatan Gupta     int readSize = 0;
2637a7a078SRatan Gupta     ssize_t readDataLen = 0;
27*40efe672SAndrew Geissler     buffer outBuffer;
2837a7a078SRatan Gupta 
2937a7a078SRatan Gupta     if (ioctl(sockfd, FIONREAD, &readSize) < 0)
3037a7a078SRatan Gupta     {
311ee36397SRatan Gupta         std::cerr << "Channel::Read : ioctl failed with errno = " << errno;
3237a7a078SRatan Gupta         rc = -errno;
3337a7a078SRatan Gupta         return std::make_tuple(rc, std::move(outBuffer));
3437a7a078SRatan Gupta     }
3537a7a078SRatan Gupta 
3637a7a078SRatan Gupta     outBuffer.resize(readSize);
3737a7a078SRatan Gupta     auto bufferSize = outBuffer.size();
3837a7a078SRatan Gupta     auto outputPtr = outBuffer.data();
3937a7a078SRatan Gupta 
405e008877SRatan Gupta     address.addrSize = static_cast<socklen_t>(sizeof(address.inAddr));
4137a7a078SRatan Gupta 
4237a7a078SRatan Gupta     do
4337a7a078SRatan Gupta     {
4437a7a078SRatan Gupta         readDataLen = recvfrom(sockfd,             // File Descriptor
4537a7a078SRatan Gupta                                outputPtr,          // Buffer
4637a7a078SRatan Gupta                                bufferSize,         // Bytes requested
4737a7a078SRatan Gupta                                0,                  // Flags
4837a7a078SRatan Gupta                                &address.sockAddr,  // Address
4937a7a078SRatan Gupta                                &address.addrSize); // Address Length
5037a7a078SRatan Gupta 
51908dee3dSRatan Gupta         if (readDataLen == 0) // Peer has performed an orderly shutdown
5237a7a078SRatan Gupta         {
5337a7a078SRatan Gupta             outBuffer.resize(0);
5437a7a078SRatan Gupta             rc = -1;
5537a7a078SRatan Gupta         }
5637a7a078SRatan Gupta         else if (readDataLen < 0) // Error
5737a7a078SRatan Gupta         {
5837a7a078SRatan Gupta             rc = -errno;
591ee36397SRatan Gupta             std::cerr << "Channel::Read : Receive Error Fd[" << sockfd << "]"
6037a7a078SRatan Gupta                       << "errno = " << rc << "\n";
6137a7a078SRatan Gupta             outBuffer.resize(0);
6237a7a078SRatan Gupta         }
63537ff140SPatrick Venture     } while ((readDataLen < 0) && (-(rc) == EINTR));
6437a7a078SRatan Gupta 
6537a7a078SRatan Gupta     // Resize the vector to the actual data read from the socket
6637a7a078SRatan Gupta     outBuffer.resize(readDataLen);
6737a7a078SRatan Gupta     return std::make_tuple(rc, std::move(outBuffer));
6837a7a078SRatan Gupta }
6937a7a078SRatan Gupta 
write(buffer & inBuffer)7037a7a078SRatan Gupta int Channel::write(buffer& inBuffer)
7137a7a078SRatan Gupta {
7237a7a078SRatan Gupta     int rc = 0;
7337a7a078SRatan Gupta     auto outputPtr = inBuffer.data();
7437a7a078SRatan Gupta     auto bufferSize = inBuffer.size();
7537a7a078SRatan Gupta     auto spuriousWakeup = false;
7637a7a078SRatan Gupta     ssize_t writeDataLen = 0;
7737a7a078SRatan Gupta     timeval varTimeout = timeout;
7837a7a078SRatan Gupta 
7937a7a078SRatan Gupta     fd_set writeSet;
8037a7a078SRatan Gupta     FD_ZERO(&writeSet);
8137a7a078SRatan Gupta     FD_SET(sockfd, &writeSet);
8237a7a078SRatan Gupta 
8337a7a078SRatan Gupta     do
8437a7a078SRatan Gupta     {
8537a7a078SRatan Gupta         spuriousWakeup = false;
8637a7a078SRatan Gupta 
8737a7a078SRatan Gupta         rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout);
8837a7a078SRatan Gupta 
8937a7a078SRatan Gupta         if (rc > 0)
9037a7a078SRatan Gupta         {
9137a7a078SRatan Gupta             if (FD_ISSET(sockfd, &writeSet))
9237a7a078SRatan Gupta             {
93537ff140SPatrick Venture                 address.addrSize =
94537ff140SPatrick Venture                     static_cast<socklen_t>(sizeof(address.inAddr));
9537a7a078SRatan Gupta                 do
9637a7a078SRatan Gupta                 {
97537ff140SPatrick Venture                     writeDataLen =
98537ff140SPatrick Venture                         sendto(sockfd,            // File Descriptor
9937a7a078SRatan Gupta                                outputPtr,         // Message
10037a7a078SRatan Gupta                                bufferSize,        // Length
10137a7a078SRatan Gupta                                MSG_NOSIGNAL,      // Flags
10237a7a078SRatan Gupta                                &address.sockAddr, // Destination Address
10337a7a078SRatan Gupta                                address.addrSize); // Address Length
10437a7a078SRatan Gupta 
10537a7a078SRatan Gupta                     if (writeDataLen < 0)
10637a7a078SRatan Gupta                     {
10737a7a078SRatan Gupta                         rc = -errno;
108537ff140SPatrick Venture                         std::cerr
109537ff140SPatrick Venture                             << "Channel::Write: Write failed with errno:" << rc
110537ff140SPatrick Venture                             << "\n";
11137a7a078SRatan Gupta                     }
11237a7a078SRatan Gupta                     else if (static_cast<size_t>(writeDataLen) < bufferSize)
11337a7a078SRatan Gupta                     {
11437a7a078SRatan Gupta                         rc = -1;
11537a7a078SRatan Gupta                         std::cerr << "Channel::Write: Complete data not written"
11637a7a078SRatan Gupta                                      " to the socket\n";
11737a7a078SRatan Gupta                     }
118537ff140SPatrick Venture                 } while ((writeDataLen < 0) && (-(rc) == EINTR));
11937a7a078SRatan Gupta             }
12037a7a078SRatan Gupta             else
12137a7a078SRatan Gupta             {
12237a7a078SRatan Gupta                 // Spurious wake up
1231ee36397SRatan Gupta                 std::cerr << "Spurious wake up on select (writeset)\n";
12437a7a078SRatan Gupta                 spuriousWakeup = true;
12537a7a078SRatan Gupta             }
12637a7a078SRatan Gupta         }
12737a7a078SRatan Gupta         else
12837a7a078SRatan Gupta         {
12937a7a078SRatan Gupta             if (rc == 0)
13037a7a078SRatan Gupta             {
13137a7a078SRatan Gupta                 // Timed out
13237a7a078SRatan Gupta                 rc = -1;
1331ee36397SRatan Gupta                 std::cerr << "We timed out on select call (writeset)\n";
13437a7a078SRatan Gupta             }
13537a7a078SRatan Gupta             else
13637a7a078SRatan Gupta             {
13737a7a078SRatan Gupta                 // Error
13837a7a078SRatan Gupta                 rc = -errno;
139537ff140SPatrick Venture                 std::cerr << "select call (writeset) had an error : " << rc
140537ff140SPatrick Venture                           << "\n";
14137a7a078SRatan Gupta             }
14237a7a078SRatan Gupta         }
143537ff140SPatrick Venture     } while (spuriousWakeup);
14437a7a078SRatan Gupta 
14537a7a078SRatan Gupta     return rc;
14637a7a078SRatan Gupta }
14737a7a078SRatan Gupta 
14837a7a078SRatan Gupta } // namespace udpsocket
149