286 requestlog = ui.configbool(b'devel', b'debug.peer-request') |
285 requestlog = ui.configbool(b'devel', b'debug.peer-request') |
287 |
286 |
288 # Generate a random token to help identify responses to version 2 |
287 # Generate a random token to help identify responses to version 2 |
289 # upgrade request. |
288 # upgrade request. |
290 token = pycompat.sysbytes(str(uuid.uuid4())) |
289 token = pycompat.sysbytes(str(uuid.uuid4())) |
291 upgradecaps = [ |
|
292 (b'proto', wireprotoserver.SSHV2), |
|
293 ] |
|
294 upgradecaps = util.urlreq.urlencode(upgradecaps) |
|
295 |
290 |
296 try: |
291 try: |
297 pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40) |
292 pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40) |
298 handshake = [ |
293 handshake = [ |
299 b'hello\n', |
294 b'hello\n', |
300 b'between\n', |
295 b'between\n', |
301 b'pairs %d\n' % len(pairsarg), |
296 b'pairs %d\n' % len(pairsarg), |
302 pairsarg, |
297 pairsarg, |
303 ] |
298 ] |
304 |
|
305 # Request upgrade to version 2 if configured. |
|
306 if ui.configbool(b'experimental', b'sshpeer.advertise-v2'): |
|
307 ui.debug(b'sending upgrade request: %s %s\n' % (token, upgradecaps)) |
|
308 handshake.insert(0, b'upgrade %s %s\n' % (token, upgradecaps)) |
|
309 |
299 |
310 if requestlog: |
300 if requestlog: |
311 ui.debug(b'devel-peer-request: hello+between\n') |
301 ui.debug(b'devel-peer-request: hello+between\n') |
312 ui.debug(b'devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) |
302 ui.debug(b'devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) |
313 ui.debug(b'sending hello command\n') |
303 ui.debug(b'sending hello command\n') |
363 # Look for response to ``hello`` command. Scan from the back so |
353 # Look for response to ``hello`` command. Scan from the back so |
364 # we don't misinterpret banner output as the command reply. |
354 # we don't misinterpret banner output as the command reply. |
365 if l.startswith(b'capabilities:'): |
355 if l.startswith(b'capabilities:'): |
366 caps.update(l[:-1].split(b':')[1].split()) |
356 caps.update(l[:-1].split(b':')[1].split()) |
367 break |
357 break |
368 elif protoname == wireprotoserver.SSHV2: |
|
369 # We see a line with number of bytes to follow and then a value |
|
370 # looking like ``capabilities: *``. |
|
371 line = stdout.readline() |
|
372 try: |
|
373 valuelen = int(line) |
|
374 except ValueError: |
|
375 badresponse() |
|
376 |
|
377 capsline = stdout.read(valuelen) |
|
378 if not capsline.startswith(b'capabilities: '): |
|
379 badresponse() |
|
380 |
|
381 ui.debug(b'remote: %s\n' % capsline) |
|
382 |
|
383 caps.update(capsline.split(b':')[1].split()) |
|
384 # Trailing newline. |
|
385 stdout.read(1) |
|
386 |
358 |
387 # Error if we couldn't find capabilities, this means: |
359 # Error if we couldn't find capabilities, this means: |
388 # |
360 # |
389 # 1. Remote isn't a Mercurial server |
361 # 1. Remote isn't a Mercurial server |
390 # 2. Remote is a <0.9.1 Mercurial server |
362 # 2. Remote is a <0.9.1 Mercurial server |
599 self._pipeo.flush() |
571 self._pipeo.flush() |
600 if self._autoreadstderr: |
572 if self._autoreadstderr: |
601 self._readerr() |
573 self._readerr() |
602 |
574 |
603 |
575 |
604 class sshv2peer(sshv1peer): |
|
605 """A peer that speakers version 2 of the transport protocol.""" |
|
606 |
|
607 # Currently version 2 is identical to version 1 post handshake. |
|
608 # And handshake is performed before the peer is instantiated. So |
|
609 # we need no custom code. |
|
610 |
|
611 |
|
612 def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): |
576 def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): |
613 """Make a peer instance from existing pipes. |
577 """Make a peer instance from existing pipes. |
614 |
578 |
615 ``path`` and ``proc`` are stored on the eventual peer instance and may |
579 ``path`` and ``proc`` are stored on the eventual peer instance and may |
616 not be used for anything meaningful. |
580 not be used for anything meaningful. |