3 #include "../app/init.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(TCPsocket sock)
35 Socket::~Socket() noexcept {
37 SDLNet_TCP_Close(sock);
41 Socket::Socket(Socket &&other) noexcept
46 Socket &Socket::operator =(Socket &&other) noexcept {
47 swap(sock, other.sock);
52 Socket Socket::Accept() noexcept {
53 return Socket(SDLNet_TCP_Accept(sock));
56 bool Socket::Ready() const noexcept {
57 return SDLNet_SocketReady(sock);
60 size_t Socket::Recv(void *buf, std::size_t max_len) {
61 const int len = SDLNet_TCP_Recv(sock, buf, max_len);
63 throw NetError("TCP socket recv");
68 size_t Socket::Send(const void *buf, size_t max_len) {
69 /// TODO: make TCP send non-blocking
70 const int len = SDLNet_TCP_Send(sock, buf, max_len);
71 if (len < int(max_len)) {
72 throw NetError("TCP socket send");
78 int Socket::AddTo(SDLNet_SocketSet set) {
79 return SDLNet_TCP_AddSocket(set, sock);
82 int Socket::RemoveFrom(SDLNet_SocketSet set) {
83 return SDLNet_TCP_DelSocket(set, sock);
87 Pool::Pool(int max_conn, size_t buf_siz)
88 : set(SDLNet_AllocSocketSet(max_conn))
89 , buffer(buf_siz, '\0')
95 throw runtime_error("failed to allocate socket set");
99 Pool::~Pool() noexcept {
100 SDLNet_FreeSocketSet(set);
104 void Pool::AddConnection(Socket sock, IOHandler *handler) {
105 if (FreeSlots() == 0) {
106 Resize(TotalSlots() * 2);
108 int num = sock.AddTo(set);
110 throw NetError("failed to add socket to set");
113 connections.emplace_back(move(sock), handler);
114 handler->OnCreate(connections.back().first);
118 for (auto i = connections.begin(); i != connections.end(); ++i) {
119 if (i->second->Closed()) {
124 i->second->OnSend(i->first);
126 i->second->OnError(i->first);
131 bool Pool::Check(unsigned long timeout) {
132 // SDL_net considers checking an empty set an error, so
133 // we're checking that ourselves
134 if (OccupiedSlots() == 0) {
138 int num = SDLNet_CheckSockets(set, timeout);
140 throw NetError("error checking sockets");
145 void Pool::Receive() {
146 for (auto i = connections.begin(); i != connections.end(); ++i) {
147 if (!i->first.Ready() || i->second->Closed()) {
152 i->second->OnRecv(i->first);
154 i->second->OnError(i->first);
160 for (auto i = connections.begin(); i != connections.end();) {
161 if (i->second->Closed()) {
162 int num = i->first.RemoveFrom(set);
164 throw NetError("failed to remove socket from set");
167 i->second->OnRemove(i->first);
168 i = connections.erase(i);
176 void Pool::Resize(int new_max) {
177 if (new_max < max_conn) {
181 int new_size = max(new_max, max_conn * 2);
182 SDLNet_SocketSet new_set(SDLNet_AllocSocketSet(new_size));
184 throw NetError("failed to allocate socket set");
187 for (auto &conn : connections) {
188 if (conn.first.AddTo(new_set) == -1) {
189 NetError error("failed to migrate socket to new set");
190 SDLNet_FreeSocketSet(new_set);
195 SDLNet_FreeSocketSet(set);