This prevents client and server from being sent a SIGPIPE (and terminating) when the other side unexpectedly closes the connection. It's way easier to handle this condition when checking the write() return value, than to do anything smart in a SIGPIPE handler. More details: <http://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly> Change-Id: I1da5bf5ef79c8b7b00ede976e96ed4f1c560049d
97 lines
2.0 KiB
C++
97 lines
2.0 KiB
C++
#include <string>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
|
|
#include "SocketComm.hpp"
|
|
|
|
namespace fail {
|
|
|
|
void SocketComm::init()
|
|
{
|
|
// It's usually much easier to handle the error on write(), than to do
|
|
// anything intelligent in a SIGPIPE handler.
|
|
signal(SIGPIPE, SIG_IGN);
|
|
}
|
|
|
|
bool SocketComm::sendMsg(int sockfd, google::protobuf::Message& msg)
|
|
{
|
|
#ifdef USE_SIZE_PREFIX
|
|
int size = htonl(msg.ByteSize());
|
|
std::string buf;
|
|
if (safe_write(sockfd, &size, sizeof(size)) == -1
|
|
|| !msg.SerializeToString(&buf)
|
|
|| safe_write(sockfd, buf.c_str(), buf.size()) == -1) {
|
|
return false;
|
|
}
|
|
#else
|
|
char c = 0;
|
|
if (!msg.SerializeToFileDescriptor(sockfd)
|
|
|| safe_write(sockfd, &c, 1) == -1) {
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
bool SocketComm::rcvMsg(int sockfd, google::protobuf::Message& msg)
|
|
{
|
|
#ifdef USE_SIZE_PREFIX
|
|
int size;
|
|
if (safe_read(sockfd, &size, sizeof(size)) == -1) {
|
|
return false;
|
|
}
|
|
size = ntohl(size);
|
|
char *buf = new char[size];
|
|
if (safe_read(sockfd, buf, size) == -1) {
|
|
delete [] buf;
|
|
return false;
|
|
}
|
|
std::string st(buf, size);
|
|
delete [] buf;
|
|
return msg.ParseFromString(st);
|
|
#else
|
|
return msg.ParseFromFileDescriptor(sockfd);
|
|
#endif
|
|
}
|
|
|
|
ssize_t SocketComm::safe_write(int fd, const void *buf, size_t count)
|
|
{
|
|
ssize_t ret;
|
|
const char *cbuf = (const char *) buf;
|
|
do {
|
|
ret = write(fd, cbuf, count);
|
|
if (ret == -1) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
return -1;
|
|
}
|
|
count -= ret;
|
|
cbuf += ret;
|
|
} while (count);
|
|
return cbuf - (const char *)buf;
|
|
}
|
|
|
|
ssize_t SocketComm::safe_read(int fd, void *buf, size_t count)
|
|
{
|
|
ssize_t ret;
|
|
char *cbuf = (char *) buf;
|
|
do {
|
|
ret = read(fd, cbuf, count);
|
|
if (ret == -1) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
return -1;
|
|
} else if (ret == 0) {
|
|
// this deliberately deviates from read(2)
|
|
return -1;
|
|
}
|
|
count -= ret;
|
|
cbuf += ret;
|
|
} while (count);
|
|
return cbuf - (const char *) buf;
|
|
}
|
|
|
|
} // end-of-namespace: fail
|