1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* win32/win32.[ch] (recvmsg, sendmsg): new functions to support recvmsg/

sendmsg like UNIX. these functions are experimental and not tested
	  well. bug reports are welcome.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24218 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
usa 2009-07-21 04:38:20 +00:00
parent 3f0308dbf1
commit 9dd0d27156
3 changed files with 229 additions and 1 deletions

View file

@ -1,3 +1,9 @@
Tue Jul 21 13:36:20 2009 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/win32.[ch] (recvmsg, sendmsg): new functions to support recvmsg/
sendmsg like UNIX. these functions are experimental and not tested
well. bug reports are welcome.
Tue Jul 21 13:35:21 2009 NAKAMURA Usaku <usa@ruby-lang.org>
* win32/Makefile.sub (TEST_RUNNABLE): follow r24209.

View file

@ -203,6 +203,21 @@ struct timezone {
#undef isascii
#define isascii __isascii
#endif
struct iovec {
void *iov_base;
size_t iov_len;
};
struct msghdr {
void *msg_name;
int msg_namelen;
struct iovec *msg_iov;
int msg_iovlen;
void *msg_control;
int msg_controllen;
int msg_flags;
};
#define NtInitialize ruby_sysinit
extern int rb_w32_cmdvector(const char *, char ***);
extern rb_pid_t rb_w32_pipe_exec(const char *, const char *, int, int *, int *);
@ -224,6 +239,8 @@ extern int WSAAPI rb_w32_recv(int, char *, int, int);
extern int WSAAPI rb_w32_recvfrom(int, char *, int, int, struct sockaddr *, int *);
extern int WSAAPI rb_w32_send(int, const char *, int, int);
extern int WSAAPI rb_w32_sendto(int, const char *, int, int, const struct sockaddr *, int);
extern int recvmsg(int, struct msghdr *, int);
extern int sendmsg(int, const struct msghdr *, int);
extern int WSAAPI rb_w32_setsockopt(int, int, int, const char *, int);
extern int WSAAPI rb_w32_shutdown(int, int);
extern int WSAAPI rb_w32_socket(int, int, int);

View file

@ -2770,7 +2770,7 @@ overlapped_socket_io(BOOL input, int fd, char *buf, int len, int flags,
}
/* thru */
default:
errno = map_errno(err);
errno = map_errno(WSAGetLastError());
/* thru */
case WAIT_OBJECT_0 + 1:
/* interrupted */
@ -2816,6 +2816,211 @@ rb_w32_sendto(int fd, const char *buf, int len, int flags,
(struct sockaddr *)to, &tolen);
}
#ifndef WSAID_WSARECVMSG
typedef struct {
SOCKADDR *name;
int namelen;
WSABUF *lpBuffers;
DWORD dwBufferCount;
WSABUF Control;
DWORD dwFlags;
} WSAMSG;
#define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}}
#endif
#ifndef WSAID_WSASENDMSG
#define WSAID_WSASENDMSG {0xa441e712,0x754f,0x43ca,{0x84,0xa7,0x0d,0xee,0x44,0xcf,0x60,0x6d}}
#endif
#define msghdr_to_wsamsg(msg, wsamsg) \
do { \
int i; \
(wsamsg)->name = (msg)->msg_name; \
(wsamsg)->namelen = (msg)->msg_namelen; \
(wsamsg)->lpBuffers = ALLOCA_N(WSABUF, (msg)->msg_iovlen); \
(wsamsg)->dwBufferCount = (msg)->msg_iovlen; \
for (i = 0; i < (msg)->msg_iovlen; ++i) { \
(wsamsg)->lpBuffers[i].buf = (msg)->msg_iov[i].iov_base; \
(wsamsg)->lpBuffers[i].len = (msg)->msg_iov[i].iov_len; \
} \
(wsamsg)->Control.buf = (msg)->msg_control; \
(wsamsg)->Control.len = (msg)->msg_controllen; \
(wsamsg)->dwFlags = (msg)->msg_flags; \
} while (0)
int
recvmsg(int fd, struct msghdr *msg, int flags)
{
typedef int (WSAAPI *WSARecvMsg_t)(SOCKET, WSAMSG *, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
static WSARecvMsg_t pWSARecvMsg = NULL;
WSAMSG wsamsg;
SOCKET s;
st_data_t data;
int mode;
DWORD len;
int ret;
if (!NtSocketsInitialized)
StartSockets();
s = TO_SOCKET(fd);
if (!pWSARecvMsg) {
static GUID guid = WSAID_WSARECVMSG;
DWORD dmy;
WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
&pWSARecvMsg, sizeof(pWSARecvMsg), &dmy, NULL, NULL);
if (!pWSARecvMsg)
rb_notimplement();
}
msghdr_to_wsamsg(msg, &wsamsg);
wsamsg.dwFlags |= flags;
st_lookup(socklist, (st_data_t)s, &data);
mode = (int)data;
if (!cancel_io || (mode & O_NONBLOCK)) {
RUBY_CRITICAL({
if ((ret = pWSARecvMsg(s, &wsamsg, &len, NULL, NULL)) == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
len = -1;
}
});
}
else {
DWORD size;
int err;
WSAOVERLAPPED wol;
memset(&wol, 0, sizeof(wol));
RUBY_CRITICAL({
wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ret = pWSARecvMsg(s, &wsamsg, &len, &wol, NULL);
});
if (ret != SOCKET_ERROR) {
/* nothing to do */
}
else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
DWORD flg;
switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
case WAIT_OBJECT_0:
RUBY_CRITICAL(
ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
);
if (ret) {
len = size;
break;
}
/* thru */
default:
errno = map_errno(WSAGetLastError());
/* thru */
case WAIT_OBJECT_0 + 1:
/* interrupted */
len = -1;
cancel_io((HANDLE)s);
break;
}
}
else {
errno = map_errno(err);
len = -1;
}
CloseHandle(&wol.hEvent);
}
if (ret == SOCKET_ERROR)
return -1;
/* WSAMSG to msghdr */
msg->msg_name = wsamsg.name;
msg->msg_namelen = wsamsg.namelen;
msg->msg_flags = wsamsg.dwFlags;
return len;
}
int
sendmsg(int fd, const struct msghdr *msg, int flags)
{
typedef int (WSAAPI *WSASendMsg_t)(SOCKET, const WSAMSG *, DWORD, DWORD *, WSAOVERLAPPED *, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
static WSASendMsg_t pWSASendMsg = NULL;
WSAMSG wsamsg;
SOCKET s;
st_data_t data;
int mode;
DWORD len;
int ret;
if (!NtSocketsInitialized)
StartSockets();
s = TO_SOCKET(fd);
if (!pWSASendMsg) {
static GUID guid = WSAID_WSASENDMSG;
DWORD dmy;
WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid),
&pWSASendMsg, sizeof(pWSASendMsg), &dmy, NULL, NULL);
if (!pWSASendMsg)
rb_notimplement();
}
msghdr_to_wsamsg(msg, &wsamsg);
st_lookup(socklist, (st_data_t)s, &data);
mode = (int)data;
if (!cancel_io || (mode & O_NONBLOCK)) {
RUBY_CRITICAL({
if ((ret = pWSASendMsg(s, &wsamsg, flags, &len, NULL, NULL)) == SOCKET_ERROR) {
errno = map_errno(WSAGetLastError());
len = -1;
}
});
}
else {
DWORD size;
int err;
WSAOVERLAPPED wol;
memset(&wol, 0, sizeof(wol));
RUBY_CRITICAL({
wol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ret = pWSASendMsg(s, &wsamsg, flags, &len, &wol, NULL);
});
if (ret != SOCKET_ERROR) {
/* nothing to do */
}
else if ((err = WSAGetLastError()) == WSA_IO_PENDING) {
DWORD flg;
switch (rb_w32_wait_events_blocking(&wol.hEvent, 1, INFINITE)) {
case WAIT_OBJECT_0:
RUBY_CRITICAL(
ret = WSAGetOverlappedResult(s, &wol, &size, TRUE, &flg)
);
if (ret) {
len = size;
break;
}
/* thru */
default:
errno = map_errno(WSAGetLastError());
/* thru */
case WAIT_OBJECT_0 + 1:
/* interrupted */
len = -1;
cancel_io((HANDLE)s);
break;
}
}
else {
errno = map_errno(err);
len = -1;
}
CloseHandle(&wol.hEvent);
}
return len;
}
#undef setsockopt
int WSAAPI