1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// +build darwin dragonfly freebsd netbsd openbsd 6 7package unix 8 9import ( 10 "reflect" 11 "strings" 12 "testing" 13 "unsafe" 14) 15 16// as per socket(2) 17type SocketSpec struct { 18 domain int 19 typ int 20 protocol int 21} 22 23func Test_anyToSockaddr(t *testing.T) { 24 tests := []struct { 25 name string 26 rsa *RawSockaddrAny 27 sa Sockaddr 28 err error 29 skt SocketSpec 30 }{ 31 { 32 name: "AF_UNIX zero length", 33 rsa: sockaddrUnixToAny(RawSockaddrUnix{ 34 Family: AF_UNIX, 35 }), 36 err: EINVAL, 37 }, 38 { 39 name: "AF_UNIX unnamed", 40 rsa: sockaddrUnixToAny(RawSockaddrUnix{ 41 Len: 2, // family (uint16) 42 Family: AF_UNIX, 43 }), 44 sa: &SockaddrUnix{}, 45 }, 46 { 47 name: "AF_UNIX named", 48 rsa: sockaddrUnixToAny(RawSockaddrUnix{ 49 Len: uint8(2 + len("gopher")), // family (uint16) + len(gopher) 50 Family: AF_UNIX, 51 Path: [104]int8{'g', 'o', 'p', 'h', 'e', 'r'}, 52 }), 53 sa: &SockaddrUnix{ 54 Name: "gopher", 55 }, 56 }, 57 { 58 name: "AF_UNIX named", 59 rsa: sockaddrUnixToAny(RawSockaddrUnix{ 60 Len: uint8(2 + len("go")), 61 Family: AF_UNIX, 62 Path: [104]int8{'g', 'o', 'p', 'h', 'e', 'r'}, 63 }), 64 sa: &SockaddrUnix{ 65 Name: "go", 66 }, 67 }, 68 { 69 name: "AF_MAX EAFNOSUPPORT", 70 rsa: &RawSockaddrAny{ 71 Addr: RawSockaddr{ 72 Family: AF_MAX, 73 }, 74 }, 75 err: EAFNOSUPPORT, 76 }, 77 // TODO: expand to support other families. 78 } 79 80 for _, tt := range tests { 81 t.Run(tt.name, func(t *testing.T) { 82 fd := int(0) 83 var err error 84 if tt.skt.domain != 0 { 85 fd, err = Socket(tt.skt.domain, tt.skt.typ, tt.skt.protocol) 86 // Some sockaddr types need specific kernel modules running: if these 87 // are not present we'll get EPROTONOSUPPORT back when trying to create 88 // the socket. Skip the test in this situation. 89 if err == EPROTONOSUPPORT { 90 t.Skip("socket family/protocol not supported by kernel") 91 } else if err != nil { 92 t.Fatalf("socket(%v): %v", tt.skt, err) 93 } 94 defer Close(fd) 95 } 96 sa, err := anyToSockaddr(fd, tt.rsa) 97 if err != tt.err { 98 t.Fatalf("unexpected error: %v, want: %v", err, tt.err) 99 } 100 101 if !reflect.DeepEqual(sa, tt.sa) { 102 t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa) 103 } 104 }) 105 } 106} 107 108func TestSockaddrUnix_sockaddr(t *testing.T) { 109 tests := []struct { 110 name string 111 sa *SockaddrUnix 112 raw *RawSockaddrUnix 113 err error 114 }{ 115 { 116 name: "unnamed", 117 sa: &SockaddrUnix{}, 118 raw: &RawSockaddrUnix{ 119 Family: AF_UNIX, 120 }, 121 err: EINVAL, 122 }, 123 { 124 name: "named", 125 sa: &SockaddrUnix{ 126 Name: "gopher", 127 }, 128 raw: &RawSockaddrUnix{ 129 Len: uint8(2 + len("gopher") + 1), // family (uint16) + len(gopher) + '\0' 130 Family: AF_UNIX, 131 Path: [104]int8{'g', 'o', 'p', 'h', 'e', 'r'}, 132 }, 133 }, 134 { 135 name: "named too long", 136 sa: &SockaddrUnix{ 137 Name: strings.Repeat("A", 104), 138 }, 139 err: EINVAL, 140 }, 141 } 142 143 for _, tt := range tests { 144 t.Run(tt.name, func(t *testing.T) { 145 out, _, err := tt.sa.sockaddr() 146 if err != tt.err { 147 t.Fatalf("unexpected error: %v, want: %v", err, tt.err) 148 } 149 150 if out == nil { 151 // No pointer to cast, return early. 152 return 153 } 154 155 raw := (*RawSockaddrUnix)(out) 156 if !reflect.DeepEqual(raw, tt.raw) { 157 t.Fatalf("unexpected RawSockaddrUnix:\n got: %#v\nwant: %#v", raw, tt.raw) 158 } 159 }) 160 } 161} 162 163func sockaddrUnixToAny(in RawSockaddrUnix) *RawSockaddrAny { 164 var out RawSockaddrAny 165 166 // Explicitly copy the contents of in into out to produce the correct 167 // sockaddr structure, without relying on unsafe casting to a type of a 168 // larger size. 169 copy( 170 (*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:], 171 (*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:], 172 ) 173 174 return &out 175} 176