/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2015 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #ifndef XENIA_BASE_SOCKET_H_ #define XENIA_BASE_SOCKET_H_ #include #include #include #include #include #include #include "xenia/base/threading.h" namespace xe { // An asynchronous bidirectional socket. // Sockets are wait-based and operate in a thread-free manner. Data may be // read from or written to a socket from any thread with the wait handle as // a mechanism to efficiently wait until new data is available. // Consumers should wait on the wait handle and when signalled poll to see // if the socket is still connected or new data is available. When reading // data Receive should be called until it returns 0 new bytes and then the // wait handle should be waited on until new data arrives. class Socket { public: // Synchronously connects to the given hostname:port. static std::unique_ptr Connect(std::string hostname, uint16_t port); virtual ~Socket() = default; // TODO(benvanik): socket info? remote IP? etc? // Returns a wait handle that can be used to wait on incoming client data or // status updates. When this handle is signalled consumers should poll for // new data and react accordingly. virtual xe::threading::WaitHandle* wait_handle() = 0; // Returns true if the client is connected and can send/receive data. virtual bool is_connected() = 0; // Closes the socket. // This will signal the wait handle. virtual void Close() = 0; // Receives incoming data up to the given capacity and returns the total // number of bytes received. // 0 is returned if there is no data available. -1 is returned if the client // has been closed. virtual size_t Receive(void* buffer, size_t buffer_capacity) = 0; // Asynchronously sends a set of buffers. // The buffers are copied and may be modified immediately after the function // returns. // Returns false if the socket is disconnected or the data cannot be sent. virtual bool Send(const std::pair* buffers, size_t buffer_count) = 0; // Asynchronously sends a set of buffers. // The buffers are copied and may be modified immediately after the function // returns. // Returns false if the socket is disconnected or the data cannot be sent. bool Send(std::vector> buffers) { return Send(buffers.data(), buffers.size()); } // Asynchronously sends a buffer of data. // The buffer is copied and may be modified immediately after the function // returns. // Returns false if the socket is disconnected or the data cannot be sent. bool Send(const void* buffer, size_t buffer_length) { auto buffer_list = std::make_pair(buffer, buffer_length); return Send(&buffer_list, 1); } // Asynchronously sends a buffer of data. // The buffer is copied and may be modified immediately after the function // returns. // Returns false if the socket is disconnected or the data cannot be sent. bool Send(const std::vector& buffer) { auto buffer_list = std::make_pair(buffer.data(), buffer.size()); return Send(&buffer_list, 1); } // Asynchronously sends a string buffer. // Returns false if the socket is disconnected or the data cannot be sent. bool Send(const std::string& value) { return Send(value.data(), value.size()); } }; // Runs a socket server on the specified local port. // The server accepts clients from a background thread until closed (by // deletion). Clients are not tied to their creating server and the server // may be closed while clients remain connected. class SocketServer { public: // Creates a new socket server bound to the given local port. // The accept callback will be called from a random thread when a new client // connects. // Returns null if the server cannot be bound to the given port (in use, etc). static std::unique_ptr Create( uint16_t port, std::function client)> accept_callback); virtual ~SocketServer() = default; }; } // namespace xe #endif // XENIA_BASE_SOCKET_H_