135 lines
4.2 KiB
C++
135 lines
4.2 KiB
C++
// 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.
|
|
|
|
#include <lib/fidl/coding.h>
|
|
|
|
#include <stdalign.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <lib/fidl/internal.h>
|
|
#include <zircon/assert.h>
|
|
#include <zircon/compiler.h>
|
|
|
|
#ifdef __Fuchsia__
|
|
#include <zircon/syscalls.h>
|
|
#endif
|
|
|
|
#include "buffer_walker.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
// TODO(kulakowski) Design zx_status_t error values.
|
|
|
|
namespace {
|
|
|
|
class FidlEncoder final : public fidl::internal::BufferWalker<FidlEncoder, true, true> {
|
|
typedef fidl::internal::BufferWalker<FidlEncoder, true, true> Super;
|
|
|
|
public:
|
|
FidlEncoder(const fidl_type_t* type, void* bytes, uint32_t num_bytes, zx_handle_t* handles,
|
|
uint32_t num_handles, uint32_t* out_actual_handles, const char** out_error_msg)
|
|
: Super(type), bytes_(static_cast<uint8_t*>(bytes)), num_bytes_(num_bytes),
|
|
handles_(handles), num_handles_(num_handles), out_actual_handles_(out_actual_handles),
|
|
out_error_msg_(out_error_msg) {}
|
|
|
|
void Walk() {
|
|
if (handles_ == nullptr && num_handles_ != 0u) {
|
|
SetError("Cannot provide non-zero handle count and null handle pointer");
|
|
return;
|
|
}
|
|
if (out_actual_handles_ == nullptr) {
|
|
SetError("Cannot encode with null out_actual_handles");
|
|
return;
|
|
}
|
|
Super::Walk();
|
|
if (status_ == ZX_OK) {
|
|
*out_actual_handles_ = handle_idx();
|
|
}
|
|
}
|
|
|
|
uint8_t* bytes() const { return bytes_; }
|
|
uint32_t num_bytes() const { return num_bytes_; }
|
|
uint32_t num_handles() const { return num_handles_; }
|
|
|
|
bool ValidateOutOfLineStorageClaim(const void* a, const void* b) {
|
|
return a == b;
|
|
}
|
|
|
|
void UnclaimedHandle(zx_handle_t* out_handle) {
|
|
#ifdef __Fuchsia__
|
|
// Return value intentionally ignored: this is best-effort cleanup.
|
|
zx_handle_close(*out_handle);
|
|
#endif
|
|
}
|
|
void ClaimedHandle(zx_handle_t* out_handle, uint32_t idx) {
|
|
assert(out_handle != nullptr);
|
|
handles_[idx] = *out_handle;
|
|
*out_handle = FIDL_HANDLE_PRESENT;
|
|
}
|
|
|
|
PointerState GetPointerState(const void* ptr) const {
|
|
return *static_cast<const uintptr_t*>(ptr) == 0
|
|
? PointerState::ABSENT
|
|
: PointerState::PRESENT;
|
|
}
|
|
HandleState GetHandleState(zx_handle_t p) const {
|
|
return p == ZX_HANDLE_INVALID
|
|
? HandleState::ABSENT
|
|
: HandleState::PRESENT;
|
|
}
|
|
|
|
template <class T>
|
|
void UpdatePointer(T** p, T* v) {
|
|
assert(*p == v);
|
|
assert(v != nullptr);
|
|
*p = reinterpret_cast<T*>(FIDL_ALLOC_PRESENT);
|
|
}
|
|
|
|
void SetError(const char* error_msg) {
|
|
if (status_ != ZX_OK) {
|
|
return;
|
|
}
|
|
status_ = ZX_ERR_INVALID_ARGS;
|
|
if (out_error_msg_ != nullptr) {
|
|
*out_error_msg_ = error_msg;
|
|
}
|
|
#ifdef __Fuchsia__
|
|
if (handles_) {
|
|
// Return value intentionally ignored: this is best-effort cleanup.
|
|
zx_handle_close_many(handles_, num_handles());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
zx_status_t status() const { return status_; }
|
|
|
|
private:
|
|
// Message state passed in to the constructor.
|
|
uint8_t* const bytes_;
|
|
const uint32_t num_bytes_;
|
|
zx_handle_t* const handles_;
|
|
const uint32_t num_handles_;
|
|
uint32_t* const out_actual_handles_;
|
|
const char** const out_error_msg_;
|
|
zx_status_t status_ = ZX_OK;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
zx_status_t fidl_encode(const fidl_type_t* type, void* bytes, uint32_t num_bytes,
|
|
zx_handle_t* handles, uint32_t max_handles, uint32_t* out_actual_handles,
|
|
const char** out_error_msg) {
|
|
FidlEncoder encoder(type, bytes, num_bytes, handles, max_handles, out_actual_handles,
|
|
out_error_msg);
|
|
encoder.Walk();
|
|
return encoder.status();
|
|
}
|
|
|
|
zx_status_t fidl_encode_msg(const fidl_type_t* type, fidl_msg_t* msg,
|
|
uint32_t* out_actual_handles, const char** out_error_msg) {
|
|
return fidl_encode(type, msg->bytes, msg->num_bytes, msg->handles, msg->num_handles,
|
|
out_actual_handles, out_error_msg);
|
|
}
|