github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/fdchannel/fdchannel_test.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fdchannel 16 17 import ( 18 "io/ioutil" 19 "os" 20 "syscall" 21 "testing" 22 "time" 23 24 "golang.org/x/sys/unix" 25 "github.com/SagerNet/gvisor/pkg/sync" 26 ) 27 28 func TestSendRecvFD(t *testing.T) { 29 sendFile, err := ioutil.TempFile("", "fdchannel_test_") 30 if err != nil { 31 t.Fatalf("failed to create temporary file: %v", err) 32 } 33 defer sendFile.Close() 34 35 chanFDs, err := NewConnectedSockets() 36 if err != nil { 37 t.Fatalf("failed to create fdchannel sockets: %v", err) 38 } 39 sendEP := NewEndpoint(chanFDs[0]) 40 defer sendEP.Destroy() 41 recvEP := NewEndpoint(chanFDs[1]) 42 defer recvEP.Destroy() 43 44 recvFD, err := recvEP.RecvFDNonblock() 45 if err != unix.EAGAIN && err != unix.EWOULDBLOCK { 46 t.Errorf("RecvFDNonblock before SendFD: got (%d, %v), wanted (<unspecified>, EAGAIN or EWOULDBLOCK", recvFD, err) 47 } 48 49 if err := sendEP.SendFD(int(sendFile.Fd())); err != nil { 50 t.Fatalf("SendFD failed: %v", err) 51 } 52 recvFD, err = recvEP.RecvFD() 53 if err != nil { 54 t.Fatalf("RecvFD failed: %v", err) 55 } 56 recvFile := os.NewFile(uintptr(recvFD), "received file") 57 defer recvFile.Close() 58 59 sendInfo, err := sendFile.Stat() 60 if err != nil { 61 t.Fatalf("failed to stat sent file: %v", err) 62 } 63 sendInfoSys := sendInfo.Sys() 64 sendStat, ok := sendInfoSys.(*syscall.Stat_t) 65 if !ok { 66 t.Fatalf("sent file's FileInfo is backed by unknown type %T", sendInfoSys) 67 } 68 69 recvInfo, err := recvFile.Stat() 70 if err != nil { 71 t.Fatalf("failed to stat received file: %v", err) 72 } 73 recvInfoSys := recvInfo.Sys() 74 recvStat, ok := recvInfoSys.(*syscall.Stat_t) 75 if !ok { 76 t.Fatalf("received file's FileInfo is backed by unknown type %T", recvInfoSys) 77 } 78 79 if sendStat.Dev != recvStat.Dev || sendStat.Ino != recvStat.Ino { 80 t.Errorf("sent file (dev=%d, ino=%d) does not match received file (dev=%d, ino=%d)", sendStat.Dev, sendStat.Ino, recvStat.Dev, recvStat.Ino) 81 } 82 } 83 84 func TestShutdownThenRecvFD(t *testing.T) { 85 sendFile, err := ioutil.TempFile("", "fdchannel_test_") 86 if err != nil { 87 t.Fatalf("failed to create temporary file: %v", err) 88 } 89 defer sendFile.Close() 90 91 chanFDs, err := NewConnectedSockets() 92 if err != nil { 93 t.Fatalf("failed to create fdchannel sockets: %v", err) 94 } 95 sendEP := NewEndpoint(chanFDs[0]) 96 defer sendEP.Destroy() 97 recvEP := NewEndpoint(chanFDs[1]) 98 defer recvEP.Destroy() 99 100 recvEP.Shutdown() 101 if _, err := recvEP.RecvFD(); err == nil { 102 t.Error("RecvFD succeeded unexpectedly") 103 } 104 } 105 106 func TestRecvFDThenShutdown(t *testing.T) { 107 sendFile, err := ioutil.TempFile("", "fdchannel_test_") 108 if err != nil { 109 t.Fatalf("failed to create temporary file: %v", err) 110 } 111 defer sendFile.Close() 112 113 chanFDs, err := NewConnectedSockets() 114 if err != nil { 115 t.Fatalf("failed to create fdchannel sockets: %v", err) 116 } 117 sendEP := NewEndpoint(chanFDs[0]) 118 defer sendEP.Destroy() 119 recvEP := NewEndpoint(chanFDs[1]) 120 defer recvEP.Destroy() 121 122 var receiverWG sync.WaitGroup 123 receiverWG.Add(1) 124 go func() { 125 defer receiverWG.Done() 126 if _, err := recvEP.RecvFD(); err == nil { 127 t.Error("RecvFD succeeded unexpectedly") 128 } 129 }() 130 defer receiverWG.Wait() 131 time.Sleep(time.Second) // to ensure recvEP.RecvFD() has blocked 132 recvEP.Shutdown() 133 }