119 lines
4.5 KiB
C++
119 lines
4.5 KiB
C++
/**
|
|
******************************************************************************
|
|
* 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 <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#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<Socket> 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<const void*, size_t>* 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<std::pair<const void*, size_t>> 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<uint8_t>& 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<SocketServer> Create(
|
|
uint16_t port,
|
|
std::function<void(std::unique_ptr<Socket> client)> accept_callback);
|
|
|
|
virtual ~SocketServer() = default;
|
|
};
|
|
|
|
} // namespace xe
|
|
|
|
#endif // XENIA_BASE_SOCKET_H_
|