help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] [PATCH 1/2] use file descriptors for sockets on MinGW


From: Paolo Bonzini
Subject: [Help-smalltalk] [PATCH 1/2] use file descriptors for sockets on MinGW
Date: Sun, 17 Aug 2008 15:29:35 +0200
User-agent: Thunderbird 2.0.0.16 (Macintosh/20080707)


1) If I am correct, your emulation only works with file descriptors. So I should wrap all socket functions under Win32 so that they call _open_osfhandle or _get_osfhandle: otherwise, socketx.c receives half-file descriptors and half-file handles.

I committed a patch for this part; testing is appreciated -- I tried to write it in a portable way so that I could catch mishaps under POSIX sockets too, but bad things can happen.

Paolo
diff --git a/lib-src/socketx.h b/lib-src/socketx.h
index eaa15cd..419142a 100644
--- a/lib-src/socketx.h
+++ b/lib-src/socketx.h
@@ -101,6 +101,9 @@ int win_recv(int fd, void* buffer, int n, int flags);
 #undef recv
 #define recv win_recv
 
+#define FD_TO_SOCKET(fd)   ((SOCKET) _get_osfhandle ((fd)))
+#define SOCKET_TO_FD(fh)   (_open_osfhandle ((HANDLE) (fh), O_RDWR | O_BINARY))
+
 #else /* !__MSVCRT__ */
 
 #include <sys/types.h>
@@ -117,6 +120,14 @@ int win_recv(int fd, void* buffer, int n, int flags);
 #define closesocket(x)            close(x)
 #define is_socket_error(err)      (errno == (err))
 #define clear_socket_error()      (errno = 0)
+
+#define FD_TO_SOCKET(fd)         (fd)
+#define SOCKET_TO_FD(fd)         (fd)
+typedef int SOCKET;
+
+#ifndef SOCKET_ERROR
+#define SOCKET_ERROR             (-1)
+#endif
 #endif /* !__MSVCRT__ */
 
 #include "getaddrinfo.h"
diff --git a/libgst/prims.def b/libgst/prims.def
index b797c23..918b24c 100644
--- a/libgst/prims.def
+++ b/libgst/prims.def
@@ -5600,7 +5600,7 @@ primitive VMpr_FileDescriptor_fileOp [succeed,fail]
       }
 
     case PRIM_SHUTDOWN_WRITE:
-      shutdown (fd, 1);
+      shutdown (FD_TO_SOCKET (fd), 1);
 #ifdef ENOTSOCK
       if (errno == ENOTSOCK && isatty (fd))
        {
@@ -5659,7 +5659,7 @@ primitive VMpr_FileDescriptor_socketOp [succeed,fail]
       {
        int result;
         _gst_remove_fd_polling_handlers (fd);
-        result = closesocket (fd);
+        result = closesocket (FD_TO_SOCKET (fd));
         resultOOP = FROM_INT (result);
         goto succeed;
       }
diff --git a/libgst/sysdep.c b/libgst/sysdep.c
index bb95eb9..ee6f00d 100644
--- a/libgst/sysdep.c
+++ b/libgst/sysdep.c
@@ -1786,8 +1786,8 @@ _gst_recv (int fd,
 
   for (;;)
     {
-      result = recvfrom (fd, buffer, size, flags, NULL, NULL);
-      if (errno == EFAULT)
+      result = recvfrom (FD_TO_SOCKET (fd), buffer, size, flags, NULL, NULL);
+      if (is_socket_error (EFAULT))
         abort ();
 
       if (is_socket_error (EINTR))
@@ -1818,8 +1818,8 @@ _gst_send (int fd,
 
   for (;;)
     {
-      result = send (fd, buffer, size, flags);
-      if (errno == EFAULT)
+      result = send (FD_TO_SOCKET (fd), buffer, size, flags);
+      if (is_socket_error (EFAULT))
         abort ();
 
       if (is_socket_error (EINTR))
diff --git a/packages/sockets/sockets.c b/packages/sockets/sockets.c
index 1bb17a3..6ae8d10 100644
--- a/packages/sockets/sockets.c
+++ b/packages/sockets/sockets.c
@@ -113,21 +113,7 @@
 
 static VMProxy *vmProxy;
 
-/* Same as connect, but forces the socket to be in non-blocking mode */
-static void
-myConnect (int fd, const struct sockaddr *sockaddr, int len)
-{
-#ifdef F_GETFL
-  int oldflags = fcntl (fd, F_GETFL, NULL);
 
-  if (!(oldflags & O_NONBLOCK))
-    fcntl (fd, F_SETFL, oldflags | O_NONBLOCK);
-#endif
-  
-  connect (fd, sockaddr, len);
-  if (is_socket_error (EINPROGRESS))
-    errno = 0;
-}
 
 static char *
 myGetHostByAddr (char *addr, int len, int type)
@@ -258,13 +244,123 @@ constantFunction (aiAll, AI_ALL)
 constantFunction (aiV4mapped, AI_V4MAPPED)
 
 
+
+static int
+mySocket (int domain, int type, int protocol)
+{
+  int fd;
+#if defined __MSVCRT__
+  SOCKET fh = socket (domain, type, protocol);
+  fd = SOCKET_TO_FD (fh);
+
+  /* Do not do FD_CLOEXEC under MinGW.  */
+  SetHandleInformation (fh, HANDLE_FLAG_INHERIT, 0);
+
+#elif defined SOCK_CLOEXEC
+  fd = socket (domain, type | SOCK_CLOEXEC, protocol);
+
+#else
+  fd = socket (domain, type, protocol);
+#ifdef FD_CLOEXEC
+  if (fd != -1)
+    fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
+#endif
+#endif
+
+  return fd;
+}
+
+/* Same as connect, but forces the socket to be in non-blocking mode */
+static void
+myConnect (int fd, const struct sockaddr *sockaddr, int len)
+{
+  SOCKET sock = FD_TO_SOCKET (fd);
+#ifdef __MSVCRT__
+  unsigned long iMode = 1;
+  ioctlsocket (sock, FIONBIO, &iMode);
+
+#elif defined F_GETFL
+  int oldflags = fcntl (sock, F_GETFL, NULL);
+
+  if (!(oldflags & O_NONBLOCK))
+    fcntl (sock, F_SETFL, oldflags | O_NONBLOCK);
+#endif
+  
+  connect (sock, sockaddr, len);
+  if (is_socket_error (EINPROGRESS))
+    errno = 0;
+}
+
+static int
+myAccept (int fd, struct sockaddr *addr, int *addrlen)
+{
+  SOCKET r = accept (FD_TO_SOCKET (fd), addr, addrlen);
+  return r == SOCKET_ERROR ? -1 : SOCKET_TO_FD (r);
+}
+
+static int
+myBind (int fd, const struct sockaddr *addr, int addrlen)
+{
+  return bind (FD_TO_SOCKET (fd), addr, addrlen);
+}
+
+static int
+myGetpeername (int fd, struct sockaddr *addr, int *addrlen)
+{
+  return getpeername (FD_TO_SOCKET (fd), addr, addrlen);
+}
+
+static int
+myGetsockname (int fd, struct sockaddr *addr, int *addrlen)
+{
+  return getsockname (FD_TO_SOCKET (fd), addr, addrlen);
+}
+
+static int
+myGetsockopt (int fd, int level, int optname, char *optval, int *optlen)
+{
+  return getsockopt (FD_TO_SOCKET (fd), level, optname, optval, optlen);
+}
 
 static int
+myListen (int fd, int backlog)
+{
+  return listen (FD_TO_SOCKET (fd), backlog);
+}
+
+static int
+myRecvfrom (int fd, char *buf, int len, int flags, struct sockaddr *from,
+           int *fromlen)
+{
+  int frombufsize = *fromlen;
+  int r = recvfrom (FD_TO_SOCKET (fd), buf, len, flags, from, fromlen);
+
+  /* Winsock recvfrom() only returns a valid 'from' when the socket is
+     connectionless.  POSIX gives a valid 'from' for all types of sockets.  */
+  if (r != SOCKET_ERROR && frombufsize == *fromlen)
+    (void) myGetpeername (fd, from, fromlen);
+
+  return r;
+}
+
+static int
+mySendto (int fd, const char *buf, int len, int flags,
+         const struct sockaddr *to, int tolen)
+{
+  return sendto (FD_TO_SOCKET (fd), buf, len, flags, to, tolen);
+}
+
+static int
+mySetsockopt (int fd, int level, int optname, const char *optval, int optlen)
+{
+  return setsockopt (FD_TO_SOCKET (fd), level, optname, optval, optlen);
+}
+static int
 getSoError (int fd)
 {
   int error;
   int size = sizeof (error);
-  getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *)&error, &size);
+  myGetsockopt (fd, SOL_SOCKET, SO_ERROR, (char *)&error, &size);
 
   /* When we get one of these, we don't return an error.  However,
      the primitive still fails and the file/socket is closed by the
@@ -276,28 +372,7 @@ getSoError (int fd)
     return error;
 }
 
-static int
-mySocket (int domain, int type, int protocol)
-{
-  int fd;
-#ifdef SOCK_CLOEXEC
-  fd = socket (domain, type | SOCK_CLOEXEC, protocol);
-
-#else
-  fd = socket (domain, type, protocol);
-
-  /* Do not do FD_CLOEXEC under MinGW.  */
-#if defined __MSVCRT__
-  SetHandleInformation (fd, HANDLE_FLAG_INHERIT, 0);
-#elif defined FD_CLOEXEC
-  if (fd != -1)
-    fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
-#endif
-#endif
-
-  return fd;
-}
-
+
 void
 gst_initModule (VMProxy * proxy)
 {
@@ -319,16 +394,16 @@ gst_initModule (VMProxy * proxy)
   vmProxy->defineCFunc ("TCPgetAiCanonname", get_aiCanonname);
   vmProxy->defineCFunc ("TCPgetAiAddr", get_aiAddr);
 
-  vmProxy->defineCFunc ("TCPaccept", accept);
-  vmProxy->defineCFunc ("TCPbind", bind);
+  vmProxy->defineCFunc ("TCPaccept", myAccept);
+  vmProxy->defineCFunc ("TCPbind", myBind);
   vmProxy->defineCFunc ("TCPconnect", myConnect);
-  vmProxy->defineCFunc ("TCPgetpeername", getpeername);
-  vmProxy->defineCFunc ("TCPgetsockname", getsockname);
-  vmProxy->defineCFunc ("TCPlisten", listen);
-  vmProxy->defineCFunc ("TCPrecvfrom", recvfrom);
-  vmProxy->defineCFunc ("TCPsendto", sendto);
-  vmProxy->defineCFunc ("TCPsetsockopt", setsockopt);
-  vmProxy->defineCFunc ("TCPgetsockopt", getsockopt);
+  vmProxy->defineCFunc ("TCPgetpeername", myGetpeername);
+  vmProxy->defineCFunc ("TCPgetsockname", myGetsockname);
+  vmProxy->defineCFunc ("TCPlisten", myListen);
+  vmProxy->defineCFunc ("TCPrecvfrom", myRecvfrom);
+  vmProxy->defineCFunc ("TCPsendto", mySendto);
+  vmProxy->defineCFunc ("TCPsetsockopt", mySetsockopt);
+  vmProxy->defineCFunc ("TCPgetsockopt", myGetsockopt);
   vmProxy->defineCFunc ("TCPgetSoError", getSoError);
   vmProxy->defineCFunc ("TCPsocket", mySocket);
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]