| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Code shared between devhost and devmgr |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <zircon/syscalls.h> |
| #include <zircon/syscalls/port.h> |
| |
| #include "devcoordinator.h" |
| |
| zx_status_t dc_msg_pack(dc_msg_t* msg, uint32_t* len_out, |
| const void* data, size_t datalen, |
| const char* name, const char* args) { |
| uint32_t max = DC_MAX_DATA; |
| uint8_t* ptr = msg->data; |
| |
| if (data) { |
| if (datalen > max) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| memcpy(ptr, data, datalen); |
| max -= datalen; |
| ptr += datalen; |
| msg->datalen = datalen; |
| } else { |
| msg->datalen = 0; |
| } |
| if (name) { |
| datalen = strlen(name) + 1; |
| if (datalen > max) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| memcpy(ptr, name, datalen); |
| max -= datalen; |
| ptr += datalen; |
| msg->namelen = datalen; |
| } else { |
| msg->namelen = 0; |
| } |
| if (args) { |
| datalen = strlen(args) + 1; |
| if (datalen > max) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| memcpy(ptr, args, datalen); |
| ptr += datalen; |
| msg->argslen = datalen; |
| } else { |
| msg->argslen = 0; |
| } |
| *len_out = sizeof(dc_msg_t) - DC_MAX_DATA + (ptr - msg->data); |
| return ZX_OK; |
| } |
| |
| |
| zx_status_t dc_msg_unpack(dc_msg_t* msg, size_t len, const void** data, |
| const char** name, const char** args) { |
| if (len < (sizeof(dc_msg_t) - DC_MAX_DATA)) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| len -= sizeof(dc_msg_t); |
| uint8_t* ptr = msg->data; |
| if (msg->datalen) { |
| if (msg->datalen > len) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| *data = ptr; |
| ptr += msg->datalen; |
| len -= msg->datalen; |
| } else { |
| *data = NULL; |
| } |
| if (msg->namelen) { |
| if (msg->namelen > len) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| *name = (char*) ptr; |
| ptr[msg->namelen - 1] = 0; |
| ptr += msg->namelen; |
| len -= msg->namelen; |
| } else { |
| *name = ""; |
| } |
| if (msg->argslen) { |
| if (msg->argslen > len) { |
| return ZX_ERR_BUFFER_TOO_SMALL; |
| } |
| *args = (char*) ptr; |
| ptr[msg->argslen - 1] = 0; |
| } else { |
| *args = ""; |
| } |
| return ZX_OK; |
| } |
| |
| zx_status_t dc_msg_rpc(zx_handle_t h, dc_msg_t* msg, size_t msglen, |
| zx_handle_t* handles, size_t hcount, |
| dc_status_t* rsp, size_t rsplen) { |
| zx_channel_call_args_t args = { |
| .wr_bytes = msg, |
| .wr_handles = handles, |
| .rd_bytes = rsp, |
| .rd_handles = NULL, |
| .wr_num_bytes = msglen, |
| .wr_num_handles = hcount, |
| .rd_num_bytes = rsplen, |
| .rd_num_handles = 0, |
| }; |
| |
| //TODO: incrementing txids |
| msg->txid = 1; |
| zx_status_t r; |
| if ((r = zx_channel_call(h, 0, ZX_TIME_INFINITE, |
| &args, &args.rd_num_bytes, &args.rd_num_handles, |
| NULL)) < 0) { |
| for (size_t n = 0; n < hcount; n++) { |
| zx_handle_close(handles[n]); |
| } |
| return r; |
| } |
| if (args.rd_num_bytes < sizeof(dc_status_t)) { |
| return ZX_ERR_INTERNAL; |
| } |
| |
| return rsp->status; |
| } |