blob: c41211ece7c69a190c554decd7d70600944f802e [file] [log] [blame]
#include "utils.hpp"
#include <libpldm/base.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <phosphor-logging/lg2.hpp>
#include <iostream>
PHOSPHOR_LOG2_USING;
namespace pldm
{
namespace responder
{
namespace utils
{
int setupUnixSocket(const std::string& socketInterface)
{
int sock;
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (strnlen(socketInterface.c_str(), sizeof(addr.sun_path)) ==
sizeof(addr.sun_path))
{
error("setupUnixSocket: UNIX socket path too long");
return -1;
}
strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
{
error("setupUnixSocket: socket() call failed");
return -1;
}
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
{
error("setupUnixSocket: bind() call failed with errno {ERR}", "ERR",
errno);
close(sock);
return -1;
}
if (listen(sock, 1) == -1)
{
error("setupUnixSocket: listen() call failed");
close(sock);
return -1;
}
fd_set rfd;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_SET(sock, &rfd);
int nfd = sock + 1;
int fd = -1;
int retval = select(nfd, &rfd, NULL, NULL, &tv);
if (retval < 0)
{
error("setupUnixSocket: select call failed {ERR}", "ERR", errno);
close(sock);
return -1;
}
if ((retval > 0) && (FD_ISSET(sock, &rfd)))
{
fd = accept(sock, NULL, NULL);
if (fd < 0)
{
error("setupUnixSocket: accept() call failed {ERR}", "ERR", errno);
close(sock);
return -1;
}
close(sock);
}
return fd;
}
int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
{
uint64_t i;
int nwrite = 0;
for (i = 0; i < blockSize; i = i + nwrite)
{
fd_set wfd;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&wfd);
FD_SET(sock, &wfd);
int nfd = sock + 1;
int retval = select(nfd, NULL, &wfd, NULL, &tv);
if (retval < 0)
{
error("writeToUnixSocket: select call failed {ERR}", "ERR", errno);
close(sock);
return -1;
}
if (retval == 0)
{
nwrite = 0;
continue;
}
if ((retval > 0) && (FD_ISSET(sock, &wfd)))
{
nwrite = write(sock, buf + i, blockSize - i);
if (nwrite < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
{
error(
"writeToUnixSocket: Write call failed with EAGAIN or EWOULDBLOCK or EINTR");
nwrite = 0;
continue;
}
error("writeToUnixSocket: Failed to write {ERR}", "ERR", errno);
close(sock);
return -1;
}
}
else
{
nwrite = 0;
}
}
return 0;
}
} // namespace utils
} // namespace responder
} // namespace pldm