]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: implement Unix Socket for Windows
authorYasuhiro Matsumoto <mattn.jp@gmail.com>
Sun, 22 Jul 2018 16:47:11 +0000 (01:47 +0900)
committerAlex Brainman <alex.brainman@gmail.com>
Tue, 28 Aug 2018 09:26:45 +0000 (09:26 +0000)
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>
api/except.txt
src/net/unixsock_windows_test.go [new file with mode: 0644]
src/syscall/syscall_windows.go
src/syscall/types_windows.go

index 46dbb458923c1ada187a7bd46b089938bb5f9c73..850724196d2492cab829f813d346ebbed4c2195f 100644 (file)
@@ -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 (file)
index 0000000..a1da5d4
--- /dev/null
@@ -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)
+                       }
+               }
+       }
+}
index 638a81882af9be8fc91ae49c5288f2a1ac348f1a..528ef4f26dfe69b15d490d756d301123a7d10be7 100644 (file)
@@ -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))
index 6911fe509cbbcea929ae28f371021aa70a9f5efd..0b839339d2f1976dbb546cce4198b8677e668b0e 100644 (file)
@@ -1139,3 +1139,5 @@ const (
        SYMBOLIC_LINK_FLAG_DIRECTORY     = 0x1
        _SYMLINK_FLAG_RELATIVE           = 1
 )
+
+const UNIX_PATH_MAX = 108 // defined in afunix.h