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.
Beispiel #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.