16static const uint32_t RPC_MSGTYPE_CALL = 0;
17static const uint32_t RPC_MSGTYPE_REPLY = 1;
29static void xw_u32(XdrW *w, uint32_t v)
31 if (!w->ok || w->off + 4 > w->cap)
41static void xw_bytes(XdrW *w,
const uint8_t *d,
size_t n)
43 size_t pad = (4 - (n & 3)) & 3;
44 if (!w->ok || w->off + 4 + n + pad > w->cap)
53 memcpy(w->p + w->off, d, n);
56 for (
size_t i = 0; i < pad; i++)
70static uint32_t xr_u32(XdrR *r)
72 if (!r->ok || r->off + 4 > r->len)
83static bool xr_bytes(XdrR *r,
const uint8_t **d,
size_t *n)
85 uint32_t len = xr_u32(r);
90 size_t pad = (4 - (len & 3)) & 3;
91 if (r->off + len + pad > r->len)
110size_t pc_rpc_record_mark(uint8_t *buf,
size_t cap, uint32_t payload_len)
112 if (!buf || cap < 4 || (payload_len & 0x80000000u))
116 pc_wr32be(buf, 0x80000000u | payload_len);
120bool pc_rpc_parse_record_mark(
const uint8_t *buf,
size_t len,
bool *last, uint32_t *frag_len)
129 *last = (rm & 0x80000000u) != 0;
133 *frag_len = rm & 0x7FFFFFFFu;
140static XdrW begin_call(uint8_t *buf,
size_t cap, uint32_t xid, uint32_t prog, uint32_t vers, uint32_t proc)
142 XdrW w = {buf, cap, 4, buf !=
nullptr};
144 xw_u32(&w, RPC_MSGTYPE_CALL);
149 xw_u32(&w, PC_RPC_AUTH_NONE);
151 xw_u32(&w, PC_RPC_AUTH_NONE);
156static size_t finish_call(XdrW *w)
162 pc_rpc_record_mark(w->p, w->cap, (uint32_t)(w->off - 4));
166bool pc_rpc_parse_reply(
const uint8_t *rpc,
size_t len, uint32_t *xid, uint32_t *accept_stat,
size_t *result_off)
172 XdrR r = {rpc, len, 0,
true};
173 uint32_t x = xr_u32(&r);
174 uint32_t mtype = xr_u32(&r);
175 uint32_t reply_stat = xr_u32(&r);
177 xr_bytes(&r,
nullptr,
nullptr);
178 uint32_t astat = xr_u32(&r);
179 if (!r.ok || mtype != RPC_MSGTYPE_REPLY || reply_stat != PC_RPC_MSG_ACCEPTED)
189 *accept_stat = astat;
199static bool reply_results(
const uint8_t *rpc,
size_t len, XdrR *r)
203 if (!pc_rpc_parse_reply(rpc, len,
nullptr, &astat, &off) || astat != PC_RPC_ACCEPT_SUCCESS)
216size_t pc_vxi11_build_getport(uint8_t *buf,
size_t cap, uint32_t xid, uint32_t prog, uint32_t vers, uint32_t proto)
218 XdrW w = begin_call(buf, cap, xid, PC_RPC_PMAP_PROG, PC_RPC_PMAP_VERS, PC_RPC_PMAP_GETPORT);
223 return finish_call(&w);
226bool pc_vxi11_parse_getport_resp(
const uint8_t *rpc,
size_t len, uint32_t *port)
229 if (!reply_results(rpc, len, &r))
233 uint32_t p = xr_u32(&r);
247size_t pc_vxi11_build_create_link(uint8_t *buf,
size_t cap, uint32_t xid, int32_t client_id,
bool lock_device,
248 uint32_t lock_timeout,
const char *device)
250 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::CREATE_LINK);
251 xw_u32(&w, (uint32_t)client_id);
252 xw_u32(&w, lock_device ? 1 : 0);
253 xw_u32(&w, lock_timeout);
254 size_t dlen = device ? strnlen(device, cap) : 0;
255 xw_bytes(&w, (
const uint8_t *)device, dlen);
256 return finish_call(&w);
259bool pc_vxi11_parse_create_link_resp(
const uint8_t *rpc,
size_t len, Vxi11CreateLinkResp *out)
262 if (!out || !reply_results(rpc, len, &r))
266 out->error = (int32_t)xr_u32(&r);
267 out->lid = (int32_t)xr_u32(&r);
268 out->abort_port = xr_u32(&r);
269 out->max_recv_size = xr_u32(&r);
273size_t pc_vxi11_build_device_write(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid, uint32_t io_timeout,
274 uint32_t lock_timeout, uint32_t flags,
const uint8_t *data,
size_t data_len)
276 if (data_len && !data)
280 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DEVICE_WRITE);
281 xw_u32(&w, (uint32_t)lid);
282 xw_u32(&w, io_timeout);
283 xw_u32(&w, lock_timeout);
285 xw_bytes(&w, data, data_len);
286 return finish_call(&w);
289bool pc_vxi11_parse_write_resp(
const uint8_t *rpc,
size_t len, Vxi11WriteResp *out)
292 if (!out || !reply_results(rpc, len, &r))
296 out->error = (int32_t)xr_u32(&r);
297 out->size = xr_u32(&r);
301size_t pc_vxi11_build_device_read(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid, uint32_t request_size,
302 uint32_t io_timeout, uint32_t lock_timeout, uint32_t flags, uint8_t term_char)
304 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DEVICE_READ);
305 xw_u32(&w, (uint32_t)lid);
306 xw_u32(&w, request_size);
307 xw_u32(&w, io_timeout);
308 xw_u32(&w, lock_timeout);
310 xw_u32(&w, term_char);
311 return finish_call(&w);
314bool pc_vxi11_parse_read_resp(
const uint8_t *rpc,
size_t len, Vxi11ReadResp *out)
317 if (!out || !reply_results(rpc, len, &r))
321 out->error = (int32_t)xr_u32(&r);
322 out->reason = (int32_t)xr_u32(&r);
325 xr_bytes(&r, &out->data, &out->data_len);
329size_t pc_vxi11_build_device_readstb(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid, uint32_t flags,
330 uint32_t lock_timeout, uint32_t io_timeout)
332 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DEVICE_READSTB);
333 xw_u32(&w, (uint32_t)lid);
335 xw_u32(&w, lock_timeout);
336 xw_u32(&w, io_timeout);
337 return finish_call(&w);
340bool pc_vxi11_parse_readstb_resp(
const uint8_t *rpc,
size_t len, Vxi11ReadStbResp *out)
343 if (!out || !reply_results(rpc, len, &r))
347 out->error = (int32_t)xr_u32(&r);
348 out->stb = (uint8_t)xr_u32(&r);
352size_t pc_vxi11_build_device_clear(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid, uint32_t flags,
353 uint32_t lock_timeout, uint32_t io_timeout)
355 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DEVICE_CLEAR);
356 xw_u32(&w, (uint32_t)lid);
358 xw_u32(&w, lock_timeout);
359 xw_u32(&w, io_timeout);
360 return finish_call(&w);
363size_t pc_vxi11_build_device_trigger(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid, uint32_t flags,
364 uint32_t lock_timeout, uint32_t io_timeout)
366 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DEVICE_TRIGGER);
367 xw_u32(&w, (uint32_t)lid);
369 xw_u32(&w, lock_timeout);
370 xw_u32(&w, io_timeout);
371 return finish_call(&w);
374size_t pc_vxi11_build_destroy_link(uint8_t *buf,
size_t cap, uint32_t xid, int32_t lid)
376 XdrW w = begin_call(buf, cap, xid, PC_VXI11_CORE_PROG, PC_VXI11_CORE_VERS, (uint32_t)Vxi11Proc::DESTROY_LINK);
377 xw_u32(&w, (uint32_t)lid);
378 return finish_call(&w);
381bool pc_vxi11_parse_error_resp(
const uint8_t *rpc,
size_t len, int32_t *error)
384 if (!reply_results(rpc, len, &r))
388 int32_t e = (int32_t)xr_u32(&r);
400const char *pc_vxi11_error_str(int32_t error)
404 case PC_VXI11_ERR_NONE:
406 case PC_VXI11_ERR_SYNTAX:
407 return "syntax error";
408 case PC_VXI11_ERR_NOT_ACCESSIBLE:
409 return "device not accessible";
410 case PC_VXI11_ERR_INVALID_LINK:
411 return "invalid link identifier";
412 case PC_VXI11_ERR_PARAMETER:
413 return "parameter error";
415 return "channel not established";
417 return "operation not supported";
419 return "out of resources";
421 return "device locked by another link";
422 case PC_VXI11_ERR_NO_LOCK:
423 return "no lock held by this link";
424 case PC_VXI11_ERR_IO_TIMEOUT:
425 return "I/O timeout";
426 case PC_VXI11_ERR_IO_ERROR:
429 return "invalid address";
430 case PC_VXI11_ERR_ABORT:
433 return "channel already established";
435 return "unknown error";
Fixed-width integer serializers into a raw uint8_t* buffer - one source of truth.
uint32_t pc_rd32be(const uint8_t *p)
Read a big-endian u32 at p.
size_t pc_wr32be(uint8_t *p, uint32_t v)
Write v big-endian at p.
VXI-11 (TCP/IP Instrument Protocol) codec over ONC RPC / XDR (PC_ENABLE_VXI11) - a zero-heap codec fo...