Skip to content

Commit 798ec04

Browse files
committed
fix stdio "cannot listen", fix udp goroutine leak
1 parent 4f33489 commit 798ec04

File tree

6 files changed

+34
-18
lines changed

6 files changed

+34
-18
lines changed

client/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ func NewClient(c *Config) (*Client, error) {
138138
hasStdio = true
139139
}
140140
//confirm non-reverse tunnel is available
141-
if !r.Reverse && !r.CanListen() {
142-
return nil, fmt.Errorf("Remote %s cannot listen", r.String())
141+
if !r.Reverse && !r.Stdio && !r.CanListen() {
142+
return nil, fmt.Errorf("Client cannot listen on %s", r.String())
143143
}
144144
client.computed.Remotes = append(client.computed.Remotes, r)
145145
}

client/client_connect.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"io"
78
"net"
89
"strings"
910
"time"
@@ -29,8 +30,8 @@ func (c *Client) connectionLoop(ctx context.Context) error {
2930
//connection error
3031
attempt := int(b.Attempt())
3132
maxAttempt := c.config.MaxRetryCount
32-
if err != nil {
33-
//show error and attempt counts
33+
//show error message and attempt counts (excluding disconnects)
34+
if err != nil && err != io.EOF && !strings.HasSuffix(err.Error(), "use of closed network connection") {
3435
msg := fmt.Sprintf("Connection error: %s", err)
3536
if attempt > 0 {
3637
msg += fmt.Sprintf(" (Attempt: %d", attempt)

server/server_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, req *http.Request) {
128128
}
129129
//confirm reverse tunnel is available
130130
if r.Reverse && !r.CanListen() {
131-
failed(s.Errorf("Remote %s cannot listen", r.String()))
131+
failed(s.Errorf("Server cannot listen on %s", r.String()))
132132
return
133133
}
134134
}

share/tunnel/tunnel_out_ssh.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ func (t *Tunnel) handleSSHChannel(ch ssh.NewChannel) {
5151
t.Debugf("Failed to accept stream: %s", err)
5252
return
5353
}
54-
stream := io.ReadWriteCloser(sshChan) //cnet.MeterRWC(t.Logger.Fork("sshchan"), sshChan)
54+
stream := io.ReadWriteCloser(sshChan)
55+
//cnet.MeterRWC(t.Logger.Fork("sshchan"), sshChan)
5556
defer stream.Close()
5657
go ssh.DiscardRequests(reqs)
5758
l := t.Logger.Fork("conn#%d", t.connStats.New())

share/tunnel/tunnel_out_ssh_udp.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import (
1212
)
1313

1414
func (t *Tunnel) handleUDP(l *cio.Logger, rwc io.ReadWriteCloser, hostPort string) error {
15+
conns := &udpConns{
16+
Logger: l,
17+
m: map[string]*udpConn{},
18+
}
19+
defer conns.closeAll()
1520
h := &udpHandler{
1621
Logger: l,
1722
hostPort: hostPort,
@@ -20,10 +25,7 @@ func (t *Tunnel) handleUDP(l *cio.Logger, rwc io.ReadWriteCloser, hostPort strin
2025
w: gob.NewEncoder(rwc),
2126
c: rwc,
2227
},
23-
udpConns: &udpConns{
24-
Logger: l,
25-
m: map[string]*udpConn{},
26-
},
28+
udpConns: conns,
2729
}
2830
for {
2931
p := udpPacket{}
@@ -136,6 +138,15 @@ func (cs *udpConns) remove(id string) {
136138
cs.Unlock()
137139
}
138140

141+
func (cs *udpConns) closeAll() {
142+
cs.Lock()
143+
for id, conn := range cs.m {
144+
conn.Close()
145+
delete(cs.m, id)
146+
}
147+
cs.Unlock()
148+
}
149+
139150
type udpConn struct {
140151
id string
141152
net.Conn

test/e2e/setup_test.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"log"
77
"net"
88
"net/http"
9+
"os"
10+
"runtime"
11+
"runtime/pprof"
912
"strings"
1013
"testing"
1114
"time"
@@ -27,7 +30,7 @@ type testLayout struct {
2730

2831
func (tl *testLayout) setup(t *testing.T) (server *chserver.Server, client *chclient.Client, teardown func()) {
2932
//start of the world
30-
// goroutines := runtime.NumGoroutine()
33+
goroutines := runtime.NumGoroutine()
3134
//root cancel
3235
ctx, cancel := context.WithCancel(context.Background())
3336
//fileserver (fake endpoint)
@@ -97,13 +100,13 @@ func (tl *testLayout) setup(t *testing.T) (server *chserver.Server, client *chcl
97100
server.Wait()
98101
client.Wait()
99102
//confirm goroutines have been cleaned up
100-
// time.Sleep(1 * time.Second)
101-
//TODO remove sleep
102-
// d := runtime.NumGoroutine() - goroutines
103-
// if d != 0 {
104-
// pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
105-
// t.Fatalf("goroutines left %d", d)
106-
// }
103+
time.Sleep(500 * time.Millisecond)
104+
// TODO remove sleep
105+
d := runtime.NumGoroutine() - goroutines
106+
if d != 0 {
107+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
108+
t.Fatalf("goroutines left %d", d)
109+
}
107110
}
108111
//wait a bit...
109112
//TODO: client signal API, similar to os.Notify(signal)

0 commit comments

Comments
 (0)