Browse Source

windows: add support for AF_UNIX sockets

CL 125456 added the implementation of AF_UNIX to the syscall package.
Add the same implementation to golang.org/x/sys/windows as well.

This works only on Windows 10.

https://blogs.msdn.microsoft.com/commandline/2017/12/19/af_unix-comes-to-windows/

Updates golang/go#26072

Change-Id: Ibd4a17342ed4f9f4f2b16b82c7b02834e681b7b4
Reviewed-on: https://go-review.googlesource.com/132555
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Tobias Klauser 7 years ago
parent
commit
fa5fdf94c7
2 changed files with 56 additions and 4 deletions
  1. 54 4
      windows/syscall_windows.go
  2. 2 0
      windows/types_windows.go

+ 54 - 4
windows/syscall_windows.go

@@ -655,7 +655,7 @@ type RawSockaddr struct {
 
 
 type RawSockaddrAny struct {
 type RawSockaddrAny struct {
 	Addr RawSockaddr
 	Addr RawSockaddr
-	Pad  [96]int8
+	Pad  [100]int8
 }
 }
 
 
 type Sockaddr interface {
 type Sockaddr interface {
@@ -704,19 +704,69 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
 	return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 	return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
 }
 }
 
 
+type RawSockaddrUnix struct {
+	Family uint16
+	Path   [UNIX_PATH_MAX]int8
+}
+
 type SockaddrUnix struct {
 type SockaddrUnix struct {
 	Name string
 	Name string
+	raw  RawSockaddrUnix
 }
 }
 
 
 func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
 func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
-	// TODO(brainman): implement SockaddrUnix.sockaddr()
-	return nil, 0, syscall.EWINDOWS
+	name := sa.Name
+	n := len(name)
+	if n > len(sa.raw.Path) {
+		return nil, 0, syscall.EINVAL
+	}
+	if n == len(sa.raw.Path) && name[0] != '@' {
+		return nil, 0, syscall.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) {
 func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
 	switch rsa.Addr.Family {
 	switch rsa.Addr.Family {
 	case AF_UNIX:
 	case AF_UNIX:
-		return nil, syscall.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:
 	case AF_INET:
 		pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
 		pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))

+ 2 - 0
windows/types_windows.go

@@ -1465,3 +1465,5 @@ type ConsoleScreenBufferInfo struct {
 	Window            SmallRect
 	Window            SmallRect
 	MaximumWindowSize Coord
 	MaximumWindowSize Coord
 }
 }
+
+const UNIX_PATH_MAX = 108 // defined in afunix.h