@@ -121,22 +121,22 @@ func (c ClientStatus) String() string {
121
121
type ClientConn struct {
122
122
* connKit
123
123
124
- receiveSocket * websocket.Conn
125
- receiveStreamMu sync.Mutex
124
+ receiveSocket * websocket.Conn
125
+ receiveMu sync.Mutex
126
126
127
- sendSocket * websocket.Conn
128
- sendStreamMu sync.Mutex
127
+ sendSocket * websocket.Conn
128
+ sendMu sync.Mutex
129
129
130
130
gbnConn * gbn.GoBackNConn
131
131
gbnOptions []gbn.Option
132
132
133
- closeOnce sync.Once
134
-
135
133
status ClientStatus
136
134
onNewStatus func (status ClientStatus )
137
135
statusMu sync.Mutex
138
136
139
- quit chan struct {}
137
+ quit chan struct {}
138
+ cancel func ()
139
+ closeOnce sync.Once
140
140
}
141
141
142
142
// NewClientConn creates a new client connection with the given receive and send
@@ -151,6 +151,7 @@ func NewClientConn(ctx context.Context, sid [64]byte, serverHost string,
151
151
log .Debugf ("New client conn, read_stream=%x, write_stream=%x" ,
152
152
receiveSID [:], sendSID [:])
153
153
154
+ ctxc , cancel := context .WithCancel (ctx )
154
155
c := & ClientConn {
155
156
gbnOptions : []gbn.Option {
156
157
gbn .WithTimeout (gbnTimeout ),
@@ -162,17 +163,18 @@ func NewClientConn(ctx context.Context, sid [64]byte, serverHost string,
162
163
status : ClientStatusNotConnected ,
163
164
onNewStatus : onNewStatus ,
164
165
quit : make (chan struct {}),
166
+ cancel : cancel ,
165
167
}
166
168
c .connKit = & connKit {
167
- ctx : ctx ,
169
+ ctx : ctxc ,
168
170
impl : c ,
169
171
receiveSID : receiveSID ,
170
172
sendSID : sendSID ,
171
173
serverAddr : serverHost ,
172
174
}
173
175
174
176
gbnConn , err := gbn .NewClientConn (
175
- ctx , gbnN , c .sendToStream , c .recvFromStream , c .gbnOptions ... ,
177
+ ctxc , gbnN , c .send , c .recv , c .gbnOptions ... ,
176
178
)
177
179
if err != nil {
178
180
return nil , err
@@ -188,25 +190,25 @@ func NewClientConn(ctx context.Context, sid [64]byte, serverHost string,
188
190
func RefreshClientConn (ctx context.Context , c * ClientConn ) (* ClientConn ,
189
191
error ) {
190
192
191
- c .sendStreamMu .Lock ()
192
- defer c .sendStreamMu .Unlock ()
193
+ c .sendMu .Lock ()
194
+ defer c .sendMu .Unlock ()
193
195
194
- c .receiveStreamMu .Lock ()
195
- defer c .receiveStreamMu .Unlock ()
196
+ c .receiveMu .Lock ()
197
+ defer c .receiveMu .Unlock ()
198
+
199
+ c .statusMu .Lock ()
200
+ defer c .statusMu .Unlock ()
196
201
197
202
log .Debugf ("Refreshing client conn, read_stream=%x, write_stream=%x" ,
198
203
c .receiveSID [:], c .sendSID [:])
199
204
200
205
cc := & ClientConn {
201
- receiveSocket : c .receiveSocket ,
202
- sendSocket : c .sendSocket ,
203
- status : ClientStatusNotConnected ,
204
- onNewStatus : c .onNewStatus ,
205
- gbnOptions : c .gbnOptions ,
206
- quit : make (chan struct {}),
206
+ status : ClientStatusNotConnected ,
207
+ onNewStatus : c .onNewStatus ,
208
+ gbnOptions : c .gbnOptions ,
209
+ cancel : c .cancel ,
210
+ quit : make (chan struct {}),
207
211
}
208
- c .sendSocket = nil
209
- c .receiveSocket = nil
210
212
211
213
cc .connKit = & connKit {
212
214
ctx : ctx ,
@@ -217,7 +219,7 @@ func RefreshClientConn(ctx context.Context, c *ClientConn) (*ClientConn,
217
219
}
218
220
219
221
gbnConn , err := gbn .NewClientConn (
220
- ctx , gbnN , cc .sendToStream , cc .recvFromStream , cc .gbnOptions ... ,
222
+ ctx , gbnN , cc .send , cc .recv , cc .gbnOptions ... ,
221
223
)
222
224
if err != nil {
223
225
return nil , err
@@ -267,16 +269,16 @@ func statusFromError(err error) ClientStatus {
267
269
}
268
270
}
269
271
270
- // recvFromStream is used to receive a payload from the receive socket.
271
- // The function is passed to and used by the gbn connection.
272
- // It therefore takes in and reacts on the cancellation of a context so that
273
- // the gbn connection is able to close independently of the ClientConn.
274
- func (c * ClientConn ) recvFromStream (ctx context.Context ) ([]byte , error ) {
275
- c .receiveStreamMu .Lock ()
272
+ // recv is used to receive a payload from the receive socket. The function is
273
+ // passed to and used by the gbn connection. It therefore takes in and reacts
274
+ // on the cancellation of a context so that the gbn connection is able to close
275
+ // independently of the ClientConn.
276
+ func (c * ClientConn ) recv (ctx context.Context ) ([]byte , error ) {
277
+ c .receiveMu .Lock ()
276
278
if c .receiveSocket == nil {
277
279
c .createReceiveMailBox (ctx , 0 )
278
280
}
279
- c .receiveStreamMu .Unlock ()
281
+ c .receiveMu .Unlock ()
280
282
281
283
for {
282
284
select {
@@ -287,15 +289,15 @@ func (c *ClientConn) recvFromStream(ctx context.Context) ([]byte, error) {
287
289
default :
288
290
}
289
291
290
- c .receiveStreamMu .Lock ()
292
+ c .receiveMu .Lock ()
291
293
_ , msg , err := c .receiveSocket .Read (ctx )
292
294
if err != nil {
293
295
log .Debugf ("Client: got failure on receive socket, " +
294
296
"re-trying: %v" , err )
295
297
296
298
c .setStatus (ClientStatusNotConnected )
297
299
c .createReceiveMailBox (ctx , retryWait )
298
- c .receiveStreamMu .Unlock ()
300
+ c .receiveMu .Unlock ()
299
301
continue
300
302
}
301
303
unwrapped , err := stripJSONWrapper (string (msg ))
@@ -305,10 +307,10 @@ func (c *ClientConn) recvFromStream(ctx context.Context) ([]byte, error) {
305
307
306
308
c .setStatus (statusFromError (err ))
307
309
c .createReceiveMailBox (ctx , retryWait )
308
- c .receiveStreamMu .Unlock ()
310
+ c .receiveMu .Unlock ()
309
311
continue
310
312
}
311
- c .receiveStreamMu .Unlock ()
313
+ c .receiveMu .Unlock ()
312
314
313
315
mailboxMsg := & hashmailrpc.CipherBox {}
314
316
err = defaultMarshaler .Unmarshal ([]byte (unwrapped ), mailboxMsg )
@@ -322,17 +324,17 @@ func (c *ClientConn) recvFromStream(ctx context.Context) ([]byte, error) {
322
324
}
323
325
}
324
326
325
- // sendToStream is used to send a payload on the send socket. The function
326
- // is passed to and used by the gbn connection. It therefore takes in and
327
- // reacts on the cancellation of a context so that the gbn connection is able to
328
- // close independently of the ClientConn.
329
- func (c * ClientConn ) sendToStream (ctx context.Context , payload []byte ) error {
330
- // Set up the send socket if it has not yet been initialized.
331
- c .sendStreamMu .Lock ()
327
+ // send is used to send a payload on the send socket. The function is passed to
328
+ // and used by the gbn connection. It therefore takes in and reacts on the
329
+ // cancellation of a context so that the gbn connection is able to close
330
+ // independently of the ClientConn.
331
+ func (c * ClientConn ) send (ctx context.Context , payload []byte ) error {
332
+ // Set up the send- socket if it has not yet been initialized.
333
+ c .sendMu .Lock ()
332
334
if c .sendSocket == nil {
333
335
c .createSendMailBox (ctx , 0 )
334
336
}
335
- c .sendStreamMu .Unlock ()
337
+ c .sendMu .Unlock ()
336
338
337
339
// Retry sending the payload to the hashmail server until it succeeds.
338
340
for {
@@ -356,7 +358,7 @@ func (c *ClientConn) sendToStream(ctx context.Context, payload []byte) error {
356
358
return err
357
359
}
358
360
359
- c .sendStreamMu .Lock ()
361
+ c .sendMu .Lock ()
360
362
ctxt , cancel := context .WithTimeout (ctx , sendSocketTimeout )
361
363
err = c .sendSocket .Write (
362
364
ctxt , websocket .MessageText , sendInitBytes ,
@@ -368,10 +370,10 @@ func (c *ClientConn) sendToStream(ctx context.Context, payload []byte) error {
368
370
369
371
c .setStatus (statusFromError (err ))
370
372
c .createSendMailBox (ctx , retryWait )
371
- c .sendStreamMu .Unlock ()
373
+ c .sendMu .Unlock ()
372
374
continue
373
375
}
374
- c .sendStreamMu .Unlock ()
376
+ c .sendMu .Unlock ()
375
377
376
378
return nil
377
379
}
@@ -516,37 +518,46 @@ func (c *ClientConn) Close() error {
516
518
c .closeOnce .Do (func () {
517
519
log .Debugf ("Closing client connection" )
518
520
519
- if err := c .gbnConn .Close (); err != nil {
520
- log .Debugf ("Error closing gbn connection: %v" , err )
521
+ if c .gbnConn != nil {
522
+ if err := c .gbnConn .Close (); err != nil {
523
+ log .Debugf ("Error closing gbn connection: %v" ,
524
+ err )
525
+
526
+ returnErr = err
527
+ }
521
528
}
522
529
523
- c .receiveStreamMu .Lock ()
530
+ c .receiveMu .Lock ()
524
531
if c .receiveSocket != nil {
525
532
log .Debugf ("sending bye on receive socket" )
526
- returnErr = c .receiveSocket .Close (
533
+ err : = c .receiveSocket .Close (
527
534
websocket .StatusNormalClosure , "bye" ,
528
535
)
529
- if returnErr != nil {
536
+ if err != nil {
530
537
log .Errorf ("Error closing receive socket: %v" ,
531
- returnErr )
538
+ err )
539
+
540
+ returnErr = err
532
541
}
533
542
}
534
- c .receiveStreamMu .Unlock ()
543
+ c .receiveMu .Unlock ()
535
544
536
- c .sendStreamMu .Lock ()
545
+ c .sendMu .Lock ()
537
546
if c .sendSocket != nil {
538
547
log .Debugf ("sending bye on send socket" )
539
- returnErr = c .sendSocket .Close (
548
+ err : = c .sendSocket .Close (
540
549
websocket .StatusNormalClosure , "bye" ,
541
550
)
542
- if returnErr != nil {
543
- log .Errorf ("Error closing send socket: %v" ,
544
- returnErr )
551
+ if err != nil {
552
+ log .Errorf ("Error closing send socket: %v" , err )
553
+
554
+ returnErr = err
545
555
}
546
556
}
547
- c .sendStreamMu .Unlock ()
557
+ c .sendMu .Unlock ()
548
558
549
559
close (c .quit )
560
+ c .cancel ()
550
561
})
551
562
552
563
return returnErr
0 commit comments