3 #include "../app/error.hpp"
18 Socket::Socket(unsigned short port)
21 if (SDLNet_ResolveHost(&ip, nullptr, port) == -1) {
22 throw NetError("failed to resolve local host");
24 sock = SDLNet_TCP_Open(&ip);
26 throw NetError("failed to open local socket");
30 Socket::Socket(const string &host, unsigned short port)
33 if (SDLNet_ResolveHost(&ip, host.c_str(), port) == -1) {
34 throw NetError("failed to resolve host " + host);
36 sock = SDLNet_TCP_Open(&ip);
38 throw NetError("failed to connect to " + host + ':' + to_string(port));
42 Socket::Socket(TCPsocket sock)
47 Socket::~Socket() noexcept {
49 SDLNet_TCP_Close(sock);
53 Socket::Socket(Socket &&other) noexcept
58 Socket &Socket::operator =(Socket &&other) noexcept {
59 swap(sock, other.sock);
64 Socket Socket::Accept() noexcept {
65 return Socket(SDLNet_TCP_Accept(sock));
68 bool Socket::Ready() const noexcept {
69 return SDLNet_SocketReady(sock);
72 size_t Socket::Recv(void *buf, std::size_t max_len) {
73 const int len = SDLNet_TCP_Recv(sock, buf, max_len);
75 throw NetError("TCP socket recv");
80 size_t Socket::Send(const void *buf, size_t max_len) {
81 /// TODO: make TCP send non-blocking
82 const int len = SDLNet_TCP_Send(sock, buf, max_len);
83 if (len < int(max_len)) {
84 throw NetError("TCP socket send");
90 int Socket::AddTo(SDLNet_SocketSet set) {
91 return SDLNet_TCP_AddSocket(set, sock);
94 int Socket::RemoveFrom(SDLNet_SocketSet set) {
95 return SDLNet_TCP_DelSocket(set, sock);
99 Pool::Pool(int max_conn, size_t buf_siz)
100 : set(SDLNet_AllocSocketSet(max_conn))
106 throw runtime_error("failed to allocate socket set");
110 Pool::~Pool() noexcept {
111 SDLNet_FreeSocketSet(set);
115 void Pool::AddConnection(Socket sock, IOHandler *handler) {
116 if (FreeSlots() == 0) {
117 Resize(TotalSlots() * 2);
119 int num = sock.AddTo(set);
121 throw NetError("failed to add socket to set");
124 connections.emplace_back(move(sock), handler);
125 handler->OnCreate(connections.back().first);
129 for (auto i = connections.begin(); i != connections.end(); ++i) {
130 if (i->second->Closed()) {
135 i->second->OnSend(i->first);
137 i->second->OnError(i->first);
142 bool Pool::Check(unsigned long timeout) {
143 // SDL_net considers checking an empty set an error, so
144 // we're checking that ourselves
145 if (OccupiedSlots() == 0) {
149 int num = SDLNet_CheckSockets(set, timeout);
151 throw NetError("error checking sockets");
156 void Pool::Receive() {
157 for (auto i = connections.begin(); i != connections.end(); ++i) {
158 if (!i->first.Ready() || i->second->Closed()) {
163 i->second->OnRecv(i->first);
165 i->second->OnError(i->first);
171 for (auto i = connections.begin(); i != connections.end();) {
172 if (i->second->Closed()) {
173 int num = i->first.RemoveFrom(set);
175 throw NetError("failed to remove socket from set");
178 i->second->OnRemove(i->first);
179 i = connections.erase(i);
187 void Pool::Resize(int new_max) {
188 if (new_max < max_conn) {
192 int new_size = max(new_max, max_conn * 2);
193 SDLNet_SocketSet new_set(SDLNet_AllocSocketSet(new_size));
195 throw NetError("failed to allocate socket set");
198 for (auto &conn : connections) {
199 if (conn.first.AddTo(new_set) == -1) {
200 NetError error("failed to migrate socket to new set");
201 SDLNet_FreeSocketSet(new_set);
206 SDLNet_FreeSocketSet(set);