@@ -54,6 +54,7 @@ import (
5454 "runtime"
5555 "strings"
5656 "sync"
57+ "sync/atomic"
5758 "time"
5859
5960 "golang.org/x/crypto/ssh"
@@ -80,10 +81,12 @@ func registerManagedSSH() error {
8081}
8182
8283func sshSmartSubtransportFactory (remote * git2go.Remote , transport * git2go.Transport ) (git2go.SmartSubtransport , error ) {
84+ var closed int32 = 0
8385 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 ,
8790 }, nil
8891}
8992
@@ -109,15 +112,12 @@ type sshSmartSubtransport struct {
109112 stdin io.WriteCloser
110113 stdout io.Reader
111114
112- con connection
113- }
115+ closedSessions * int32
114116
115- type connection struct {
116117 client * ssh.Client
117118 session * ssh.Session
118119 currentStream * sshSmartSubtransportStream
119120 connected bool
120- m sync.RWMutex
121121}
122122
123123func (t * sshSmartSubtransport ) Action (transportOptionsURL string , action git2go.SmartServiceAction ) (git2go.SmartSubtransportStream , error ) {
@@ -151,17 +151,17 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
151151 var cmd string
152152 switch action {
153153 case git2go .SmartServiceActionUploadpackLs , git2go .SmartServiceActionUploadpack :
154- if t .con . currentStream != nil {
154+ if t .currentStream != nil {
155155 if t .lastAction == git2go .SmartServiceActionUploadpackLs {
156- return t .con . currentStream , nil
156+ return t .currentStream , nil
157157 }
158158 }
159159 cmd = fmt .Sprintf ("git-upload-pack '%s'" , uPath )
160160
161161 case git2go .SmartServiceActionReceivepackLs , git2go .SmartServiceActionReceivepack :
162- if t .con . currentStream != nil {
162+ if t .currentStream != nil {
163163 if t .lastAction == git2go .SmartServiceActionReceivepackLs {
164- return t .con . currentStream , nil
164+ return t .currentStream , nil
165165 }
166166 }
167167 cmd = fmt .Sprintf ("git-receive-pack '%s'" , uPath )
@@ -208,32 +208,30 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
208208 return nil
209209 }
210210
211- t .con .m .RLock ()
212- if t .con .connected == true {
211+ if t .connected {
213212 // The connection is no longer shared across actions, so ensures
214213 // all has been released before starting a new connection.
215214 _ = t .Close ()
216215 }
217- t .con .m .RUnlock ()
218216
219217 err = t .createConn (addr , sshConfig )
220218 if err != nil {
221219 return nil , err
222220 }
223221
224222 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 {
226224 return nil , err
227225 }
228226
229- if t .stdin , err = t .con . session .StdinPipe (); err != nil {
227+ if t .stdin , err = t .session .StdinPipe (); err != nil {
230228 return nil , err
231229 }
232230
233231 var w * io.PipeWriter
234232 var reader io.Reader
235233 t .stdout , w = io .Pipe ()
236- if reader , err = t .con . session .StdoutPipe (); err != nil {
234+ if reader , err = t .session .StdoutPipe (); err != nil {
237235 return nil , err
238236 }
239237
@@ -251,7 +249,6 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
251249 "recovered from libgit2 ssh smart subtransport panic" )
252250 }
253251 }()
254-
255252 var cancel context.CancelFunc
256253 ctx := t .ctx
257254
@@ -261,19 +258,17 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
261258 defer cancel ()
262259 }
263260
261+ closedAlready := atomic .LoadInt32 (t .closedSessions )
264262 for {
265263 select {
266264 case <- ctx .Done ():
267265 t .Close ()
268266 return nil
269267
270268 default :
271- t .con .m .RLock ()
272- if ! t .con .connected {
273- t .con .m .RUnlock ()
269+ if atomic .LoadInt32 (t .closedSessions ) > closedAlready {
274270 return nil
275271 }
276- t .con .m .RUnlock ()
277272
278273 _ , err := io .Copy (w , reader )
279274 if err != nil {
@@ -285,16 +280,16 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
285280 }()
286281
287282 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 {
289284 return nil , err
290285 }
291286
292287 t .lastAction = action
293- t .con . currentStream = & sshSmartSubtransportStream {
288+ t .currentStream = & sshSmartSubtransportStream {
294289 owner : t ,
295290 }
296291
297- return t .con . currentStream , nil
292+ return t .currentStream , nil
298293}
299294
300295func (t * sshSmartSubtransport ) createConn (addr string , sshConfig * ssh.ClientConfig ) error {
@@ -311,10 +306,8 @@ func (t *sshSmartSubtransport) createConn(addr string, sshConfig *ssh.ClientConf
311306 return err
312307 }
313308
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 )
318311
319312 return nil
320313}
@@ -330,27 +323,27 @@ func (t *sshSmartSubtransport) createConn(addr string, sshConfig *ssh.ClientConf
330323// SmartSubTransport (i.e. unreleased resources, staled connections).
331324func (t * sshSmartSubtransport ) Close () error {
332325 t .logger .V (logger .TraceLevel ).Info ("sshSmartSubtransport.Close()" )
333- t .con .m .Lock ()
334- defer t .con .m .Unlock ()
335326
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 {
338329 _ = t .stdin .Close ()
339330 }
340331 t .stdin = nil
341332
342- if t .con . session != nil {
333+ if t .session != nil {
343334 t .logger .V (logger .TraceLevel ).Info ("session.Close()" )
344- _ = t .con . session .Close ()
335+ _ = t .session .Close ()
345336 }
346- t .con . session = nil
337+ t .session = nil
347338
348- if t .con . client != nil {
349- _ = t .con . client .Close ()
339+ if t .client != nil {
340+ _ = t .client .Close ()
350341 t .logger .V (logger .TraceLevel ).Info ("close client" )
351342 }
343+ t .client = nil
352344
353- t .con .connected = false
345+ t .connected = false
346+ atomic .AddInt32 (t .closedSessions , 1 )
354347
355348 return nil
356349}
0 commit comments