aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYasuhiro Matsumoto <mattn.jp@gmail.com>2018-07-23 01:47:11 +0900
committerAlex Brainman <alex.brainman@gmail.com>2018-08-28 09:26:45 +0000
commit76c45877c9e72ccc84db787dc08299e0182e0efb (patch)
treece7f3169335049a4918df6a5b465a0ea1d727721
parentded941158042d8b09164a9f8049fd7108b715680 (diff)
downloadgo-76c45877c9e72ccc84db787dc08299e0182e0efb.tar.gz
go-76c45877c9e72ccc84db787dc08299e0182e0efb.zip
syscall: implement Unix Socket for Windows
Add implementation of AF_UNIX. This works only on Windows 10. https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows/ Fixes #26072 Change-Id: I76a96a472385a17901885271622fbe55d66bb720 Reviewed-on: https://go-review.googlesource.com/125456 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
-rw-r--r--api/except.txt2
-rw-r--r--src/net/unixsock_windows_test.go93
-rw-r--r--src/syscall/syscall_windows.go58
-rw-r--r--src/syscall/types_windows.go2
4 files changed, 151 insertions, 4 deletions
diff --git a/api/except.txt b/api/except.txt
index 46dbb45892..850724196d 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -370,6 +370,7 @@ pkg syscall (windows-386), type CertContext struct, CertInfo uintptr
pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo uintptr
pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr
+pkg syscall (windows-386), type RawSockaddrAny struct, Pad [96]int8
pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295
pkg syscall (windows-amd64), type AddrinfoW struct, Addr uintptr
pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
@@ -378,3 +379,4 @@ pkg syscall (windows-amd64), type CertContext struct, CertInfo uintptr
pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
+pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
diff --git a/src/net/unixsock_windows_test.go b/src/net/unixsock_windows_test.go
new file mode 100644
index 0000000000..a1da5d4062
--- /dev/null
+++ b/src/net/unixsock_windows_test.go
@@ -0,0 +1,93 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package net
+
+import (
+ "internal/syscall/windows/registry"
+ "os"
+ "reflect"
+ "strconv"
+ "testing"
+)
+
+func isBuild17063() bool {
+ k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.READ)
+ if err != nil {
+ return false
+ }
+ defer k.Close()
+
+ s, _, err := k.GetStringValue("CurrentBuild")
+ if err != nil {
+ return false
+ }
+ ver, err := strconv.Atoi(s)
+ if err != nil {
+ return false
+ }
+ return ver >= 17063
+}
+
+func TestUnixConnLocalWindows(t *testing.T) {
+ if !isBuild17063() {
+ t.Skip("unix test")
+ }
+
+ handler := func(ls *localServer, ln Listener) {}
+ for _, laddr := range []string{"", testUnixAddr()} {
+ laddr := laddr
+ taddr := testUnixAddr()
+ ta, err := ResolveUnixAddr("unix", taddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ln, err := ListenUnix("unix", ta)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ls, err := (&streamListener{Listener: ln}).newLocalServer()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ls.teardown()
+ if err := ls.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
+
+ la, err := ResolveUnixAddr("unix", laddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ c, err := DialUnix("unix", la, ta)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ c.Close()
+ if la != nil {
+ defer os.Remove(laddr)
+ }
+ }()
+ if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
+ t.Fatal(err)
+ }
+
+ if laddr == "" {
+ laddr = "@"
+ }
+ var connAddrs = [3]struct{ got, want Addr }{
+ {ln.Addr(), ta},
+ {c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
+ {c.RemoteAddr(), ta},
+ }
+ for _, ca := range connAddrs {
+ if !reflect.DeepEqual(ca.got, ca.want) {
+ t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+ }
+ }
+ }
+}
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 638a81882a..528ef4f26d 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -634,7 +634,7 @@ type RawSockaddr struct {
type RawSockaddrAny struct {
Addr RawSockaddr
- Pad [96]int8
+ Pad [100]int8
}
type Sockaddr interface {
@@ -683,19 +683,69 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
}
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [UNIX_PATH_MAX]int8
+}
+
type SockaddrUnix struct {
Name string
+ raw RawSockaddrUnix
}
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
- // TODO(brainman): implement SockaddrUnix.sockaddr()
- return nil, 0, EWINDOWS
+ name := sa.Name
+ n := len(name)
+ if n > len(sa.raw.Path) {
+ return nil, 0, EINVAL
+ }
+ if n == len(sa.raw.Path) && name[0] != '@' {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = int8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := int32(2)
+ if n > 0 {
+ sl += int32(n) + 1
+ }
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0
+ // Don't count trailing NUL for abstract address.
+ sl--
+ }
+
+ return unsafe.Pointer(&sa.raw), sl, nil
}
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
- return nil, EWINDOWS
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+ if pp.Path[0] == 0 {
+ // "Abstract" Unix domain socket.
+ // Rewrite leading NUL as @ for textual display.
+ // (This is the standard convention.)
+ // Not friendly to overwrite in place,
+ // but the callers below don't care.
+ pp.Path[0] = '@'
+ }
+
+ // Assume path ends at NUL.
+ // This is not technically the Linux semantics for
+ // abstract Unix domain sockets--they are supposed
+ // to be uninterpreted fixed-size binary blobs--but
+ // everyone uses this convention.
+ n := 0
+ for n < len(pp.Path) && pp.Path[n] != 0 {
+ n++
+ }
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, nil
case AF_INET:
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go
index 6911fe509c..0b839339d2 100644
--- a/src/syscall/types_windows.go
+++ b/src/syscall/types_windows.go
@@ -1139,3 +1139,5 @@ const (
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
_SYMLINK_FLAG_RELATIVE = 1
)
+
+const UNIX_PATH_MAX = 108 // defined in afunix.h