summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-18 05:59:46 +0000
committerusa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-07-18 05:59:46 +0000
commit068dd60372d659c97a76224dfce38ed96984cb6f (patch)
tree2ad9e03b90b8cd3a696776f2995b09089607188f /win32
parentbfc8925b1be8bb58b25085fcc74a0143a72f387b (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18124 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'win32')
-rw-r--r--win32/win32.c257
1 files changed, 160 insertions, 97 deletions
diff --git a/win32/win32.c b/win32/win32.c
index b1e461649a..f6ef84328b 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -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 @@ static void invalid_parameter(const wchar_t *expr, const wchar_t *func, const wc
#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 @@ exit_handler(void)
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 @@ rb_w32_open_osfhandle(intptr_t osfhandle, int flags)
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 @@ rb_w32_fdisset(int fd, fd_set *set)
#undef select
-static int NtSocketsInitialized = 0;
-
static int
extract_fd(fd_set *dst, fd_set *src, int (*func)(SOCKET))
{
@@ -2236,27 +2241,6 @@ rb_w32_select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
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 @@ rb_w32_accept(int s, struct sockaddr *addr, int *addrlen)
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 @@ rb_w32_listen(int s, int backlog)
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 @@ open_ifs_socket(int af, int type, int protocol)
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 @@ rb_w32_socket(int af, int type, int protocol)
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 @@ rb_w32_socketpair(int af, int type, int protocol, int *sv)
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 @@ fcntl(int fd, int cmd, ...)
va_list va;
int arg;
int ret;
+ int flag = 0;
u_long ioctlArg;
if (!is_socket(sock)) {
@@ -2847,17 +2905,21 @@ fcntl(int fd, int cmd, ...)
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 @@ rb_w32_close(int fd)
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) {