| // Copyright 2020 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 <arpa/inet.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <sys/socket.h> |
| #include <unistd.h> |
| |
| #include <set> |
| |
| #include "src/developer/debug/shared/buffered_fd.h" |
| #include "src/developer/debug/shared/platform_message_loop.h" |
| #include "src/developer/shell/mirror/common.h" |
| #include "src/developer/shell/mirror/wire_format.h" |
| |
| #ifndef SRC_DEVELOPER_SHELL_MIRROR_SERVER_H_ |
| #define SRC_DEVELOPER_SHELL_MIRROR_SERVER_H_ |
| |
| namespace shell::mirror { |
| |
| class SocketServer; |
| |
| // Represents a instance of a connection "attempt" to a client. |
| class SocketConnection { |
| public: |
| explicit SocketConnection(SocketServer* server) : server_(server), id_(global_id_++) {} |
| ~SocketConnection(); |
| |
| SocketConnection& operator=(SocketConnection&) = delete; |
| SocketConnection(SocketConnection&) = delete; |
| |
| // |main_thread_loop| is used for posting a task that creates the debug agent after accepting a |
| // a connection. This is because the debug agent assumes it's running on the message loop's |
| // thread. |
| Err Accept(debug_ipc::MessageLoop* main_thread_loop, int server_fd); |
| |
| struct SocketConnectionComparator { |
| bool operator()(const SocketConnection& one, const SocketConnection& two) { |
| return one.id_ < two.id_; |
| } |
| }; |
| |
| // Unregisters this socket connection from a given server. This has the effect |
| // of deleting the connection, so use with caution. |
| void UnregisterAndDestroy(); |
| |
| private: |
| static uint64_t global_id_; |
| |
| SocketServer* server_; |
| debug_ipc::BufferedFD buffer_; |
| bool connected_ = false; |
| uint64_t id_; |
| }; |
| |
| // Represents a server. |
| class SocketServer : public debug_ipc::FDWatcher { |
| public: |
| SocketServer() = default; |
| |
| // A configuration object for the server. |
| struct ConnectionConfig { |
| debug_ipc::PlatformMessageLoop* message_loop = nullptr; |
| int port = 0; |
| std::optional<std::string> path; |
| }; |
| |
| // Runs the server with the given configuration. |
| void Run(ConnectionConfig config); |
| |
| // Sets up loops in a sensible way (one loop to accept a connection, and one loop to respond to |
| // requests), and runs a server. Calls inited_fn when it is done initing. |
| Err RunInLoop(ConnectionConfig config, debug_ipc::FileLineFunction from_here, |
| fit::closure inited_fn); |
| |
| int GetPort() { return config_.port; } |
| std::string GetPath() { return *config_.path; } |
| |
| void RemoveConnection(SocketConnection* connection) { |
| for (auto it = connections_.begin(); it != connections_.end(); ++it) { |
| if (it->get() == connection) { |
| connections_.erase(it); |
| return; |
| } |
| } |
| } |
| |
| // IMPORTANT: All others can only be called on the main thread. |
| |
| // Initialize the server. |
| // |port| is the port to use. If *port is 0, the function will try to assign one. |
| Err Init(uint16_t* port); |
| |
| virtual void OnFDReady(int fd, bool read, bool write, bool err) override; |
| |
| private: |
| fbl::unique_fd server_socket_; |
| std::set<std::unique_ptr<SocketConnection>> connections_; |
| debug_ipc::MessageLoop::WatchHandle connection_monitor_; |
| ConnectionConfig config_; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(SocketServer); |
| }; |
| |
| // Manages sending data along a given StreamBuffer. |
| class Update { |
| public: |
| Update(debug_ipc::StreamBuffer* stream, const std::string* path) |
| : stream_(stream), files_(*path), path_(*path) {} |
| |
| // Sends the contents of |path| to |stream|. |
| Err SendUpdates(); |
| |
| private: |
| debug_ipc::StreamBuffer* stream_; |
| Files files_; |
| std::string path_; |
| }; |
| |
| } // namespace shell::mirror |
| |
| #endif // SRC_DEVELOPER_SHELL_MIRROR_SERVER_H_ |