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

ruby-changes:12515

From: usa <ko1@a...>
Date: Tue, 21 Jul 2009 13:38:39 +0900 (JST)
Subject: [ruby-changes:12515] Ruby:r24218 (trunk): * win32/win32.[ch] (recvmsg, sendmsg): new functions to support recvmsg/

usa	2009-07-21 13:38:20 +0900 (Tue, 21 Jul 2009)

  New Revision: 24218

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

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/win32.h
    trunk/win32/win32.c

Index: include/ruby/win32.h
===================================================================
--- include/ruby/win32.h	(revision 24217)
+++ include/ruby/win32.h	(revision 24218)
@@ -203,6 +203,21 @@
 #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_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);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 24217)
+++ ChangeLog	(revision 24218)
@@ -1,3 +1,9 @@
+Tue Jul 21 13:36:20 2009  NAKAMURA Usaku  <usa@r...>
+
+	* 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@r...>
 
 	* win32/Makefile.sub (TEST_RUNNABLE): follow r24209.
Index: win32/win32.c
===================================================================
--- win32/win32.c	(revision 24217)
+++ win32/win32.c	(revision 24218)
@@ -2770,7 +2770,7 @@
 		}
 		/* thru */
 	      default:
-		errno = map_errno(err);
+		errno = map_errno(WSAGetLastError());
 		/* thru */
 	      case WAIT_OBJECT_0 + 1:
 		/* interrupted */
@@ -2816,6 +2816,211 @@
 				(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

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

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