Fix compiler warnings.
[openttd-joker.git] / src / network / core / udp.cpp
blobbd175fa4c9639afe7dcc16bf77dcdbdb2f633375
1 /* $Id: udp.cpp 26046 2013-11-22 21:41:19Z rubidium $ */
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 */
10 /**
11 * @file core/udp.cpp Basic functions to receive and send UDP packets.
14 #ifdef ENABLE_NETWORK
16 #include "../../stdafx.h"
17 #include "../../date_func.h"
18 #include "../../debug.h"
20 #include "udp.h"
22 #include "../../safeguards.h"
24 /**
25 * Create an UDP socket but don't listen yet.
26 * @param bind the addresses to bind to.
28 NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
30 if (bind != NULL) {
31 for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) {
32 *this->bind.Append() = *addr;
34 } else {
35 /* As hostname NULL and port 0/NULL don't go well when
36 * resolving it we need to add an address for each of
37 * the address families we support. */
38 *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
39 *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6);
44 /**
45 * Start listening on the given host and port.
46 * @return true if at least one port is listening
48 bool NetworkUDPSocketHandler::Listen()
50 /* Make sure socket is closed */
51 this->Close();
53 for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) {
54 addr->Listen(SOCK_DGRAM, &this->sockets);
57 return this->sockets.Length() != 0;
60 /**
61 * Close the given UDP socket
63 void NetworkUDPSocketHandler::Close()
65 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
66 closesocket(s->second);
68 this->sockets.Clear();
71 NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error)
73 NetworkSocketHandler::CloseConnection(error);
74 return NETWORK_RECV_STATUS_OKAY;
77 /**
78 * Send a packet over UDP
79 * @param p the packet to send
80 * @param recv the receiver (target) of the packet
81 * @param all send the packet using all sockets that can send it
82 * @param broadcast whether to send a broadcast message
84 void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
86 if (this->sockets.Length() == 0) this->Listen();
88 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
89 /* Make a local copy because if we resolve it we cannot
90 * easily unresolve it so we can resolve it later again. */
91 NetworkAddress send(*recv);
93 /* Not the same type */
94 if (!send.IsFamily(s->first.GetAddress()->ss_family)) continue;
96 p->PrepareToSend();
98 #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
99 if (broadcast) {
100 /* Enable broadcast */
101 unsigned long val = 1;
102 if (setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
103 DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR());
106 #endif
108 /* Send the buffer */
109 int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
110 DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString());
112 /* Check for any errors, but ignore it otherwise */
113 if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString(), GET_LAST_ERROR());
115 if (!all) break;
120 * Receive a packet at UDP level
122 void NetworkUDPSocketHandler::ReceivePackets()
124 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
125 for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP
126 struct sockaddr_storage client_addr;
127 memset(&client_addr, 0, sizeof(client_addr));
129 Packet p(this);
130 socklen_t client_len = sizeof(client_addr);
132 /* Try to receive anything */
133 SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket
134 int nbytes = recvfrom(s->second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len);
136 /* Did we get the bytes for the base header of the packet? */
137 if (nbytes <= 0) break; // No data, i.e. no packet
138 if (nbytes <= 2) continue; // Invalid data; try next packet
140 NetworkAddress address(client_addr, client_len);
141 p.PrepareToRead();
143 /* If the size does not match the packet must be corrupted.
144 * Otherwise it will be marked as corrupted later on. */
145 if (nbytes != p.size) {
146 DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString());
147 continue;
150 /* Handle the packet */
151 this->HandleUDPPacket(&p, &address);
157 * Serializes the NewGRF information of the NetworkGameInfo struct to several packets
158 * @param p the packet type to write the data to
159 * @param info the NetworkGameInfo struct to serialize
160 * @return The ready to send packets.
162 std::list<std::shared_ptr<Packet>> NetworkUDPSocketHandler::SendNetworkGameNewGrfInfo(PacketType packet_type, const NetworkGameInfo *info)
164 /* Only send the GRF Identification (GRF_ID and MD5 checksum) of
165 * the GRFs that are needed, i.e. the ones that the server has
166 * selected in the NewGRF GUI and not the ones that are used due
167 * to the fact that they are in [newgrf-static] in openttd.cfg */
168 uint count = 0;
169 uint packet_id = 0;
170 std::shared_ptr<Packet> packet = std::make_shared<Packet>(PACKET_UDP_SERVER_NEWGRF_RESPONSE);
171 std::list<std::shared_ptr<Packet>> packets_to_send;
172 std::list<std::pair<std::shared_ptr<Packet>, std::list<GRFIdentifier>>> packet_content_pairs;
174 /* Collect GRF Identifications and split them into several packages */
175 for (auto config = info->grfconfig; config != nullptr; config = config->next) {
176 if (HasBit(config->flags, GCF_STATIC)) continue;
178 if ((count % NETWORK_MAX_GRF_COUNT) == 0) {
179 auto new_pair = std::make_pair(std::make_shared<Packet>(PACKET_UDP_SERVER_NEWGRF_RESPONSE), std::list<GRFIdentifier>());
180 packet_content_pairs.push_back(new_pair);
183 assert(!packet_content_pairs.empty());
185 packet_content_pairs.back().second.push_back(config->ident);
187 ++count;
190 /* Send actual GRF Identifications */
191 for (auto pair : packet_content_pairs) {
192 auto packet = pair.first;
194 packet->Send_uint8(NETWORK_NEWGRF_INFO_VERSION);
195 packet->Send_uint8(packet_id++); // The id of this packet
196 packet->Send_uint8((uint8)pair.second.size()); // Number of NewGRFs in this packet
198 for (auto grf_ident : pair.second) {
199 this->SendGRFIdentifier(packet.get(), &grf_ident);
202 packets_to_send.push_back(packet);
205 return packets_to_send;
210 * Serializes the NetworkGameInfo struct to the packet
211 * @param p the packet to write the data to
212 * @param info the NetworkGameInfo struct to serialize
214 void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
216 p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
219 * Please observe the order.
220 * The parts must be read in the same order as they are sent!
223 /* Update the documentation in udp.h on changes
224 * to the NetworkGameInfo wire-protocol! */
226 /* NETWORK_GAME_INFO_VERSION = 128 */
228 /* Only send the GRF Identification (GRF_ID and MD5 checksum) of
229 * the GRFs that are needed, i.e. the ones that the server has
230 * selected in the NewGRF GUI and not the ones that are used due
231 * to the fact that they are in [newgrf-static] in openttd.cfg */
232 uint count = 0;
234 /* Count number of GRFs to send information about */
235 for (auto config = info->grfconfig; config != nullptr; config = config->next) {
236 if (!HasBit(config->flags, GCF_STATIC)) ++count;
239 uint8 num_grf_packets_to_expect = std::ceil((float)count / NETWORK_MAX_GRF_COUNT);
241 // Send number of GRF info packets that will be sent
242 p->Send_uint8(num_grf_packets_to_expect);
244 // Actual GRF Identifications will be send in multiple PACKET_UDP_SERVER_NEWGRF_RESPONSE packages.
245 // This package has not enough storage to send all that data depending on how many NewGRFs are active.
248 /* NETWORK_GAME_INFO_VERSION = 4 */
250 // This part is deprecated and is no longer sent. The version 128 part replaces it.
253 /* NETWORK_GAME_INFO_VERSION = 3 */
254 p->Send_uint32(info->game_date);
255 p->Send_uint32(info->start_date);
257 /* NETWORK_GAME_INFO_VERSION = 2 */
258 p->Send_uint8 (info->companies_max);
259 p->Send_uint8 (info->companies_on);
260 p->Send_uint8 (info->spectators_max);
262 /* NETWORK_GAME_INFO_VERSION = 1 */
263 p->Send_string(info->server_name);
264 p->Send_string(info->server_revision);
265 p->Send_uint8 (info->server_lang);
266 p->Send_bool (info->use_password);
267 p->Send_uint8 (info->clients_max);
268 p->Send_uint8 (info->clients_on);
269 p->Send_uint8 (info->spectators_on);
270 p->Send_string(info->map_name);
271 p->Send_uint16(info->map_width);
272 p->Send_uint16(info->map_height);
273 p->Send_uint8 (info->map_set);
274 p->Send_bool (info->dedicated);
278 * Deserializes the NewGRF information of the NetworkGameInfo struct from one out of several sent packets
279 * @param p the packet to read the data from
280 * @param info the NetworkGameInfo to deserialize into
282 void NetworkUDPSocketHandler::ReceiveNetworkGameNewGrfInfo(Packet *p, NetworkGameInfo *info)
284 auto new_grf_info_packet_version = p->Recv_uint8();
286 // For now we only handle this specific version.
287 if (new_grf_info_packet_version != NETWORK_NEWGRF_INFO_VERSION) return;
289 auto packet_id = p->Recv_uint8();
291 // Check if we already received this one. Bail if so. No need to process it again.
292 if (std::any_of(info->received_grf_identifiers.begin(), info->received_grf_identifiers.end(), [&](auto item) {
293 return item.first == packet_id;
294 })) return;
296 auto num_grfs = p->Recv_uint8();
298 /* Broken/bad data. It cannot have that many NewGRFs. */
299 if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
301 auto received_pair = std::make_pair(packet_id, std::list<GRFIdentifier>());
303 for (auto i = 0; i < num_grfs; ++i) {
304 GRFIdentifier ident;
305 this->ReceiveGRFIdentifier(p, &ident);
307 received_pair.second.push_back(ident);
310 info->received_grf_identifiers.push_back(received_pair);
314 * Deserializes the NetworkGameInfo struct minus NewGRF information from the packet
315 * @param p the packet to read the data from
316 * @param info the NetworkGameInfo to deserialize into
318 void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info)
320 static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
322 info->game_info_version = p->Recv_uint8();
325 * Please observe the order.
326 * The parts must be read in the same order as they are sent!
329 /* Update the documentation in udp.h on changes
330 * to the NetworkGameInfo wire-protocol! */
332 switch (info->game_info_version) {
333 case 128: FALLTHROUGH;
334 case 4: {
335 if (info->game_info_version == 4) {
336 GRFConfig **dst = &info->grfconfig;
337 uint i;
338 uint num_grfs = p->Recv_uint8();
340 /* Broken/bad data. It cannot have that many NewGRFs. */
341 if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
343 for (i = 0; i < num_grfs; i++) {
344 GRFConfig *c = new GRFConfig();
345 this->ReceiveGRFIdentifier(p, &c->ident);
346 this->HandleIncomingNetworkGameInfoGRFConfig(c);
348 /* Append GRFConfig to the list */
349 *dst = c;
350 dst = &c->next;
352 } else if (info->game_info_version == 128) {
353 // In NETWORK_GAME_INFO_VERSION 128 the actual newGRF information is sent via a different package type.
354 // Check ReceiveNetworkGameNewGrfInfo().
355 info->new_grf_packages_to_expect = p->Recv_uint8();
358 FALLTHROUGH;
360 case 3:
361 info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
362 info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
363 FALLTHROUGH;
365 case 2:
366 info->companies_max = p->Recv_uint8 ();
367 info->companies_on = p->Recv_uint8 ();
368 info->spectators_max = p->Recv_uint8 ();
369 FALLTHROUGH;
371 case 1:
372 p->Recv_string(info->server_name, sizeof(info->server_name));
373 p->Recv_string(info->server_revision, sizeof(info->server_revision));
374 info->server_lang = p->Recv_uint8 ();
375 info->use_password = p->Recv_bool ();
376 info->clients_max = p->Recv_uint8 ();
377 info->clients_on = p->Recv_uint8 ();
378 info->spectators_on = p->Recv_uint8 ();
379 if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
380 info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
381 info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
383 p->Recv_string(info->map_name, sizeof(info->map_name));
384 info->map_width = p->Recv_uint16();
385 info->map_height = p->Recv_uint16();
386 info->map_set = p->Recv_uint8 ();
387 info->dedicated = p->Recv_bool ();
389 if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0;
390 if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
395 * Handle an incoming packets by sending it to the correct function.
396 * @param p the received packet
397 * @param client_addr the sender of the packet
399 void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_addr)
401 PacketUDPType type;
403 /* New packet == new client, which has not quit yet */
404 this->Reopen();
406 type = (PacketUDPType)p->Recv_uint8();
408 switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
409 case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
410 case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
411 case PACKET_UDP_SERVER_NEWGRF_RESPONSE: this->Receive_SERVER_NEWGRF_RESPONSE(p, client_addr); break;
412 case PACKET_UDP_CLIENT_DETAIL_INFO: this->Receive_CLIENT_DETAIL_INFO(p, client_addr); break;
413 case PACKET_UDP_SERVER_DETAIL_INFO: this->Receive_SERVER_DETAIL_INFO(p, client_addr); break;
414 case PACKET_UDP_SERVER_REGISTER: this->Receive_SERVER_REGISTER(p, client_addr); break;
415 case PACKET_UDP_MASTER_ACK_REGISTER: this->Receive_MASTER_ACK_REGISTER(p, client_addr); break;
416 case PACKET_UDP_CLIENT_GET_LIST: this->Receive_CLIENT_GET_LIST(p, client_addr); break;
417 case PACKET_UDP_MASTER_RESPONSE_LIST: this->Receive_MASTER_RESPONSE_LIST(p, client_addr); break;
418 case PACKET_UDP_SERVER_UNREGISTER: this->Receive_SERVER_UNREGISTER(p, client_addr); break;
419 case PACKET_UDP_CLIENT_GET_NEWGRFS: this->Receive_CLIENT_GET_NEWGRFS(p, client_addr); break;
420 case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break;
421 case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break;
423 default:
424 if (this->HasClientQuit()) {
425 DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
426 } else {
427 DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString());
429 break;
434 * Helper for logging receiving invalid packets.
435 * @param type The received packet type.
436 * @param client_addr The address we received the packet from.
438 void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress *client_addr)
440 DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString());
443 void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
444 void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
445 void NetworkUDPSocketHandler::Receive_SERVER_NEWGRF_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRF_RESPONSE, client_addr); }
446 void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO, client_addr); }
447 void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO, client_addr); }
448 void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER, client_addr); }
449 void NetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_ACK_REGISTER, client_addr); }
450 void NetworkUDPSocketHandler::Receive_CLIENT_GET_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_LIST, client_addr); }
451 void NetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_RESPONSE_LIST, client_addr); }
452 void NetworkUDPSocketHandler::Receive_SERVER_UNREGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_UNREGISTER, client_addr); }
453 void NetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_NEWGRFS, client_addr); }
454 void NetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRFS, client_addr); }
455 void NetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_SESSION_KEY, client_addr); }
457 #endif /* ENABLE_NETWORK */