your emulation of select vs. winsock

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

your emulation of select vs. winsock

Paolo Bonzini-2
I was wondering how does your Win32 emulation of select work with
respect to sockets.  Sockets are normal filehandles in Win32, right?

I have two questions then:

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.

2) Even though MsgWaitForMultipleObjects works for sockets, I guess
GetFileType should be called earlier, so that the state of sockets is
correctly returned as readable or writable or both.

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

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

Paolo Bonzini-2

> 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);
 

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/2 RFT] support socket select in lib-src/socketx.c's win_select

Paolo Bonzini-2
In reply to this post by Paolo Bonzini-2

> 2) Even though MsgWaitForMultipleObjects works for sockets, I guess
> GetFileType should be called earlier, so that the state of sockets is
> correctly returned as readable or writable or both.

The attached patch (not applied yet) tries to implement this.  I have
not even compiled it; help is appreciated.

Paolo

diff --git a/lib-src/socketx.c b/lib-src/socketx.c
index 64a9060..1be2e20 100644
--- a/lib-src/socketx.c
+++ b/lib-src/socketx.c
@@ -33,6 +33,8 @@ int
 win_select (int n, fd_set * rfds, fd_set * wfds, fd_set * efds,
     struct timeval *ptv)
 {
+  static struct timeval tv0;
+  static HANDLE hEvent;
   HANDLE handle_array[MAX_WIN_HANDLES];
   int handle_fd[MAX_WIN_HANDLES];
   fd_set *handle_set[MAX_WIN_HANDLES];
@@ -40,30 +42,65 @@ win_select (int n, fd_set * rfds, fd_set * wfds, fd_set * efds,
   int i, nset;
   BOOL bRet;
   MSG msg;
+  char sockbuf[256];
 
   _flushall ();
-  nhandles = 0;
+  if (!hEvent)
+    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+  handle_array[nhandles] = hEvent;
+  handle_fd[nhandles] = 0;
+  handle_set[nhandles] = NULL;
+  nhandles = 1;
   for (i = 0; i < n; i++)
     {
-      if ((efds != NULL) && FD_ISSET (i, efds))
- FD_CLR (i, efds); /* assume no exceptions */
-
-      if ((wfds != NULL) && FD_ISSET (i, wfds))
+      int in_efds = 0, in_wfds = 0, in_rfds = 0;
+      int optlen;
+      HANDLE h;
+      if (efds && FD_ISSET (i, wfds))
+ in_efds = 1;
+      if (wfds && FD_ISSET (i, wfds))
+ in_wfds = 1;
+      if (rfds && FD_ISSET (i, rfds))
+ in_rfds = 1;
+
+      h = (HANDLE) _get_osfhandle (i);
+      optlen = sizeof(sockbuf);
+      if ((getsockopt ((SOCKET) h, SOL_SOCKET, SO_TYPE, sockbuf, &optlen)
+   != SOCKET_ERROR)
+  || WSAGetLastError() != WSAENOTSOCK)
  {
-  handle_array[nhandles] = (HANDLE) _get_osfhandle (i);
-  handle_fd[nhandles] = i;
-  handle_set[nhandles] = wfds;
-  nhandles++;
-  FD_CLR (i, wfds); /* we will set it later if there is output */
+  int ev = 0;
+  if (in_rfds)
+    ev |= FD_READ | FD_ACCEPT;
+  if (in_wfds)
+    ev |= FD_WRITE | FD_CONNECT;
+  if (in_efds)
+    ev |= FD_OOB;
+  if (ev)
+    WSAEventSelect ((SOCKET) h, hEvent, ev);
  }
-
-      if ((rfds != NULL) && FD_ISSET (i, rfds))
+      else
  {
-  handle_array[nhandles] = (HANDLE) _get_osfhandle (i);
-  handle_fd[nhandles] = i;
-  handle_set[nhandles] = rfds;
-  nhandles++;
-  FD_CLR (i, rfds); /* we will set it later if there is input */
+          if (in_efds)
+            FD_CLR (i, efds);
+
+  if (in_wfds)
+    {
+              FD_CLR (i, wfds);
+      handle_array[nhandles] = h;
+      handle_fd[nhandles] = i;
+      handle_set[nhandles] = wfds;
+      nhandles++;
+    }
+
+          if (in_rfds)
+    {
+              FD_CLR (i, rfds);
+      handle_array[nhandles] = h;
+      handle_fd[nhandles] = i;
+      handle_set[nhandles] = rfds;
+      nhandles++;
+    }
  }
     }
 
@@ -89,9 +126,10 @@ win_select (int n, fd_set * rfds, fd_set * wfds, fd_set * efds,
  }
     }
 
-  /* now do a quick poll of all handles to see how many are ready */
-  nset = 0;
-  for (i = 0; i < nhandles; i++)
+  /* now do a quick poll of all handles to see how many are ready; the first
+     handle is the WSAEventSelect handle */
+  nset = select (n, rfds, wfds, efds, tv0);
+  for (i = 1; i < nhandles; i++)
     {
       HANDLE h = handle_array[i];
       ret = WaitForSingleObject (h, 0);

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 2/2 RFT] support socket select in lib-src/socketx.c's win_select

Paolo Bonzini-2
Paolo Bonzini wrote:
>
>> 2) Even though MsgWaitForMultipleObjects works for sockets, I guess
>> GetFileType should be called earlier, so that the state of sockets is
>> correctly returned as readable or writable or both.
>
> The attached patch (not applied yet) tries to implement this.  I have
> not even compiled it; help is appreciated.

Code for this (actually a different patch that gets rid of socketx.c
completely and moves its code into poll.c) is in the poll-for-win32
branch of http://www.inf.unisi.ch/phd/bonzini/webdav/smalltalk.git (my
git repository).

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk