Skip to content

Commit c0914d5

Browse files
os: add SyscallConn method for os.File
Fixes #24331 Change-Id: I119c09a4259d852cdf8ea31b3e03e6f09a5f7bda Reviewed-on: https://go-review.googlesource.com/c/155517 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 6a64efc commit c0914d5

File tree

7 files changed

+146
-1
lines changed

7 files changed

+146
-1
lines changed

src/os/file.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,12 @@ func (f *File) SetReadDeadline(t time.Time) error {
473473
func (f *File) SetWriteDeadline(t time.Time) error {
474474
return f.setWriteDeadline(t)
475475
}
476+
477+
// SyscallConn returns a raw file.
478+
// This implements the syscall.Conn interface.
479+
func (f *File) SyscallConn() (syscall.RawConn, error) {
480+
if err := f.checkValid("SyscallConn"); err != nil {
481+
return nil, err
482+
}
483+
return newRawConn(f)
484+
}

src/os/file_plan9.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,3 +534,21 @@ func (f *File) checkValid(op string) error {
534534
}
535535
return nil
536536
}
537+
538+
type rawConn struct{}
539+
540+
func (c *rawConn) Control(f func(uintptr)) error {
541+
return syscall.EPLAN9
542+
}
543+
544+
func (c *rawConn) Read(f func(uintptr) bool) error {
545+
return syscall.EPLAN9
546+
}
547+
548+
func (c *rawConn) Write(f func(uintptr) bool) error {
549+
return syscall.EPLAN9
550+
}
551+
552+
func newRawConn(file *File) (*rawConn, error) {
553+
return nil, syscall.EPLAN9
554+
}

src/os/os_unix_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ func init() {
2222
isReadonlyError = func(err error) bool { return err == syscall.EROFS }
2323
}
2424

25+
// For TestRawConnReadWrite.
26+
type syscallDescriptor = int
27+
2528
func checkUidGid(t *testing.T, path string, uid, gid int) {
2629
dir, err := Lstat(path)
2730
if err != nil {

src/os/os_windows_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import (
2626
"unsafe"
2727
)
2828

29+
// For TestRawConnReadWrite.
30+
type syscallDescriptor = syscall.Handle
31+
2932
func TestSameWindowsFile(t *testing.T) {
3033
temp, err := ioutil.TempDir("", "TestSameWindowsFile")
3134
if err != nil {

src/os/rawconn.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2018 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 !plan9
6+
7+
package os
8+
9+
import (
10+
"runtime"
11+
)
12+
13+
// rawConn implements syscall.RawConn.
14+
type rawConn struct {
15+
file *File
16+
}
17+
18+
func (c *rawConn) Control(f func(uintptr)) error {
19+
if err := c.file.checkValid("SyscallConn.Control"); err != nil {
20+
return err
21+
}
22+
err := c.file.pfd.RawControl(f)
23+
runtime.KeepAlive(c.file)
24+
return err
25+
}
26+
27+
func (c *rawConn) Read(f func(uintptr) bool) error {
28+
if err := c.file.checkValid("SyscallConn.Read"); err != nil {
29+
return err
30+
}
31+
err := c.file.pfd.RawRead(f)
32+
runtime.KeepAlive(c.file)
33+
return err
34+
}
35+
36+
func (c *rawConn) Write(f func(uintptr) bool) error {
37+
if err := c.file.checkValid("SyscallConn.Write"); err != nil {
38+
return err
39+
}
40+
err := c.file.pfd.RawWrite(f)
41+
runtime.KeepAlive(c.file)
42+
return err
43+
}
44+
45+
func newRawConn(file *File) (*rawConn, error) {
46+
return &rawConn{file: file}, nil
47+
}

src/os/rawconn_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2018 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+
// Test use of raw connections.
6+
// +build !plan9,!nacl,!js
7+
8+
package os_test
9+
10+
import (
11+
"os"
12+
"syscall"
13+
"testing"
14+
)
15+
16+
func TestRawConnReadWrite(t *testing.T) {
17+
t.Parallel()
18+
19+
r, w, err := os.Pipe()
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
defer r.Close()
24+
defer w.Close()
25+
26+
rconn, err := r.SyscallConn()
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
wconn, err := w.SyscallConn()
31+
if err != nil {
32+
t.Fatal(err)
33+
}
34+
35+
var operr error
36+
err = wconn.Write(func(s uintptr) bool {
37+
_, operr = syscall.Write(syscallDescriptor(s), []byte{'b'})
38+
return operr != syscall.EAGAIN
39+
})
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
if operr != nil {
44+
t.Fatal(err)
45+
}
46+
47+
var n int
48+
buf := make([]byte, 1)
49+
err = rconn.Read(func(s uintptr) bool {
50+
n, operr = syscall.Read(syscallDescriptor(s), buf)
51+
return operr != syscall.EAGAIN
52+
})
53+
if err != nil {
54+
t.Fatal(err)
55+
}
56+
if operr != nil {
57+
t.Fatal(operr)
58+
}
59+
if n != 1 {
60+
t.Errorf("read %d bytes, expected 1", n)
61+
}
62+
if buf[0] != 'b' {
63+
t.Errorf("read %q, expected %q", buf, "b")
64+
}
65+
}

src/syscall/net.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type RawConn interface {
2626
Write(f func(fd uintptr) (done bool)) error
2727
}
2828

29-
// Conn is implemented by some types in the net package to provide
29+
// Conn is implemented by some types in the net and os packages to provide
3030
// access to the underlying file descriptor or handle.
3131
type Conn interface {
3232
// SyscallConn returns a raw network connection.

0 commit comments

Comments
 (0)