-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.go
More file actions
121 lines (99 loc) · 2.31 KB
/
server.go
File metadata and controls
121 lines (99 loc) · 2.31 KB
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
package main
import (
"context"
"errors"
"fmt"
"io"
"log"
"net"
"sync"
"time"
"github.com/dblokhin/proxyme"
)
// todo: make it configurable?
var keepAliveConfig = net.KeepAliveConfig{
Enable: true,
Idle: 20 * time.Second,
Interval: 5 * time.Second,
Count: 5,
}
type server struct {
protocol *proxyme.SOCKS5
}
// ListenAndServe starts listening incoming connection for SOCKS5 clients.
// Use context for graceful shutdown.
func (s server) ListenAndServe(ctx context.Context, address string) error {
lc := net.ListenConfig{}
ls, err := lc.Listen(ctx, "tcp", address)
if err != nil {
return fmt.Errorf("listen: %w", err)
}
go func() {
// don't forget to close listener by ctx
<-ctx.Done()
_ = ls.Close()
}()
var wg sync.WaitGroup
defer func() {
log.Println("waiting all connections be closed")
wg.Wait()
}()
for {
conn, err := ls.Accept()
if err != nil {
var ne net.Error
if errors.As(err, &ne) && ne.Timeout() {
time.Sleep(time.Second / 5) // nolint
continue
}
return fmt.Errorf("accept: %w", err)
}
wg.Add(1)
go func() {
defer wg.Done()
s.serve(ctx, conn.(*net.TCPConn))
}()
}
}
func (s server) serve(ctx context.Context, tcpConn *net.TCPConn) {
_ = tcpConn.SetLinger(0)
_ = tcpConn.SetKeepAliveConfig(keepAliveConfig)
// set up deadline for idle connections
conn := tcpConnWithTimeout{
TCPConn: tcpConn,
timeout: time.Hour,
}
done := make(chan any)
// run socks
go func() {
s.protocol.Handle(conn, func(err error) {
log.Println(err)
})
close(done)
}()
select {
case <-ctx.Done():
case <-done:
}
_ = conn.Close()
}
type tcpConnWithTimeout struct {
*net.TCPConn
timeout time.Duration
}
func (t tcpConnWithTimeout) ReadFrom(r io.Reader) (n int64, err error) {
_ = t.TCPConn.SetDeadline(time.Now().Add(t.timeout)) // nolint
return t.TCPConn.ReadFrom(r)
}
func (t tcpConnWithTimeout) WriteTo(w io.Writer) (n int64, err error) {
_ = t.TCPConn.SetDeadline(time.Now().Add(t.timeout)) // nolint
return t.TCPConn.WriteTo(w)
}
func (t tcpConnWithTimeout) Write(p []byte) (n int, err error) {
_ = t.TCPConn.SetDeadline(time.Now().Add(t.timeout)) // nolint
return t.TCPConn.Write(p)
}
func (t tcpConnWithTimeout) Read(p []byte) (n int, err error) {
_ = t.TCPConn.SetDeadline(time.Now().Add(t.timeout)) // nolint
return t.TCPConn.Read(p)
}