diff --git a/src/evhelper.cpp b/src/evhelper.cpp index f629e72..b47843f 100644 --- a/src/evhelper.cpp +++ b/src/evhelper.cpp @@ -370,7 +370,7 @@ bool evbase::assertInRunningLoop() const bool evsocket::canIPv6; evsocket::ipstack_t evsocket::ipstack; -evsocket::evsocket(int af, evutil_socket_t sock) +evsocket::evsocket(int af, evutil_socket_t sock, bool blocking) :sock(sock) ,af(af) { @@ -390,7 +390,7 @@ evsocket::evsocket(int af, evutil_socket_t sock) evutil_make_socket_closeonexec(sock); - if(evutil_make_socket_nonblocking(sock)) { + if(!blocking && evutil_make_socket_nonblocking(sock)) { evutil_closesocket(sock); throw std::runtime_error("Unable to make non-blocking socket"); } @@ -401,8 +401,8 @@ evsocket::evsocket(int af, evutil_socket_t sock) # define SOCK_CLOEXEC 0 #endif -evsocket::evsocket(int af, int type, int proto) - :evsocket(af, socket(af, type | SOCK_CLOEXEC, proto)) +evsocket::evsocket(int af, int type, int proto, bool blocking) + :evsocket(af, socket(af, type | SOCK_CLOEXEC, proto), blocking) { #ifdef __linux__ # ifndef IP_MULTICAST_ALL diff --git a/src/evhelper.h b/src/evhelper.h index 88f61a6..d1a3917 100644 --- a/src/evhelper.h +++ b/src/evhelper.h @@ -199,10 +199,10 @@ struct PVXS_API evsocket constexpr evsocket() noexcept :sock(-1), af(AF_UNSPEC) {} // construct from a valid (not -1) socket - explicit evsocket(int af, evutil_socket_t sock); + explicit evsocket(int af, evutil_socket_t sock, bool blocking=false); // create a new socket - evsocket(int, int, int); + evsocket(int af, int type, int proto, bool blocking=false); // movable evsocket(evsocket&& o) noexcept; diff --git a/test/testsock.cpp b/test/testsock.cpp index 2abaa74..3f9b0ec 100644 --- a/test/testsock.cpp +++ b/test/testsock.cpp @@ -6,6 +6,10 @@ #include +#ifndef _WIN32 +# include +#endif + #include #include #include @@ -13,6 +17,7 @@ #include #include #include +#include #include #include @@ -22,6 +27,42 @@ namespace { using namespace pvxs; +#ifdef _WIN32 +# define poll WSAPoll +# ifndef POLLIN +# define POLLIN POLLRDNORM +# endif +#endif + +bool waitReadable(const evsocket& sock, double timeout=5.0) +{ + pollfd pfd{}; + + pfd.fd = sock.sock; + pfd.events = POLLIN; + + auto expire(epicsTime::getCurrent() + timeout); + while(true) { + auto remaining = expire - epicsTime::getCurrent(); + int msleft = remaining*1000.0; + if(msleft <= 0) + return false; + + testDiag("%s waiting for %d ms", __func__, msleft); + auto ret = poll(&pfd, 1u, msleft); + if(ret < 0) { + auto err(SOCKERRNO); + if(err == SOCK_EINTR) + continue; + testFail("%s fails with %d after %f", __func__, err, remaining); + return false; + } + + if(ret == 1 && (pfd.revents & POLLIN)) + return true; + } +} + void test_bind46(const char* saddr1, const char* saddr2, int type, int expect) { const std::string label = SB()<<__func__<<"("<sa, mcast_addr.addr.size()); testEq(ret, int(msglen))<<" sendto("< "<