Handle a number of failure conditions in the network code
[openttd/fttd.git] / src / network / core / udp.cpp
blobf7abc7e35a74ff8c624f7d184ee07a47bf349a5a
1 /* $Id$ */
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"
19 #include "udp.h"
21 /**
22 * Create an UDP socket but don't listen yet.
23 * @param bind the addresses to bind to.
25 NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
27 if (bind != NULL) {
28 for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) {
29 *this->bind.Append() = *addr;
31 } else {
32 /* As hostname NULL and port 0/NULL don't go well when
33 * resolving it we need to add an address for each of
34 * the address families we support. */
35 *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
36 *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6);
41 /**
42 * Start listening on the given host and port.
43 * @return true if at least one port is listening
45 bool NetworkUDPSocketHandler::Listen()
47 /* Make sure socket is closed */
48 this->Close();
50 for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) {
51 addr->Listen(SOCK_DGRAM, &this->sockets);
54 return this->sockets.Length() != 0;
57 /**
58 * Close the given UDP socket
60 void NetworkUDPSocketHandler::Close()
62 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
63 closesocket(s->second);
65 this->sockets.Clear();
68 NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error)
70 NetworkSocketHandler::CloseConnection(error);
71 return NETWORK_RECV_STATUS_OKAY;
74 /**
75 * Send a packet over UDP
76 * @param p the packet to send
77 * @param recv the receiver (target) of the packet
78 * @param all send the packet using all sockets that can send it
79 * @param broadcast whether to send a broadcast message
81 void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
83 if (this->sockets.Length() == 0) this->Listen();
85 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
86 /* Make a local copy because if we resolve it we cannot
87 * easily unresolve it so we can resolve it later again. */
88 NetworkAddress send(*recv);
90 /* Not the same type */
91 if (!send.IsFamily(s->first.GetAddress()->ss_family)) continue;
93 p->PrepareToSend();
95 #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
96 if (broadcast) {
97 /* Enable broadcast */
98 unsigned long val = 1;
99 if (setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
100 DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR());
103 #endif
105 /* Send the buffer */
106 int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
107 DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString());
109 /* Check for any errors, but ignore it otherwise */
110 if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString(), GET_LAST_ERROR());
112 if (!all) break;
117 * Receive a packet at UDP level
119 void NetworkUDPSocketHandler::ReceivePackets()
121 for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
122 for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP
123 struct sockaddr_storage client_addr;
124 memset(&client_addr, 0, sizeof(client_addr));
126 Packet p(this);
127 socklen_t client_len = sizeof(client_addr);
129 /* Try to receive anything */
130 SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket
131 int nbytes = recvfrom(s->second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len);
133 /* Did we get the bytes for the base header of the packet? */
134 if (nbytes <= 0) break; // No data, i.e. no packet
135 if (nbytes <= 2) continue; // Invalid data; try next packet
137 NetworkAddress address(client_addr, client_len);
138 p.PrepareToRead();
140 /* If the size does not match the packet must be corrupted.
141 * Otherwise it will be marked as corrupted later on. */
142 if (nbytes != p.size) {
143 DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString());
144 continue;
147 /* Handle the packet */
148 this->HandleUDPPacket(&p, &address);
155 * Serializes the NetworkGameInfo struct to the packet
156 * @param p the packet to write the data to
157 * @param info the NetworkGameInfo struct to serialize
159 void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info)
161 p->Send_uint8 (NETWORK_GAME_INFO_VERSION);
164 * Please observe the order.
165 * The parts must be read in the same order as they are sent!
168 /* Update the documentation in udp.h on changes
169 * to the NetworkGameInfo wire-protocol! */
171 /* NETWORK_GAME_INFO_VERSION = 4 */
173 /* Only send the GRF Identification (GRF_ID and MD5 checksum) of
174 * the GRFs that are needed, i.e. the ones that the server has
175 * selected in the NewGRF GUI and not the ones that are used due
176 * to the fact that they are in [newgrf-static] in openttd.cfg */
177 const GRFConfig *c;
178 uint count = 0;
180 /* Count number of GRFs to send information about */
181 for (c = info->grfconfig; c != NULL; c = c->next) {
182 if (!HasBit(c->flags, GCF_STATIC)) count++;
184 p->Send_uint8 (count); // Send number of GRFs
186 /* Send actual GRF Identifications */
187 for (c = info->grfconfig; c != NULL; c = c->next) {
188 if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
192 /* NETWORK_GAME_INFO_VERSION = 3 */
193 p->Send_uint32(info->game_date);
194 p->Send_uint32(info->start_date);
196 /* NETWORK_GAME_INFO_VERSION = 2 */
197 p->Send_uint8 (info->companies_max);
198 p->Send_uint8 (info->companies_on);
199 p->Send_uint8 (info->spectators_max);
201 /* NETWORK_GAME_INFO_VERSION = 1 */
202 p->Send_string(info->server_name);
203 p->Send_string(info->server_revision);
204 p->Send_uint8 (info->server_lang);
205 p->Send_bool (info->use_password);
206 p->Send_uint8 (info->clients_max);
207 p->Send_uint8 (info->clients_on);
208 p->Send_uint8 (info->spectators_on);
209 p->Send_string(info->map_name);
210 p->Send_uint16(info->map_width);
211 p->Send_uint16(info->map_height);
212 p->Send_uint8 (info->map_set);
213 p->Send_bool (info->dedicated);
217 * Deserializes the NetworkGameInfo struct from the packet
218 * @param p the packet to read the data from
219 * @param info the NetworkGameInfo to deserialize into
221 void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info)
223 static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
225 info->game_info_version = p->Recv_uint8();
228 * Please observe the order.
229 * The parts must be read in the same order as they are sent!
232 /* Update the documentation in udp.h on changes
233 * to the NetworkGameInfo wire-protocol! */
235 switch (info->game_info_version) {
236 case 4: {
237 GRFConfig **dst = &info->grfconfig;
238 uint i;
239 uint num_grfs = p->Recv_uint8();
241 /* Broken/bad data. It cannot have that many NewGRFs. */
242 if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
244 for (i = 0; i < num_grfs; i++) {
245 GRFConfig *c = new GRFConfig();
246 this->ReceiveGRFIdentifier(p, &c->ident);
247 this->HandleIncomingNetworkGameInfoGRFConfig(c);
249 /* Append GRFConfig to the list */
250 *dst = c;
251 dst = &c->next;
253 /* FALL THROUGH */
255 case 3:
256 info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
257 info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
258 /* FALL THROUGH */
259 case 2:
260 info->companies_max = p->Recv_uint8 ();
261 info->companies_on = p->Recv_uint8 ();
262 info->spectators_max = p->Recv_uint8 ();
263 /* FALL THROUGH */
264 case 1:
265 p->Recv_string(info->server_name, sizeof(info->server_name));
266 p->Recv_string(info->server_revision, sizeof(info->server_revision));
267 info->server_lang = p->Recv_uint8 ();
268 info->use_password = p->Recv_bool ();
269 info->clients_max = p->Recv_uint8 ();
270 info->clients_on = p->Recv_uint8 ();
271 info->spectators_on = p->Recv_uint8 ();
272 if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier
273 info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
274 info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR;
276 p->Recv_string(info->map_name, sizeof(info->map_name));
277 info->map_width = p->Recv_uint16();
278 info->map_height = p->Recv_uint16();
279 info->map_set = p->Recv_uint8 ();
280 info->dedicated = p->Recv_bool ();
282 if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0;
283 if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
288 * Handle an incoming packets by sending it to the correct function.
289 * @param p the received packet
290 * @param client_addr the sender of the packet
292 void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_addr)
294 PacketUDPType type;
296 /* New packet == new client, which has not quit yet */
297 this->Reopen();
299 type = (PacketUDPType)p->Recv_uint8();
301 switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
302 case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
303 case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
304 case PACKET_UDP_CLIENT_DETAIL_INFO: this->Receive_CLIENT_DETAIL_INFO(p, client_addr); break;
305 case PACKET_UDP_SERVER_DETAIL_INFO: this->Receive_SERVER_DETAIL_INFO(p, client_addr); break;
306 case PACKET_UDP_SERVER_REGISTER: this->Receive_SERVER_REGISTER(p, client_addr); break;
307 case PACKET_UDP_MASTER_ACK_REGISTER: this->Receive_MASTER_ACK_REGISTER(p, client_addr); break;
308 case PACKET_UDP_CLIENT_GET_LIST: this->Receive_CLIENT_GET_LIST(p, client_addr); break;
309 case PACKET_UDP_MASTER_RESPONSE_LIST: this->Receive_MASTER_RESPONSE_LIST(p, client_addr); break;
310 case PACKET_UDP_SERVER_UNREGISTER: this->Receive_SERVER_UNREGISTER(p, client_addr); break;
311 case PACKET_UDP_CLIENT_GET_NEWGRFS: this->Receive_CLIENT_GET_NEWGRFS(p, client_addr); break;
312 case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break;
313 case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break;
315 default:
316 if (this->HasClientQuit()) {
317 DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
318 } else {
319 DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString());
321 break;
326 * Helper for logging receiving invalid packets.
327 * @param type The received packet type.
328 * @param client_addr The address we received the packet from.
330 void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress *client_addr)
332 DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString());
335 void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
336 void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
337 void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO, client_addr); }
338 void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO, client_addr); }
339 void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER, client_addr); }
340 void NetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_ACK_REGISTER, client_addr); }
341 void NetworkUDPSocketHandler::Receive_CLIENT_GET_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_LIST, client_addr); }
342 void NetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_RESPONSE_LIST, client_addr); }
343 void NetworkUDPSocketHandler::Receive_SERVER_UNREGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_UNREGISTER, client_addr); }
344 void NetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_NEWGRFS, client_addr); }
345 void NetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRFS, client_addr); }
346 void NetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_SESSION_KEY, client_addr); }
348 #endif /* ENABLE_NETWORK */