##// END OF EJS Templates
sshpeer: move handshake outside of sshpeer...
Gregory Szorc -
r35956:80a2b8ae default
parent child Browse files
Show More
@@ -156,13 +156,69 b' def _makeconnection(ui, sshcmd, args, re'
156
156
157 return proc, stdin, stdout, stderr
157 return proc, stdin, stdout, stderr
158
158
159 def _performhandshake(ui, stdin, stdout, stderr):
160 def badresponse():
161 msg = _('no suitable response from remote hg')
162 hint = ui.config('ui', 'ssherrorhint')
163 raise error.RepoError(msg, hint=hint)
164
165 requestlog = ui.configbool('devel', 'debug.peer-request')
166
167 try:
168 pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
169 handshake = [
170 'hello\n',
171 'between\n',
172 'pairs %d\n' % len(pairsarg),
173 pairsarg,
174 ]
175
176 if requestlog:
177 ui.debug('devel-peer-request: hello\n')
178 ui.debug('sending hello command\n')
179 if requestlog:
180 ui.debug('devel-peer-request: between\n')
181 ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg))
182 ui.debug('sending between command\n')
183
184 stdin.write(''.join(handshake))
185 stdin.flush()
186 except IOError:
187 badresponse()
188
189 lines = ['', 'dummy']
190 max_noise = 500
191 while lines[-1] and max_noise:
192 try:
193 l = stdout.readline()
194 _forwardoutput(ui, stderr)
195 if lines[-1] == '1\n' and l == '\n':
196 break
197 if l:
198 ui.debug('remote: ', l)
199 lines.append(l)
200 max_noise -= 1
201 except IOError:
202 badresponse()
203 else:
204 badresponse()
205
206 caps = set()
207 for l in reversed(lines):
208 if l.startswith('capabilities:'):
209 caps.update(l[:-1].split(':')[1].split())
210 break
211
212 return caps
213
159 class sshpeer(wireproto.wirepeer):
214 class sshpeer(wireproto.wirepeer):
160 def __init__(self, ui, url, proc, stdin, stdout, stderr):
215 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps):
161 """Create a peer from an existing SSH connection.
216 """Create a peer from an existing SSH connection.
162
217
163 ``proc`` is a handle on the underlying SSH process.
218 ``proc`` is a handle on the underlying SSH process.
164 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
219 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio
165 pipes for that process.
220 pipes for that process.
221 ``caps`` is a set of capabilities supported by the remote.
166 """
222 """
167 self._url = url
223 self._url = url
168 self._ui = ui
224 self._ui = ui
@@ -172,8 +228,7 b' class sshpeer(wireproto.wirepeer):'
172 self._pipeo = stdin
228 self._pipeo = stdin
173 self._pipei = stdout
229 self._pipei = stdout
174 self._pipee = stderr
230 self._pipee = stderr
175
231 self._caps = caps
176 self._validaterepo()
177
232
178 # Begin of _basepeer interface.
233 # Begin of _basepeer interface.
179
234
@@ -205,61 +260,6 b' class sshpeer(wireproto.wirepeer):'
205
260
206 # End of _basewirecommands interface.
261 # End of _basewirecommands interface.
207
262
208 def _validaterepo(self):
209 def badresponse():
210 msg = _("no suitable response from remote hg")
211 hint = self.ui.config("ui", "ssherrorhint")
212 self._abort(error.RepoError(msg, hint=hint))
213
214 try:
215 pairsarg = '%s-%s' % ('0' * 40, '0' * 40)
216
217 handshake = [
218 'hello\n',
219 'between\n',
220 'pairs %d\n' % len(pairsarg),
221 pairsarg,
222 ]
223
224 requestlog = self.ui.configbool('devel', 'debug.peer-request')
225
226 if requestlog:
227 self.ui.debug('devel-peer-request: hello\n')
228 self.ui.debug('sending hello command\n')
229 if requestlog:
230 self.ui.debug('devel-peer-request: between\n')
231 self.ui.debug('devel-peer-request: pairs: %d bytes\n' %
232 len(pairsarg))
233 self.ui.debug('sending between command\n')
234
235 self._pipeo.write(''.join(handshake))
236 self._pipeo.flush()
237 except IOError:
238 badresponse()
239
240 lines = ["", "dummy"]
241 max_noise = 500
242 while lines[-1] and max_noise:
243 try:
244 l = self._pipei.readline()
245 _forwardoutput(self.ui, self._pipee)
246 if lines[-1] == "1\n" and l == "\n":
247 break
248 if l:
249 self.ui.debug("remote: ", l)
250 lines.append(l)
251 max_noise -= 1
252 except IOError:
253 badresponse()
254 else:
255 badresponse()
256
257 self._caps = set()
258 for l in reversed(lines):
259 if l.startswith("capabilities:"):
260 self._caps.update(l[:-1].split(":")[1].split())
261 break
262
263 def _readerr(self):
263 def _readerr(self):
264 _forwardoutput(self.ui, self._pipee)
264 _forwardoutput(self.ui, self._pipee)
265
265
@@ -414,4 +414,10 b' def instance(ui, path, create):'
414 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
414 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
415 remotepath, sshenv)
415 remotepath, sshenv)
416
416
417 return sshpeer(ui, path, proc, stdin, stdout, stderr)
417 try:
418 caps = _performhandshake(ui, stdin, stdout, stderr)
419 except Exception:
420 _cleanuppipes(ui, stdout, stdin, stderr)
421 raise
422
423 return sshpeer(ui, path, proc, stdin, stdout, stderr, caps)
@@ -12,6 +12,7 b' from __future__ import absolute_import'
12
12
13 from mercurial import (
13 from mercurial import (
14 error,
14 error,
15 extensions,
15 registrar,
16 registrar,
16 sshpeer,
17 sshpeer,
17 wireproto,
18 wireproto,
@@ -52,30 +53,26 b' class prehelloserver(wireprotoserver.ssh'
52
53
53 super(prehelloserver, self).serve_forever()
54 super(prehelloserver, self).serve_forever()
54
55
55 class extrahandshakecommandspeer(sshpeer.sshpeer):
56 def performhandshake(orig, ui, stdin, stdout, stderr):
56 """An ssh peer that sends extra commands as part of initial handshake."""
57 """Wrapped version of sshpeer._performhandshake to send extra commands."""
57 def _validaterepo(self):
58 mode = ui.config(b'sshpeer', b'handshake-mode')
58 mode = self._ui.config(b'sshpeer', b'handshake-mode')
59 if mode == b'pre-no-args':
59 if mode == b'pre-no-args':
60 ui.debug(b'sending no-args command\n')
60 self._callstream(b'no-args')
61 stdin.write(b'no-args\n')
61 return super(extrahandshakecommandspeer, self)._validaterepo()
62 stdin.flush()
62 elif mode == b'pre-multiple-no-args':
63 return orig(ui, stdin, stdout, stderr)
63 self._callstream(b'unknown1')
64 elif mode == b'pre-multiple-no-args':
64 self._callstream(b'unknown2')
65 ui.debug(b'sending unknown1 command\n')
65 self._callstream(b'unknown3')
66 stdin.write(b'unknown1\n')
66 return super(extrahandshakecommandspeer, self)._validaterepo()
67 ui.debug(b'sending unknown2 command\n')
67 else:
68 stdin.write(b'unknown2\n')
68 raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' %
69 ui.debug(b'sending unknown3 command\n')
69 mode)
70 stdin.write(b'unknown3\n')
70
71 stdin.flush()
71 def registercommands():
72 return orig(ui, stdin, stdout, stderr)
72 def dummycommand(repo, proto):
73 else:
73 raise error.ProgrammingError('this should never be called')
74 raise error.ProgrammingError(b'unknown HANDSHAKECOMMANDMODE: %s' %
74
75 mode)
75 wireproto.wireprotocommand(b'no-args', b'')(dummycommand)
76 wireproto.wireprotocommand(b'unknown1', b'')(dummycommand)
77 wireproto.wireprotocommand(b'unknown2', b'')(dummycommand)
78 wireproto.wireprotocommand(b'unknown3', b'')(dummycommand)
79
76
80 def extsetup(ui):
77 def extsetup(ui):
81 # It's easier for tests to define the server behavior via environment
78 # It's easier for tests to define the server behavior via environment
@@ -94,7 +91,6 b' def extsetup(ui):'
94 peermode = ui.config(b'sshpeer', b'mode')
91 peermode = ui.config(b'sshpeer', b'mode')
95
92
96 if peermode == b'extra-handshake-commands':
93 if peermode == b'extra-handshake-commands':
97 sshpeer.sshpeer = extrahandshakecommandspeer
94 extensions.wrapfunction(sshpeer, '_performhandshake', performhandshake)
98 registercommands()
99 elif peermode:
95 elif peermode:
100 raise error.ProgrammingError(b'unknown peer mode: %s' % peermode)
96 raise error.ProgrammingError(b'unknown peer mode: %s' % peermode)
@@ -51,10 +51,6 b' class dummyrepo(object):'
51 pass
51 pass
52
52
53 # Facilitates testing sshpeer without requiring an SSH server.
53 # Facilitates testing sshpeer without requiring an SSH server.
54 class testingsshpeer(sshpeer.sshpeer):
55 def _validaterepo(self, *args, **kwargs):
56 pass
57
58 class badpeer(httppeer.httppeer):
54 class badpeer(httppeer.httppeer):
59 def __init__(self):
55 def __init__(self):
60 super(badpeer, self).__init__(uimod.ui(), 'http://localhost')
56 super(badpeer, self).__init__(uimod.ui(), 'http://localhost')
@@ -69,8 +65,8 b' def main():'
69 checkobject(badpeer())
65 checkobject(badpeer())
70 checkobject(httppeer.httppeer(ui, 'http://localhost'))
66 checkobject(httppeer.httppeer(ui, 'http://localhost'))
71 checkobject(localrepo.localpeer(dummyrepo()))
67 checkobject(localrepo.localpeer(dummyrepo()))
72 checkobject(testingsshpeer(ui, 'ssh://localhost/foo', None, None, None,
68 checkobject(sshpeer.sshpeer(ui, 'ssh://localhost/foo', None, None, None,
73 None))
69 None, None))
74 checkobject(bundlerepo.bundlepeer(dummyrepo()))
70 checkobject(bundlerepo.bundlepeer(dummyrepo()))
75 checkobject(statichttprepo.statichttppeer(dummyrepo()))
71 checkobject(statichttprepo.statichttppeer(dummyrepo()))
76 checkobject(unionrepo.unionpeer(dummyrepo()))
72 checkobject(unionrepo.unionpeer(dummyrepo()))
@@ -146,7 +146,6 b' Sending an unknown command to the server'
146
146
147 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server
147 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server
148 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
148 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
149 devel-peer-request: no-args
150 sending no-args command
149 sending no-args command
151 devel-peer-request: hello
150 devel-peer-request: hello
152 sending hello command
151 sending hello command
@@ -182,11 +181,8 b' Send multiple unknown commands before he'
182
181
183 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server
182 $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server
184 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
183 running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob)
185 devel-peer-request: unknown1
186 sending unknown1 command
184 sending unknown1 command
187 devel-peer-request: unknown2
188 sending unknown2 command
185 sending unknown2 command
189 devel-peer-request: unknown3
190 sending unknown3 command
186 sending unknown3 command
191 devel-peer-request: hello
187 devel-peer-request: hello
192 sending hello command
188 sending hello command
General Comments 0
You need to be logged in to leave comments. Login now