diff options
author | Tom Joseph <tomjoseph@in.ibm.com> | 2016-08-10 06:36:33 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2016-11-08 19:13:25 +0000 |
commit | aaeb29e3ee61064e40aee935d952faef89c589a5 (patch) | |
tree | 1f8fd02e28f4b8e4b8230e19cfca3e7cc315e98d /socket_channel.cpp | |
parent | 9b672192023546296aeaad77252daccdf09ffbf3 (diff) | |
download | phosphor-net-ipmid-aaeb29e3ee61064e40aee935d952faef89c589a5.tar.gz phosphor-net-ipmid-aaeb29e3ee61064e40aee935d952faef89c589a5.zip |
IPMI Socket Class to encapsulate the socket operations
This class represents the details regarding an IPMI client like IP
address, port number and the file descriptor associated with it. The
operations provided are reading the UDP packet, writing the packet.
Change-Id: I58cde0edb04fd2fbedd3068de83379eebea8508d
Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Diffstat (limited to 'socket_channel.cpp')
-rw-r--r-- | socket_channel.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/socket_channel.cpp b/socket_channel.cpp new file mode 100644 index 0000000..4a6d827 --- /dev/null +++ b/socket_channel.cpp @@ -0,0 +1,156 @@ +#include "socket_channel.hpp" + +#include <errno.h> +#include <netinet/in.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <iostream> +#include <string> + +namespace udpsocket +{ + +std::string Channel::getRemoteAddress() const +{ + char tmp[INET_ADDRSTRLEN] = { 0 }; + inet_ntop(AF_INET, &address.inAddr.sin_addr, tmp, sizeof(tmp)); + return std::string(tmp); +} + +std::tuple<int, buffer> Channel::read() +{ + int rc = 0; + int readSize = 0; + ssize_t readDataLen = 0; + buffer outBuffer(0); + + if (ioctl(sockfd, FIONREAD, &readSize) < 0) + { + std::cerr << "E> Channel::Read : ioctl failed with errno = " << errno; + rc = -errno; + return std::make_tuple(rc, std::move(outBuffer)); + } + + outBuffer.resize(readSize); + auto bufferSize = outBuffer.size(); + auto outputPtr = outBuffer.data(); + + address.addrSize = sizeof(address.inAddr); + + do + { + readDataLen = recvfrom(sockfd, // File Descriptor + outputPtr , // Buffer + bufferSize, // Bytes requested + 0, // Flags + &address.sockAddr, // Address + &address.addrSize); // Address Length + + if (readDataLen > 0) // Data read from the socket + { + std::cout << "I> Channel::Read : DataIn Fd[" << sockfd << "] Req[" + << bufferSize << "] Recv[" << readDataLen << "]\n"; + } + else if (readDataLen == 0) // Peer has performed an orderly shutdown + { + std::cerr << "E> Channel::Read : Connection Closed Fd[" << sockfd + << "]\n"; + outBuffer.resize(0); + rc = -1; + } + else if (readDataLen < 0) // Error + { + rc = -errno; + std::cerr << "E> Channel::Read : Receive Error Fd[" << sockfd << "]" + << "errno = " << rc << "\n"; + outBuffer.resize(0); + } + } + while ((readDataLen < 0) && (-(rc) == EINTR)); + + // Resize the vector to the actual data read from the socket + outBuffer.resize(readDataLen); + return std::make_tuple(rc, std::move(outBuffer)); +} + +int Channel::write(buffer& inBuffer) +{ + int rc = 0; + auto outputPtr = inBuffer.data(); + auto bufferSize = inBuffer.size(); + auto spuriousWakeup = false; + ssize_t writeDataLen = 0; + timeval varTimeout = timeout; + + fd_set writeSet; + FD_ZERO(&writeSet); + FD_SET(sockfd, &writeSet); + + do + { + spuriousWakeup = false; + + rc = select((sockfd + 1), nullptr, &writeSet, NULL, &varTimeout); + + if (rc > 0) + { + if (FD_ISSET(sockfd, &writeSet)) + { + address.addrSize = sizeof(address.inAddr); + do + { + writeDataLen = sendto(sockfd, // File Descriptor + outputPtr, // Message + bufferSize, // Length + MSG_NOSIGNAL, // Flags + &address.sockAddr,// Destination Address + address.addrSize);// Address Length + + if (writeDataLen < 0) + { + rc = -errno; + std::cerr << "Channel::Write: Write failed with errno:" + << rc << "\n"; + } + else if (static_cast<size_t>(writeDataLen) < bufferSize) + { + rc = -1; + std::cerr << "Channel::Write: Complete data not written" + " to the socket\n"; + } + } + while ((writeDataLen < 0) && (-(rc) == EINTR)); + } + else + { + // Spurious wake up + std::cerr << "E> Spurious wake up on select (writeset)\n"; + spuriousWakeup = true; + } + } + else + { + if (rc == 0) + { + // Timed out + rc = -1; + std::cerr << "E> We timed out on select call (writeset)\n"; + } + else + { + // Error + rc = -errno; + std::cerr << "E> select call (writeset) had an error : " + << rc << "\n"; + } + + } + } + while (spuriousWakeup); + + return rc; +} + +} // namespace udpsocket |