5
5
"encoding/json"
6
6
"errors"
7
7
"fmt"
8
+ "log"
8
9
"net"
9
10
"time"
10
11
@@ -13,7 +14,24 @@ import (
13
14
14
15
type ExchangeCandidatesFun func ([]byte ) []byte
15
16
16
- func Connect (xchg ExchangeCandidatesFun , initiator bool ) (net.Conn , error ) {
17
+ type Config struct {
18
+ ProbeTimeout time.Duration
19
+ ProbeInterval time.Duration
20
+ DecisionTime time.Duration
21
+ PeerDeadline time.Duration
22
+ Verbose bool
23
+ }
24
+
25
+ func DefaultConfig () * Config {
26
+ return & Config {
27
+ ProbeTimeout : 500 * time .Millisecond ,
28
+ ProbeInterval : 100 * time .Millisecond ,
29
+ DecisionTime : 2 * time .Second ,
30
+ PeerDeadline : 5 * time .Second ,
31
+ }
32
+ }
33
+
34
+ func ConnectOpt (xchg ExchangeCandidatesFun , initiator bool , cfg * Config ) (net.Conn , error ) {
17
35
sock , err := net .ListenUDP ("udp" , & net.UDPAddr {})
18
36
if err != nil {
19
37
return nil , err
@@ -22,7 +40,9 @@ func Connect(xchg ExchangeCandidatesFun, initiator bool) (net.Conn, error) {
22
40
engine := & attemptEngine {
23
41
xchg : xchg ,
24
42
sock : sock ,
25
- initiator : initiator }
43
+ initiator : initiator ,
44
+ cfg : cfg ,
45
+ }
26
46
27
47
conn , err := engine .run ()
28
48
if err != nil {
@@ -32,6 +52,10 @@ func Connect(xchg ExchangeCandidatesFun, initiator bool) (net.Conn, error) {
32
52
return conn , nil
33
53
}
34
54
55
+ func Connect (xchg ExchangeCandidatesFun , initiator bool ) (net.Conn , error ) {
56
+ return ConnectOpt (xchg , initiator , DefaultConfig ())
57
+ }
58
+
35
59
type attempt struct {
36
60
candidate
37
61
tid []byte
@@ -48,15 +72,9 @@ type attemptEngine struct {
48
72
attempts []attempt
49
73
decision time.Time
50
74
p2pconn net.Conn
75
+ cfg * Config
51
76
}
52
77
53
- const (
54
- probeTimeout = 500 * time .Millisecond
55
- probeInterval = 100 * time .Millisecond
56
- decisionTime = 2 * time .Second
57
- peerDeadline = 5 * time .Second
58
- )
59
-
60
78
func (e * attemptEngine ) init () error {
61
79
candidates , err := GatherCandidates (e .sock )
62
80
if err != nil {
@@ -80,7 +98,7 @@ func (e *attemptEngine) init() error {
80
98
}
81
99
82
100
e .sock .SetWriteDeadline (time.Time {})
83
- e .decision = time .Now ().Add (decisionTime )
101
+ e .decision = time .Now ().Add (e . cfg . DecisionTime )
84
102
85
103
return nil
86
104
}
@@ -92,7 +110,7 @@ func (e *attemptEngine) xmit() (time.Time, error) {
92
110
93
111
for i := range e .attempts {
94
112
if e .attempts [i ].timeout .Before (now ) {
95
- e .attempts [i ].timeout = time .Now ().Add (probeTimeout )
113
+ e .attempts [i ].timeout = time .Now ().Add (e . cfg . ProbeTimeout )
96
114
e .attempts [i ].tid , err = stun .RandomTid ()
97
115
if err != nil {
98
116
return time.Time {}, err
@@ -101,6 +119,9 @@ func (e *attemptEngine) xmit() (time.Time, error) {
101
119
if err != nil {
102
120
return time.Time {}, err
103
121
}
122
+ if e .cfg .Verbose {
123
+ log .Printf ("TX probe %v to %v" , e .attempts [i ].tid , e .attempts [i ].Addr )
124
+ }
104
125
e .sock .WriteToUDP (packet , e .attempts [i ].Addr )
105
126
}
106
127
if ret .IsZero () || e .attempts [i ].timeout .Before (ret ) {
@@ -122,20 +143,32 @@ func (e *attemptEngine) read() error {
122
143
123
144
packet , err := stun .ParsePacket (buf [:n ], nil )
124
145
if err != nil {
146
+ if e .cfg .Verbose {
147
+ log .Printf ("Cannot parse packet from %v: %v" , from , err )
148
+ }
125
149
return nil
126
150
}
127
151
128
152
if packet .Method != stun .MethodBinding {
153
+ if e .cfg .Verbose {
154
+ log .Printf ("Packet from %v is not a binding request" , from )
155
+ }
129
156
return nil
130
157
}
131
158
132
159
switch packet .Class {
133
160
case stun .ClassRequest :
134
161
response , err := stun .BindResponse (packet .Tid [:], from , nil , false )
135
162
if err != nil {
163
+ if e .cfg .Verbose {
164
+ log .Printf ("Cannot bind response: %v" , err )
165
+ }
136
166
return nil
137
167
}
138
168
e .sock .WriteToUDP (response , from )
169
+ if e .cfg .Verbose {
170
+ log .Printf ("RX %v from %v use candidate %v, answering" , packet .Tid [:], from , packet .UseCandidate )
171
+ }
139
172
if packet .UseCandidate {
140
173
for i := range e .attempts {
141
174
if from .String () != e .attempts [i ].Addr .String () {
@@ -144,12 +177,18 @@ func (e *attemptEngine) read() error {
144
177
if ! e .attempts [i ].success {
145
178
return errors .New ("Initiator told us to use bad link" )
146
179
}
180
+ if e .cfg .Verbose {
181
+ log .Printf ("Choose local %v remote %v" , e .attempts [i ].localaddr , e .attempts [i ].Addr )
182
+ }
147
183
e .p2pconn = newConn (e .sock , e .attempts [i ].localaddr , e .attempts [i ].Addr )
148
184
return nil
149
185
}
150
186
}
151
187
152
188
case stun .ClassSuccess :
189
+ if e .cfg .Verbose {
190
+ log .Printf ("RX %v from %v" , packet .Tid [:], from )
191
+ }
153
192
for i := range e .attempts {
154
193
if ! bytes .Equal (packet .Tid [:], e .attempts [i ].tid ) {
155
194
continue
@@ -158,44 +197,28 @@ func (e *attemptEngine) read() error {
158
197
return nil
159
198
}
160
199
if e .attempts [i ].chosen {
200
+ if e .cfg .Verbose {
201
+ log .Printf ("Choose local %v remote %v" , e .attempts [i ].localaddr , e .attempts [i ].Addr )
202
+ }
161
203
e .p2pconn = newConn (e .sock , e .attempts [i ].localaddr , e .attempts [i ].Addr )
162
204
return nil
163
205
}
164
206
e .attempts [i ].success = true
165
207
e .attempts [i ].localaddr = packet .Addr
166
- e .attempts [i ].timeout = time .Now ().Add (probeInterval )
208
+ e .attempts [i ].timeout = time .Now ().Add (e . cfg . ProbeInterval )
167
209
return nil
168
210
}
169
211
}
170
212
171
213
return nil
172
214
}
173
215
174
- func (e * attemptEngine ) debug () {
175
- if e .initiator {
176
- return
177
- }
178
- buf := new (bytes.Buffer )
179
- fmt .Fprintf (buf , "%t\t " , e .initiator )
180
- for _ , att := range e .attempts {
181
- timeout := att .timeout .Sub (time .Now ())
182
- if timeout < 0 {
183
- timeout = 0
184
- }
185
- fmt .Fprintf (buf , "%s/%s/%s/%t\t " , att .Addr , att .localaddr , timeout , att .success )
186
- }
187
- if e .initiator {
188
- buf .WriteString ("\n " )
189
- }
190
- fmt .Println (buf .String ())
191
- }
192
-
193
216
func (e * attemptEngine ) run () (net.Conn , error ) {
194
217
if err := e .init (); err != nil {
195
218
return nil , err
196
219
}
197
220
198
- endTime := time .Now ().Add (peerDeadline )
221
+ endTime := time .Now ().Add (e . cfg . PeerDeadline )
199
222
for {
200
223
if e .initiator && ! e .decision .IsZero () && time .Now ().After (e .decision ) {
201
224
e .decision = time.Time {}
@@ -204,15 +227,13 @@ func (e *attemptEngine) run() (net.Conn, error) {
204
227
}
205
228
}
206
229
207
- e .debug ()
208
-
209
230
timeout , err := e .xmit ()
210
231
if err != nil {
211
232
return nil , err
212
233
}
213
234
214
235
if time .Now ().After (timeout ) {
215
- timeout = time .Now ().Add (peerDeadline )
236
+ timeout = time .Now ().Add (e . cfg . PeerDeadline )
216
237
}
217
238
218
239
e .sock .SetReadDeadline (timeout )
@@ -225,7 +246,7 @@ func (e *attemptEngine) run() (net.Conn, error) {
225
246
}
226
247
227
248
if time .Now ().After (endTime ) {
228
- return nil , fmt .Errorf ("haven't heard from my peer after %v" , peerDeadline )
249
+ return nil , fmt .Errorf ("haven't heard from my peer after %v" , e . cfg . PeerDeadline )
229
250
}
230
251
}
231
252
0 commit comments