Browse code

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

Andrei Pelinescu-Onciul authored on 30/04/2008 19:54:34
Showing 2 changed files
... ...
@@ -33,16 +33,22 @@
33 33
   *               to handle signals  (andrei)
34 34
   *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
35 35
   *              or semi-nonblocking mode (andrei)
36
+  *  2008-04-30  added MSG_WAITALL emulation for cygwin (andrei)
36 37
   */
37 38
 
38 39
 #ifdef USE_TCP
39 40
 
41
+#include "pass_fd.h"
42
+
40 43
 #include <sys/types.h>
41 44
 #include <sys/socket.h>
42 45
 #include <sys/uio.h>
43 46
 #include <stdlib.h> /* for NULL definition on openbsd */
44 47
 #include <errno.h>
45 48
 #include <string.h>
49
+#ifdef NO_MSG_WAITALL
50
+#include <poll.h>
51
+#endif /* NO_MSG_WAITALL */
46 52
 
47 53
 #include "dprint.h"
48 54
 
... ...
@@ -68,9 +74,18 @@ int recv_all(int socket, void* data, int data_len, int flags)
68 68
 {
69 69
 	int b_read;
70 70
 	int n;
71
+#ifdef NO_MSG_WAITALL
72
+	struct pollfd pfd;
73
+#endif /* NO_MSG_WAITALL */
71 74
 	
72 75
 	b_read=0;
73 76
 again:
77
+#ifdef NO_MSG_WAITALL
78
+	if (flags & MSG_WAITALL){
79
+		n=-1;
80
+		goto poll_recv; /* simulate MSG_WAITALL */
81
+	}
82
+#endif /* NO_MSG_WAITALL */
74 83
 	n=recv(socket, (char*)data, data_len, flags);
75 84
 	if (n<0){
76 85
 		/* error */
... ...
@@ -83,10 +98,31 @@ again:
83 83
 	}
84 84
 	b_read+=n;
85 85
 	while( (b_read!=data_len) && (n)){
86
+#ifdef NO_MSG_WAITALL
87
+		/* cygwin & win do not support MSG_WAITALL => workaround using poll */
88
+poll_recv:
89
+		n=recv(socket, (char*)data+b_read, data_len-b_read, 0);
90
+#else /* NO_MSG_WAITALL */
86 91
 		n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
92
+#endif /* NO_MSG_WAITALL */
87 93
 		if (n<0){
88 94
 			/* error */
89 95
 			if (errno==EINTR) continue; /* signal, try again */
96
+#ifdef NO_MSG_WAITALL
97
+			if (errno==EAGAIN || errno==EWOULDBLOCK){
98
+				/* emulate MSG_WAITALL using poll */
99
+				pfd.fd=socket;
100
+				pfd.events=POLLIN;
101
+poll_retry:
102
+				n=poll(&pfd, 1, -1);
103
+				if (n<0){ 
104
+					if (errno==EINTR) goto poll_retry;
105
+					LOG(L_CRIT, "ERROR: recv_all: poll on %d failed: %s\n",
106
+								socket, strerror(errno));
107
+					return n;
108
+				} else continue; /* try recv again */
109
+			}
110
+#endif /* NO_MSG_WAITALL */
90 111
 			LOG(L_CRIT, "ERROR: recv_all: 2nd recv on %d failed: %s\n",
91 112
 					socket, strerror(errno));
92 113
 			return n;
... ...
@@ -184,6 +220,10 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
184 184
 	int new_fd;
185 185
 	int ret;
186 186
 	int n;
187
+#ifdef NO_MSG_WAITALL
188
+	struct pollfd pfd;
189
+	int f;
190
+#endif /*NO_MSG_WAITALL */
187 191
 #ifdef HAVE_MSGHDR_MSG_CONTROL
188 192
 	struct cmsghdr* cmsg;
189 193
 	union{
... ...
@@ -206,11 +246,34 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
206 206
 	msg.msg_iov=iov;
207 207
 	msg.msg_iovlen=1;
208 208
 	
209
+#ifdef NO_MSG_WAITALL
210
+	f=flags & ~MSG_WAITALL;
211
+#endif /* NO_MSG_WAITALL */
212
+
209 213
 again:
210
-	ret=recvmsg(unix_socket, &msg, flags);
214
+#ifdef NO_MSG_WAITALL
215
+		ret=recvmsg(unix_socket, &msg, f);
216
+#else /* NO_MSG_WAITALL */
217
+		ret=recvmsg(unix_socket, &msg, flags);
218
+#endif /* NO_MSG_WAITALL */
211 219
 	if (ret<0){
212 220
 		if (errno==EINTR) goto again;
213
-		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error;
221
+		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
222
+#ifdef NO_MSG_WAITALL
223
+			if (flags & MSG_WAITALL){
224
+				/* emulate MSG_WAITALL using poll */
225
+				pfd.fd=unix_socket;
226
+				pfd.events=POLLIN;
227
+poll_again:
228
+				ret=poll(&pfd, 1, -1);
229
+				if (ret>=0) goto again;
230
+				else if (errno==EINTR) goto poll_again;
231
+				LOG(L_CRIT, "ERROR: receive_fd: poll on %d failed: %s\n",
232
+							unix_socket, strerror(errno));
233
+			}
234
+#endif /* NO_MSG_WAITALL */
235
+			goto error;
236
+		}
214 237
 		LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
215 238
 				unix_socket, strerror(errno));
216 239
 		goto error;
... ...
@@ -28,6 +28,21 @@
28 28
 #ifndef _pass_fd_h
29 29
 #define _pass_fd_h
30 30
 
31
+#ifdef __OS_cygwin
32
+/* check if MSG_WAITALL is defined */
33
+#include <sys/types.h>
34
+#include <sys/socket.h>
35
+
36
+#ifndef MSG_WAITALL
37
+#define NO_MSG_WAITALL
38
+#define MSG_WAITALL 0x80000000
39
+#endif /* MSG_WAITALL */
40
+
41
+#ifndef MSG_DONTWAIT
42
+#define NO_MSG_DONTWAIT
43
+#endif /* MSG_DONT_WAIT */
44
+
45
+#endif /* __OS_cygwin */
31 46
 
32 47
 int send_fd(int unix_socket, void* data, int data_len, int fd);
33 48
 int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags);