blob: a5e058dfe11f8f901be97b044235f5dd8f989892 [file] [log] [blame]
// 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;
}