The Yar Protocol

Yar does not rely on a schema or IDL file: everything is exchanged on the wire as plain bytes. Any language that can read and write bytes can speak to a Yar service, without installing any framework at all — build one fixed-size binary header and a serialized request body, send them to the service URI, and parse the reply.

A message consists of a fixed-size header of 82 bytes followed by a body. The header is laid out exactly like the following C structure, packed with no padding, and is written to the wire field after field in declaration order:

typedef struct _yar_header {
 uint32_t id; /* transaction id */
 uint16_t version; /* protocol version, currently always 0 */
 uint32_t magic_num; /* must be 0x80DFEC60 */
 uint32_t reserved;
 unsigned char provider[32]; /* request from whom (authentication) */
 unsigned char token[32]; /* request token (authentication) */
 uint32_t body_len; /* length of the whole body, including
 the packager identifier */
} __attribute__ ((packed)) yar_header_t;

The id, magic_num, reserved and body_len fields are stored in network byte order (big-endian); the remaining fields are raw bytes.

The body starts with an 8-byte packager identifier — PHP, JSON or MSGPACK, zero-padded — telling the receiver how the remainder was encoded, followed by the serialized content itself.

  • The request body decodes to an array with the keys i (the transaction id), m (the method being called) and p (the list of parameters).

  • The response body decodes to an array with the keys i (the transaction id), s (the status, one of the YAR_ERR_* codes), r (the return value), o (any output the service method produced) and e (the error or exception, when the call failed).

Over HTTP the message is sent as the body of a POST request, with the response arriving as the body of the reply; over TCP or Unix sockets it is written directly on the stream.

Example #1 Calling a Yar service without the extension

The following self-contained script builds a valid Yar request for the php packager with nothing but standard sockets, sends it to a service URI, and prints the decoded response. Running it against the Operator service from the examples prints int(3).

<?php
$uri = "http://api.example.com/operator.php";
/* 1. the body: packager identifier + serialized request */
$serialized = serialize(array("i" => 1, "m" => "add", "p" => array(1, 2)));
$body = str_pad("PHP", 8, "0円") . $serialized;
/* 2. the header: 82 bytes, multi-byte integers in network byte order */
$header = pack("N", 1) /* id */
 . pack("v", 0) /* version */
 . pack("N", 0x80DFEC60) /* magic number */
 . pack("N", 0) /* reserved */
 . str_pad("", 32, "0円") /* provider */
 . str_pad("", 32, "0円") /* token */
 . pack("N", strlen($body)); /* body length */
/* 3. send it as the body of a POST request */
$stream = stream_context_create(array("http" => array(
 "method" => "POST",
 "header" => "Content-Type: application/octet-stream\r\n",
 "content" => $header . $body,
)));
$reply = file_get_contents($uri, false, $stream);
/* 4. parse the reply: 82-byte header, then the response body */
$response = unserialize(substr($reply, 82 + 8));
var_dump($response["r"]);
?>

A more complete client implementation in plain PHP, which also decodes the response header and supports concurrent calls, lives in the tools/ directory of the » Yar source repository.

Found A Problem?

Learn How To Improve This Page • Submit a Pull Request • Report a Bug
+add a note

User Contributed Notes

There are no user contributed notes for this page.

AltStyle によって変換されたページ (->オリジナル) /