#include <cstring>
#include <cerrno>
#include <unistd.h>
+#include <chrono>
+#include <poll.h>
namespace config {
+namespace {
+
+void waitForEvent(int fd,
+ short event,
+ const std::chrono::high_resolution_clock::time_point deadline)
+{
+ // Wait for the rest of the data
+ struct pollfd fds[1];
+ fds[0].fd = fd;
+ fds[0].events = event | POLLHUP;
+
+ for (;;) {
+ std::chrono::milliseconds timeoutMS =
+ std::chrono::duration_cast<std::chrono::milliseconds>(deadline - std::chrono::high_resolution_clock::now());
+ if (timeoutMS.count() < 0) {
+ throw ConfigException("Timeout");
+ }
+
+ int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count());
+
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ throw ConfigException("Error in poll: " + std::string(strerror(errno)));
+ }
+
+ if (ret == 0) {
+ throw ConfigException("Timeout");
+ }
+
+ if (fds[0].revents & POLLHUP) {
+ throw ConfigException("Peer disconnected");
+ }
+
+ // Here Comes the Sun
+ break;
+ }
+}
+
+} // namespace
FDStore::FDStore(int fd)
: mFD(fd)
{
}
-void FDStore::write(const void* bufferPtr, const size_t size)
+void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS)
{
+ std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+ std::chrono::milliseconds(timeoutMS);
+
size_t nTotal = 0;
- int n;
+ for (;;) {
+ int n = ::write(mFD,
+ reinterpret_cast<const char*>(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n > 0) {
+ nTotal += n;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ // Neglected errors
+ } else {
+ throw ConfigException("Error during reading: " + std::string(strerror(errno)));
+ }
- do {
- n = ::write(mFD,
- reinterpret_cast<const char*>(bufferPtr) + nTotal,
- size - nTotal);
- if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
- throw ConfigException("Error during witting: " + std::string(strerror(errno)));
+ if (nTotal >= size) {
+ // All data is written, break loop
+ break;
+ } else {
+ waitForEvent(mFD, POLLOUT, deadline);
}
- nTotal += n;
- } while (nTotal < size);
+ }
}
-void FDStore::read(void* bufferPtr, const size_t size)
+void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeoutMS)
{
- size_t nTotal = 0;
- int n;
+ std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+ std::chrono::milliseconds(timeoutMS);
- do {
- n = ::read(mFD,
- reinterpret_cast<char*>(bufferPtr) + nTotal,
- size - nTotal);
- if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
+ size_t nTotal = 0;
+ for (;;) {
+ int n = ::read(mFD,
+ reinterpret_cast<char*>(bufferPtr) + nTotal,
+ size - nTotal);
+ if (n > 0) {
+ nTotal += n;
+ } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ // Neglected errors
+ } else {
throw ConfigException("Error during reading: " + std::string(strerror(errno)));
}
- nTotal += n;
- } while (nTotal < size);
-}
+ if (nTotal >= size) {
+ // All data is read, break loop
+ break;
+ } else {
+ waitForEvent(mFD, POLLIN, deadline);
+ }
+ }
+}
} // namespace config
*
* @param bufferPtr buffer with the data
* @param size size of the buffer
+ * @param timeoutMS timeout in milliseconds
*/
- void write(const void* bufferPtr, const size_t size);
+ void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
/**
* Reads a value of the given type.
*
* @param bufferPtr buffer with the data
* @param size size of the buffer
+ * @param timeoutMS timeout in milliseconds
*/
- void read(void* bufferPtr, const size_t size);
+ void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
private:
int mFD;