* 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
This commit is contained in:
usa 2008-07-18 05:59:46 +00:00
parent bfc8925b1b
commit 068dd60372
2 changed files with 198 additions and 109 deletions

View File

@ -1,3 +1,29 @@
Fri Jul 18 14:52:14 2008 NAKAMURA Usaku <usa@ruby-lang.org>
* 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.

View File

@ -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,76 +2392,144 @@ rb_w32_listen(int s, int backlog)
return r;
}
typedef BOOL (WINAPI *cancel_io_t)(HANDLE);
static inline void
cancel_io(HANDLE f)
{
static cancel_io_t func = NULL;
if (!func) {
func = (cancel_io_t)GetProcAddress(GetModuleHandle("kernel32"),
"CancelIo");
if (!func)
func = (cancel_io_t)-1;
}
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
int WSAAPI
rb_w32_recv(int s, char *buf, int len, int flags)
{
int r;
if (!NtSocketsInitialized) {
StartSockets();
}
RUBY_CRITICAL({
r = recv(TO_SOCKET(s), buf, len, flags);
if (r == SOCKET_ERROR)
errno = map_errno(WSAGetLastError());
});
return r;
}
#undef recvfrom
int WSAAPI
rb_w32_recvfrom(int s, char *buf, int len, int flags,
struct sockaddr *from, int *fromlen)
{
int r;
if (!NtSocketsInitialized) {
StartSockets();
}
RUBY_CRITICAL({
r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen);
if (r == SOCKET_ERROR)
errno = map_errno(WSAGetLastError());
});
return r;
}
#undef send
int WSAAPI
rb_w32_send(int s, const char *buf, int len, int flags)
{
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;
}
#undef sendto
int WSAAPI
rb_w32_sendto(int s, const char *buf, int len, int flags,
const struct sockaddr *to, int tolen)
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 = sendto(TO_SOCKET(s), buf, len, flags, to, tolen);
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;
}
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_recvfrom(int fd, char *buf, int len, int flags,
struct sockaddr *from, int *fromlen)
{
return overlapped_socket_io(TRUE, fd, buf, len, flags, from, fromlen);
}
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 fd, const char *buf, int len, int flags,
const struct sockaddr *to, int tolen)
{
return overlapped_socket_io(FALSE, fd, (char *)buf, len, flags,
(struct sockaddr *)to, &tolen);
}
#undef setsockopt
int WSAAPI
@ -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) {