OpenTTD
udp.cpp
Go to the documentation of this file.
1 /* $Id: udp.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
14 #ifdef ENABLE_NETWORK
15 
16 #include "../../stdafx.h"
17 #include "../../date_func.h"
18 #include "../../debug.h"
19 #include "udp.h"
20 
21 #include "../../safeguards.h"
22 
28 {
29  if (bind != NULL) {
30  for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) {
31  *this->bind.Append() = *addr;
32  }
33  } else {
34  /* As hostname NULL and port 0/NULL don't go well when
35  * resolving it we need to add an address for each of
36  * the address families we support. */
37  *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
38  *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6);
39  }
40 }
41 
42 
48 {
49  /* Make sure socket is closed */
50  this->Close();
51 
52  for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) {
53  addr->Listen(SOCK_DGRAM, &this->sockets);
54  }
55 
56  return this->sockets.Length() != 0;
57 }
58 
63 {
64  for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
65  closesocket(s->second);
66  }
67  this->sockets.Clear();
68 }
69 
71 {
74 }
75 
83 void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
84 {
85  if (this->sockets.Length() == 0) this->Listen();
86 
87  for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
88  /* Make a local copy because if we resolve it we cannot
89  * easily unresolve it so we can resolve it later again. */
90  NetworkAddress send(*recv);
91 
92  /* Not the same type */
93  if (!send.IsFamily(s->first.GetAddress()->ss_family)) continue;
94 
95  p->PrepareToSend();
96 
97 #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
98  if (broadcast) {
99  /* Enable broadcast */
100  unsigned long val = 1;
101  if (setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
102  DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR());
103  }
104  }
105 #endif
106 
107  /* Send the buffer */
108  int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
109  DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString());
110 
111  /* Check for any errors, but ignore it otherwise */
112  if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString(), GET_LAST_ERROR());
113 
114  if (!all) break;
115  }
116 }
117 
122 {
123  for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
124  for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP
125  struct sockaddr_storage client_addr;
126  memset(&client_addr, 0, sizeof(client_addr));
127 
128  Packet p(this);
129  socklen_t client_len = sizeof(client_addr);
130 
131  /* Try to receive anything */
132  SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket
133  int nbytes = recvfrom(s->second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len);
134 
135  /* Did we get the bytes for the base header of the packet? */
136  if (nbytes <= 0) break; // No data, i.e. no packet
137  if (nbytes <= 2) continue; // Invalid data; try next packet
138 
139  NetworkAddress address(client_addr, client_len);
140  p.PrepareToRead();
141 
142  /* If the size does not match the packet must be corrupted.
143  * Otherwise it will be marked as corrupted later on. */
144  if (nbytes != p.size) {
145  DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString());
146  continue;
147  }
148 
149  /* Handle the packet */
150  this->HandleUDPPacket(&p, &address);
151  }
152  }
153 }
154 
155 
162 {
164 
165  /*
166  * Please observe the order.
167  * The parts must be read in the same order as they are sent!
168  */
169 
170  /* Update the documentation in udp.h on changes
171  * to the NetworkGameInfo wire-protocol! */
172 
173  /* NETWORK_GAME_INFO_VERSION = 4 */
174  {
175  /* Only send the GRF Identification (GRF_ID and MD5 checksum) of
176  * the GRFs that are needed, i.e. the ones that the server has
177  * selected in the NewGRF GUI and not the ones that are used due
178  * to the fact that they are in [newgrf-static] in openttd.cfg */
179  const GRFConfig *c;
180  uint count = 0;
181 
182  /* Count number of GRFs to send information about */
183  for (c = info->grfconfig; c != NULL; c = c->next) {
184  if (!HasBit(c->flags, GCF_STATIC)) count++;
185  }
186  p->Send_uint8 (count); // Send number of GRFs
187 
188  /* Send actual GRF Identifications */
189  for (c = info->grfconfig; c != NULL; c = c->next) {
190  if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
191  }
192  }
193 
194  /* NETWORK_GAME_INFO_VERSION = 3 */
195  p->Send_uint32(info->game_date);
196  p->Send_uint32(info->start_date);
197 
198  /* NETWORK_GAME_INFO_VERSION = 2 */
199  p->Send_uint8 (info->companies_max);
200  p->Send_uint8 (info->companies_on);
201  p->Send_uint8 (info->spectators_max);
202 
203  /* NETWORK_GAME_INFO_VERSION = 1 */
204  p->Send_string(info->server_name);
205  p->Send_string(info->server_revision);
206  p->Send_uint8 (info->server_lang);
207  p->Send_bool (info->use_password);
208  p->Send_uint8 (info->clients_max);
209  p->Send_uint8 (info->clients_on);
210  p->Send_uint8 (info->spectators_on);
211  p->Send_string(info->map_name);
212  p->Send_uint16(info->map_width);
213  p->Send_uint16(info->map_height);
214  p->Send_uint8 (info->map_set);
215  p->Send_bool (info->dedicated);
216 }
217 
224 {
225  static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
226 
227  info->game_info_version = p->Recv_uint8();
228 
229  /*
230  * Please observe the order.
231  * The parts must be read in the same order as they are sent!
232  */
233 
234  /* Update the documentation in udp.h on changes
235  * to the NetworkGameInfo wire-protocol! */
236 
237  switch (info->game_info_version) {
238  case 4: {
239  GRFConfig **dst = &info->grfconfig;
240  uint i;
241  uint num_grfs = p->Recv_uint8();
242 
243  /* Broken/bad data. It cannot have that many NewGRFs. */
244  if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
245 
246  for (i = 0; i < num_grfs; i++) {
247  GRFConfig *c = new GRFConfig();
248  this->ReceiveGRFIdentifier(p, &c->ident);
250 
251  /* Append GRFConfig to the list */
252  *dst = c;
253  dst = &c->next;
254  }
255  /* FALL THROUGH */
256  }
257  case 3:
258  info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
259  info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
260  /* FALL THROUGH */
261  case 2:
262  info->companies_max = p->Recv_uint8 ();
263  info->companies_on = p->Recv_uint8 ();
264  info->spectators_max = p->Recv_uint8 ();
265  /* FALL THROUGH */
266  case 1:
267  p->Recv_string(info->server_name, sizeof(info->server_name));
268  p->Recv_string(info->server_revision, sizeof(info->server_revision));
269  info->server_lang = p->Recv_uint8 ();
270  info->use_password = p->Recv_bool ();
271  info->clients_max = p->Recv_uint8 ();
272  info->clients_on = p->Recv_uint8 ();
273  info->spectators_on = p->Recv_uint8 ();
274  if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
277  }
278  p->Recv_string(info->map_name, sizeof(info->map_name));
279  info->map_width = p->Recv_uint16();
280  info->map_height = p->Recv_uint16();
281  info->map_set = p->Recv_uint8 ();
282  info->dedicated = p->Recv_bool ();
283 
284  if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0;
285  if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
286  }
287 }
288 
295 {
296  PacketUDPType type;
297 
298  /* New packet == new client, which has not quit yet */
299  this->Reopen();
300 
301  type = (PacketUDPType)p->Recv_uint8();
302 
303  switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
304  case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
305  case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
306  case PACKET_UDP_CLIENT_DETAIL_INFO: this->Receive_CLIENT_DETAIL_INFO(p, client_addr); break;
307  case PACKET_UDP_SERVER_DETAIL_INFO: this->Receive_SERVER_DETAIL_INFO(p, client_addr); break;
308  case PACKET_UDP_SERVER_REGISTER: this->Receive_SERVER_REGISTER(p, client_addr); break;
309  case PACKET_UDP_MASTER_ACK_REGISTER: this->Receive_MASTER_ACK_REGISTER(p, client_addr); break;
310  case PACKET_UDP_CLIENT_GET_LIST: this->Receive_CLIENT_GET_LIST(p, client_addr); break;
311  case PACKET_UDP_MASTER_RESPONSE_LIST: this->Receive_MASTER_RESPONSE_LIST(p, client_addr); break;
312  case PACKET_UDP_SERVER_UNREGISTER: this->Receive_SERVER_UNREGISTER(p, client_addr); break;
313  case PACKET_UDP_CLIENT_GET_NEWGRFS: this->Receive_CLIENT_GET_NEWGRFS(p, client_addr); break;
314  case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break;
315  case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break;
316 
317  default:
318  if (this->HasClientQuit()) {
319  DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
320  } else {
321  DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString());
322  }
323  break;
324  }
325 }
326 
333 {
334  DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString());
335 }
336 
349 
350 #endif /* ENABLE_NETWORK */