[go] syscall: add WSASendMsg/WSARecvMsg wrappers on Windows

218 views
Skip to first unread message

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 1:38:56 PM11/7/17
to Alex Brainman, Ian Lance Taylor, Rob Pike, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Aman Gupta would like Alex Brainman to review this change.

View Change

syscall: add WSASendMsg/WSARecvMsg wrappers on Windows

The function pointers for these syscalls have to be loaded at runtime
with WSAIoctl, similar to how the ConnectEx syscall is loaded. A similar
pattern is used here to load the pair together.

Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
---
M src/syscall/syscall_windows.go
M src/syscall/types_windows.go
2 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 84d5528..ba935d7 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -813,6 +813,83 @@
return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
}

+var sendRecvMsgFunc struct {
+ once sync.Once
+ sendAddr uintptr
+ recvAddr uintptr
+ err error
+}
+
+func LoadSendRecvMsg() error {
+ sendRecvMsgFunc.once.Do(func() {
+ var s Handle
+ s, sendRecvMsgFunc.err = Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+ if sendRecvMsgFunc.err != nil {
+ return
+ }
+ defer CloseHandle(s)
+ var n uint32
+ sendRecvMsgFunc.err = WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)),
+ uint32(unsafe.Sizeof(WSAID_WSASENDMSG)),
+ (*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)),
+ uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)),
+ &n, nil, 0)
+ if sendRecvMsgFunc.err != nil {
+ return
+ }
+ sendRecvMsgFunc.err = WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)),
+ uint32(unsafe.Sizeof(WSAID_WSARECVMSG)),
+ (*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)),
+ uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)),
+ &n, nil, 0)
+ })
+ return sendRecvMsgFunc.err
+}
+
+func sendMsg(s Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ r1, _, e1 := Syscall9(sendRecvMsgFunc.sendAddr, 6, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), completionRoutine, 0, 0, 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func recvMsg(s Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ r1, _, e1 := Syscall9(sendRecvMsgFunc.recvAddr, 5, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), completionRoutine, 0, 0, 0, 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func WSASendMsg(fd Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *Overlapped, completionRoutine uintptr) error {
+ err := LoadSendRecvMsg()
+ if err != nil {
+ return errorspkg.New("failed to find WSASendMsg/WSARecvMsg: " + err.Error())
+ }
+ return sendMsg(fd, msg, flags, bytesSent, overlapped, completionRoutine)
+}
+
+func WSARecvMsg(fd Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *Overlapped, completionRoutine uintptr) error {
+ err := LoadSendRecvMsg()
+ if err != nil {
+ return errorspkg.New("failed to find WSASendMsg/WSARecvMsg: " + err.Error())
+ }
+ return recvMsg(fd, msg, bytesReceived, overlapped, completionRoutine)
+}
+
// Invented structures to support what package os expects.
type Rusage struct {
CreationTime Filetime
diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go
index bc9bd4d..0144d65 100644
--- a/src/syscall/types_windows.go
+++ b/src/syscall/types_windows.go
@@ -579,6 +579,16 @@

WSADESCRIPTION_LEN = 256
WSASYS_STATUS_LEN = 128
+
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_DONTROUTE = 0x4
+ MSG_WAITALL = 0x8
+
+ MSG_TRUNC = 0x0100
+ MSG_CTRUNC = 0x0200
+ MSG_BCAST = 0x0400
+ MSG_MCAST = 0x0800
)

type WSABuf struct {
@@ -586,6 +596,15 @@
Buf *byte
}

+type WSAMsg struct {
+ Name uintptr
+ Namelen int32
+ Buffers *WSABuf
+ Bufferslen uint32
+ Control WSABuf
+ Flags uint32
+}
+
// Invented values to support what package os expects.
const (
S_IFMT = 0x1f000
@@ -1013,6 +1032,20 @@
[8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
}

+var WSAID_WSASENDMSG = GUID{
+ 0xa441e712,
+ 0x754f,
+ 0x43ca,
+ [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d},
+}
+
+var WSAID_WSARECVMSG = GUID{
+ 0xf689d7c8,
+ 0x6f1f,
+ 0x436b,
+ [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22},
+}
+
const (
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
FILE_SKIP_SET_EVENT_ON_HANDLE = 2

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 1
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 6:47:32 PM11/7/17
to Alex Brainman, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Aman Gupta uploaded patch set #3 to this change.

View Change

syscall: add WSASendMsg/WSARecvMsg wrappers on Windows

The function pointers for these syscalls have to be loaded at runtime
with WSAIoctl, similar to how the ConnectEx syscall is loaded. A similar
pattern is used here to load the pair together.

Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
---
M src/syscall/syscall_windows.go
M src/syscall/types_windows.go
2 files changed, 111 insertions(+), 0 deletions(-)

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3

Alex Brainman (Gerrit)

unread,
Nov 7, 2017, 7:06:45 PM11/7/17
to Aman Gupta, goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Thank you for doing this.

Alex

View Change

4 comments:

  • Commit Message:

    • Patch Set #2, Line 7: syscall: add WSASendMsg/WSARecvMsg wrappers on Windows

      You cannot change syscall package (grep "go doc syscall" for "This package is locked down" for details).

      So please move all that code into internal/syscall/windows.

  • File src/syscall/syscall_windows.go:

    • Patch Set #2, Line 832: sendRecvMsgFunc.err = WSAIoctl(s,

      Both WSASendMsg and WSARecvMsg live inside of ws2_32.dll. So you code could be simpler. You could just add this:

      const socket_error = uintptr(^uint32(0))

      //sys WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSASendMsg

      and then run "go generate" command, and it will create the code you need. Same for WSARecvMsg.

      These functions do not exist on Windows XP for example, so you would have to keep LoadSendRecvMsg, but it could be just one line - see syscall.LoadGetAddrInfo for details.

  • File src/syscall/types_windows.go:

    • Patch Set #2, Line 600: struct

      This is actually a pointer to SOCKADDR. I am not an expert in this area, so I wouldn't know. But maybe uintptr is what you want here. Maybe mikio knows.

    • Patch Set #2, Line 603: Buffers

      I suggest

      s/Bufferslen/BufferCount/

      because it is "The number of buffers pointed to in the lpBuffers member."

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 00:06:41 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 7:20:27 PM11/7/17
to goph...@pubsubhelper.golang.org, Alex Brainman, golang-co...@googlegroups.com

Thanks for the review!

View Change

3 comments:

    • You cannot change syscall package (grep "go doc syscall" for "This package is locked down" for detai […]

      Oof. Does that mean I have to implement them in both go and x/net since both use them?

  • File src/syscall/syscall_windows.go:

    • Patch Set #2, Line 832: sendRecvMsgFunc.err = WSAIoctl(s,

      Both WSASendMsg and WSARecvMsg live inside of ws2_32.dll. So you code could be simpler. You could just add this:

      const socket_error = uintptr(^uint32(0))

      //sys WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSASendMsg

      and then run "go generate" command, and it will create the code you need. Same for WSARecvMsg.

      These functions do not exist on Windows XP for example, so you would have to keep LoadSendRecvMsg, but it could be just one line - see syscall.LoadGetAddrInfo for details.

    • I copied the pattern used by the existing ConnectEx wrapper, because according to the documentation the WSASendMsg/WSARecvMsg function pointers must be loaded via WSAIoctl. See the Remarks section of https://msdn.microsoft.com/en-us/library/windows/desktop/ms741687%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396:

      >The function pointer for the WSARecvMsg function must be obtained at run time by making a call to the WSAIoctl function with the SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. The input buffer passed to the WSAIoctl function must contain WSAID_WSARECVMSG, a globally unique identifier (GUID) whose value identifies the WSARecvMsg extension function. On success, the output returned by the WSAIoctl function contains a pointer to the WSARecvMsg function. The WSAID_WSARECVMSG GUID is defined in the Mswsock.h header file.

      I have no idea why it's designed this way, or if WSAIoctl is required. I assumed it was required because ConnectEx uses it too.

  • File src/syscall/types_windows.go:

    • Patch Set #2, Line 603: Buffers

      I suggest […]

      I also considered using Iov and Iovlen to match the convention of the platforms. I'm fine changing it to BufferCount.

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 00:20:24 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Brad Fitzpatrick (Gerrit)

unread,
Nov 7, 2017, 7:37:36 PM11/7/17
to Aman Gupta, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, Alex Brainman, golang-co...@googlegroups.com

View Change

1 comment:

  • Commit Message:

    • Patch Set #2, Line 7: syscall: add WSASendMsg/WSARecvMsg wrappers on Windows

      Oof. […]

      If by "implement them in both" includes copy/pasting, yes.

      You can make x/net be the upstream and we can vendor it into go's src/internal/... directory or something probably. We've done similar things in the past, depending on what layer we need this at.

      Otherwise, yes, copy/paste.

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 00:37:33 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 7:59:50 PM11/7/17
to goph...@pubsubhelper.golang.org, Brad Fitzpatrick, Alex Brainman, golang-co...@googlegroups.com

View Change

2 comments:

    • If by "implement them in both" includes copy/pasting, yes.

    • I have no idea why it's designed this way, or if WSAIoctl is required. I assumed it was required because ConnectEx uses it too.

      I found a good explanation here: https://stackoverflow.com/a/37356935/332798

      In Vista and later, WSAIoctl is not required. I'll simplify this code accordingly. Thanks for the pointer!

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 00:59:46 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Alex Brainman (Gerrit)

unread,
Nov 7, 2017, 8:00:42 PM11/7/17
to Aman Gupta, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, golang-co...@googlegroups.com

View Change

2 comments:

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 2
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 01:00:40 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 10:25:34 PM11/7/17
to goph...@pubsubhelper.golang.org, Alex Brainman, Brad Fitzpatrick, golang-co...@googlegroups.com

Aman Gupta abandoned this change.

View Change

Abandoned folded into CL76393 since the syscall package is frozen

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: abandon
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 11:05:47 PM11/7/17
to goph...@pubsubhelper.golang.org, Alex Brainman, Brad Fitzpatrick, golang-co...@googlegroups.com

View Change

1 comment:

    • Yes, two copies. Normally we make changes in internal/syscall/windows, and then copy them into golang.org/x/sys/windows. But whatever you think is best, or whatever Brad suggests is fine with me too.

    • Okay so I was able to copy this into internal/syscall/windows and everything on the go side works.

      Now I'm trying to make another copy in x/net. You said you generally copy into x/sys/windows, and I see a lot of infrastructure in there to lazy load system DLLs. However, I need this code in x/net and there's nothing I can re-use there.

      Should I put it in x/sys instead, and then make x/net depend on x/sys?

      Or should I copy the DLL loading code from x/sys into x/net?

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 04:05:43 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Aman Gupta (Gerrit)

unread,
Nov 7, 2017, 11:30:59 PM11/7/17
to goph...@pubsubhelper.golang.org, Alex Brainman, Brad Fitzpatrick, golang-co...@googlegroups.com

View Change

1 comment:

    • DLL Ws2_32.dll

      so I tried and it is there.

    • I tried this and it works for WSASendMsg

      But it does not work for WSARecvMsg 😡

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 3
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 04:30:54 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No

Alex Brainman (Gerrit)

unread,
Nov 7, 2017, 11:58:44 PM11/7/17
to Aman Gupta, goph...@pubsubhelper.golang.org, Brad Fitzpatrick, golang-co...@googlegroups.com

Abandoned

folded into CL76393 since the syscall package is frozen

Sounds good.

Alex

View Change

2 comments:


    • Should I put it in x/sys instead, and then make x/net depend on
      x/sys?

    • Yes, please. Put the Windows APIs and stucts and consts in golang.org/x/sys/windows. Make them exported. And use them in x/net.


    • Or should I copy the DLL loading code from x/sys into x/net?

    • > It is fine to leave your code as is, if you don't to follow my advice. […]

      I just tried WSARecvMsg and it is not in ws2_32.dll. Sorry. You would have to go to your original version.

To view, visit change 76392. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: go
Gerrit-Branch: master
Gerrit-MessageType: comment
Gerrit-Change-Id: I4fbef1c3b8e0ac0ab3b50b47c26845d43ea0233a
Gerrit-Change-Number: 76392
Gerrit-PatchSet: 2
Gerrit-Owner: Aman Gupta <am...@tmm1.net>
Gerrit-Reviewer: Alex Brainman <alex.b...@gmail.com>
Gerrit-Reviewer: Aman Gupta <am...@tmm1.net>
Gerrit-CC: Brad Fitzpatrick <brad...@golang.org>
Gerrit-CC: Mikio Hara <mikioh...@gmail.com>
Gerrit-Comment-Date: Wed, 08 Nov 2017 04:58:42 +0000
Gerrit-HasComments: Yes
Gerrit-HasLabels: No
Reply all
Reply to author
Forward
0 new messages