blob: 188c498eeaaf023b1f042da63fef436965df6011 [file] [log] [blame]
// Copyright 2019 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 <fuchsia/device/llcpp/fidl.h>
#include <fuchsia/hardware/pty/llcpp/fidl.h>
#include <lib/zx/eventpair.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include "fifo.h"
#include "pty-server.h"
class PtyClient : public fbl::RefCounted<PtyClient>,
public fbl::DoublyLinkedListable<fbl::RefPtr<PtyClient>> {
// This ctor is only public for the use of fbl::MakeRefCounted. Use Create()
// instead.
PtyClient(fbl::RefPtr<PtyServer> server, uint32_t id, zx::eventpair local, zx::eventpair remote);
// Create a new PtyClient. This method is preferred to the ctor.
static zx_status_t Create(fbl::RefPtr<PtyServer> server, uint32_t id,
fbl::RefPtr<PtyClient>* out);
zx_status_t Read(void* data, size_t len, size_t* out_actual);
zx_status_t Write(const void* data, size_t len, size_t* out_actual);
zx_status_t GetEvent(zx::eventpair* event) { return remote_.duplicate(ZX_RIGHTS_BASIC, event); }
Fifo* rx_fifo() { return &rx_fifo_; }
void AssertHangupSignal() {
ClearSetFlags(0, kFlagPeerClosed);
void AssertActiveHungup() {
0, fuchsia_hardware_pty::wire::kSignalEvent | fuchsia_device::wire::kDeviceSignalHangup);
void AssertReadableSignal() {
local_.signal_peer(0, fuchsia_device::wire::kDeviceSignalReadable);
void AssertWritableSignal() {
local_.signal_peer(0, fuchsia_device::wire::kDeviceSignalWritable);
void AssertEventSignal() {
static_assert(fuchsia_hardware_pty::wire::kSignalEvent ==
local_.signal_peer(0, fuchsia_hardware_pty::wire::kSignalEvent);
void DeAssertReadableSignal() {
local_.signal_peer(fuchsia_device::wire::kDeviceSignalReadable, 0);
void DeAssertWritableSignal() {
local_.signal_peer(fuchsia_device::wire::kDeviceSignalWritable, 0);
void DeAssertEventSignal() { local_.signal_peer(fuchsia_hardware_pty::wire::kSignalEvent, 0); }
void ClearSetFlags(uint32_t clr, uint32_t set) { flags_ = (flags_ & ~clr) | set; }
uint32_t flags() const { return flags_; }
[[nodiscard]] bool in_raw_mode() const { return flags_ & kFlagRawMode; }
[[nodiscard]] bool is_peer_closed() const { return flags_ & kFlagPeerClosed; }
uint32_t id() const { return id_; }
// Ensure READABLE/WRITABLE signals are properly asserted based on active
// status and rx_fifo status.
void AdjustSignals();
[[nodiscard]] bool is_active() { return server_->is_active(this); }
[[nodiscard]] bool is_control() { return server_->is_control(this); }
const fbl::RefPtr<PtyServer>& server() const { return server_; }
// Teardown this client
void Shutdown();
zx_status_t WriteChunk(const void* buf, size_t count, size_t* actual);
const fbl::RefPtr<PtyServer> server_;
const uint32_t id_;
// remote_ is signaled to indicate to client connections various status
// conditions.
zx::eventpair local_, remote_;
static constexpr uint32_t kFlagRawMode = 0x00000001u;
static_assert(kFlagRawMode == fuchsia_hardware_pty::wire::kFeatureRaw);
static constexpr uint32_t kFlagPeerClosed = 0x00000002u;
uint32_t flags_ = 0;
Fifo rx_fifo_;