Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/source/contributing/conventions/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ House Conventions
* :ref:`mint-criterion` -- :mod:`pcapkit.const`, which is where the settled
questions have mostly arisen;
* :ref:`sentinel-convention` -- :mod:`pcapkit.corekit`;
* :ref:`registry-protocol` -- :mod:`pcapkit.const` again;
* :ref:`registry-protocol` -- :mod:`pcapkit.const` again, and the registration
wrappers of :mod:`pcapkit.foundation.registry`;
* :ref:`extension-header-subclassing` -- a protocol class hierarchy;
* :ref:`protocol-family-grouping` -- how a protocol family's base and members
spell :meth:`~pcapkit.protocols.protocol.Protocol.id`;
Expand Down
81 changes: 81 additions & 0 deletions docs/source/contributing/conventions/registry-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -642,3 +642,84 @@ reasoning.
:mod:`pcapkit.vendor.default`'s template, never in the generated file alone --
the next regeneration would discard it.

Registration Wrappers
~~~~~~~~~~~~~~~~~~~~~

The owner ruled on :issue:`2511` that every class-level registry map a protocol
dispatches through -- ``__proto__``, ``__option__``, ``__chunk__`` and the like -- has a
public wrapper in :mod:`pcapkit.foundation.registry`, carrying the validation the
established ones carry. A map's registration comes in two parts:

1. **A** ``register`` **or** ``register_<kind>`` **classmethod** on the class owning
the map -- ``register`` for ``__proto__``, ``register_<kind>`` for ``__<kind>__``
-- which writes it and warns when it displaces an entry. An inherited one counts
only when it is typed and validated for exactly that map's keys, which the owner
chose over an override on every class (:issue:`2511`). So
:class:`~pcapkit.protocols.transport.tcp.TCP` and
:class:`~pcapkit.protocols.transport.udp.UDP` keep
:meth:`Transport.register <pcapkit.protocols.transport.transport.Transport.register>`,
typed for the port their maps are keyed by, while
:class:`~pcapkit.protocols.internet.ipx.IPX` and
:class:`~pcapkit.protocols.link.loopback.Loopback` override their parents'
:meth:`Internet.register <pcapkit.protocols.internet.internet.Internet.register>`
and :meth:`Link.register <pcapkit.protocols.link.link.Link.register>`: those are
typed for :class:`~pcapkit.const.reg.transtype.TransType` and
:class:`~pcapkit.const.reg.ethertype.EtherType`, not for the IPX packet type and
address family these two maps are keyed by.
2. **A** ``register_<name>`` **function** in
:mod:`pcapkit.foundation.registry.protocols`, tagged ``# NOTE: <map path>`` on the
line above its ``def``. It calls the classmethod and logs, and a bad argument
writes nothing: ``_check_code`` checks the code against the map's enum, or, with
``kind=None``, as a bare :class:`int` where no enum keys the map; a parser named
by string has to exist as a ``_read_*`` method; and a ``__proto__`` entry has to
be a :class:`~pcapkit.protocols.protocol.ProtocolBase` subclass or a descriptor
naming one. A wrapper writing a ``__proto__`` map also records the class's name
with ``_register_name``, and one whose entries have a schema registry takes a
keyword-only ``schema``.

**A** ``__proto__`` **wrapper is named after its keys.** One taking only an enum's
members takes the enum's name, as
:func:`~pcapkit.foundation.registry.protocols.register_ethertype` does; one taking
bare :class:`int` keys, with or without an enum beside them, takes the owning
protocol's name, as :func:`~pcapkit.foundation.registry.protocols.register_tcp` and
:func:`~pcapkit.foundation.registry.protocols.register_loopback` do. These depart
from it:

* :func:`~pcapkit.foundation.registry.protocols.register_pcap` and
:func:`~pcapkit.foundation.registry.protocols.register_pcapng` take only
:class:`~pcapkit.const.reg.linktype.LinkType` members, but
:func:`~pcapkit.foundation.registry.protocols.register_linktype` holds that name
for writing both their maps at once, so each takes its capture format's name.
* :func:`~pcapkit.foundation.registry.protocols.register_apptype` takes bare
:class:`int` keys, but writes :class:`~pcapkit.protocols.transport.tcp.TCP`'s map,
:class:`~pcapkit.protocols.transport.udp.UDP`'s or both, by transport, so no one
owner's name fits and it takes
:class:`~pcapkit.const.reg.apptype.apptype.AppType`'s.

:func:`~pcapkit.foundation.registry.protocols.register_protocol` and
:func:`~pcapkit.foundation.registry.protocols.register_protocol_code` are outside the
rule: the first writes :data:`pcapkit.protocols.__proto__`, keyed by class name, and
the second whichever maps its ``code`` names.

:func:`~pcapkit.foundation.registry.protocols.register_sctp_chunk` is the shape for a
parser map:

.. code-block:: python

# NOTE: pcapkit.protocols.transport.sctp.SCTP.__chunk__
def register_sctp_chunk(code, meth, *, schema=None):
_check_code(code, SCTP_Chunk, SCTP)
if isinstance(meth, str) and not hasattr(SCTP, f'_read_chunk_{meth}'):
raise RegistryError('method must be a valid SCTP chunk parser function')

SCTP.register_chunk(code, meth)
if schema is not None:
Schema_SCTP_Chunk.register(code, schema)
logger.debug('registered SCTP chunk parser: %s', code.name)

:file:`tests/foundation/registry/test_registry_wrapper_coverage_2511_unit.py` walks
every protocol class for such a map, and fails on one that no wrapper's tag names
unless its ``EXCUSED`` table gives the reason. It fails as well on a map whose owner
defines no ``register*`` classmethod of its own, unless its ``INHERITED`` table names
the one typed for that map's keys.

16 changes: 11 additions & 5 deletions docs/source/ext.rst
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ The registry function per protocol type:
| | | :func:`~pcapkit.foundation.registry.protocols.register_sctp` | |
+-------------------+-------------------------------------------------------------------+----------------------------------------------------------------+--------------------+

A protocol carried over IPX is keyed by IPX Packet Type rather than by IP protocol
number, so it registers through
:func:`~pcapkit.foundation.registry.protocols.register_ipx`; one carried over BSD
loopback is keyed by address family rather than by EtherType, and registers through
:func:`~pcapkit.foundation.registry.protocols.register_loopback`.

Samples
~~~~~~~

Expand Down Expand Up @@ -384,19 +390,19 @@ writes them:
+ + +-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | | :attr:`MH.__extension__ <pcapkit.protocols.internet.mh.MH.__extension__>` | :func:`~pcapkit.foundation.registry.protocols.register_mh_extension` |
+ +------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | :class:`~pcapkit.protocols.internet.icmpv4.ICMPv4` | :attr:`ICMPv4.__type__ <pcapkit.protocols.internet.icmpv4.ICMPv4.__type__>` | :meth:`~pcapkit.protocols.internet.icmpv4.ICMPv4.register_type` |
| | :class:`~pcapkit.protocols.internet.icmpv4.ICMPv4` | :attr:`ICMPv4.__type__ <pcapkit.protocols.internet.icmpv4.ICMPv4.__type__>` | :func:`~pcapkit.foundation.registry.protocols.register_icmp_type` |
+ +------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | :class:`~pcapkit.protocols.internet.icmpv6.ICMPv6` | :attr:`ICMPv6.__type__ <pcapkit.protocols.internet.icmpv6.ICMPv6.__type__>` | :meth:`~pcapkit.protocols.internet.icmpv6.ICMPv6.register_type` |
| | :class:`~pcapkit.protocols.internet.icmpv6.ICMPv6` | :attr:`ICMPv6.__type__ <pcapkit.protocols.internet.icmpv6.ICMPv6.__type__>` | :func:`~pcapkit.foundation.registry.protocols.register_icmp_type` |
+-------------------+------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | | :attr:`TCP.__option__ <pcapkit.protocols.transport.tcp.TCP.__option__>` | :func:`~pcapkit.foundation.registry.protocols.register_tcp_option` |
+ Transport Layer + :class:`~pcapkit.protocols.transport.tcp.TCP` +-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | | :attr:`TCP.__mp_option__ <pcapkit.protocols.transport.tcp.TCP.__mp_option__>` | :func:`~pcapkit.foundation.registry.protocols.register_tcp_mp_option` |
+ +------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | | :attr:`SCTP.__chunk__ <pcapkit.protocols.transport.sctp.SCTP.__chunk__>` | :meth:`~pcapkit.protocols.transport.sctp.SCTP.register_chunk` |
| | | :attr:`SCTP.__chunk__ <pcapkit.protocols.transport.sctp.SCTP.__chunk__>` | :func:`~pcapkit.foundation.registry.protocols.register_sctp_chunk` |
+ + +-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | :class:`~pcapkit.protocols.transport.sctp.SCTP` | :attr:`SCTP.__parameter__ <pcapkit.protocols.transport.sctp.SCTP.__parameter__>` | :meth:`~pcapkit.protocols.transport.sctp.SCTP.register_parameter` |
| | :class:`~pcapkit.protocols.transport.sctp.SCTP` | :attr:`SCTP.__parameter__ <pcapkit.protocols.transport.sctp.SCTP.__parameter__>` | :func:`~pcapkit.foundation.registry.protocols.register_sctp_parameter` |
+ + +-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| | | :attr:`SCTP.__cause__ <pcapkit.protocols.transport.sctp.SCTP.__cause__>` | :meth:`~pcapkit.protocols.transport.sctp.SCTP.register_cause` |
| | | :attr:`SCTP.__cause__ <pcapkit.protocols.transport.sctp.SCTP.__cause__>` | :func:`~pcapkit.foundation.registry.protocols.register_sctp_cause` |
+-------------------+------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
| Application Layer | :class:`~pcapkit.protocols.application.httpv2.HTTP` | :attr:`HTTP.__frame__ <pcapkit.protocols.application.httpv2.HTTP.__frame__>` | :func:`~pcapkit.foundation.registry.protocols.register_http_frame` |
+-------------------+------------------------------------------------------------+-----------------------------------------------------------------------------------------------+----------------------------------------------------------------------------+
Expand Down
10 changes: 10 additions & 0 deletions docs/source/pcapkit/foundation/registry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,15 @@ Link Layer Registries

.. autofunction:: pcapkit.foundation.registry.protocols.register_ethertype

.. autofunction:: pcapkit.foundation.registry.protocols.register_loopback

Internet Layer Registries
~~~~~~~~~~~~~~~~~~~~~~~~~

.. autofunction:: pcapkit.foundation.registry.protocols.register_transtype

.. autofunction:: pcapkit.foundation.registry.protocols.register_ipx

.. autofunction:: pcapkit.foundation.registry.protocols.register_ipv4_option

.. autofunction:: pcapkit.foundation.registry.protocols.register_icmp_type
Expand Down Expand Up @@ -121,6 +125,12 @@ Transport Layer Registries

.. autofunction:: pcapkit.foundation.registry.protocols.register_sctp

.. autofunction:: pcapkit.foundation.registry.protocols.register_sctp_chunk

.. autofunction:: pcapkit.foundation.registry.protocols.register_sctp_parameter

.. autofunction:: pcapkit.foundation.registry.protocols.register_sctp_cause

Application Layer Registries
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
3 changes: 3 additions & 0 deletions docs/source/pcapkit/protocols/internet/ipx.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Octets Bits Name Description

.. automethod:: read
.. automethod:: make
.. automethod:: register

.. automethod:: _make_data
.. automethod:: _next_exthdr_depth
Expand All @@ -40,6 +41,8 @@ Octets Bits Name Description

.. autoattribute:: __proto__
:no-value:
.. autoattribute:: __proto_key__
:no-value:

Header Schemas
--------------
Expand Down
1 change: 1 addition & 0 deletions docs/source/pcapkit/protocols/link/loopback.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ is kept as ``loopback.byteorder``.

.. automethod:: read
.. automethod:: make
.. automethod:: register

.. automethod:: _make_data

Expand Down
3 changes: 3 additions & 0 deletions pcapkit/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,17 @@
'register_linktype',
'register_pcap', 'register_pcapng',
'register_ethertype',
'register_loopback',
'register_transtype',
'register_ipx',
'register_icmp_type',
'register_ipv4_option', 'register_hip_parameter', 'register_hopopt_option',
'register_ipv6_opts_option', 'register_ipv6_route_routing',
'register_mh_message', 'register_mh_option', 'register_mh_extension',
'register_apptype',
'register_tcp', 'register_udp', 'register_sctp',
'register_tcp_option', 'register_tcp_mp_option',
'register_sctp_chunk', 'register_sctp_parameter', 'register_sctp_cause',
'register_http_frame',
'register_pcapng_block', 'register_pcapng_option', 'register_pcapng_secrets',
'register_pcapng_record',
Expand Down
3 changes: 3 additions & 0 deletions pcapkit/foundation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@
'register_linktype',
'register_pcap', 'register_pcapng',
'register_ethertype',
'register_loopback',
'register_transtype',
'register_ipx',
'register_icmp_type',
'register_ipv4_option', 'register_hip_parameter', 'register_hopopt_option',
'register_ipv6_opts_option', 'register_ipv6_route_routing',
'register_mh_message', 'register_mh_option', 'register_mh_extension',
'register_apptype',
'register_tcp', 'register_udp', 'register_sctp',
'register_tcp_option', 'register_tcp_mp_option',
'register_sctp_chunk', 'register_sctp_parameter', 'register_sctp_cause',
'register_http_frame',
'register_pcapng_block', 'register_pcapng_option', 'register_pcapng_secrets',
'register_pcapng_record',
Expand Down
3 changes: 3 additions & 0 deletions pcapkit/foundation/registry/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
'register_pcap', 'register_pcapng',

'register_ethertype',
'register_loopback',

'register_transtype',
'register_ipx',
'register_icmp_type',
'register_ipv4_option', 'register_hip_parameter', 'register_hopopt_option',
'register_ipv6_opts_option', 'register_ipv6_route_routing',
Expand All @@ -41,6 +43,7 @@
'register_apptype',
'register_tcp', 'register_udp', 'register_sctp',
'register_tcp_option', 'register_tcp_mp_option',
'register_sctp_chunk', 'register_sctp_parameter', 'register_sctp_cause',

'register_http_frame',

Expand Down
Loading
Loading