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

89 lines
6.0 KiB
HTML
Raw Normal View History

2022-06-13 02:41:05 +00:00
{% 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 Command 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 protocll (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 do so.</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>Payloads are a non-zero number of <code>&</code> delimited <code>=</code> seperated key-value pairs. i.e.
<code>key1=value2&key2=value2</code>. Both the key and the value can contain any alphanumeric character, and any of
the symbols <code>._-:@%/\{}</code>. The value may alternatively be a single <code>?</code>. Leading and trailing
ampersands are illegal, as is more than one ampersand consecuitevely. Empty strings for either the key or value is
likewise illegal.
</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 observe the same restrictions as keys
and values. 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 %}