Skip to content

Commit 8c4d37f

Browse files
committed
Added documentation for the handshake pattern
1 parent 891e4e4 commit 8c4d37f

File tree

2 files changed

+102
-6
lines changed

2 files changed

+102
-6
lines changed

docs/kernels.rst

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,33 @@ There are three options for writing a kernel:
3232
- `xeus-python <https://github.com/jupyter-xeus/xeus-python>`_
3333
- `JuniperKernel <https://github.com/JuniperKernel/JuniperKernel>`_
3434

35+
.. _connection_file:
36+
3537
Connection files
3638
================
3739

38-
Your kernel will be given the path to a connection file when it starts (see
39-
:ref:`kernelspecs` for how to specify the command line arguments for your kernel).
40-
This file, which is accessible only to the current user, will contain a JSON
41-
dictionary looking something like this::
40+
When a kernel is started, it is provided **exactly one** of the following files as
41+
startup information (typically as a path passed on the kernel command line):
42+
43+
1. **A connection file** (the “classic” approach described below), containing the
44+
transport, IP, ports, and authentication key needed to connect the kernel’s
45+
ZeroMQ channels.
46+
47+
2. **A registration file** (handshake-based approach), used as part of the kernel
48+
startup handshake pattern. In this mode, the file does not directly provide all
49+
channel endpoints up front; instead, it enables a registration/handshake step
50+
through which the connection information is established.
51+
52+
Which of these two files is given to the kernel depends on the **kernel protocol
53+
version** supported by both the client and the kernel. Clients and kernels will use
54+
the most appropriate mechanism they both support. The handshake pattern is
55+
implemented in version 5.6 of the protocol.
56+
57+
Connection file format
58+
----------------------
59+
60+
A connection file, which is accessible only to the current user, will contain a
61+
JSON dictionary looking something like this::
4262

4363
{
4464
"control_port": 50160,
@@ -64,6 +84,38 @@ New ports are chosen at random for each kernel started.
6484
that other users on the system can't send code to run in this kernel. See
6585
:ref:`wire_protocol` for the details of how this signature is calculated.
6686

87+
Registration file format
88+
------------------------
89+
90+
A registration file will also contain a JSON dictionary, with the following
91+
fields::
92+
93+
{
94+
"kernel_id": "unique_kernel_id",
95+
"transport": "tcp",
96+
"registration_ip": "127.0.0.1",
97+
"registration_port": 51587,
98+
"signature_scheme": "hmac-sha256",
99+
"key": "a0436f6c-1916-498b-8eb9-e81ab9368e84"
100+
}
101+
102+
The ``transport``, ``registration_ip`` and ``registration_port`` fields specify
103+
the port the kernel should connect to to send its connection information. For
104+
instance, the address of the registration socket in the example above would be::
105+
106+
tcp://127.0.0.1:51587
107+
108+
``signature_scheme`` and ``key`` are used to cryptographically sign messages, so
109+
that other users on the system can't send code to run in this kernel. See
110+
:ref:`wire_protocol` for the details of how this signature is calculated.
111+
112+
``kernel_id`` is used so that the registration service can identify which kernel
113+
is sending its connection information on the registration socket.
114+
115+
See :ref:`kernel_startup_handshake` for the detail of how the kernel communications
116+
its connection information to the registration service.
117+
118+
67119
Handling messages
68120
=================
69121

@@ -163,6 +215,8 @@ JSON serialised dictionary containing the following keys and values:
163215
- **metadata** (optional): A dictionary of additional attributes about this
164216
kernel; used by clients to aid in kernel selection. Metadata added
165217
here should be namespaced for the tool reading and writing that metadata.
218+
- **kernel_protocol_version** (optional): A string indicating which version of the
219+
kernel protocol the kernel supports.
166220

167221
For example, the kernel.json file for IPython looks like this::
168222

docs/messaging.rst

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ messages are sent.
1111

1212
.. important::
1313
This document contains the authoritative description of the
14-
IPython messaging protocol. All developers are strongly encouraged to
14+
Jupyter messaging protocol. All developers are strongly encouraged to
1515
keep it updated as the implementation evolves, so that we have a single
1616
common reference for all protocol details.
1717

@@ -87,7 +87,8 @@ kernel has dedicated sockets for the following functions:
8787
.. versionchanged:: 5.5
8888
The **IOPub** PUB socket is replaced with an XPUB socket,
8989
to enable the ``iopub_welcome`` message.
90-
There is no other difference between kernel PUB and XPUB sockets from the client perspective.
90+
There is no other difference between kernel PUB and XPUB sockets from the client
91+
perspective.
9192

9293
The actual format of the messages allowed on each of these channels is
9394
specified below. Messages are dicts of dicts with string keys and values that
@@ -354,6 +355,47 @@ After the serialized dicts are zero to many raw data buffers,
354355
which can be used by message types that support binary data,
355356
which can be used in custom messages, such as comms and extensions to the protocol.
356357

358+
.. _kernel_startup_handshake:
359+
360+
Kernel startup handshake
361+
========================
362+
363+
If the kernel is passed a registration file instead of a connection file
364+
(see :ref:`connection_file`) when starting, this initiates the handshake.
365+
The kernel is responsible for selecting the ports for its five channels. It
366+
then connects a DEALER socket to the registration address it received, and
367+
sends a message containing the following JSON dictionary::
368+
369+
{
370+
'kernel_id': str,
371+
'control_port': str,
372+
'shell_port': str,
373+
'stdin_port': str,
374+
'iopub_port': str,
375+
'hb_port': str
376+
}
377+
378+
The ``kernel_id`` value must be that from the registration file.
379+
380+
This message is **not** a full Jupyter message with header, parent and metadata.
381+
It is a minimal, signed, single-frame content dict, serialized to the following
382+
blobs of bytes:
383+
384+
.. sourcecode:: python
385+
386+
[
387+
b"u-u-i-d", # zmq identity(ies)
388+
b"<IDS|MSG>", # delimiter
389+
b"baddad42", # HMAC signature
390+
b"{content}" # serialized content dict
391+
]
392+
393+
When the registration service receives this messages, it sends back a signed,
394+
single-frame content ACK message to the kernel. The content of this message is
395+
let to the implementation. The kernel can then close its DEALER socket and the
396+
handshake is over.
397+
398+
.. versionadded:: 5.6
357399

358400
Python API
359401
==========

0 commit comments

Comments
 (0)