1 /* $Id: udp.cpp 26046 2013-11-22 21:41:19Z rubidium $ */
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/>.
11 * @file core/udp.cpp Basic functions to receive and send UDP packets.
16 #include "../../stdafx.h"
17 #include "../../date_func.h"
18 #include "../../debug.h"
21 #include "../../safeguards.h"
24 * Create an UDP socket but don't listen yet.
25 * @param bind the addresses to bind to.
27 NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList
*bind
)
30 for (NetworkAddress
*addr
= bind
->Begin(); addr
!= bind
->End(); addr
++) {
31 *this->bind
.Append() = *addr
;
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
);
44 * Start listening on the given host and port.
45 * @return true if at least one port is listening
47 bool NetworkUDPSocketHandler::Listen()
49 /* Make sure socket is closed */
52 for (NetworkAddress
*addr
= this->bind
.Begin(); addr
!= this->bind
.End(); addr
++) {
53 addr
->Listen(SOCK_DGRAM
, &this->sockets
);
56 return this->sockets
.Length() != 0;
60 * Close the given UDP socket
62 void NetworkUDPSocketHandler::Close()
64 for (SocketList::iterator s
= this->sockets
.Begin(); s
!= this->sockets
.End(); s
++) {
65 closesocket(s
->second
);
67 this->sockets
.Clear();
70 NetworkRecvStatus
NetworkUDPSocketHandler::CloseConnection(bool error
)
72 NetworkSocketHandler::CloseConnection(error
);
73 return NETWORK_RECV_STATUS_OKAY
;
77 * Send a packet over UDP
78 * @param p the packet to send
79 * @param recv the receiver (target) of the packet
80 * @param all send the packet using all sockets that can send it
81 * @param broadcast whether to send a broadcast message
83 void NetworkUDPSocketHandler::SendPacket(Packet
*p
, NetworkAddress
*recv
, bool all
, bool broadcast
)
85 if (this->sockets
.Length() == 0) this->Listen();
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
);
92 /* Not the same type */
93 if (!send
.IsFamily(s
->first
.GetAddress()->ss_family
)) continue;
97 #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */
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());
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());
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());
119 * Receive a packet at UDP level
121 void NetworkUDPSocketHandler::ReceivePackets()
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
));
129 socklen_t client_len
= sizeof(client_addr
);
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
);
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
139 NetworkAddress
address(client_addr
, client_len
);
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());
149 /* Handle the packet */
150 this->HandleUDPPacket(&p
, &address
);
157 * Serializes the NetworkGameInfo struct to the packet
158 * @param p the packet to write the data to
159 * @param info the NetworkGameInfo struct to serialize
161 void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet
*p
, const NetworkGameInfo
*info
)
163 p
->Send_uint8 (NETWORK_GAME_INFO_VERSION
);
166 * Please observe the order.
167 * The parts must be read in the same order as they are sent!
170 /* Update the documentation in udp.h on changes
171 * to the NetworkGameInfo wire-protocol! */
173 /* NETWORK_GAME_INFO_VERSION = 4 */
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 */
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
++;
186 p
->Send_uint8 (count
); // Send number of GRFs
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
);
194 /* NETWORK_GAME_INFO_VERSION = 3 */
195 p
->Send_uint32(info
->game_date
);
196 p
->Send_uint32(info
->start_date
);
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
);
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
);
219 * Deserializes the NetworkGameInfo struct from the packet
220 * @param p the packet to read the data from
221 * @param info the NetworkGameInfo to deserialize into
223 void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet
*p
, NetworkGameInfo
*info
)
225 static const Date MAX_DATE
= ConvertYMDToDate(MAX_YEAR
, 11, 31); // December is month 11
227 info
->game_info_version
= p
->Recv_uint8();
230 * Please observe the order.
231 * The parts must be read in the same order as they are sent!
234 /* Update the documentation in udp.h on changes
235 * to the NetworkGameInfo wire-protocol! */
237 switch (info
->game_info_version
) {
239 GRFConfig
**dst
= &info
->grfconfig
;
241 uint num_grfs
= p
->Recv_uint8();
243 /* Broken/bad data. It cannot have that many NewGRFs. */
244 if (num_grfs
> NETWORK_MAX_GRF_COUNT
) return;
246 for (i
= 0; i
< num_grfs
; i
++) {
247 GRFConfig
*c
= new GRFConfig();
248 this->ReceiveGRFIdentifier(p
, &c
->ident
);
249 this->HandleIncomingNetworkGameInfoGRFConfig(c
);
251 /* Append GRFConfig to the list */
259 info
->game_date
= Clamp(p
->Recv_uint32(), 0, MAX_DATE
);
260 info
->start_date
= Clamp(p
->Recv_uint32(), 0, MAX_DATE
);
264 info
->companies_max
= p
->Recv_uint8 ();
265 info
->companies_on
= p
->Recv_uint8 ();
266 info
->spectators_max
= p
->Recv_uint8 ();
270 p
->Recv_string(info
->server_name
, sizeof(info
->server_name
));
271 p
->Recv_string(info
->server_revision
, sizeof(info
->server_revision
));
272 info
->server_lang
= p
->Recv_uint8 ();
273 info
->use_password
= p
->Recv_bool ();
274 info
->clients_max
= p
->Recv_uint8 ();
275 info
->clients_on
= p
->Recv_uint8 ();
276 info
->spectators_on
= p
->Recv_uint8 ();
277 if (info
->game_info_version
< 3) { // 16 bits dates got scrapped and are read earlier
278 info
->game_date
= p
->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR
;
279 info
->start_date
= p
->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR
;
281 p
->Recv_string(info
->map_name
, sizeof(info
->map_name
));
282 info
->map_width
= p
->Recv_uint16();
283 info
->map_height
= p
->Recv_uint16();
284 info
->map_set
= p
->Recv_uint8 ();
285 info
->dedicated
= p
->Recv_bool ();
287 if (info
->server_lang
>= NETWORK_NUM_LANGUAGES
) info
->server_lang
= 0;
288 if (info
->map_set
>= NETWORK_NUM_LANDSCAPES
) info
->map_set
= 0;
293 * Handle an incoming packets by sending it to the correct function.
294 * @param p the received packet
295 * @param client_addr the sender of the packet
297 void NetworkUDPSocketHandler::HandleUDPPacket(Packet
*p
, NetworkAddress
*client_addr
)
301 /* New packet == new client, which has not quit yet */
304 type
= (PacketUDPType
)p
->Recv_uint8();
306 switch (this->HasClientQuit() ? PACKET_UDP_END
: type
) {
307 case PACKET_UDP_CLIENT_FIND_SERVER
: this->Receive_CLIENT_FIND_SERVER(p
, client_addr
); break;
308 case PACKET_UDP_SERVER_RESPONSE
: this->Receive_SERVER_RESPONSE(p
, client_addr
); break;
309 case PACKET_UDP_CLIENT_DETAIL_INFO
: this->Receive_CLIENT_DETAIL_INFO(p
, client_addr
); break;
310 case PACKET_UDP_SERVER_DETAIL_INFO
: this->Receive_SERVER_DETAIL_INFO(p
, client_addr
); break;
311 case PACKET_UDP_SERVER_REGISTER
: this->Receive_SERVER_REGISTER(p
, client_addr
); break;
312 case PACKET_UDP_MASTER_ACK_REGISTER
: this->Receive_MASTER_ACK_REGISTER(p
, client_addr
); break;
313 case PACKET_UDP_CLIENT_GET_LIST
: this->Receive_CLIENT_GET_LIST(p
, client_addr
); break;
314 case PACKET_UDP_MASTER_RESPONSE_LIST
: this->Receive_MASTER_RESPONSE_LIST(p
, client_addr
); break;
315 case PACKET_UDP_SERVER_UNREGISTER
: this->Receive_SERVER_UNREGISTER(p
, client_addr
); break;
316 case PACKET_UDP_CLIENT_GET_NEWGRFS
: this->Receive_CLIENT_GET_NEWGRFS(p
, client_addr
); break;
317 case PACKET_UDP_SERVER_NEWGRFS
: this->Receive_SERVER_NEWGRFS(p
, client_addr
); break;
318 case PACKET_UDP_MASTER_SESSION_KEY
: this->Receive_MASTER_SESSION_KEY(p
, client_addr
); break;
321 if (this->HasClientQuit()) {
322 DEBUG(net
, 0, "[udp] received invalid packet type %d from %s", type
, client_addr
->GetAddressAsString());
324 DEBUG(net
, 0, "[udp] received illegal packet from %s", client_addr
->GetAddressAsString());
331 * Helper for logging receiving invalid packets.
332 * @param type The received packet type.
333 * @param client_addr The address we received the packet from.
335 void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type
, NetworkAddress
*client_addr
)
337 DEBUG(net
, 0, "[udp] received packet type %d on wrong port from %s", type
, client_addr
->GetAddressAsString());
340 void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER
, client_addr
); }
341 void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE
, client_addr
); }
342 void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO
, client_addr
); }
343 void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO
, client_addr
); }
344 void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER
, client_addr
); }
345 void NetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_ACK_REGISTER
, client_addr
); }
346 void NetworkUDPSocketHandler::Receive_CLIENT_GET_LIST(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_LIST
, client_addr
); }
347 void NetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_RESPONSE_LIST
, client_addr
); }
348 void NetworkUDPSocketHandler::Receive_SERVER_UNREGISTER(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_UNREGISTER
, client_addr
); }
349 void NetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_NEWGRFS
, client_addr
); }
350 void NetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRFS
, client_addr
); }
351 void NetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet
*p
, NetworkAddress
*client_addr
) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_SESSION_KEY
, client_addr
); }
353 #endif /* ENABLE_NETWORK */