blob: 2fa350a29e6a25e52753cebdb08ce23be6e5bd3a [file] [log] [blame]
#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_INET6, &address.inAddr.sin6_addr, tmp, sizeof(tmp));
return std::string(tmp);
}
std::tuple<int, std::vector<uint8_t>> Channel::read()
{
int rc = 0;
int readSize = 0;
ssize_t readDataLen = 0;
std::vector<uint8_t> 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 = static_cast<socklen_t>(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) // 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(const std::vector<uint8_t>& 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 =
static_cast<socklen_t>(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