@@ -54,6 +54,7 @@ import (
54
54
"runtime"
55
55
"strings"
56
56
"sync"
57
+ "sync/atomic"
57
58
"time"
58
59
59
60
"golang.org/x/crypto/ssh"
@@ -80,10 +81,12 @@ func registerManagedSSH() error {
80
81
}
81
82
82
83
func sshSmartSubtransportFactory (remote * git2go.Remote , transport * git2go.Transport ) (git2go.SmartSubtransport , error ) {
84
+ var closed int32 = 0
83
85
return & sshSmartSubtransport {
84
- transport : transport ,
85
- ctx : context .Background (),
86
- logger : logr .Discard (),
86
+ transport : transport ,
87
+ ctx : context .Background (),
88
+ logger : logr .Discard (),
89
+ closedSessions : & closed ,
87
90
}, nil
88
91
}
89
92
@@ -109,15 +112,12 @@ type sshSmartSubtransport struct {
109
112
stdin io.WriteCloser
110
113
stdout io.Reader
111
114
112
- con connection
113
- }
115
+ closedSessions * int32
114
116
115
- type connection struct {
116
117
client * ssh.Client
117
118
session * ssh.Session
118
119
currentStream * sshSmartSubtransportStream
119
120
connected bool
120
- m sync.RWMutex
121
121
}
122
122
123
123
func (t * sshSmartSubtransport ) Action (transportOptionsURL string , action git2go.SmartServiceAction ) (git2go.SmartSubtransportStream , error ) {
@@ -151,17 +151,17 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
151
151
var cmd string
152
152
switch action {
153
153
case git2go .SmartServiceActionUploadpackLs , git2go .SmartServiceActionUploadpack :
154
- if t .con . currentStream != nil {
154
+ if t .currentStream != nil {
155
155
if t .lastAction == git2go .SmartServiceActionUploadpackLs {
156
- return t .con . currentStream , nil
156
+ return t .currentStream , nil
157
157
}
158
158
}
159
159
cmd = fmt .Sprintf ("git-upload-pack '%s'" , uPath )
160
160
161
161
case git2go .SmartServiceActionReceivepackLs , git2go .SmartServiceActionReceivepack :
162
- if t .con . currentStream != nil {
162
+ if t .currentStream != nil {
163
163
if t .lastAction == git2go .SmartServiceActionReceivepackLs {
164
- return t .con . currentStream , nil
164
+ return t .currentStream , nil
165
165
}
166
166
}
167
167
cmd = fmt .Sprintf ("git-receive-pack '%s'" , uPath )
@@ -208,32 +208,30 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
208
208
return nil
209
209
}
210
210
211
- t .con .m .RLock ()
212
- if t .con .connected == true {
211
+ if t .connected {
213
212
// The connection is no longer shared across actions, so ensures
214
213
// all has been released before starting a new connection.
215
214
_ = t .Close ()
216
215
}
217
- t .con .m .RUnlock ()
218
216
219
217
err = t .createConn (addr , sshConfig )
220
218
if err != nil {
221
219
return nil , err
222
220
}
223
221
224
222
t .logger .V (logger .TraceLevel ).Info ("creating new ssh session" )
225
- if t .con . session , err = t . con .client .NewSession (); err != nil {
223
+ if t .session , err = t .client .NewSession (); err != nil {
226
224
return nil , err
227
225
}
228
226
229
- if t .stdin , err = t .con . session .StdinPipe (); err != nil {
227
+ if t .stdin , err = t .session .StdinPipe (); err != nil {
230
228
return nil , err
231
229
}
232
230
233
231
var w * io.PipeWriter
234
232
var reader io.Reader
235
233
t .stdout , w = io .Pipe ()
236
- if reader , err = t .con . session .StdoutPipe (); err != nil {
234
+ if reader , err = t .session .StdoutPipe (); err != nil {
237
235
return nil , err
238
236
}
239
237
@@ -251,7 +249,6 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
251
249
"recovered from libgit2 ssh smart subtransport panic" )
252
250
}
253
251
}()
254
-
255
252
var cancel context.CancelFunc
256
253
ctx := t .ctx
257
254
@@ -261,19 +258,17 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
261
258
defer cancel ()
262
259
}
263
260
261
+ closedAlready := atomic .LoadInt32 (t .closedSessions )
264
262
for {
265
263
select {
266
264
case <- ctx .Done ():
267
265
t .Close ()
268
266
return nil
269
267
270
268
default :
271
- t .con .m .RLock ()
272
- if ! t .con .connected {
273
- t .con .m .RUnlock ()
269
+ if atomic .LoadInt32 (t .closedSessions ) > closedAlready {
274
270
return nil
275
271
}
276
- t .con .m .RUnlock ()
277
272
278
273
_ , err := io .Copy (w , reader )
279
274
if err != nil {
@@ -285,16 +280,16 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
285
280
}()
286
281
287
282
t .logger .V (logger .TraceLevel ).Info ("run on remote" , "cmd" , cmd )
288
- if err := t .con . session .Start (cmd ); err != nil {
283
+ if err := t .session .Start (cmd ); err != nil {
289
284
return nil , err
290
285
}
291
286
292
287
t .lastAction = action
293
- t .con . currentStream = & sshSmartSubtransportStream {
288
+ t .currentStream = & sshSmartSubtransportStream {
294
289
owner : t ,
295
290
}
296
291
297
- return t .con . currentStream , nil
292
+ return t .currentStream , nil
298
293
}
299
294
300
295
func (t * sshSmartSubtransport ) createConn (addr string , sshConfig * ssh.ClientConfig ) error {
@@ -311,10 +306,8 @@ func (t *sshSmartSubtransport) createConn(addr string, sshConfig *ssh.ClientConf
311
306
return err
312
307
}
313
308
314
- t .con .m .Lock ()
315
- t .con .connected = true
316
- t .con .client = ssh .NewClient (c , chans , reqs )
317
- t .con .m .Unlock ()
309
+ t .connected = true
310
+ t .client = ssh .NewClient (c , chans , reqs )
318
311
319
312
return nil
320
313
}
@@ -330,27 +323,27 @@ func (t *sshSmartSubtransport) createConn(addr string, sshConfig *ssh.ClientConf
330
323
// SmartSubTransport (i.e. unreleased resources, staled connections).
331
324
func (t * sshSmartSubtransport ) Close () error {
332
325
t .logger .V (logger .TraceLevel ).Info ("sshSmartSubtransport.Close()" )
333
- t .con .m .Lock ()
334
- defer t .con .m .Unlock ()
335
326
336
- t .con . currentStream = nil
337
- if t .con . client != nil && t .stdin != nil {
327
+ t .currentStream = nil
328
+ if t .client != nil && t .stdin != nil {
338
329
_ = t .stdin .Close ()
339
330
}
340
331
t .stdin = nil
341
332
342
- if t .con . session != nil {
333
+ if t .session != nil {
343
334
t .logger .V (logger .TraceLevel ).Info ("session.Close()" )
344
- _ = t .con . session .Close ()
335
+ _ = t .session .Close ()
345
336
}
346
- t .con . session = nil
337
+ t .session = nil
347
338
348
- if t .con . client != nil {
349
- _ = t .con . client .Close ()
339
+ if t .client != nil {
340
+ _ = t .client .Close ()
350
341
t .logger .V (logger .TraceLevel ).Info ("close client" )
351
342
}
343
+ t .client = nil
352
344
353
- t .con .connected = false
345
+ t .connected = false
346
+ atomic .AddInt32 (t .closedSessions , 1 )
354
347
355
348
return nil
356
349
}
0 commit comments