[前][次][番号順一覧][スレッド一覧]

ruby-changes:6608

From: usa <ko1@a...>
Date: Fri, 18 Jul 2008 15:00:12 +0900 (JST)
Subject: [ruby-changes:6608] Ruby:r18124 (trunk): * win32/win32.c (socklist): table for registering socket options

usa	2008-07-18 14:59:46 +0900 (Fri, 18 Jul 2008)

  New Revision: 18124

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18124

  Log:
    * win32/win32.c (socklist): table for registering socket options
      (currently only O_NONBLOCK).
    
    * win32/win32.c (StartSockets, exit_handler): alloc/free socklist.
    
    * win32/win32.c (is_socket): use socklist.
    
    * win32/win32.c (rb_w32_accept, rb_w32_socket, rb_w32_socketpair):
      register new socket to socklist.
    
    * win32/win32.c (rb_w32_close): remove closing socket from socklist.
    
    * win32/win32.c (fcntl): register socket options.
    
    * win32/win32.c (overlapped_socket_io): send to/recv from socket with
      overlapped operation if the socket is not nonblocking mode.
      [experimental]
    
    * win32/win32.c (rb_w32_send, rb_w32_sendto, rb_w32_recv,
      rb_w32_recvfrom): use overlapped_socket_io().
    
    * win32/win32.c (open_ifs_socket): set overlapped mode. this is the
      default mode of winsock's socket(), so lacking it is an old bug.

  Modified files:
    trunk/ChangeLog
    trunk/win32/win32.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 18123)
+++ ChangeLog	(revision 18124)
@@ -1,3 +1,29 @@
+Fri Jul 18 14:52:14 2008  NAKAMURA Usaku  <usa@r...>
+
+	* win32/win32.c (socklist): table for registering socket options
+	  (currently only O_NONBLOCK).
+
+	* win32/win32.c (StartSockets, exit_handler): alloc/free socklist.
+
+	* win32/win32.c (is_socket): use socklist.
+
+	* win32/win32.c (rb_w32_accept, rb_w32_socket, rb_w32_socketpair):
+	  register new socket to socklist.
+
+	* win32/win32.c (rb_w32_close): remove closing socket from socklist.
+
+	* win32/win32.c (fcntl): register socket options.
+
+	* win32/win32.c (overlapped_socket_io): send to/recv from socket with
+	  overlapped operation if the socket is not nonblocking mode.
+	  [experimental]
+
+	* win32/win32.c (rb_w32_send, rb_w32_sendto, rb_w32_recv,
+	  rb_w32_recvfrom): use overlapped_socket_io().
+
+	* win32/win32.c (open_ifs_socket): set overlapped mode. this is the
+	  default mode of winsock's socket(), so lacking it is an old bug.
+
 Fri Jul 18 09:44:30 2008
 
 	* lib/rdoc/*: Import RDoc r101.
Index: win32/win32.c
===================================================================
--- win32/win32.c	(revision 18123)
+++ win32/win32.c	(revision 18124)
@@ -67,7 +67,6 @@
 
 static struct ChildRecord *CreateChild(const char *, const char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
 static int has_redirection(const char *);
-static void StartSockets(void);
 int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
 #if !defined(_WIN32_WCE)
 static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
@@ -419,14 +418,18 @@
 #endif
 
 static CRITICAL_SECTION select_mutex;
-static BOOL fWinsock;
+static int NtSocketsInitialized = 0;
+static st_table *socklist = NULL;
 static char *envarea;
+
 static void
 exit_handler(void)
 {
-    if (fWinsock) {
+    if (NtSocketsInitialized) {
 	WSACleanup();
-	fWinsock = FALSE;
+	xfree(socklist);
+	socklist = NULL;
+	NtSocketsInitialized = 0;
     }
     if (envarea) {
 	FreeEnvironmentStrings(envarea);
@@ -435,6 +438,27 @@
     DeleteCriticalSection(&select_mutex);
 }
 
+static void
+StartSockets(void)
+{
+    WORD version;
+    WSADATA retdata;
+
+    //
+    // initalize the winsock interface and insure that it's
+    // cleaned up at exit.
+    //
+    version = MAKEWORD(2, 0);
+    if (WSAStartup(version, &retdata))
+	rb_fatal ("Unable to locate winsock library!\n");
+    if (LOBYTE(retdata.wVersion) != 2)
+	rb_fatal("could not find version 2 of winsock dll\n");
+
+    socklist = st_init_numtable();
+
+    NtSocketsInitialized = 1;
+}
+
 //
 // Initialization stuff
 //
@@ -1785,27 +1809,10 @@
 static int
 is_socket(SOCKET sock)
 {
-    char sockbuf[80];
-    int optlen;
-    int retval;
-    int result = TRUE;
-
-    optlen = sizeof(sockbuf);
-    RUBY_CRITICAL({
-	retval = getsockopt(sock, SOL_SOCKET, SO_TYPE, sockbuf, &optlen);
-	if (retval == SOCKET_ERROR) {
-	    int iRet;
-	    iRet = WSAGetLastError();
-	    if (iRet == WSAENOTSOCK || iRet == WSANOTINITIALISED)
-		result = FALSE;
-	}
-    });
-
-    //
-    // If we get here, then sock is actually a socket.
-    //
-
-    return result;
+    if (st_lookup(socklist, (st_data_t)sock, NULL))
+	return TRUE;
+    else
+	return FALSE;
 }
 
 int
@@ -1982,8 +1989,6 @@
 
 #undef select
 
-static int NtSocketsInitialized = 0;
-
 static int
 extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
 {
@@ -2236,27 +2241,6 @@
     return r;
 }
 
-static void
-StartSockets(void)
-{
-    WORD version;
-    WSADATA retdata;
-
-    //
-    // initalize the winsock interface and insure that it's
-    // cleaned up at exit.
-    //
-    version = MAKEWORD(2, 0);
-    if (WSAStartup(version, &retdata))
-	rb_fatal ("Unable to locate winsock library!\n");
-    if (LOBYTE(retdata.wVersion) != 2)
-	rb_fatal("could not find version 2 of winsock dll\n");
-
-    fWinsock = TRUE;
-
-    NtSocketsInitialized = 1;
-}
-
 #undef accept
 
 int WSAAPI
@@ -2274,6 +2258,7 @@
 	    s = -1;
 	}
 	else {
+	    st_insert(socklist, (st_data_t)r, (st_data_t)0);
 	    s = rb_w32_open_osfhandle(r, O_RDWR|O_BINARY|O_NOINHERIT);
 	}
     });
@@ -2407,74 +2392,142 @@
     return r;
 }
 
-#undef recv
-
-int WSAAPI
-rb_w32_recv(int s, char *buf, int len, int flags)
+typedef BOOL (WINAPI *cancel_io_t)(HANDLE);
+static inline void
+cancel_io(HANDLE f)
 {
-    int r;
-    if (!NtSocketsInitialized) {
-	StartSockets();
+    static cancel_io_t func = NULL;
+    if (!func) {
+	func = (cancel_io_t)GetProcAddress(GetModuleHandle("kernel32"),
+					   "CancelIo");
+	if (!func)
+	    func = (cancel_io_t)-1;
     }
-    RUBY_CRITICAL({
-	r = recv(TO_SOCKET(s), buf, len, flags);
-	if (r == SOCKET_ERROR)
-	    errno = map_errno(WSAGetLastError());
-    });
-    return r;
+    else if (func != (cancel_io_t)-1)
+	func(f);
+    /* Win9x and NT3.x doesn't have CancelIo().
+       We expect to cancel the I/O by close or ending the thread */
 }
 
+#undef recv
 #undef recvfrom
+#undef send
+#undef sendto
 
-int WSAAPI
-rb_w32_recvfrom(int s, char *buf, int len, int flags,
-		 struct sockaddr *from, int *fromlen)
+static int
+overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
+		     struct sockaddr *addr, int *addrlen)
 {
     int r;
-    if (!NtSocketsInitialized) {
+    int ret;
+    int mode;
+    int flg;
+    WSAOVERLAPPED wol;
+    WSABUF wbuf;
+    int err;
+    SOCKET s;
+
+    if (!NtSocketsInitialized)
 	StartSockets();
+
+    s = TO_SOCKET(fd);
+    st_lookup(socklist, (st_data_t)s, (st_data_t *)&mode);
+    if (mode & O_NONBLOCK) {
+	RUBY_CRITICAL({
+	    if (input) {
+		if (addr && addrlen)
+		    r = recvfrom(s, buf, len, flags, addr, addrlen);
+		else
+		    r = recv(s, buf, len, flags);
+	    }
+	    else {
+		if (addr && addrlen)
+		    r = sendto(s, buf, len, flags, addr, *addrlen);
+		else
+		    r = send(s, buf, len, flags);
+	    }
+	    if (r == SOCKET_ERROR)
+		errno = map_errno(WSAGetLastError());
+	});
     }
-    RUBY_CRITICAL({
-	r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen);
-	if (r == SOCKET_ERROR)
-	    errno = map_errno(WSAGetLastError());
-    });
+    else {
+	wbuf.len = len;
+	wbuf.buf = buf;
+	memset(&wol, 0, sizeof(wol));
+	RUBY_CRITICAL({
+	    wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+	    if (input) {
+		flg = flags;
+		if (addr && addrlen)
+		    ret = WSARecvFrom(s, &wbuf, 1, &r, &flg, addr, addrlen, &wol,
+				      NULL);
+		else
+		    ret = WSARecv(s, &wbuf, 1, &r, &flg, &wol, NULL);
+	    }
+	    else {
+		if (addr && addrlen)
+		    ret = WSASendTo(s, &wbuf, 1, &r, flags, addr, *addrlen, &wol,
+				    NULL);
+		else
+		    ret = WSASend(s, &wbuf, 1, &r, flags, &wol, NULL);
+	    }
+	    err = WSAGetLastError();
+	});
+
+	if (ret == SOCKET_ERROR && err == WSA_IO_PENDING) {
+	    switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
+	      case WAIT_OBJECT_0:
+		RUBY_CRITICAL(
+		    ret = WSAGetOverlappedResult(s, &wol, &r, TRUE, &flg)
+		    );
+		if (ret)
+		    break;
+		/* thru */
+	      default:
+		errno = map_errno(err);
+		/* thru */
+	      case WAIT_OBJECT_0 + 1:
+		/* interrupted */
+		r = -1;
+		cancel_io((HANDLE)s);
+		break;
+	    }
+	}
+	else if (ret == SOCKET_ERROR) {
+	    errno = map_errno(err);
+	    r = -1;
+	}
+	CloseHandle(&wol.hEvent);
+    }
+
     return r;
 }
 
-#undef send
+int WSAAPI
+rb_w32_recv(int fd, char *buf, int len, int flags)
+{
+    return overlapped_socket_io(TRUE, fd, buf, len, flags, NULL, NULL);
+}
 
 int WSAAPI
-rb_w32_send(int s, const char *buf, int len, int flags)
+rb_w32_recvfrom(int fd, char *buf, int len, int flags,
+		struct sockaddr *from, int *fromlen)
 {
-    int r;
-    if (!NtSocketsInitialized) {
-	StartSockets();
-    }
-    RUBY_CRITICAL({
-	r = send(TO_SOCKET(s), buf, len, flags);
-	if (r == SOCKET_ERROR)
-	    errno = map_errno(WSAGetLastError());
-    });
-    return r;
+    return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
 }
 
-#undef sendto
+int WSAAPI
+rb_w32_send(int fd, const char *buf, int len, int flags)
+{
+    return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags, NULL, NULL);
+}
 
 int WSAAPI
-rb_w32_sendto(int s, const char *buf, int len, int flags, 
+rb_w32_sendto(int fd, const char *buf, int len, int flags, 
 	      const struct sockaddr *to, int tolen)
 {
-    int r;
-    if (!NtSocketsInitialized) {
-	StartSockets();
-    }
-    RUBY_CRITICAL({
-	r = sendto(TO_SOCKET(s), buf, len, flags, to, tolen);
-	if (r == SOCKET_ERROR)
-	    errno = map_errno(WSAGetLastError());
-    });
-    return r;
+    return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
+				(struct sockaddr *)to, &tolen);
 }
 
 #undef setsockopt
@@ -2543,7 +2596,8 @@
 		    if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0)
 			continue;
 
-		    out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0, 0);
+		    out = WSASocket(af, type, protocol, &(proto_buffers[i]), 0,
+				    WSA_FLAG_OVERLAPPED);
 		    break;
 		}
 	    }
@@ -2573,6 +2627,7 @@
 	    fd = -1;
 	}
 	else {
+	    st_insert(socklist, (st_data_t)s, (st_data_t)0);
 	    fd = rb_w32_open_osfhandle(s, O_RDWR|O_BINARY|O_NOINHERIT);
 	}
     });
@@ -2793,6 +2848,8 @@
 
     if (socketpair_internal(af, type, protocol, pair) < 0)
 	return -1;
+    st_insert(socklist, (st_data_t)pair[0], (st_data_t)0);
+    st_insert(socklist, (st_data_t)pair[1], (st_data_t)0);
     sv[0] = rb_w32_open_osfhandle(pair[0], O_RDWR|O_BINARY|O_NOINHERIT);
     sv[1] = rb_w32_open_osfhandle(pair[1], O_RDWR|O_BINARY|O_NOINHERIT);
 
@@ -2833,6 +2890,7 @@
     va_list va;
     int arg;
     int ret;
+    int flag = 0;
     u_long ioctlArg;
 
     if (!is_socket(sock)) {
@@ -2847,17 +2905,21 @@
     va_start(va, cmd);
     arg = va_arg(va, int);
     va_end(va);
+    st_lookup(socklist, (st_data_t)sock, (st_data_t*)&flag);
     if (arg & O_NONBLOCK) {
+	flag |= O_NONBLOCK;
 	ioctlArg = 1;
     }
     else {
+	flag &= ~O_NONBLOCK;
 	ioctlArg = 0;
     }
     RUBY_CRITICAL({
 	ret = ioctlsocket(sock, FIONBIO, &ioctlArg);
-	if (ret == -1) {
+	if (ret == 0)
+	    st_insert(socklist, (st_data_t)sock, (st_data_t)flag);
+	else
 	    errno = map_errno(WSAGetLastError());
-	}
     });
 
     return ret;
@@ -3901,6 +3963,7 @@
 	return _close(fd);
     }
     _set_osfhnd(fd, (SOCKET)INVALID_HANDLE_VALUE);
+    st_delete(socklist, (st_data_t *)&sock, NULL);
     _close(fd);
     errno = save_errno;
     if (closesocket(sock) == SOCKET_ERROR) {

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]