146 |
146 |
147 def flush(self): |
147 def flush(self): |
148 return self._main.flush() |
148 return self._main.flush() |
149 |
149 |
150 |
150 |
151 def _cleanuppipes(ui, pipei, pipeo, pipee): |
151 def _cleanuppipes(ui, pipei, pipeo, pipee, warn): |
152 """Clean up pipes used by an SSH connection.""" |
152 """Clean up pipes used by an SSH connection.""" |
153 if pipeo: |
153 didsomething = False |
|
154 if pipeo and not pipeo.closed: |
|
155 didsomething = True |
154 pipeo.close() |
156 pipeo.close() |
155 if pipei: |
157 if pipei and not pipei.closed: |
|
158 didsomething = True |
156 pipei.close() |
159 pipei.close() |
157 |
160 |
158 if pipee: |
161 if pipee and not pipee.closed: |
|
162 didsomething = True |
159 # Try to read from the err descriptor until EOF. |
163 # Try to read from the err descriptor until EOF. |
160 try: |
164 try: |
161 for l in pipee: |
165 for l in pipee: |
162 ui.status(_(b'remote: '), l) |
166 ui.status(_(b'remote: '), l) |
163 except (IOError, ValueError): |
167 except (IOError, ValueError): |
164 pass |
168 pass |
165 |
169 |
166 pipee.close() |
170 pipee.close() |
|
171 |
|
172 if didsomething and warn is not None: |
|
173 # Encourage explicit close of sshpeers. Closing via __del__ is |
|
174 # not very predictable when exceptions are thrown, which has led |
|
175 # to deadlocks due to a peer get gc'ed in a fork |
|
176 # We add our own stack trace, because the stacktrace when called |
|
177 # from __del__ is useless. |
|
178 if False: # enabled in next commit |
|
179 ui.develwarn( |
|
180 b'missing close on SSH connection created at:\n%s' % warn |
|
181 ) |
167 |
182 |
168 |
183 |
169 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): |
184 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): |
170 """Create an SSH connection to a server. |
185 """Create an SSH connection to a server. |
171 |
186 |
454 |
470 |
455 def _abort(self, exception): |
471 def _abort(self, exception): |
456 self._cleanup() |
472 self._cleanup() |
457 raise exception |
473 raise exception |
458 |
474 |
459 def _cleanup(self): |
475 def _cleanup(self, warn=None): |
460 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) |
476 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee, warn=warn) |
461 |
477 |
462 __del__ = _cleanup |
478 def __del__(self): |
|
479 self._cleanup(warn=self._initstack) |
463 |
480 |
464 def _sendrequest(self, cmd, args, framed=False): |
481 def _sendrequest(self, cmd, args, framed=False): |
465 if self.ui.debugflag and self.ui.configbool( |
482 if self.ui.debugflag and self.ui.configbool( |
466 b'devel', b'debug.peer-request' |
483 b'devel', b'debug.peer-request' |
467 ): |
484 ): |
609 testing. |
626 testing. |
610 """ |
627 """ |
611 try: |
628 try: |
612 protoname, caps = _performhandshake(ui, stdin, stdout, stderr) |
629 protoname, caps = _performhandshake(ui, stdin, stdout, stderr) |
613 except Exception: |
630 except Exception: |
614 _cleanuppipes(ui, stdout, stdin, stderr) |
631 _cleanuppipes(ui, stdout, stdin, stderr, warn=None) |
615 raise |
632 raise |
616 |
633 |
617 if protoname == wireprototypes.SSHV1: |
634 if protoname == wireprototypes.SSHV1: |
618 return sshv1peer( |
635 return sshv1peer( |
619 ui, |
636 ui, |
635 stderr, |
652 stderr, |
636 caps, |
653 caps, |
637 autoreadstderr=autoreadstderr, |
654 autoreadstderr=autoreadstderr, |
638 ) |
655 ) |
639 else: |
656 else: |
640 _cleanuppipes(ui, stdout, stdin, stderr) |
657 _cleanuppipes(ui, stdout, stdin, stderr, warn=None) |
641 raise error.RepoError( |
658 raise error.RepoError( |
642 _(b'unknown version of SSH protocol: %s') % protoname |
659 _(b'unknown version of SSH protocol: %s') % protoname |
643 ) |
660 ) |
644 |
661 |
645 |
662 |