changeset 35939:a622a927fe03

sshpeer: document the handshake mechanism The mechanism by which SSH peers establish connections with remotes is wonky and requires a bit of code archeology to understand. While it is already documented in `hg help internals.wireproto`, it helps to have documentation in the code as well. Differential Revision: https://phab.mercurial-scm.org/D2035
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 04 Feb 2018 14:44:04 -0800
parents 80a2b8ae42a1
children 556218e08e25
files mercurial/sshpeer.py
diffstat 1 files changed, 33 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/sshpeer.py	Mon Feb 05 09:14:32 2018 -0800
+++ b/mercurial/sshpeer.py	Sun Feb 04 14:44:04 2018 -0800
@@ -162,6 +162,37 @@
         hint = ui.config('ui', 'ssherrorhint')
         raise error.RepoError(msg, hint=hint)
 
+    # The handshake consists of sending 2 wire protocol commands:
+    # ``hello`` and ``between``.
+    #
+    # The ``hello`` command (which was introduced in Mercurial 0.9.1)
+    # instructs the server to advertise its capabilities.
+    #
+    # The ``between`` command (which has existed in all Mercurial servers
+    # for as long as SSH support has existed), asks for the set of revisions
+    # between a pair of revisions.
+    #
+    # The ``between`` command is issued with a request for the null
+    # range. If the remote is a Mercurial server, this request will
+    # generate a specific response: ``1\n\n``. This represents the
+    # wire protocol encoded value for ``\n``. We look for ``1\n\n``
+    # in the output stream and know this is the response to ``between``
+    # and we're at the end of our handshake reply.
+    #
+    # The response to the ``hello`` command will be a line with the
+    # length of the value returned by that command followed by that
+    # value. If the server doesn't support ``hello`` (which should be
+    # rare), that line will be ``0\n``. Otherwise, the value will contain
+    # RFC 822 like lines. Of these, the ``capabilities:`` line contains
+    # the capabilities of the server.
+    #
+    # In addition to the responses to our command requests, the server
+    # may emit "banner" output on stdout. SSH servers are allowed to
+    # print messages to stdout on login. Issuing commands on connection
+    # allows us to flush this banner output from the server by scanning
+    # for output to our well-known ``between`` command. Of course, if
+    # the banner contains ``1\n\n``, this will throw off our detection.
+
     requestlog = ui.configbool('devel', 'debug.peer-request')
 
     try:
@@ -205,6 +236,8 @@
 
     caps = set()
     for l in reversed(lines):
+        # Look for response to ``hello`` command. Scan from the back so
+        # we don't misinterpret banner output as the command reply.
         if l.startswith('capabilities:'):
             caps.update(l[:-1].split(':')[1].split())
             break