1// Copyright 2023 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 unix 6 7package net 8 9import ( 10 "internal/syscall/unix" 11 "testing" 12) 13 14// For backward compatibility, opening a net.Conn, turning it into an os.File, 15// and calling the Fd method should return a blocking descriptor. 16func TestFileFdBlocks(t *testing.T) { 17 if !testableNetwork("unix") { 18 t.Skipf("skipping: unix sockets not supported") 19 } 20 21 ls := newLocalServer(t, "unix") 22 defer ls.teardown() 23 24 errc := make(chan error, 1) 25 done := make(chan bool) 26 handler := func(ls *localServer, ln Listener) { 27 server, err := ln.Accept() 28 errc <- err 29 if err != nil { 30 return 31 } 32 defer server.Close() 33 <-done 34 } 35 if err := ls.buildup(handler); err != nil { 36 t.Fatal(err) 37 } 38 defer close(done) 39 40 client, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) 41 if err != nil { 42 t.Fatal(err) 43 } 44 defer client.Close() 45 46 if err := <-errc; err != nil { 47 t.Fatalf("server error: %v", err) 48 } 49 50 // The socket should be non-blocking. 51 rawconn, err := client.(*UnixConn).SyscallConn() 52 if err != nil { 53 t.Fatal(err) 54 } 55 err = rawconn.Control(func(fd uintptr) { 56 nonblock, err := unix.IsNonblock(int(fd)) 57 if err != nil { 58 t.Fatal(err) 59 } 60 if !nonblock { 61 t.Fatal("unix socket is in blocking mode") 62 } 63 }) 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 file, err := client.(*UnixConn).File() 69 if err != nil { 70 t.Fatal(err) 71 } 72 73 // At this point the descriptor should still be non-blocking. 74 rawconn, err = file.SyscallConn() 75 if err != nil { 76 t.Fatal(err) 77 } 78 err = rawconn.Control(func(fd uintptr) { 79 nonblock, err := unix.IsNonblock(int(fd)) 80 if err != nil { 81 t.Fatal(err) 82 } 83 if !nonblock { 84 t.Fatal("unix socket as os.File is in blocking mode") 85 } 86 }) 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 fd := file.Fd() 92 93 // Calling Fd should have put the descriptor into blocking mode. 94 nonblock, err := unix.IsNonblock(int(fd)) 95 if err != nil { 96 t.Fatal(err) 97 } 98 if nonblock { 99 t.Error("unix socket through os.File.Fd is non-blocking") 100 } 101} 102