// 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. #pragma once #include #include #include #include #include #include "usb-handler.h" namespace xdc { class Client { public: 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 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& usb_handler); // Writes data read from the client to the usb handler. zx_status_t ProcessWrites(const std::unique_ptr& usb_handler); // Returns any unused transfers to the usb handler. void ReturnTransfers(const std::unique_ptr& 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; } private: 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> completed_reads_; // Data read from the client, to be sent to the usb handler. std::unique_ptr pending_write_; }; class XdcServer { // This is required by the XdcServer constructor, to stop clients calling it directly. struct ConstructorTag { explicit ConstructorTag() = default; }; public: // Create should be called instead. This is public for make_unique. XdcServer(ConstructorTag tag) {} static std::unique_ptr Create(); void Run(); private: 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); // Returns the client registered to the given stream id, or nullptr if none was foumd. std::shared_ptr GetClient(uint32_t stream_id); void UsbReadComplete(std::unique_ptr 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 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> clients_; // File descriptors we are currently polling on. std::vector poll_fds_; // Stream ids registered on the xdc device side. std::set dev_stream_ids_; std::vector queued_ctrl_msgs_; xdc_packet_state_t read_packet_state_; }; } // namespace xdc