-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket.h
155 lines (119 loc) · 4.07 KB
/
socket.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#ifndef TERMCHAT_SOCKET_H
#define TERMCHAT_SOCKET_H
#include <cstddef>
#include <exception>
#include <memory>
#include <span>
#include <string>
// A set of abstractions over the sockets API. It is not meant to be fully featured
// but to only support the use-cases of the application.
class SocketError : public std::exception {
private:
std::string msg;
int code;
const char* function;
public:
SocketError(const char* fn, const char* info);
const char* what() const noexcept override { return msg.c_str(); }
// Whether the error is EWOULDBLOCK/EAGAIN or not.
bool would_block() const noexcept;
// Whether the error is EBADF or not.
bool bad_fd() const noexcept;
};
class ServerClient;
enum class ServerClientStatus { New, PendingData };
struct ServerPollResult;
class Server {
private:
struct Private;
std::unique_ptr<Private> m;
public:
// Creates a new server which listens on the given port.
// If the port is less than 1024 or another error occurs,
// the constructor throws.
Server(unsigned short port);
Server() = delete;
Server(const Server&) = delete;
Server& operator=(const Server&) = delete;
Server(Server&&) = default;
Server& operator=(Server&&) = default;
// Polls the server for new connections and the given connections
// for data.
void poll(std::span<const ServerClient>, std::vector<ServerPollResult>&);
// Closes the server and prevents any subsequent sends or recvs
// on any of its ServerClients.
// Multiple calls to shutdown() will throw an error.
void shutdown();
~Server();
};
class Receiver {
protected:
virtual ~Receiver() = default;
public:
// Receives exactly res.size() bytes from the client, blocking if necessary.
// Returns true if the client is still connected, false if it disconnected.
// Throws if the receive fails.
virtual bool recv(std::vector<std::byte>& res) = 0;
};
class Sender {
protected:
virtual ~Sender() = default;
public:
// Send the given bytes to the client.
// It is ensured that all bytes are sent.
// Throws if the send doesn't succeed.
virtual void send(std::span<const std::byte>) = 0;
};
class ServerClient : public Receiver, public Sender {
private:
struct Private;
std::shared_ptr<Private> m;
friend class Server;
explicit ServerClient(Private*);
public:
// This is required in order to be able to put it in a
// vector on which resize() is called. A ServerClient
// shouldn't be created using the default constructor.
ServerClient() = default;
ServerClient(const ServerClient&) = default;
ServerClient& operator=(const ServerClient&) = default;
ServerClient(ServerClient&&) = default;
ServerClient& operator=(ServerClient&&) = default;
void send(std::span<const std::byte>) override;
bool recv(std::vector<std::byte>& res) override;
void set_blocking(bool should_block);
using ID = std::size_t;
// Returns an unique ID associated with this client, given by the server.
// It is useful because multiple clients can have the same IP address.
ID id() const noexcept;
// Returns the IP address of the client.
std::string address() const noexcept;
// Closes the connection to this client.
// Multiple calls to close() will throw an error.
void close();
~ServerClient();
};
struct ServerPollResult {
ServerClient client;
ServerClientStatus status;
};
class Client : public Receiver, public Sender {
private:
int m_fd;
public:
// Creates a client which connects to the given address.
// Throws if a connection error occurs.
Client(std::string ip, unsigned short port);
Client() = delete;
Client(const Client&) = delete;
Client& operator=(const Client&) = delete;
Client(Client&&) = default;
Client& operator=(Client&&) = default;
void send(std::span<const std::byte>) override;
bool recv(std::vector<std::byte>& res) override;
// Closes the connection to the server.
// Multiple calls to close() will throw an error.
void close();
~Client();
};
#endif