Forráskód Böngészése

- MSG_WAITALL emulation for OSes that don't support it (win+cygwin)

Andrei Pelinescu-Onciul 17 éve
szülő
commit
3d4bb4b17b
2 módosított fájl, 80 hozzáadás és 2 törlés
  1. 65 2
      pass_fd.c
  2. 15 0
      pass_fd.h

+ 65 - 2
pass_fd.c

@@ -33,16 +33,22 @@
   *               to handle signals  (andrei)
   *               to handle signals  (andrei)
   *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
   *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
   *              or semi-nonblocking mode (andrei)
   *              or semi-nonblocking mode (andrei)
+  *  2008-04-30  added MSG_WAITALL emulation for cygwin (andrei)
   */
   */
 
 
 #ifdef USE_TCP
 #ifdef USE_TCP
 
 
+#include "pass_fd.h"
+
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
 #include <sys/uio.h>
 #include <stdlib.h> /* for NULL definition on openbsd */
 #include <stdlib.h> /* for NULL definition on openbsd */
 #include <errno.h>
 #include <errno.h>
 #include <string.h>
 #include <string.h>
+#ifdef NO_MSG_WAITALL
+#include <poll.h>
+#endif /* NO_MSG_WAITALL */
 
 
 #include "dprint.h"
 #include "dprint.h"
 
 
@@ -68,9 +74,18 @@ int recv_all(int socket, void* data, int data_len, int flags)
 {
 {
 	int b_read;
 	int b_read;
 	int n;
 	int n;
+#ifdef NO_MSG_WAITALL
+	struct pollfd pfd;
+#endif /* NO_MSG_WAITALL */
 	
 	
 	b_read=0;
 	b_read=0;
 again:
 again:
+#ifdef NO_MSG_WAITALL
+	if (flags & MSG_WAITALL){
+		n=-1;
+		goto poll_recv; /* simulate MSG_WAITALL */
+	}
+#endif /* NO_MSG_WAITALL */
 	n=recv(socket, (char*)data, data_len, flags);
 	n=recv(socket, (char*)data, data_len, flags);
 	if (n<0){
 	if (n<0){
 		/* error */
 		/* error */
@@ -83,10 +98,31 @@ again:
 	}
 	}
 	b_read+=n;
 	b_read+=n;
 	while( (b_read!=data_len) && (n)){
 	while( (b_read!=data_len) && (n)){
+#ifdef NO_MSG_WAITALL
+		/* cygwin & win do not support MSG_WAITALL => workaround using poll */
+poll_recv:
+		n=recv(socket, (char*)data+b_read, data_len-b_read, 0);
+#else /* NO_MSG_WAITALL */
 		n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
 		n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
+#endif /* NO_MSG_WAITALL */
 		if (n<0){
 		if (n<0){
 			/* error */
 			/* error */
 			if (errno==EINTR) continue; /* signal, try again */
 			if (errno==EINTR) continue; /* signal, try again */
+#ifdef NO_MSG_WAITALL
+			if (errno==EAGAIN || errno==EWOULDBLOCK){
+				/* emulate MSG_WAITALL using poll */
+				pfd.fd=socket;
+				pfd.events=POLLIN;
+poll_retry:
+				n=poll(&pfd, 1, -1);
+				if (n<0){ 
+					if (errno==EINTR) goto poll_retry;
+					LOG(L_CRIT, "ERROR: recv_all: poll on %d failed: %s\n",
+								socket, strerror(errno));
+					return n;
+				} else continue; /* try recv again */
+			}
+#endif /* NO_MSG_WAITALL */
 			LOG(L_CRIT, "ERROR: recv_all: 2nd recv on %d failed: %s\n",
 			LOG(L_CRIT, "ERROR: recv_all: 2nd recv on %d failed: %s\n",
 					socket, strerror(errno));
 					socket, strerror(errno));
 			return n;
 			return n;
@@ -184,6 +220,10 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
 	int new_fd;
 	int new_fd;
 	int ret;
 	int ret;
 	int n;
 	int n;
+#ifdef NO_MSG_WAITALL
+	struct pollfd pfd;
+	int f;
+#endif /*NO_MSG_WAITALL */
 #ifdef HAVE_MSGHDR_MSG_CONTROL
 #ifdef HAVE_MSGHDR_MSG_CONTROL
 	struct cmsghdr* cmsg;
 	struct cmsghdr* cmsg;
 	union{
 	union{
@@ -206,11 +246,34 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
 	msg.msg_iov=iov;
 	msg.msg_iov=iov;
 	msg.msg_iovlen=1;
 	msg.msg_iovlen=1;
 	
 	
+#ifdef NO_MSG_WAITALL
+	f=flags & ~MSG_WAITALL;
+#endif /* NO_MSG_WAITALL */
+
 again:
 again:
-	ret=recvmsg(unix_socket, &msg, flags);
+#ifdef NO_MSG_WAITALL
+		ret=recvmsg(unix_socket, &msg, f);
+#else /* NO_MSG_WAITALL */
+		ret=recvmsg(unix_socket, &msg, flags);
+#endif /* NO_MSG_WAITALL */
 	if (ret<0){
 	if (ret<0){
 		if (errno==EINTR) goto again;
 		if (errno==EINTR) goto again;
-		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error;
+		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
+#ifdef NO_MSG_WAITALL
+			if (flags & MSG_WAITALL){
+				/* emulate MSG_WAITALL using poll */
+				pfd.fd=unix_socket;
+				pfd.events=POLLIN;
+poll_again:
+				ret=poll(&pfd, 1, -1);
+				if (ret>=0) goto again;
+				else if (errno==EINTR) goto poll_again;
+				LOG(L_CRIT, "ERROR: receive_fd: poll on %d failed: %s\n",
+							unix_socket, strerror(errno));
+			}
+#endif /* NO_MSG_WAITALL */
+			goto error;
+		}
 		LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
 		LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
 				unix_socket, strerror(errno));
 				unix_socket, strerror(errno));
 		goto error;
 		goto error;

+ 15 - 0
pass_fd.h

@@ -28,6 +28,21 @@
 #ifndef _pass_fd_h
 #ifndef _pass_fd_h
 #define _pass_fd_h
 #define _pass_fd_h
 
 
+#ifdef __OS_cygwin
+/* check if MSG_WAITALL is defined */
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifndef MSG_WAITALL
+#define NO_MSG_WAITALL
+#define MSG_WAITALL 0x80000000
+#endif /* MSG_WAITALL */
+
+#ifndef MSG_DONTWAIT
+#define NO_MSG_DONTWAIT
+#endif /* MSG_DONT_WAIT */
+
+#endif /* __OS_cygwin */
 
 
 int send_fd(int unix_socket, void* data, int data_len, int fd);
 int send_fd(int unix_socket, void* data, int data_len, int fd);
 int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags);
 int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags);