Skip to content

Commit 19df653

Browse files
NZSmartieLexicality
authored andcommitted
Support polling sockets and general house-keeping
1 parent 5c0215e commit 19df653

File tree

1 file changed

+86
-66
lines changed

1 file changed

+86
-66
lines changed

npiperelay.go

Lines changed: 86 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import (
1717

1818
const cERROR_PIPE_NOT_CONNECTED syscall.Errno = 233
1919

20+
const WSAECONNREFUSED syscall.Errno = 10061
21+
const WSAENETUNREACH syscall.Errno = 10051
22+
const WSAETIMEDOUT syscall.Errno = 10060
23+
const ERROR_CONNECTION_REFUSED syscall.Errno = 1225
24+
2025
var (
2126
poll = flag.Bool("p", false, "poll until the the named pipe exists")
2227
closeWrite = flag.Bool("s", false, "send a 0-byte message to the pipe after EOF on stdin")
@@ -30,60 +35,46 @@ func dialPipe(p string, poll bool) (*overlappedFile, error) {
3035
if err != nil {
3136
return nil, err
3237
}
33-
for {
34-
h, err := windows.CreateFile(&p16[0], windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OVERLAPPED, 0)
35-
if err == nil {
36-
return newOverlappedFile(h), nil
37-
}
38-
if poll && os.IsNotExist(err) {
39-
time.Sleep(200 * time.Millisecond)
40-
continue
41-
}
42-
return nil, &os.PathError{Path: p, Op: "open", Err: err}
38+
39+
h, err := windows.CreateFile(&p16[0], windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, windows.FILE_FLAG_OVERLAPPED, 0)
40+
if err == nil {
41+
return newOverlappedFile(h), nil
4342
}
43+
44+
return nil, err
4445
}
4546

4647
func dialPort(p int, poll bool) (*overlappedFile, error) {
4748
if p < 0 || p > 65535 {
4849
return nil, errors.New("Invalid port value")
4950
}
5051

51-
for {
52-
h, err := windows.Socket(windows.AF_INET, windows.SOCK_STREAM, 0)
53-
if err != nil {
54-
return nil, err
55-
}
56-
57-
// Create a SockaddrInet4 for connecting to
58-
sa := &windows.SockaddrInet4{Addr: [4]byte{0x7F, 0x00, 0x00, 0x01}, Port: p}
59-
if err != nil {
60-
return nil, err
61-
}
62-
63-
// Bind to a randomly assigned port
64-
err = windows.Bind(h, &windows.SockaddrInet4{})
65-
if err != nil {
66-
return nil, err
67-
}
68-
69-
conn := newOverlappedFile(h)
52+
h, err := windows.Socket(windows.AF_INET, windows.SOCK_STREAM, 0)
53+
if err != nil {
54+
return nil, err
55+
}
7056

71-
_, err = conn.asyncIo(func(h windows.Handle, n *uint32, o *windows.Overlapped) error {
72-
return windows.ConnectEx(h, sa, nil, 0, nil, o)
73-
})
74-
err = os.NewSyscallError("connectEx", err)
57+
// Create a SockaddrInet4 for connecting to
58+
sa := &windows.SockaddrInet4{Addr: [4]byte{0x7F, 0x00, 0x00, 0x01}, Port: p}
7559

76-
if err == nil {
77-
return conn, nil
78-
}
60+
// Bind to a randomly assigned local port
61+
err = windows.Bind(h, &windows.SockaddrInet4{})
62+
if err != nil {
63+
return nil, err
64+
}
7965

80-
if poll && os.IsNotExist(err) {
81-
time.Sleep(200 * time.Millisecond)
82-
continue
83-
}
66+
// Wrap our socket up to be properly handled
67+
conn := newOverlappedFile(h)
8468

85-
return nil, err
69+
// Connect to the LibAssuan socket using overlapped ConnectEx operation
70+
_, err = conn.asyncIo(func(h windows.Handle, n *uint32, o *windows.Overlapped) error {
71+
return windows.ConnectEx(h, sa, nil, 0, nil, o)
72+
})
73+
if err == nil {
74+
return conn, nil
8675
}
76+
77+
return nil, err
8778
}
8879

8980
func underlyingError(err error) error {
@@ -105,44 +96,73 @@ func main() {
10596
log.Println("connecting to", args[0])
10697
}
10798

108-
conn, err := dialPipe(args[0], *poll)
109-
if err != nil {
110-
log.Fatalln(err)
111-
}
99+
var conn *overlappedFile
100+
var err error
112101

113-
if !strings.HasPrefix("//./", args[0]) {
114-
tmp := make([]byte, 22) // 5 bytes for ascii port number, 1 for newline, 16 for nonce
102+
// Loop only if we're polling the named pipe or socket
103+
for {
104+
conn, err = dialPipe(args[0], *poll)
115105

116-
var port int
117-
nonce := make([]byte, 16)
106+
if *poll && os.IsNotExist(err) {
107+
time.Sleep(200 * time.Millisecond)
108+
continue
109+
}
118110

119-
// Check if file is a LibAssuane socket
120-
_, err := conn.Read(tmp)
121111
if err != nil {
122-
log.Fatalln("Could not open socket", err)
112+
err = &os.PathError{Path: args[0], Op: "open", Err: err}
113+
log.Fatalln(err)
123114
}
124115

125-
for i, c := range tmp {
126-
// Find the new line
127-
if c == 0x0A {
128-
port, _ = strconv.Atoi(string(tmp[:i]))
129-
copy(nonce, tmp[i+1:])
116+
// Not a named pipe, so attempt to read contents and connect to a TCP port for LibAssaaun
117+
if !strings.HasPrefix("//./", args[0]) {
118+
tmp := make([]byte, 22) // 5 bytes for ascii port number, 1 for newline, 16 for nonce
119+
120+
var port int
121+
var nonce [16]byte
122+
123+
_, err := conn.Read(tmp)
124+
if err != nil {
125+
log.Fatalln("Could not open file", err)
126+
}
127+
128+
for i, c := range tmp {
129+
// Find the new line
130+
if c == 0x0A {
131+
port, err = strconv.Atoi(string(tmp[:i]))
132+
if err != nil {
133+
log.Fatalln(err)
134+
}
135+
136+
copy(nonce[:], tmp[i+1:])
130137

131-
if *verbose {
132-
log.Printf("Port: %d, Nonce: %X", port, nonce)
138+
if *verbose {
139+
log.Printf("Port: %d, Nonce: %X", port, nonce)
140+
}
141+
break
133142
}
134-
break
135143
}
136-
}
137144

138-
_ = conn.Close()
145+
_ = conn.Close()
139146

140-
conn, err = dialPort(port, *poll)
147+
conn, err = dialPort(port, *poll)
141148

142-
_, err = conn.Write(nonce)
143-
if err != nil {
144-
log.Fatal(err)
149+
if *poll && (err == WSAETIMEDOUT || err == WSAECONNREFUSED || err == WSAENETUNREACH || err == ERROR_CONNECTION_REFUSED) {
150+
time.Sleep(200 * time.Millisecond)
151+
continue
152+
}
153+
154+
err = os.NewSyscallError("ConnectEx", err)
155+
156+
if err != nil {
157+
log.Fatal(err)
158+
}
159+
160+
_, err = conn.Write(nonce[:])
161+
if err != nil {
162+
log.Fatal(err)
163+
}
145164
}
165+
break
146166
}
147167

148168
if *verbose {

0 commit comments

Comments
 (0)