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 |
> 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 |
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 |
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 |
Free forum by Nabble | Edit this page |