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 74
 {
69 75
 	int b_read;
70 76
 	int n;
77
+#ifdef NO_MSG_WAITALL
78
+	struct pollfd pfd;
79
+#endif /* NO_MSG_WAITALL */
71 80
 	
72 81
 	b_read=0;
73 82
 again:
83
+#ifdef NO_MSG_WAITALL
84
+	if (flags & MSG_WAITALL){
85
+		n=-1;
86
+		goto poll_recv; /* simulate MSG_WAITALL */
87
+	}
88
+#endif /* NO_MSG_WAITALL */
74 89
 	n=recv(socket, (char*)data, data_len, flags);
75 90
 	if (n<0){
76 91
 		/* error */
... ...
@@ -83,10 +98,31 @@ again:
83 98
 	}
84 99
 	b_read+=n;
85 100
 	while( (b_read!=data_len) && (n)){
101
+#ifdef NO_MSG_WAITALL
102
+		/* cygwin & win do not support MSG_WAITALL => workaround using poll */
103
+poll_recv:
104
+		n=recv(socket, (char*)data+b_read, data_len-b_read, 0);
105
+#else /* NO_MSG_WAITALL */
86 106
 		n=recv(socket, (char*)data+b_read, data_len-b_read, MSG_WAITALL);
107
+#endif /* NO_MSG_WAITALL */
87 108
 		if (n<0){
88 109
 			/* error */
89 110
 			if (errno==EINTR) continue; /* signal, try again */
111
+#ifdef NO_MSG_WAITALL
112
+			if (errno==EAGAIN || errno==EWOULDBLOCK){
113
+				/* emulate MSG_WAITALL using poll */
114
+				pfd.fd=socket;
115
+				pfd.events=POLLIN;
116
+poll_retry:
117
+				n=poll(&pfd, 1, -1);
118
+				if (n<0){ 
119
+					if (errno==EINTR) goto poll_retry;
120
+					LOG(L_CRIT, "ERROR: recv_all: poll on %d failed: %s\n",
121
+								socket, strerror(errno));
122
+					return n;
123
+				} else continue; /* try recv again */
124
+			}
125
+#endif /* NO_MSG_WAITALL */
90 126
 			LOG(L_CRIT, "ERROR: recv_all: 2nd recv on %d failed: %s\n",
91 127
 					socket, strerror(errno));
92 128
 			return n;
... ...
@@ -184,6 +220,10 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
184 220
 	int new_fd;
185 221
 	int ret;
186 222
 	int n;
223
+#ifdef NO_MSG_WAITALL
224
+	struct pollfd pfd;
225
+	int f;
226
+#endif /*NO_MSG_WAITALL */
187 227
 #ifdef HAVE_MSGHDR_MSG_CONTROL
188 228
 	struct cmsghdr* cmsg;
189 229
 	union{
... ...
@@ -206,11 +246,34 @@ int receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags)
206 246
 	msg.msg_iov=iov;
207 247
 	msg.msg_iovlen=1;
208 248
 	
249
+#ifdef NO_MSG_WAITALL
250
+	f=flags & ~MSG_WAITALL;
251
+#endif /* NO_MSG_WAITALL */
252
+
209 253
 again:
210
-	ret=recvmsg(unix_socket, &msg, flags);
254
+#ifdef NO_MSG_WAITALL
255
+		ret=recvmsg(unix_socket, &msg, f);
256
+#else /* NO_MSG_WAITALL */
257
+		ret=recvmsg(unix_socket, &msg, flags);
258
+#endif /* NO_MSG_WAITALL */
211 259
 	if (ret<0){
212 260
 		if (errno==EINTR) goto again;
213
-		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)) goto error;
261
+		if ((errno==EAGAIN)||(errno==EWOULDBLOCK)){
262
+#ifdef NO_MSG_WAITALL
263
+			if (flags & MSG_WAITALL){
264
+				/* emulate MSG_WAITALL using poll */
265
+				pfd.fd=unix_socket;
266
+				pfd.events=POLLIN;
267
+poll_again:
268
+				ret=poll(&pfd, 1, -1);
269
+				if (ret>=0) goto again;
270
+				else if (errno==EINTR) goto poll_again;
271
+				LOG(L_CRIT, "ERROR: receive_fd: poll on %d failed: %s\n",
272
+							unix_socket, strerror(errno));
273
+			}
274
+#endif /* NO_MSG_WAITALL */
275
+			goto error;
276
+		}
214 277
 		LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n",
215 278
 				unix_socket, strerror(errno));
216 279
 		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);