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//go:build darwin || dragonfly || freebsd || netbsd || openbsd
6// +build darwin dragonfly freebsd netbsd openbsd
7
8package unix
9
10import (
11	"reflect"
12	"strings"
13	"testing"
14	"unsafe"
15)
16
17func Test_anyToSockaddr(t *testing.T) {
18	tests := []struct {
19		name string
20		rsa  *RawSockaddrAny
21		sa   Sockaddr
22		err  error
23	}{
24		{
25			name: "AF_UNIX zero length",
26			rsa: sockaddrUnixToAny(RawSockaddrUnix{
27				Family: AF_UNIX,
28			}),
29			err: EINVAL,
30		},
31		{
32			name: "AF_UNIX unnamed",
33			rsa: sockaddrUnixToAny(RawSockaddrUnix{
34				Len:    2, // family (uint16)
35				Family: AF_UNIX,
36			}),
37			sa: &SockaddrUnix{},
38		},
39		{
40			name: "AF_UNIX named",
41			rsa: sockaddrUnixToAny(RawSockaddrUnix{
42				Len:    uint8(2 + len("gopher")), // family (uint16) + len(gopher)
43				Family: AF_UNIX,
44				Path:   [104]int8{'g', 'o', 'p', 'h', 'e', 'r'},
45			}),
46			sa: &SockaddrUnix{
47				Name: "gopher",
48			},
49		},
50		{
51			name: "AF_UNIX named",
52			rsa: sockaddrUnixToAny(RawSockaddrUnix{
53				Len:    uint8(2 + len("go")),
54				Family: AF_UNIX,
55				Path:   [104]int8{'g', 'o', 'p', 'h', 'e', 'r'},
56			}),
57			sa: &SockaddrUnix{
58				Name: "go",
59			},
60		},
61		{
62			name: "AF_MAX EAFNOSUPPORT",
63			rsa: &RawSockaddrAny{
64				Addr: RawSockaddr{
65					Family: AF_MAX,
66				},
67			},
68			err: EAFNOSUPPORT,
69		},
70		// TODO: expand to support other families.
71	}
72
73	for _, tt := range tests {
74		t.Run(tt.name, func(t *testing.T) {
75			fd := int(0)
76			sa, err := anyToSockaddr(fd, tt.rsa)
77			if err != tt.err {
78				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
79			}
80
81			if !reflect.DeepEqual(sa, tt.sa) {
82				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
83			}
84		})
85	}
86}
87
88func TestSockaddrUnix_sockaddr(t *testing.T) {
89	tests := []struct {
90		name string
91		sa   *SockaddrUnix
92		raw  *RawSockaddrUnix
93		err  error
94	}{
95		{
96			name: "unnamed",
97			sa:   &SockaddrUnix{},
98			raw: &RawSockaddrUnix{
99				Family: AF_UNIX,
100			},
101			err: EINVAL,
102		},
103		{
104			name: "named",
105			sa: &SockaddrUnix{
106				Name: "gopher",
107			},
108			raw: &RawSockaddrUnix{
109				Len:    uint8(2 + len("gopher") + 1), // family (uint16) + len(gopher) + '\0'
110				Family: AF_UNIX,
111				Path:   [104]int8{'g', 'o', 'p', 'h', 'e', 'r'},
112			},
113		},
114		{
115			name: "named too long",
116			sa: &SockaddrUnix{
117				Name: strings.Repeat("A", 104),
118			},
119			err: EINVAL,
120		},
121	}
122
123	for _, tt := range tests {
124		t.Run(tt.name, func(t *testing.T) {
125			out, _, err := tt.sa.sockaddr()
126			if err != tt.err {
127				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
128			}
129
130			if out == nil {
131				// No pointer to cast, return early.
132				return
133			}
134
135			raw := (*RawSockaddrUnix)(out)
136			if !reflect.DeepEqual(raw, tt.raw) {
137				t.Fatalf("unexpected RawSockaddrUnix:\n got: %#v\nwant: %#v", raw, tt.raw)
138			}
139		})
140	}
141}
142
143func sockaddrUnixToAny(in RawSockaddrUnix) *RawSockaddrAny {
144	var out RawSockaddrAny
145
146	// Explicitly copy the contents of in into out to produce the correct
147	// sockaddr structure, without relying on unsafe casting to a type of a
148	// larger size.
149	copy(
150		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
151		(*(*[SizeofSockaddrUnix]byte)(unsafe.Pointer(&in)))[:],
152	)
153
154	return &out
155}
156