]> git.localhorst.tv Git - blank.git/blob - src/net/tcp.hpp
5b5f878ae7160e41dd34282f000f8961cc471134
[blank.git] / src / net / tcp.hpp
1 #ifndef BLANK_NET_TCP_HPP_
2 #define BLANK_NET_TCP_HPP_
3
4 #include <algorithm>
5 #include <list>
6 #include <SDL_net.h>
7 #include <string>
8
9
10 namespace blank {
11 namespace tcp {
12
13 /// all failing functions throw NetError
14 class Socket {
15
16 public:
17         /// create an empty socket that is not connected to anything
18         Socket();
19         /// create TCP socket bound to given port
20         explicit Socket(unsigned short port);
21 private:
22         /// wrap given SDLNet TCP socket
23         /// for use with Accept()
24         explicit Socket(TCPsocket sock);
25 public:
26         ~Socket() noexcept;
27
28         Socket(const Socket &) = delete;
29         Socket &operator =(const Socket &) = delete;
30
31         Socket(Socket &&) noexcept;
32         Socket &operator =(Socket &&) noexcept;
33
34         explicit operator bool() const noexcept { return sock; }
35
36         bool operator ==(const Socket &other) const noexcept {
37                 return sock == other.sock;
38         }
39         bool operator <(const Socket &other) const noexcept {
40                 return sock < other.sock;
41         }
42
43 public:
44         /// create a socket for an incoming connection
45         /// @return an empty socket if there are none
46         Socket Accept() noexcept;
47         /// check if there is data available to read
48         bool Ready() const noexcept;
49         /// receive data into given buffer
50         /// @return number of bytes read, at most max_len
51         /// non-blocking if Ready() is true
52         std::size_t Recv(void *buf, std::size_t max_len);
53         /// send data from given buffer, at most max_len bytes
54         /// @return number of bytes written
55         ///         may be less than len as soon as I get to
56         ///         making it non-blocking
57         std::size_t Send(const void *buf, std::size_t max_len);
58
59         int AddTo(SDLNet_SocketSet);
60         int RemoveFrom(SDLNet_SocketSet);
61
62 private:
63         TCPsocket sock;
64
65 };
66
67
68 struct IOHandler {
69
70         virtual ~IOHandler() = default;
71
72         void Close() noexcept { closed = true; }
73         bool Closed() const noexcept { return closed; }
74
75         virtual void OnCreate(Socket &) { }
76         virtual void OnRemove(Socket &) noexcept { }
77
78         virtual void OnSend(Socket &) { };
79         virtual void OnRecv(Socket &) { };
80         virtual void OnError(Socket &) noexcept { Close(); }
81
82 private:
83         bool closed = false;
84
85 };
86
87
88 class Pool {
89
90 public:
91         using ConnectionSet = std::list<std::pair<Socket, IOHandler *>>;
92
93 public:
94         explicit Pool(int max_conn = 32, std::size_t buf_siz = 1500);
95         ~Pool() noexcept;
96
97         Pool(const Pool &) = delete;
98         Pool &operator =(const Pool &) = delete;
99
100 public:
101         void AddConnection(Socket, IOHandler *);
102         void Send();
103         bool Check(unsigned long timeout);
104         void Receive();
105         void Clean();
106
107         int FreeSlots() const noexcept { return max_conn - use_conn; }
108         int OccupiedSlots() const noexcept { return use_conn; }
109         int TotalSlots() const noexcept { return max_conn; }
110         /// reallocate the pool to accomodate at least new_max sockets
111         void Resize(int new_max);
112
113 private:
114         SDLNet_SocketSet set;
115         std::string buffer;
116         ConnectionSet connections;
117         int use_conn;
118         int max_conn;
119         std::size_t buf_siz;
120
121 };
122
123 }
124 }
125
126 #endif