blob: 5e56c4de29fb63df1ee152324d5d0aca6760c559 [file] [log] [blame]
// Copyright 2018 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 <poll.h>
#include <map>
#include <set>
#include <vector>
#include <fbl/unique_fd.h>
#include <xdc-server-utils/msg.h>
#include "usb-handler.h"
namespace xdc {
class Client {
explicit Client(int fd) : fd_(fd) {}
void SetStreamId(uint32_t stream_id);
void SetConnected(bool connected);
// Returns whether the set of client events we are polling for has changed.
bool UpdatePollState(bool usb_writable);
// Queues a completed read transfer to be written to the client.
void AddCompletedRead(std::unique_ptr<UsbHandler::Transfer> transfer);
// Writes data from completed read transfers to the client until there are
// no transfers left, or the client is currently unavailable to accept data.
void ProcessCompletedReads(const std::unique_ptr<UsbHandler>& usb_handler);
// Writes data read from the client to the usb handler.
zx_status_t ProcessWrites(const std::unique_ptr<UsbHandler>& usb_handler);
// Returns any unused transfers to the usb handler.
void ReturnTransfers(const std::unique_ptr<UsbHandler>& usb_handler);
int fd() const { return fd_.get(); }
// Returns the set of client events we should poll for.
short events() const { return events_; }
bool registered() const { return registered_; }
uint32_t stream_id() const { return stream_id_; }
bool connected() const { return connected_; }
// Returns true if we have read data from the client not yet sent to the usb handler.
bool has_write_data() const { return pending_write_ && pending_write_->request_length() > 0; }
fbl::unique_fd fd_;
short events_ = 0;
// Whether the client has registered a stream id.
bool registered_ = false;
uint32_t stream_id_ = 0;
// True if the client has registered a stream id,
// and that stream id is also registered on the xdc device side.
bool connected_ = false;
std::vector<std::unique_ptr<UsbHandler::Transfer>> completed_reads_;
// Data read from the client, to be sent to the usb handler.
std::unique_ptr<UsbHandler::Transfer> pending_write_;
class XdcServer {
// This is required by the XdcServer constructor, to stop clients calling it directly.
struct ConstructorTag {
explicit ConstructorTag() = default;
// Create should be called instead. This is public for make_unique.
XdcServer(ConstructorTag tag) {}
static std::unique_ptr<XdcServer> Create();
void Run();
bool Init();
void UpdateClientPollEvents();
// Updates poll_fds_ with any newly added or removed usb handler fds.
void UpdateUsbHandlerFds();
// Processes new client connections on the server socket.
void ClientConnect();
// Returns whether registration succeeded.
bool RegisterStream(std::shared_ptr<Client> client);
// Returns the client registered to the given stream id, or nullptr if none was found.
std::shared_ptr<Client> GetClient(uint32_t stream_id);
void UsbReadComplete(std::unique_ptr<UsbHandler::Transfer> transfer);
// Parses the control message from the given transfer buffer.
void HandleCtrlMsg(unsigned char* transfer_buf, int transfer_len);
// Sends a control message the to the xdc device with whether a stream has gone on / offline.
// If the message cannot currently be sent, it is queued to be retried later.
void NotifyStreamState(uint32_t stream_id, bool online);
bool SendCtrlMsg(xdc_msg_t& msg);
void SendQueuedCtrlMsgs();
std::unique_ptr<UsbHandler> usb_handler_;
// Server socket we receive client connections on.
fbl::unique_fd socket_fd_;
// File lock acquired to ensure we don't unlink the socket of a running xdc server instance.
fbl::unique_fd socket_lock_fd_;
// Maps from client socket file descriptor to client.
std::map<int, std::shared_ptr<Client>> clients_;
// File descriptors we are currently polling on.
std::vector<pollfd> poll_fds_;
// Stream ids registered on the xdc device side.
std::set<uint32_t> dev_stream_ids_;
std::vector<xdc_msg_t> queued_ctrl_msgs_;
xdc_packet_state_t read_packet_state_;
} // namespace xdc