-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathclient.go
144 lines (134 loc) · 3.48 KB
/
client.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
139
140
141
142
143
144
package quic
import (
"errors"
"fmt"
"net"
"time"
"github.com/goburrow/quic/transport"
)
// Client is a client-side QUIC connection.
// All setters must only be invoked before calling Serve.
type Client struct {
localConn
}
// NewClient creates a new QUIC client.
func NewClient(config *transport.Config) *Client {
c := &Client{}
c.localConn.init(config)
return c
}
// ListenAndServe starts listening on UDP network address addr and
// serves incoming packets. Unlike Server.ListenAndServe, this function
// does not block as Serve is invoked in a goroutine.
func (s *Client) ListenAndServe(addr string) error {
socket, err := net.ListenPacket("udp", addr)
s.socket = socket
if err == nil {
go s.Serve()
}
return err
}
// Serve handles requests from given socket.
func (s *Client) Serve() error {
if s.socket == nil {
return errors.New("no listening connection")
}
for {
p := newPacket()
err := readPacket(p, s.socket)
if len(p.data) > 0 {
s.recv(p)
} else {
freePacket(p)
}
if err != nil {
return err
}
}
}
func (s *Client) recv(p *packet) {
_, err := p.header.Decode(p.data, s.cidIss.CIDLength())
if err != nil {
s.logger.log(levelTrace, zs("", "transport:datagrams_received"),
zv("addr", p.addr), zx("raw", p.data))
s.logger.log(levelDebug, zs("", "transport:packet_dropped"),
zv("addr", p.addr), zi("packet_size", len(p.data)), zs("trigger", "header_parse_error"), ze("message", err))
freePacket(p)
return
}
s.logger.log(levelTrace, zs("", "transport:datagrams_received"),
zx("cid", p.header.DCID), zv("addr", p.addr), zx("raw", p.data))
s.peersMu.RLock()
if s.closing {
// Server is closing
s.peersMu.RUnlock()
return
}
c := s.peers[string(p.header.DCID)]
s.peersMu.RUnlock()
if c == nil {
s.logger.log(levelDebug, zs("", "transport:packet_dropped"),
zx("cid", p.header.DCID), zv("addr", p.addr), zs("trigger", "unknown_connection_id"), zv("", &p.header))
freePacket(p)
} else {
c.recvCh <- p
}
}
// Connect establishes a new connection to UDP network address addr.
func (s *Client) Connect(addr string) error {
udpAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return err
}
c, err := s.newConn(udpAddr)
if err != nil {
return err
}
s.peersMu.Lock()
if s.closing {
s.peersMu.Unlock()
return fmt.Errorf("client is already closed")
}
if _, ok := s.peers[string(c.scid)]; ok {
s.peersMu.Unlock()
return fmt.Errorf("connection id conflict cid=%x", c.scid)
}
s.peers[string(c.scid)] = c
s.peersMu.Unlock()
// Send initial packet
s.logger.log(levelInfo, zs("", "connectivity:connection_started"),
zx("cid", c.scid), zv("addr", c.addr), zs("vantage_point", "client"))
if err = s.connSend(c); err != nil {
s.peersMu.Lock()
delete(s.peers, string(c.scid))
s.peersMu.Unlock()
return fmt.Errorf("send %s: %v", c.addr, err)
}
go s.handleConn(c)
return nil
}
// Close closes all current established connections and listening socket.
func (s *Client) Close() error {
s.close(10 * time.Second)
if s.socket != nil {
return s.socket.Close()
}
return nil
}
func (s *Client) newConn(addr net.Addr) (*Conn, error) {
scid, err := s.cidIss.NewCID()
if err != nil {
return nil, fmt.Errorf("generate connection id: %v", err)
}
dcid, err := s.cidIss.NewCID()
if err != nil {
return nil, fmt.Errorf("generate connection id: %v", err)
}
conn, err := transport.Connect(scid, dcid, s.config)
if err != nil {
return nil, err
}
c := newRemoteConn(addr, scid, conn, true)
s.logger.attachLogger(c)
return c, nil
}