change the sysroot and c++ include path to fix the bugs the application cannot find...
[platform/upstream/gcc48.git] / libgo / go / syscall / passfd_test.go
1 // Copyright 2012 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 darwin freebsd netbsd openbsd
6
7 package syscall_test
8
9 import (
10         "flag"
11         "fmt"
12         "io/ioutil"
13         "net"
14         "os"
15         "os/exec"
16         "syscall"
17         "testing"
18         "time"
19 )
20
21 // TestPassFD tests passing a file descriptor over a Unix socket.
22 //
23 // This test involved both a parent and child process. The parent
24 // process is invoked as a normal test, with "go test", which then
25 // runs the child process by running the current test binary with args
26 // "-test.run=^TestPassFD$" and an environment variable used to signal
27 // that the test should become the child process instead.
28 func TestPassFD(t *testing.T) {
29         if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
30                 passFDChild()
31                 return
32         }
33
34         tempDir, err := ioutil.TempDir("", "TestPassFD")
35         if err != nil {
36                 t.Fatal(err)
37         }
38         defer os.RemoveAll(tempDir)
39
40         fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
41         if err != nil {
42                 t.Fatalf("Socketpair: %v", err)
43         }
44         defer syscall.Close(fds[0])
45         defer syscall.Close(fds[1])
46         writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
47         readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
48         defer writeFile.Close()
49         defer readFile.Close()
50
51         cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
52         cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
53         path := os.Getenv("LD_LIBRARY_PATH")
54         if path != "" {
55                 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+path)
56         }
57         cmd.ExtraFiles = []*os.File{writeFile}
58
59         out, err := cmd.CombinedOutput()
60         if len(out) > 0 || err != nil {
61                 t.Fatalf("child process: %q, %v", out, err)
62         }
63
64         c, err := net.FileConn(readFile)
65         if err != nil {
66                 t.Fatalf("FileConn: %v", err)
67         }
68         defer c.Close()
69
70         uc, ok := c.(*net.UnixConn)
71         if !ok {
72                 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
73         }
74
75         buf := make([]byte, 32) // expect 1 byte
76         oob := make([]byte, 32) // expect 24 bytes
77         closeUnix := time.AfterFunc(5*time.Second, func() {
78                 t.Logf("timeout reading from unix socket")
79                 uc.Close()
80         })
81         _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
82         closeUnix.Stop()
83
84         scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
85         if err != nil {
86                 t.Fatalf("ParseSocketControlMessage: %v", err)
87         }
88         if len(scms) != 1 {
89                 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
90         }
91         scm := scms[0]
92         gotFds, err := syscall.ParseUnixRights(&scm)
93         if err != nil {
94                 t.Fatalf("syscall.ParseUnixRights: %v", err)
95         }
96         if len(gotFds) != 1 {
97                 t.Fatalf("wanted 1 fd; got %#v", gotFds)
98         }
99
100         f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
101         defer f.Close()
102
103         got, err := ioutil.ReadAll(f)
104         want := "Hello from child process!\n"
105         if string(got) != want {
106                 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
107         }
108 }
109
110 // passFDChild is the child process used by TestPassFD.
111 func passFDChild() {
112         defer os.Exit(0)
113
114         // Look for our fd. It should be fd 3, but we work around an fd leak
115         // bug here (http://golang.org/issue/2603) to let it be elsewhere.
116         var uc *net.UnixConn
117         for fd := uintptr(3); fd <= 10; fd++ {
118                 f := os.NewFile(fd, "unix-conn")
119                 var ok bool
120                 netc, _ := net.FileConn(f)
121                 uc, ok = netc.(*net.UnixConn)
122                 if ok {
123                         break
124                 }
125         }
126         if uc == nil {
127                 fmt.Println("failed to find unix fd")
128                 return
129         }
130
131         // Make a file f to send to our parent process on uc.
132         // We make it in tempDir, which our parent will clean up.
133         flag.Parse()
134         tempDir := flag.Arg(0)
135         f, err := ioutil.TempFile(tempDir, "")
136         if err != nil {
137                 fmt.Printf("TempFile: %v", err)
138                 return
139         }
140
141         f.Write([]byte("Hello from child process!\n"))
142         f.Seek(0, 0)
143
144         rights := syscall.UnixRights(int(f.Fd()))
145         dummyByte := []byte("x")
146         n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
147         if err != nil {
148                 fmt.Printf("WriteMsgUnix: %v", err)
149                 return
150         }
151         if n != 1 || oobn != len(rights) {
152                 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
153                 return
154         }
155 }
156
157 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
158 // and ParseUnixRights are able to successfully round-trip lists of file descriptors.
159 func TestUnixRightsRoundtrip(t *testing.T) {
160         testCases := [...][][]int{
161                 {{42}},
162                 {{1, 2}},
163                 {{3, 4, 5}},
164                 {{}},
165                 {{1, 2}, {3, 4, 5}, {}, {7}},
166         }
167         for _, testCase := range testCases {
168                 b := []byte{}
169                 var n int
170                 for _, fds := range testCase {
171                         // Last assignment to n wins
172                         n = len(b) + syscall.CmsgLen(4*len(fds))
173                         b = append(b, syscall.UnixRights(fds...)...)
174                 }
175                 // Truncate b
176                 b = b[:n]
177
178                 scms, err := syscall.ParseSocketControlMessage(b)
179                 if err != nil {
180                         t.Fatalf("ParseSocketControlMessage: %v", err)
181                 }
182                 if len(scms) != len(testCase) {
183                         t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
184                 }
185                 for i, scm := range scms {
186                         gotFds, err := syscall.ParseUnixRights(&scm)
187                         if err != nil {
188                                 t.Fatalf("ParseUnixRights: %v", err)
189                         }
190                         wantFds := testCase[i]
191                         if len(gotFds) != len(wantFds) {
192                                 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
193                         }
194                         for j, fd := range gotFds {
195                                 if fd != wantFds[j] {
196                                         t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
197                                 }
198                         }
199                 }
200         }
201 }