-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
safesocket_plan9.go
125 lines (104 loc) · 2.88 KB
/
safesocket_plan9.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build plan9
package safesocket
import (
"context"
"fmt"
"net"
"os"
"syscall"
"time"
"golang.org/x/sys/plan9"
)
// Plan 9's devsrv srv(3) is a server registry and
// it is conventionally bound to "/srv" in the default
// namespace. It is "a one level directory for holding
// already open channels to services". Post one end of
// a pipe to "/srv/tailscale.sock" and use the other
// end for communication with a requestor. Plan 9 pipes
// are bidirectional.
type plan9SrvAddr string
func (sl plan9SrvAddr) Network() string {
return "/srv"
}
func (sl plan9SrvAddr) String() string {
return string(sl)
}
// There is no net.FileListener for Plan 9 at this time
type plan9SrvListener struct {
name string
srvf *os.File
file *os.File
}
func (sl *plan9SrvListener) Accept() (net.Conn, error) {
// sl.file is the server end of the pipe that's
// connected to /srv/tailscale.sock
return plan9FileConn{name: sl.name, file: sl.file}, nil
}
func (sl *plan9SrvListener) Close() error {
sl.file.Close()
return sl.srvf.Close()
}
func (sl *plan9SrvListener) Addr() net.Addr {
return plan9SrvAddr(sl.name)
}
type plan9FileConn struct {
name string
file *os.File
}
func (fc plan9FileConn) Read(b []byte) (n int, err error) {
return fc.file.Read(b)
}
func (fc plan9FileConn) Write(b []byte) (n int, err error) {
return fc.file.Write(b)
}
func (fc plan9FileConn) Close() error {
return fc.file.Close()
}
func (fc plan9FileConn) LocalAddr() net.Addr {
return plan9SrvAddr(fc.name)
}
func (fc plan9FileConn) RemoteAddr() net.Addr {
return plan9SrvAddr(fc.name)
}
func (fc plan9FileConn) SetDeadline(t time.Time) error {
return syscall.EPLAN9
}
func (fc plan9FileConn) SetReadDeadline(t time.Time) error {
return syscall.EPLAN9
}
func (fc plan9FileConn) SetWriteDeadline(t time.Time) error {
return syscall.EPLAN9
}
func connect(_ context.Context, path string) (net.Conn, error) {
f, err := os.OpenFile(path, os.O_RDWR, 0666)
if err != nil {
return nil, err
}
return plan9FileConn{name: path, file: f}, nil
}
// Create an entry in /srv, open a pipe, write the
// client end to the entry and return the server
// end of the pipe to the caller. When the server
// end of the pipe is closed, /srv name associated
// with it will be removed (controlled by ORCLOSE flag)
func listen(path string) (net.Listener, error) {
const O_RCLOSE = 64 // remove on close; should be in plan9 package
var pip [2]int
err := plan9.Pipe(pip[:])
if err != nil {
return nil, err
}
defer plan9.Close(pip[1])
srvfd, err := plan9.Create(path, plan9.O_WRONLY|plan9.O_CLOEXEC|O_RCLOSE, 0600)
if err != nil {
return nil, err
}
srv := os.NewFile(uintptr(srvfd), path)
_, err = fmt.Fprintf(srv, "%d", pip[1])
if err != nil {
return nil, err
}
return &plan9SrvListener{name: path, srvf: srv, file: os.NewFile(uintptr(pip[0]), path)}, nil
}