SimpleAI
 All Classes Namespaces Files Functions Variables Typedefs Macros Groups Pages
NetworkImpl.h
Go to the documentation of this file.
1 
4 #pragma once
5 
6 #include "Network.h"
7 #include "IProtocolMessage.h"
8 #include "IProtocolHandler.h"
10 #include "ProtocolMessageFactory.h"
11 #ifdef WIN32
12 #define network_cleanup() WSACleanup()
13 #define network_return int
14 #else
15 #define network_return ssize_t
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <netinet/in.h>
23 #include <netinet/tcp.h>
24 #include <sys/socket.h>
25 #include <net/if.h>
26 #include <netdb.h>
27 #include <signal.h>
28 #define closesocket close
29 #define INVALID_SOCKET -1
30 #define network_cleanup()
31 #endif
32 #include <string.h>
33 #include <deque>
34 #include <algorithm>
35 #include <cassert>
36 #include <cstddef>
37 #include <memory>
38 #include <iterator>
39 #include <array>
40 
41 namespace ai {
42 
43 inline Network::Network(uint16_t port, const std::string& hostname) :
44  _port(port), _hostname(hostname), _socketFD(INVALID_SOCKET), _time(0L) {
45  FD_ZERO(&_readFDSet);
46  FD_ZERO(&_writeFDSet);
47 }
48 
49 inline Network::~Network() {
50  closesocket(_socketFD);
51  network_cleanup();
52 }
53 
54 inline bool Network::start() {
55 #ifdef WIN32
56  WSADATA wsaData;
57  const int wsaResult = WSAStartup(MAKEWORD(2,2), &wsaData);
58  if (wsaResult != NO_ERROR) {
59  return false;
60  }
61 #else
62  signal(SIGPIPE, SIG_IGN);
63 #endif
64 
65  FD_ZERO(&_readFDSet);
66  FD_ZERO(&_writeFDSet);
67 
68  _socketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
69  if (_socketFD == INVALID_SOCKET) {
70  network_cleanup();
71  return false;
72  }
73  struct sockaddr_in sin;
74  memset(&sin, 0, sizeof(sin));
75  sin.sin_family = AF_INET;
76  sin.sin_addr.s_addr = INADDR_ANY;
77  sin.sin_port = htons(_port);
78 
79  int t = 1;
80 #ifdef _WIN32
81  if (setsockopt(_socketFD, SOL_SOCKET, SO_REUSEADDR, (char*) &t, sizeof(t)) != 0) {
82 #else
83  if (setsockopt(_socketFD, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)) != 0) {
84 #endif
85  closesocket(_socketFD);
86  return false;
87  }
88 
89  if (bind(_socketFD, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
90  // Handle the error.
91  network_cleanup();
92  FD_CLR(_socketFD, &_readFDSet);
93  FD_CLR(_socketFD, &_writeFDSet);
94  closesocket(_socketFD);
95  _socketFD = INVALID_SOCKET;
96  return false;
97  }
98 
99  if (listen(_socketFD, 5) < 0) {
100  // Handle the error.
101  network_cleanup();
102  closesocket(_socketFD);
103  _socketFD = INVALID_SOCKET;
104  return false;
105  }
106 
107 #ifdef O_NONBLOCK
108  fcntl(_socketFD, F_SETFL, O_NONBLOCK);
109 #endif
110 #ifdef WIN32
111  unsigned long mode = 1;
112  ioctlsocket(_socketFD, FIONBIO, &mode);
113 #endif
114 
115  FD_SET(_socketFD, &_readFDSet);
116 
117  return true;
118 }
119 
120 inline Network::ClientSocketsIter Network::closeClient(ClientSocketsIter& iter) {
121  Client& client = *iter;
122  const SOCKET clientSocket = client.socket;
123  FD_CLR(clientSocket, &_readFDSet);
124  FD_CLR(clientSocket, &_writeFDSet);
125  closesocket(clientSocket);
126  client.socket = INVALID_SOCKET;
127  for (INetworkListener* listener : _listeners) {
128  listener->onDisconnect(&client);
129  }
130  return _clientSockets.erase(iter);
131 }
132 
133 inline bool Network::sendMessage(Client& client) {
134  if (client.out.empty()) {
135  return true;
136  }
137 
138  std::array<uint8_t, 16384> buf;
139  while (!client.out.empty()) {
140  const size_t len = std::min(buf.size(), client.out.size());
141  std::copy_n(client.out.begin(), len, buf.begin());
142  const SOCKET clientSocket = client.socket;
143  const network_return sent = send(clientSocket, (const char*)&buf[0], len, 0);
144  if (sent < 0) {
145  return false;
146  }
147  if (sent == 0) {
148  // better luck next time - but don't block others
149  return true;
150  }
151  client.out.erase(client.out.begin(), std::next(client.out.begin(), sent));
152  }
153  return true;
154 }
155 
156 inline void Network::update(int64_t deltaTime) {
157  _time += deltaTime;
158  if (_time > 5000L) {
159  if (!broadcast(AIPingMessage())) {
160  _time = 0L;
161  }
162  }
163  fd_set readFDsOut;
164  fd_set writeFDsOut;
165 
166  memcpy(&readFDsOut, &_readFDSet, sizeof(readFDsOut));
167  memcpy(&writeFDsOut, &_writeFDSet, sizeof(writeFDsOut));
168 
169  struct timeval tv;
170  tv.tv_sec = 0;
171  tv.tv_usec = 0;
172  const int ready = select(FD_SETSIZE, &readFDsOut, &writeFDsOut, nullptr, &tv);
173  if (ready < 0) {
174  return;
175  }
176  if (_socketFD != INVALID_SOCKET && FD_ISSET(_socketFD, &readFDsOut)) {
177  const SOCKET clientSocket = accept(_socketFD, nullptr, nullptr);
178  if (clientSocket != INVALID_SOCKET) {
179  FD_SET(clientSocket, &_readFDSet);
180  const Client c(clientSocket);
181  _clientSockets.push_back(c);
182  for (INetworkListener* listener : _listeners) {
183  listener->onConnect(&_clientSockets.back());
184  }
185  }
186  }
187 
188  ClientId clientId = 0;
189  for (ClientSocketsIter i = _clientSockets.begin(); i != _clientSockets.end(); ++clientId) {
190  Client& client = *i;
191  const SOCKET clientSocket = client.socket;
192  if (clientSocket == INVALID_SOCKET) {
193  i = closeClient(i);
194  continue;
195  }
196 
197  if (FD_ISSET(clientSocket, &writeFDsOut)) {
198  if (!sendMessage(client) || client.finished) {
199  i = closeClient(i);
200  continue;
201  }
202  }
203 
204  if (FD_ISSET(clientSocket, &readFDsOut)) {
205  std::array<uint8_t, 16384> buf;
206  const network_return len = recv(clientSocket, (char*)&buf[0], buf.size(), 0);
207  if (len < 0) {
208  i = closeClient(i);
209  continue;
210  }
211  std::copy_n(buf.begin(), len, std::back_inserter(client.in));
212  }
213 
214  ProtocolMessageFactory& factory = ProtocolMessageFactory::get();
215  if (factory.isNewMessageAvailable(client.in)) {
216  IProtocolMessage* msg = factory.create(client.in);
217  if (!msg) {
218  i = closeClient(i);
219  continue;
220  }
221  IProtocolHandler* handler = ProtocolHandlerRegistry::get().getHandler(*msg);
222  if (handler) {
223  handler->execute(clientId, *msg);
224  }
225  }
226  ++i;
227  }
228 }
229 
230 inline bool Network::broadcast(const IProtocolMessage& msg) {
231  if (_clientSockets.empty()) {
232  return false;
233  }
234  _time = 0L;
235  streamContainer out;
236  msg.serialize(out);
237  for (ClientSocketsIter i = _clientSockets.begin(); i != _clientSockets.end(); ++i) {
238  Client& client = *i;
239  if (client.socket == INVALID_SOCKET) {
240  i = closeClient(i);
241  continue;
242  }
243 
244  IProtocolMessage::addInt(client.out, static_cast<int32_t>(out.size()));
245  std::copy(out.begin(), out.end(), std::back_inserter(client.out));
246  FD_SET(client.socket, &_writeFDSet);
247  }
248 
249  return true;
250 }
251 
252 inline bool Network::sendToClient(Client* client, const IProtocolMessage& msg) {
253  assert(client != nullptr);
254  if (client->socket == INVALID_SOCKET) {
255  return false;
256  }
257 
258  streamContainer out;
259  msg.serialize(out);
260 
261  IProtocolMessage::addInt(client->out, static_cast<int32_t>(out.size()));
262  std::copy(out.begin(), out.end(), std::back_inserter(client->out));
263  FD_SET(client->socket, &_writeFDSet);
264  return true;
265 }
266 
267 #undef network_cleanup
268 #undef INVALID_SOCKET
269 #ifndef WIN32
270 #undef closesocket
271 #endif
272 
273 }
A protocol message is used for the serialization of the ai states for remote debugging.
Definition: IProtocolMessage.h:60
bool broadcast(const IProtocolMessage &msg)
Definition: NetworkImpl.h:230
Definition: Network.h:25