docs/templates/pages/sega/software/pcp/index.html

120 lines
6.0 KiB
HTML

{% extends "sega.html" %} {% block title %}PCP{% endblock %} {% block body %}
<h1>PCP</h1>
<h2>What is PCP?</h2>
<p>
PCP is the protocol used for inter-process communication between services running on Ring* systems. I have no idea
what it stands for; head-canon it as Process Communication Protocol or whatever you want really. The official
implementation is <code>libpcp</code>, which is statically linked in to binaries that make use of the protocol (and
is itself dependent on <code>amLib</code>).
</p>
<p>
On paper, there are many things the format would at first appear to support, but is unable to due to the reference
implementation in <code>libpcp</code>. Specification of this nature will be <span class="mark">marked</span>. Custom
implementations should be liberal in what they receive, and conservative in what they transmit; marked specification
are key areas of focus for this.
</p>
<h2>Protocol Specification</h2>
<p>
We consider two processes communicating: a server, and a consumer. A server need only be capable of processing at
least one consumer concurrently, though implementations may desire the ability to process multiple consumers.
</p>
<p>
When a server is ready to process a command, it transmits a single <code>&gt;</code> byte to its connected consumer.
</p>
<p>The consumer responds with a CRLF-terminated payload packet, containing the command.</p>
<p>
The server then responds syncronously with a CRLF-terminated payload packet. If a data transfer is being a
performed, this packet will contain <code>port</code> and <code>size</code> as paramaters.
</p>
<p>
In a server->consumer data transfer operation, the consumer connects to the provided port, and expects to receive
<code>size</code> bytes of data. It then closes the connection to the data port and transmits a <code>$</code> byte
to the server to ackgnowledge receipt. The server will only process this ackgnowledgement after it has succesfully
transmitted its data to a consumer.
</p>
<p>The characteristics of a consumer->server transfer as as yet undocumented. I'll get round to it!</p>
<p>
If the server is unable to process a request for any reason, it may respond with a single <code>?</code>. This may
be due to a non existant command being requested, or it may be due to an invalid packet.
</p>
<h3>Payload format</h3>
<p>
Outside of special packets such as <code>&gt;</code> and <code>$</code>, all communication in both directions
strictly follows the following structure:
</p>
<img src="{{ROOT}}/images/pcp-railroad.png" class="graphic" />
<p>
<i><code>Text</code></i> is defined as a series of one or more bytes matching <code>[a-zA-Z0-9._:@%/\{}-]</code>.
</p>
<p>
Spaces (ascii 20<sub>h</sub>) and tabs (ascii 09<sub>h</sub>) are allowable whitespace. They may be present anywhere
in the packet surrounding keys, values, any delimiter, or seperator, and will be ignored. They are not valid within
a key or a value.
</p>
<p>
Comments begin and end with the <code>#</code> symbol. They may appear at any point in a packet, and the packet
should be processed as if the comment is not there.
<b
>The content of comments must match <i><code>Text</code></i
>. This notably includes no whitespace.</b
>
</p>
<h2>Format restrictions</h2>
<ul>
<li><span class="mark">Payloads MUST NOT exceed 256 bytes, including the terminating CRLF.</span></li>
<li><span class="mark">There may be at most 64 key-value pairs in a payload.</span></li>
</ul>
<h2>Example communication</h2>
<p>Communication from the server is marked in blue, and communication from the client is marked in red.</p>
<pre><code><span class="server">&gt;</span><span class="client">nonsense
</span><span class="server">?
&gt;</span><span class="client">keychip.version=?&device=n2&cache=0
</span><span class="server">keychip.version=0104
&gt;</span><span class="client">keyc#comment#hip.version=?
</span><span class="server">keychip.version=0104
&gt;</span><span class="client">keychip.billing.cacertification=?
</span><span class="server">keychip.billing.cacertification=0&port=40107&size=817
</span><span class="client">$</span><span class="server">&gt;</span></code></pre>
<p>(Note an additional connection was made to <code>:40107</code> before transmitting the <code>$</code>.)</p>
<details>
<summary>libpcp bugs</summary>
<p>
When parsing requests, libpcp null-terminates <code>?</code> values with an off-by-one error. This means if you
transmit <code>test=12345</code> followed by <code>test=?</code>, it will be parsed as if you had transmitted
<code>test=?2</code>. This could actually be an issue with how I am inspecting the internal state; I will
update/remove this spoilier once I've had a chance to dig deeper.
</p>
<p>
libpcp does not enforce ampersand placement, causing strange memory artifacts. Consumers <b>MUST</b> conform to
the ampersand specification.
</p>
<p>
libpcp allows empty keys and values. The case of an empty key causes the pair to be keyed with an empty string,
however an empty value causes it to contain a random value, reading from memory where the previous packet was
decoded. In fact, the presence of a <code>=</code> is not validated either, likewise causing it to read
undefined regions of memory. Consumers <b>MUST</b> always provide both the key and the value.
</p>
</details>
<details>
<summary>Using libpcp</summary>
<p>
I have reproduced a locally functioning standalone distribution of libpcp, warts and all. Eventually I will
produce some basic docs for making use of the exported functions, and will hopefully be able to provide a
download for a precompiled library. I'm still unsure if the source code will ever be made available however
because it's a <em>very</em> true to the original reproduction, potentially problematically so!
</p>
<p>If rather than implementing your own pcp you wish to use <em>the</em> libpcp, watch this space.</p>
</details>
{% endblock %}