forked from anon55555/mt
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathproto.go
103 lines (84 loc) · 1.9 KB
/
proto.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
package mt
import (
"fmt"
"io"
"net"
"github.com/dragonfireclient/mt/rudp"
)
// A Pkt is a deserialized rudp.Pkt.
type Pkt struct {
Cmd
rudp.PktInfo
}
// Peer wraps rudp.Conn, adding (de)serialization.
type Peer struct {
*rudp.Conn
}
func (p Peer) Send(pkt Pkt) (ack <-chan struct{}, err error) {
var cmdNo uint16
if p.IsSrv() {
cmdNo = pkt.Cmd.(ToSrvCmd).toSrvCmdNo()
} else {
cmdNo = pkt.Cmd.(ToCltCmd).toCltCmdNo()
}
if cmdNo == 0xffff {
return nil, p.Close()
}
r, w := io.Pipe()
go func() (err error) {
defer w.CloseWithError(err)
buf := make([]byte, 2)
be.PutUint16(buf, cmdNo)
if _, err := w.Write(buf); err != nil {
return err
}
return serialize(w, pkt.Cmd)
}()
return p.Conn.Send(rudp.Pkt{r, pkt.PktInfo})
}
// SendCmd is equivalent to Send(Pkt{cmd, cmd.DefaultPktInfo()}).
func (p Peer) SendCmd(cmd Cmd) (ack <-chan struct{}, err error) {
return p.Send(Pkt{cmd, cmd.DefaultPktInfo()})
}
func (p Peer) Recv() (_ Pkt, rerr error) {
pkt, err := p.Conn.Recv()
if err != nil {
return Pkt{}, err
}
buf := make([]byte, 2)
if _, err := io.ReadFull(pkt, buf); err != nil {
return Pkt{}, err
}
cmdNo := be.Uint16(buf)
var newCmd func() Cmd
if p.IsSrv() {
newCmd = newToCltCmd[cmdNo]
} else {
newCmd = newToSrvCmd[cmdNo]
}
if newCmd == nil {
return Pkt{}, fmt.Errorf("unknown cmd: %d", cmdNo)
}
cmd := newCmd()
if err := deserialize(pkt, cmd); err != nil {
return Pkt{}, fmt.Errorf("%T: %w", cmd, err)
}
extra, err := io.ReadAll(pkt)
if len(extra) > 0 {
err = fmt.Errorf("%T: %w", cmd, rudp.TrailingDataError(extra))
}
return Pkt{cmd, pkt.PktInfo}, err
}
func Connect(conn net.Conn) Peer {
return Peer{rudp.Connect(conn)}
}
type Listener struct {
*rudp.Listener
}
func Listen(conn net.PacketConn) Listener {
return Listener{rudp.Listen(conn)}
}
func (l Listener) Accept() (Peer, error) {
rpeer, err := l.Listener.Accept()
return Peer{rpeer}, err
}