forked from v2fly/v2ray-core
-
Notifications
You must be signed in to change notification settings - Fork 29
/
dokodemo.go
138 lines (119 loc) · 3.26 KB
/
dokodemo.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
126
127
128
129
130
131
132
133
134
135
136
137
138
package dokodemo
import (
"io"
"net"
"sync"
"github.com/v2ray/v2ray-core/app"
"github.com/v2ray/v2ray-core/common/alloc"
"github.com/v2ray/v2ray-core/common/log"
v2net "github.com/v2ray/v2ray-core/common/net"
"github.com/v2ray/v2ray-core/common/retry"
)
type DokodemoDoor struct {
config Config
accepting bool
address v2net.Address
space *app.Space
}
func NewDokodemoDoor(space *app.Space, config Config) *DokodemoDoor {
return &DokodemoDoor{
config: config,
space: space,
address: config.Address(),
}
}
func (this *DokodemoDoor) Listen(port v2net.Port) error {
this.accepting = true
if this.config.Network().HasNetwork(v2net.TCPNetwork) {
err := this.ListenTCP(port)
if err != nil {
return err
}
}
if this.config.Network().HasNetwork(v2net.UDPNetwork) {
err := this.ListenUDP(port)
if err != nil {
return err
}
}
return nil
}
func (this *DokodemoDoor) ListenUDP(port v2net.Port) error {
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
IP: []byte{0, 0, 0, 0},
Port: int(port),
Zone: "",
})
if err != nil {
log.Error("Dokodemo failed to listen on port %d: %v", port, err)
return err
}
go this.handleUDPPackets(udpConn)
return nil
}
func (this *DokodemoDoor) handleUDPPackets(udpConn *net.UDPConn) {
defer udpConn.Close()
for this.accepting {
buffer := alloc.NewBuffer()
nBytes, addr, err := udpConn.ReadFromUDP(buffer.Value)
buffer.Slice(0, nBytes)
if err != nil {
buffer.Release()
log.Error("Dokodemo failed to read from UDP: %v", err)
return
}
packet := v2net.NewPacket(v2net.NewUDPDestination(this.address), buffer, false)
ray := this.space.PacketDispatcher().DispatchToOutbound(packet)
close(ray.InboundInput())
for payload := range ray.InboundOutput() {
udpConn.WriteToUDP(payload.Value, addr)
}
}
}
func (this *DokodemoDoor) ListenTCP(port v2net.Port) error {
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: int(port),
Zone: "",
})
if err != nil {
log.Error("Dokodemo failed to listen on port %d: %v", port, err)
return err
}
go this.AcceptTCPConnections(tcpListener)
return nil
}
func (this *DokodemoDoor) AcceptTCPConnections(tcpListener *net.TCPListener) {
for this.accepting {
retry.Timed(100, 100).On(func() error {
connection, err := tcpListener.AcceptTCP()
if err != nil {
log.Error("Dokodemo failed to accept new connections: %v", err)
return err
}
go this.HandleTCPConnection(connection)
return nil
})
}
}
func (this *DokodemoDoor) HandleTCPConnection(conn *net.TCPConn) {
defer conn.Close()
packet := v2net.NewPacket(v2net.NewTCPDestination(this.address), nil, true)
ray := this.space.PacketDispatcher().DispatchToOutbound(packet)
var inputFinish, outputFinish sync.Mutex
inputFinish.Lock()
outputFinish.Lock()
reader := v2net.NewTimeOutReader(this.config.Timeout(), conn)
go dumpInput(reader, ray.InboundInput(), &inputFinish)
go dumpOutput(conn, ray.InboundOutput(), &outputFinish)
outputFinish.Lock()
}
func dumpInput(reader io.Reader, input chan<- *alloc.Buffer, finish *sync.Mutex) {
v2net.ReaderToChan(input, reader)
finish.Unlock()
close(input)
}
func dumpOutput(writer io.Writer, output <-chan *alloc.Buffer, finish *sync.Mutex) {
v2net.ChanToWriter(writer, output)
finish.Unlock()
}