1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#pragma once
6
7#include <fbl/unique_fd.h>
8#include <map>
9#include <poll.h>
10#include <set>
11#include <vector>
12
13#include "usb-handler.h"
14
15namespace xdc {
16
17class Client {
18public:
19    explicit Client(int fd) : fd_(fd) {}
20
21    void SetStreamId(uint32_t stream_id);
22    void SetConnected(bool connected);
23    // Returns whether the set of client events we are polling for has changed.
24    bool UpdatePollState(bool usb_writable);
25
26    // Queues a completed read transfer to be written to the client.
27    void AddCompletedRead(std::unique_ptr<UsbHandler::Transfer> transfer);
28    // Writes data from completed read transfers to the client until there are
29    // no transfers left, or the client is currently unavailable to accept data.
30    void ProcessCompletedReads(const std::unique_ptr<UsbHandler>& usb_handler);
31    // Writes data read from the client to the usb handler.
32    zx_status_t ProcessWrites(const std::unique_ptr<UsbHandler>& usb_handler);
33    // Returns any unused transfers to the usb handler.
34    void ReturnTransfers(const std::unique_ptr<UsbHandler>& usb_handler);
35
36    int fd()             const { return fd_.get(); }
37    // Returns the set of client events we should poll for.
38    short events()       const { return events_; }
39    bool registered()    const { return registered_; }
40    uint32_t stream_id() const { return stream_id_; }
41    bool connected()     const { return connected_; }
42    // Returns true if we have read data from the client not yet sent to the usb handler.
43    bool has_write_data() const { return pending_write_ && pending_write_->request_length() > 0; }
44
45private:
46    fbl::unique_fd fd_;
47
48    short events_ = 0;
49
50    // Whether the client has registered a stream id.
51    bool     registered_ = false;
52    uint32_t stream_id_  = 0;
53    // True if the client has registered a stream id,
54    // and that stream id is also registered on the xdc device side.
55    bool     connected_  = false;
56
57    std::vector<std::unique_ptr<UsbHandler::Transfer>> completed_reads_;
58    // Data read from the client, to be sent to the usb handler.
59    std::unique_ptr<UsbHandler::Transfer> pending_write_;
60};
61
62class XdcServer {
63    // This is required by the XdcServer constructor, to stop clients calling it directly.
64    struct ConstructorTag { explicit ConstructorTag() = default; };
65
66public:
67    // Create should be called instead. This is public for make_unique.
68    XdcServer(ConstructorTag tag) {}
69
70    static std::unique_ptr<XdcServer> Create();
71    void Run();
72
73private:
74    bool Init();
75
76    void UpdateClientPollEvents();
77
78    // Updates poll_fds_ with any newly added or removed usb handler fds.
79    void UpdateUsbHandlerFds();
80
81    // Processes new client connections on the server socket.
82    void ClientConnect();
83
84    // Returns whether registration succeeded.
85    bool RegisterStream(std::shared_ptr<Client> client);
86
87    // Returns the client registered to the given stream id, or nullptr if none was foumd.
88    std::shared_ptr<Client> GetClient(uint32_t stream_id);
89
90    void UsbReadComplete(std::unique_ptr<UsbHandler::Transfer> transfer);
91    // Parses the control message from the given transfer buffer.
92    void HandleCtrlMsg(unsigned char* transfer_buf, int transfer_len);
93
94    // Sends a control message the to the xdc device with whether a stream has gone on / offline.
95    // If the message cannot currently be sent, it is queued to be retried later.
96    void NotifyStreamState(uint32_t stream_id, bool online);
97    bool SendCtrlMsg(xdc_msg_t& msg);
98    void SendQueuedCtrlMsgs();
99
100    std::unique_ptr<UsbHandler> usb_handler_;
101
102    // Server socket we receive client connections on.
103    fbl::unique_fd socket_fd_;
104    // File lock acquired to ensure we don't unlink the socket of a running xdc server instance.
105    fbl::unique_fd socket_lock_fd_;
106
107    // Maps from client socket file descriptor to client.
108    std::map<int, std::shared_ptr<Client>> clients_;
109
110    // File descriptors we are currently polling on.
111    std::vector<pollfd> poll_fds_;
112
113    // Stream ids registered on the xdc device side.
114    std::set<uint32_t> dev_stream_ids_;
115
116    std::vector<xdc_msg_t> queued_ctrl_msgs_;
117
118    xdc_packet_state_t read_packet_state_;
119};
120
121}  // namespace xdc
122