Skip to content

Commit bfa4e38

Browse files
author
Paulo Gomes
committed
libgit2: dispose connections in SubTransport.Close
The average SubTransport lifecycle encompass two Actions calls. Previously, it was attempted to share the same connection across both calls. That did not work as some Git Servers do not support multiple sessions from the same connection. The implementation was not fully transitioned into the "one connection per action" model, which led to connection being leaked. The transition to RW mutex was to avoid the unnecessary blocking in the goroutine at the start of the second action call. It is worth mentioning that now when the context is done, the client level resources (connection) will also be freed. This ensures that SSH connections will not outlive the subtransport. Signed-off-by: Paulo Gomes <[email protected]>
1 parent a00d0ed commit bfa4e38

File tree

1 file changed

+21
-25
lines changed

1 file changed

+21
-25
lines changed

pkg/git/libgit2/managed/ssh.go

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,11 @@ type sshSmartSubtransport struct {
9595
}
9696

9797
type connection struct {
98-
conn net.Conn
9998
client *ssh.Client
10099
session *ssh.Session
101100
currentStream *sshSmartSubtransportStream
102101
connected bool
103-
m sync.Mutex
102+
m sync.RWMutex
104103
}
105104

106105
func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.SmartServiceAction) (git2go.SmartSubtransportStream, error) {
@@ -155,11 +154,6 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
155154
return nil, fmt.Errorf("unexpected action: %v", action)
156155
}
157156

158-
if t.con.connected {
159-
// Disregard errors from previous stream, futher details inside Close().
160-
_ = t.Close()
161-
}
162-
163157
port := "22"
164158
if u.Port() != "" {
165159
port = u.Port()
@@ -189,13 +183,18 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
189183
return nil
190184
}
191185

186+
t.con.m.RLock()
187+
if t.con.connected == true {
188+
// The connection is no longer shared across actions, so ensures
189+
// all has been released before starting a new connection.
190+
_ = t.Close()
191+
}
192+
t.con.m.RUnlock()
193+
192194
err = t.createConn(t.addr, sshConfig)
193195
if err != nil {
194196
return nil, err
195197
}
196-
t.con.m.Lock()
197-
t.con.connected = true
198-
t.con.m.Unlock()
199198

200199
traceLog.Info("[ssh]: creating new ssh session")
201200
if t.con.session, err = t.con.client.NewSession(); err != nil {
@@ -244,12 +243,12 @@ func (t *sshSmartSubtransport) Action(transportOptionsURL string, action git2go.
244243
return nil
245244

246245
default:
247-
t.con.m.Lock()
246+
t.con.m.RLock()
248247
if !t.con.connected {
249-
t.con.m.Unlock()
248+
t.con.m.RUnlock()
250249
return nil
251250
}
252-
t.con.m.Unlock()
251+
t.con.m.RUnlock()
253252

254253
_, err := io.Copy(w, reader)
255254
if err != nil {
@@ -286,8 +285,10 @@ func (t *sshSmartSubtransport) createConn(addr string, sshConfig *ssh.ClientConf
286285
return err
287286
}
288287

289-
t.con.conn = conn
288+
t.con.m.Lock()
289+
t.con.connected = true
290290
t.con.client = ssh.NewClient(c, chans, reqs)
291+
t.con.m.Unlock()
291292

292293
return nil
293294
}
@@ -309,29 +310,24 @@ func (t *sshSmartSubtransport) Close() error {
309310
if t.con.client != nil && t.stdin != nil {
310311
_ = t.stdin.Close()
311312
}
312-
t.con.client = nil
313+
t.stdin = nil
313314

314315
if t.con.session != nil {
315316
traceLog.Info("[ssh]: session.Close()", "server", t.addr)
316317
_ = t.con.session.Close()
317318
}
318319
t.con.session = nil
319320

320-
return nil
321-
}
322-
323-
func (t *sshSmartSubtransport) Free() {
324-
traceLog.Info("[ssh]: sshSmartSubtransport.Free()")
325321
if t.con.client != nil {
326322
_ = t.con.client.Close()
327323
}
328324

329-
if t.con.conn != nil {
330-
_ = t.con.conn.Close()
331-
}
332-
t.con.m.Lock()
333325
t.con.connected = false
334-
t.con.m.Unlock()
326+
327+
return nil
328+
}
329+
330+
func (t *sshSmartSubtransport) Free() {
335331
}
336332

337333
type sshSmartSubtransportStream struct {

0 commit comments

Comments
 (0)