1// Copyright 2013 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 !plan9 && !windows
6
7package net
8
9import (
10	"bytes"
11	"internal/testenv"
12	"os"
13	"reflect"
14	"runtime"
15	"syscall"
16	"testing"
17	"time"
18)
19
20func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
21	if !testableNetwork("unixgram") {
22		t.Skip("unixgram test")
23	}
24	switch runtime.GOOS {
25	case "js", "wasip1":
26		t.Skipf("skipping: syscall.Socket not implemented on %s", runtime.GOOS)
27	}
28	if runtime.GOOS == "openbsd" {
29		testenv.SkipFlaky(t, 15157)
30	}
31
32	addr := testUnixAddr(t)
33	la, err := ResolveUnixAddr("unixgram", addr)
34	if err != nil {
35		t.Fatal(err)
36	}
37	c, err := ListenUnixgram("unixgram", la)
38	if err != nil {
39		t.Fatal(err)
40	}
41	defer func() {
42		c.Close()
43		os.Remove(addr)
44	}()
45
46	off := make(chan bool)
47	data := [5]byte{1, 2, 3, 4, 5}
48	go func() {
49		defer func() { off <- true }()
50		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
51		if err != nil {
52			t.Error(err)
53			return
54		}
55		defer syscall.Close(s)
56		rsa := &syscall.SockaddrUnix{Name: addr}
57		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
58			t.Error(err)
59			return
60		}
61	}()
62
63	<-off
64	b := make([]byte, 64)
65	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
66	n, from, err := c.ReadFrom(b)
67	if err != nil {
68		t.Fatal(err)
69	}
70	if from != nil {
71		t.Fatalf("unexpected peer address: %v", from)
72	}
73	if !bytes.Equal(b[:n], data[:]) {
74		t.Fatalf("got %v; want %v", b[:n], data[:])
75	}
76}
77
78func TestUnixgramZeroBytePayload(t *testing.T) {
79	if !testableNetwork("unixgram") {
80		t.Skip("unixgram test")
81	}
82
83	c1 := newLocalPacketListener(t, "unixgram")
84	defer os.Remove(c1.LocalAddr().String())
85	defer c1.Close()
86
87	c2, err := Dial("unixgram", c1.LocalAddr().String())
88	if err != nil {
89		t.Fatal(err)
90	}
91	defer os.Remove(c2.LocalAddr().String())
92	defer c2.Close()
93
94	for _, genericRead := range []bool{false, true} {
95		n, err := c2.Write(nil)
96		if err != nil {
97			t.Fatal(err)
98		}
99		if n != 0 {
100			t.Errorf("got %d; want 0", n)
101		}
102		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
103		var b [1]byte
104		var peer Addr
105		if genericRead {
106			_, err = c1.(Conn).Read(b[:])
107		} else {
108			_, peer, err = c1.ReadFrom(b[:])
109		}
110		switch err {
111		case nil: // ReadFrom succeeds
112			if peer != nil { // peer is connected-mode
113				t.Fatalf("unexpected peer address: %v", peer)
114			}
115		default: // Read may timeout, it depends on the platform
116			if !isDeadlineExceeded(err) {
117				t.Fatal(err)
118			}
119		}
120	}
121}
122
123func TestUnixgramZeroByteBuffer(t *testing.T) {
124	if !testableNetwork("unixgram") {
125		t.Skip("unixgram test")
126	}
127	// issue 4352: Recvfrom failed with "address family not
128	// supported by protocol family" if zero-length buffer provided
129
130	c1 := newLocalPacketListener(t, "unixgram")
131	defer os.Remove(c1.LocalAddr().String())
132	defer c1.Close()
133
134	c2, err := Dial("unixgram", c1.LocalAddr().String())
135	if err != nil {
136		t.Fatal(err)
137	}
138	defer os.Remove(c2.LocalAddr().String())
139	defer c2.Close()
140
141	b := []byte("UNIXGRAM ZERO BYTE BUFFER TEST")
142	for _, genericRead := range []bool{false, true} {
143		n, err := c2.Write(b)
144		if err != nil {
145			t.Fatal(err)
146		}
147		if n != len(b) {
148			t.Errorf("got %d; want %d", n, len(b))
149		}
150		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
151		var peer Addr
152		if genericRead {
153			_, err = c1.(Conn).Read(nil)
154		} else {
155			_, peer, err = c1.ReadFrom(nil)
156		}
157		switch err {
158		case nil: // ReadFrom succeeds
159			if peer != nil { // peer is connected-mode
160				t.Fatalf("unexpected peer address: %v", peer)
161			}
162		default: // Read may timeout, it depends on the platform
163			if !isDeadlineExceeded(err) {
164				t.Fatal(err)
165			}
166		}
167	}
168}
169
170func TestUnixgramWrite(t *testing.T) {
171	if !testableNetwork("unixgram") {
172		t.Skip("unixgram test")
173	}
174
175	addr := testUnixAddr(t)
176	laddr, err := ResolveUnixAddr("unixgram", addr)
177	if err != nil {
178		t.Fatal(err)
179	}
180	c, err := ListenPacket("unixgram", addr)
181	if err != nil {
182		t.Fatal(err)
183	}
184	defer os.Remove(addr)
185	defer c.Close()
186
187	testUnixgramWriteConn(t, laddr)
188	testUnixgramWritePacketConn(t, laddr)
189}
190
191func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
192	c, err := Dial("unixgram", raddr.String())
193	if err != nil {
194		t.Fatal(err)
195	}
196	defer c.Close()
197
198	b := []byte("CONNECTED-MODE SOCKET")
199	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err == nil {
200		t.Fatal("should fail")
201	} else if err.(*OpError).Err != ErrWriteToConnected {
202		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
203	}
204	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
205		t.Fatal("should fail")
206	} else if err.(*OpError).Err != ErrWriteToConnected {
207		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
208	}
209	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
210		t.Fatal("should fail")
211	} else if err.(*OpError).Err != ErrWriteToConnected {
212		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
213	}
214	if _, err := c.Write(b); err != nil {
215		t.Fatal(err)
216	}
217}
218
219func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
220	addr := testUnixAddr(t)
221	c, err := ListenPacket("unixgram", addr)
222	if err != nil {
223		t.Fatal(err)
224	}
225	defer os.Remove(addr)
226	defer c.Close()
227
228	b := []byte("UNCONNECTED-MODE SOCKET")
229	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
230		t.Fatal(err)
231	}
232	if _, err := c.WriteTo(b, raddr); err != nil {
233		t.Fatal(err)
234	}
235	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
236		t.Fatal(err)
237	}
238	if _, err := c.(*UnixConn).Write(b); err == nil {
239		t.Fatal("should fail")
240	}
241}
242
243func TestUnixConnLocalAndRemoteNames(t *testing.T) {
244	if !testableNetwork("unix") {
245		t.Skip("unix test")
246	}
247
248	handler := func(ls *localServer, ln Listener) {}
249	for _, laddr := range []string{"", testUnixAddr(t)} {
250		laddr := laddr
251		taddr := testUnixAddr(t)
252		ta, err := ResolveUnixAddr("unix", taddr)
253		if err != nil {
254			t.Fatal(err)
255		}
256		ln, err := ListenUnix("unix", ta)
257		if err != nil {
258			t.Fatal(err)
259		}
260		ls := (&streamListener{Listener: ln}).newLocalServer()
261		defer ls.teardown()
262		if err := ls.buildup(handler); err != nil {
263			t.Fatal(err)
264		}
265
266		la, err := ResolveUnixAddr("unix", laddr)
267		if err != nil {
268			t.Fatal(err)
269		}
270		c, err := DialUnix("unix", la, ta)
271		if err != nil {
272			t.Fatal(err)
273		}
274		defer func() {
275			c.Close()
276			if la != nil {
277				defer os.Remove(laddr)
278			}
279		}()
280		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
281			t.Fatal(err)
282		}
283
284		switch runtime.GOOS {
285		case "android", "linux":
286			if laddr == "" {
287				laddr = "@" // autobind feature
288			}
289		}
290		var connAddrs = [3]struct{ got, want Addr }{
291			{ln.Addr(), ta},
292			{c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
293			{c.RemoteAddr(), ta},
294		}
295		for _, ca := range connAddrs {
296			if !reflect.DeepEqual(ca.got, ca.want) {
297				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
298			}
299		}
300	}
301}
302
303func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
304	if !testableNetwork("unixgram") {
305		t.Skip("unixgram test")
306	}
307
308	for _, laddr := range []string{"", testUnixAddr(t)} {
309		laddr := laddr
310		taddr := testUnixAddr(t)
311		ta, err := ResolveUnixAddr("unixgram", taddr)
312		if err != nil {
313			t.Fatal(err)
314		}
315		c1, err := ListenUnixgram("unixgram", ta)
316		if err != nil {
317			t.Fatal(err)
318		}
319		defer func() {
320			c1.Close()
321			os.Remove(taddr)
322		}()
323
324		var la *UnixAddr
325		if laddr != "" {
326			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
327				t.Fatal(err)
328			}
329		}
330		c2, err := DialUnix("unixgram", la, ta)
331		if err != nil {
332			t.Fatal(err)
333		}
334		defer func() {
335			c2.Close()
336			if la != nil {
337				defer os.Remove(laddr)
338			}
339		}()
340
341		switch runtime.GOOS {
342		case "android", "linux":
343			if laddr == "" {
344				laddr = "@" // autobind feature
345			}
346		}
347
348		var connAddrs = [4]struct{ got, want Addr }{
349			{c1.LocalAddr(), ta},
350			{c1.RemoteAddr(), nil},
351			{c2.LocalAddr(), &UnixAddr{Name: laddr, Net: "unixgram"}},
352			{c2.RemoteAddr(), ta},
353		}
354		for _, ca := range connAddrs {
355			if !reflect.DeepEqual(ca.got, ca.want) {
356				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
357			}
358		}
359	}
360}
361
362func TestUnixUnlink(t *testing.T) {
363	if !testableNetwork("unix") {
364		t.Skip("unix test")
365	}
366	switch runtime.GOOS {
367	case "js", "wasip1":
368		t.Skipf("skipping: %s does not support Unlink", runtime.GOOS)
369	}
370
371	name := testUnixAddr(t)
372
373	listen := func(t *testing.T) *UnixListener {
374		l, err := Listen("unix", name)
375		if err != nil {
376			t.Fatal(err)
377		}
378		return l.(*UnixListener)
379	}
380	checkExists := func(t *testing.T, desc string) {
381		if _, err := os.Stat(name); err != nil {
382			t.Fatalf("unix socket does not exist %s: %v", desc, err)
383		}
384	}
385	checkNotExists := func(t *testing.T, desc string) {
386		if _, err := os.Stat(name); err == nil {
387			t.Fatalf("unix socket does exist %s: %v", desc, err)
388		}
389	}
390
391	// Listener should remove on close.
392	t.Run("Listen", func(t *testing.T) {
393		l := listen(t)
394		checkExists(t, "after Listen")
395		l.Close()
396		checkNotExists(t, "after Listener close")
397	})
398
399	// FileListener should not.
400	t.Run("FileListener", func(t *testing.T) {
401		l := listen(t)
402		f, _ := l.File()
403		l1, _ := FileListener(f)
404		checkExists(t, "after FileListener")
405		f.Close()
406		checkExists(t, "after File close")
407		l1.Close()
408		checkExists(t, "after FileListener close")
409		l.Close()
410		checkNotExists(t, "after Listener close")
411	})
412
413	// Only first call to l.Close should remove.
414	t.Run("SecondClose", func(t *testing.T) {
415		l := listen(t)
416		checkExists(t, "after Listen")
417		l.Close()
418		checkNotExists(t, "after Listener close")
419		if err := os.WriteFile(name, []byte("hello world"), 0666); err != nil {
420			t.Fatalf("cannot recreate socket file: %v", err)
421		}
422		checkExists(t, "after writing temp file")
423		l.Close()
424		checkExists(t, "after second Listener close")
425		os.Remove(name)
426	})
427
428	// SetUnlinkOnClose should do what it says.
429
430	t.Run("Listen/SetUnlinkOnClose(true)", func(t *testing.T) {
431		l := listen(t)
432		checkExists(t, "after Listen")
433		l.SetUnlinkOnClose(true)
434		l.Close()
435		checkNotExists(t, "after Listener close")
436	})
437
438	t.Run("Listen/SetUnlinkOnClose(false)", func(t *testing.T) {
439		l := listen(t)
440		checkExists(t, "after Listen")
441		l.SetUnlinkOnClose(false)
442		l.Close()
443		checkExists(t, "after Listener close")
444		os.Remove(name)
445	})
446
447	t.Run("FileListener/SetUnlinkOnClose(true)", func(t *testing.T) {
448		l := listen(t)
449		f, _ := l.File()
450		l1, _ := FileListener(f)
451		checkExists(t, "after FileListener")
452		l1.(*UnixListener).SetUnlinkOnClose(true)
453		f.Close()
454		checkExists(t, "after File close")
455		l1.Close()
456		checkNotExists(t, "after FileListener close")
457		l.Close()
458	})
459
460	t.Run("FileListener/SetUnlinkOnClose(false)", func(t *testing.T) {
461		l := listen(t)
462		f, _ := l.File()
463		l1, _ := FileListener(f)
464		checkExists(t, "after FileListener")
465		l1.(*UnixListener).SetUnlinkOnClose(false)
466		f.Close()
467		checkExists(t, "after File close")
468		l1.Close()
469		checkExists(t, "after FileListener close")
470		l.Close()
471	})
472}
473