1// Copyright 2019 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 linux
6
7package unix
8
9import (
10	"reflect"
11	"testing"
12	"unsafe"
13)
14
15func Test_anyToSockaddr(t *testing.T) {
16	tests := []struct {
17		name string
18		rsa  *RawSockaddrAny
19		sa   Sockaddr
20		err  error
21	}{
22		{
23			name: "AF_TIPC bad addrtype",
24			rsa: &RawSockaddrAny{
25				Addr: RawSockaddr{
26					Family: AF_TIPC,
27				},
28			},
29			err: EINVAL,
30		},
31		{
32			name: "AF_TIPC NameSeq",
33			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
34				Family:   AF_TIPC,
35				Addrtype: TIPC_SERVICE_RANGE,
36				Scope:    1,
37				Addr: (&TIPCServiceRange{
38					Type:  1,
39					Lower: 2,
40					Upper: 3,
41				}).tipcAddr(),
42			}),
43			sa: &SockaddrTIPC{
44				Scope: 1,
45				Addr: &TIPCServiceRange{
46					Type:  1,
47					Lower: 2,
48					Upper: 3,
49				},
50			},
51		},
52		{
53			name: "AF_TIPC Name",
54			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
55				Family:   AF_TIPC,
56				Addrtype: TIPC_SERVICE_ADDR,
57				Scope:    2,
58				Addr: (&TIPCServiceName{
59					Type:     1,
60					Instance: 2,
61					Domain:   3,
62				}).tipcAddr(),
63			}),
64			sa: &SockaddrTIPC{
65				Scope: 2,
66				Addr: &TIPCServiceName{
67					Type:     1,
68					Instance: 2,
69					Domain:   3,
70				},
71			},
72		},
73		{
74			name: "AF_TIPC ID",
75			rsa: sockaddrTIPCToAny(RawSockaddrTIPC{
76				Family:   AF_TIPC,
77				Addrtype: TIPC_SOCKET_ADDR,
78				Scope:    3,
79				Addr: (&TIPCSocketAddr{
80					Ref:  1,
81					Node: 2,
82				}).tipcAddr(),
83			}),
84			sa: &SockaddrTIPC{
85				Scope: 3,
86				Addr: &TIPCSocketAddr{
87					Ref:  1,
88					Node: 2,
89				},
90			},
91		},
92		{
93			name: "AF_MAX EAFNOSUPPORT",
94			rsa: &RawSockaddrAny{
95				Addr: RawSockaddr{
96					Family: AF_MAX,
97				},
98			},
99			err: EAFNOSUPPORT,
100		},
101		// TODO: expand to support other families.
102	}
103
104	for _, tt := range tests {
105		t.Run(tt.name, func(t *testing.T) {
106			// TODO: parameterize fd (and its setup) when needed.
107			sa, err := anyToSockaddr(0, tt.rsa)
108			if err != tt.err {
109				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
110			}
111
112			if !reflect.DeepEqual(sa, tt.sa) {
113				t.Fatalf("unexpected Sockaddr:\n got: %#v\nwant: %#v", sa, tt.sa)
114			}
115		})
116	}
117}
118
119func TestSockaddrTIPC_sockaddr(t *testing.T) {
120	tests := []struct {
121		name string
122		sa   *SockaddrTIPC
123		raw  *RawSockaddrTIPC
124		err  error
125	}{
126		{
127			name: "no fields set",
128			sa:   &SockaddrTIPC{},
129			err:  EINVAL,
130		},
131		{
132			name: "ID",
133			sa: &SockaddrTIPC{
134				Scope: 1,
135				Addr: &TIPCSocketAddr{
136					Ref:  1,
137					Node: 2,
138				},
139			},
140			raw: &RawSockaddrTIPC{
141				Family:   AF_TIPC,
142				Addrtype: TIPC_SOCKET_ADDR,
143				Scope:    1,
144				Addr: (&TIPCSocketAddr{
145					Ref:  1,
146					Node: 2,
147				}).tipcAddr(),
148			},
149		},
150		{
151			name: "NameSeq",
152			sa: &SockaddrTIPC{
153				Scope: 2,
154				Addr: &TIPCServiceRange{
155					Type:  1,
156					Lower: 2,
157					Upper: 3,
158				},
159			},
160			raw: &RawSockaddrTIPC{
161				Family:   AF_TIPC,
162				Addrtype: TIPC_SERVICE_RANGE,
163				Scope:    2,
164				Addr: (&TIPCServiceRange{
165					Type:  1,
166					Lower: 2,
167					Upper: 3,
168				}).tipcAddr(),
169			},
170		},
171		{
172			name: "Name",
173			sa: &SockaddrTIPC{
174				Scope: 3,
175				Addr: &TIPCServiceName{
176					Type:     1,
177					Instance: 2,
178					Domain:   3,
179				},
180			},
181			raw: &RawSockaddrTIPC{
182				Family:   AF_TIPC,
183				Addrtype: TIPC_SERVICE_ADDR,
184				Scope:    3,
185				Addr: (&TIPCServiceName{
186					Type:     1,
187					Instance: 2,
188					Domain:   3,
189				}).tipcAddr(),
190			},
191		},
192	}
193
194	for _, tt := range tests {
195		t.Run(tt.name, func(t *testing.T) {
196			out, l, err := tt.sa.sockaddr()
197			if err != tt.err {
198				t.Fatalf("unexpected error: %v, want: %v", err, tt.err)
199			}
200
201			// Must be 0 on error or a fixed size otherwise.
202			if (tt.err != nil && l != 0) || (tt.raw != nil && l != SizeofSockaddrTIPC) {
203				t.Fatalf("unexpected Socklen: %d", l)
204			}
205			if out == nil {
206				// No pointer to cast, return early.
207				return
208			}
209
210			raw := (*RawSockaddrTIPC)(out)
211			if !reflect.DeepEqual(raw, tt.raw) {
212				t.Fatalf("unexpected RawSockaddrTIPC:\n got: %#v\nwant: %#v", raw, tt.raw)
213			}
214		})
215	}
216}
217
218func sockaddrTIPCToAny(in RawSockaddrTIPC) *RawSockaddrAny {
219	var out RawSockaddrAny
220
221	// Explicitly copy the contents of in into out to produce the correct
222	// sockaddr structure, without relying on unsafe casting to a type of a
223	// larger size.
224	copy(
225		(*(*[SizeofSockaddrAny]byte)(unsafe.Pointer(&out)))[:],
226		(*(*[SizeofSockaddrTIPC]byte)(unsafe.Pointer(&in)))[:],
227	)
228
229	return &out
230}
231