File mono-20059-rcvtimeo-V4.patch of Package mono
--- mono/metadata/w32socket-unix.c 2020-07-01 13:59:59.417951000 +0000
+++ mono/metadata/w32socket-unix.c 2020-07-01 19:45:27.712769312 +0000
@@ -47,6 +47,10 @@
#include <sys/sendfile.h>
#endif
#include <sys/stat.h>
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
#include "w32socket.h"
#include "w32socket-internals.h"
@@ -304,6 +308,9 @@
SocketHandle *sockethandle;
int ret;
MonoThreadInfo *info;
+ struct timeval tstart, tlimit, timeout;
+ socklen_t timevallen = sizeof(struct timeval);
+ int timeoutchanged = 0;
if (!mono_fdhandle_lookup_and_ref(sock, (MonoFDHandle**) &sockethandle)) {
mono_w32error_set_last (WSAENOTSOCK);
@@ -316,13 +323,60 @@
return SOCKET_ERROR;
}
+ if (blocking) {
+ memset(&tstart, 0, timevallen);
+ memset(&tlimit, 0, timevallen);
+ memset(&timeout, 0, timevallen);
+
+ MONO_ENTER_GC_SAFE;
+ getsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, &timevallen);
+ MONO_EXIT_GC_SAFE;
+
+ if (timeout.tv_sec > 0 || timeout.tv_usec > 0) {
+ gettimeofday(&tstart, NULL);
+ timeradd(&tstart, &timeout, &tlimit);
+ }
+ }
+
info = mono_thread_info_current ();
do {
MONO_ENTER_GC_SAFE;
ret = recvfrom (((MonoFDHandle*) sockethandle)->fd, buf, len, flags, from, fromlen);
MONO_EXIT_GC_SAFE;
- } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info));
+
+ if(ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)) {
+ if (blocking && (timeout.tv_sec > 0 || timeout.tv_usec > 0)) {
+ struct timeval tnow, tremaining;
+
+ gettimeofday(&tnow, NULL);
+ if(!timercmp(&tnow, &tlimit, <)) { //< timeout exceeded
+ errno = EWOULDBLOCK; //< or EAGAIN?
+ break;
+ }
+
+ timersub(&tlimit, &tnow, &tremaining);
+ timeoutchanged = 1;
+
+ MONO_ENTER_GC_SAFE;
+ setsockopt (((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_RCVTIMEO, &tremaining, timevallen);
+ MONO_EXIT_GC_SAFE;
+
+ errno = EINTR; //< XXX: restore original errno
+ }
+ continue; //< Try recv again
+ }
+
+ break; //< No need to retry
+ } while (1);
+
+ if(timeoutchanged > 0) {
+ int serrno = errno;
+ MONO_ENTER_GC_SAFE;
+ setsockopt(((MonoFDHandle*) sockethandle)->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, timevallen);
+ MONO_EXIT_GC_SAFE;
+ errno = serrno;
+ }
if (ret == 0 && len > 0) {
/* According to the Linux man page, recvfrom only