- MSG_WAITALL emulation for OSes that don't support it (win+cygwin)
authorAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 30 Apr 2008 19:54:34 +0000 (19:54 +0000)
committerAndrei Pelinescu-Onciul <andrei@iptel.org>
Wed, 30 Apr 2008 19:54:34 +0000 (19:54 +0000)
pass_fd.c
pass_fd.h

index 667df22..7a2b30c 100644 (file)
--- a/pass_fd.c
+++ b/pass_fd.c
   *               to handle signals  (andrei)
   *  2005-06-13  added flags to recv_all & receive_fd, to allow full blocking
   *              or semi-nonblocking mode (andrei)
+  *  2008-04-30  added MSG_WAITALL emulation for cygwin (andrei)
   */
 
 #ifdef USE_TCP
 
+#include "pass_fd.h"
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
 #include <stdlib.h> /* for NULL definition on openbsd */
 #include <errno.h>
 #include <string.h>
+#ifdef NO_MSG_WAITALL
+#include <poll.h>
+#endif /* NO_MSG_WAITALL */
 
 #include "dprint.h"
 
@@ -68,9 +74,18 @@ int recv_all(int socket, void* data, int data_len, int flags)
 {
        int b_read;
        int n;
+#ifdef NO_MSG_WAITALL
+       struct pollfd pfd;
+#endif /* NO_MSG_WAITALL */
        
        b_read=0;
 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);
        if (n<0){
                /* error */
@@ -83,10 +98,31 @@ again:
        }
        b_read+=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);
+#endif /* NO_MSG_WAITALL */
                if (n<0){
                        /* error */
                        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",
                                        socket, strerror(errno));
                        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 ret;
        int n;
+#ifdef NO_MSG_WAITALL
+       struct pollfd pfd;
+       int f;
+#endif /*NO_MSG_WAITALL */
 #ifdef HAVE_MSGHDR_MSG_CONTROL
        struct cmsghdr* cmsg;
        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_iovlen=1;
        
+#ifdef NO_MSG_WAITALL
+       f=flags & ~MSG_WAITALL;
+#endif /* NO_MSG_WAITALL */
+
 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 (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",
                                unix_socket, strerror(errno));
                goto error;
index c0cb6f4..913ab2f 100644 (file)
--- a/pass_fd.h
+++ b/pass_fd.h
 #ifndef _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 receive_fd(int unix_socket, void* data, int data_len, int* fd, int flags);