OpenTTD Source 20241224-master-gf74b0cf984
udp.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
12#include "../../stdafx.h"
13#include "../../timer/timer_game_calendar.h"
14#include "../../debug.h"
15#include "network_game_info.h"
16#include "udp.h"
17
18#include "../../safeguards.h"
19
25{
26 if (bind != nullptr) {
27 for (NetworkAddress &addr : *bind) {
28 this->bind.push_back(addr);
29 }
30 } else {
31 /* As an empty hostname and port 0 don't go well when
32 * resolving it we need to add an address for each of
33 * the address families we support. */
34 this->bind.emplace_back("", 0, AF_INET);
35 this->bind.emplace_back("", 0, AF_INET6);
36 }
37}
38
39
45{
46 /* Make sure socket is closed */
47 this->CloseSocket();
48
49 for (NetworkAddress &addr : this->bind) {
50 addr.Listen(SOCK_DGRAM, &this->sockets);
51 }
52
53 return !this->sockets.empty();
54}
55
60{
61 for (auto &s : this->sockets) {
62 closesocket(s.first);
63 }
64 this->sockets.clear();
65}
66
74void NetworkUDPSocketHandler::SendPacket(Packet &p, NetworkAddress &recv, bool all, bool broadcast)
75{
76 if (this->sockets.empty()) this->Listen();
77
78 for (auto &s : this->sockets) {
79 /* Make a local copy because if we resolve it we cannot
80 * easily unresolve it so we can resolve it later again. */
81 NetworkAddress send(recv);
82
83 /* Not the same type */
84 if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue;
85
86 p.PrepareToSend();
87
88 if (broadcast) {
89 /* Enable broadcast */
90 unsigned long val = 1;
91 if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
92 Debug(net, 1, "Setting broadcast mode failed: {}", NetworkError::GetLast().AsString());
93 }
94 }
95
96 /* Send the buffer */
97 ssize_t res = p.TransferOut<int>(sendto, s.first, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
98 Debug(net, 7, "sendto({})", send.GetAddressAsString());
99
100 /* Check for any errors, but ignore it otherwise */
101 if (res == -1) Debug(net, 1, "sendto({}) failed: {}", send.GetAddressAsString(), NetworkError::GetLast().AsString());
102
103 if (!all) break;
104 }
105}
106
111{
112 for (auto &s : this->sockets) {
113 for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP
114 struct sockaddr_storage client_addr;
115 memset(&client_addr, 0, sizeof(client_addr));
116
117 /* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */
118 Packet p(this, UDP_MTU, UDP_MTU);
119 socklen_t client_len = sizeof(client_addr);
120
121 /* Try to receive anything */
122 SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket
123 ssize_t nbytes = p.TransferIn<int>(recvfrom, s.first, 0, (struct sockaddr *)&client_addr, &client_len);
124
125 /* Did we get the bytes for the base header of the packet? */
126 if (nbytes <= 0) break; // No data, i.e. no packet
127 if (nbytes <= 2) continue; // Invalid data; try next packet
128#ifdef __EMSCRIPTEN__
129 client_len = FixAddrLenForEmscripten(client_addr);
130#endif
131
132 NetworkAddress address(client_addr, client_len);
133
134 /* If the size does not match the packet must be corrupted.
135 * Otherwise it will be marked as corrupted later on. */
136 if (!p.ParsePacketSize() || static_cast<size_t>(nbytes) != p.Size()) {
137 Debug(net, 1, "Received a packet with mismatching size from {}", address.GetAddressAsString());
138 continue;
139 }
140 if (!p.PrepareToRead()) {
141 Debug(net, 1, "Invalid packet received (too small / decryption error)");
142 continue;
143 }
144
145 /* Handle the packet */
146 this->HandleUDPPacket(p, address);
147 }
148 }
149}
150
157{
158 PacketUDPType type;
159
160 /* New packet == new client, which has not quit yet */
161 this->Reopen();
162
163 type = (PacketUDPType)p.Recv_uint8();
164
165 switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
166 case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
167 case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
168
169 default:
170 if (this->HasClientQuit()) {
171 Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr.GetAddressAsString());
172 } else {
173 Debug(net, 0, "[udp] Received illegal packet from {}", client_addr.GetAddressAsString());
174 }
175 break;
176 }
177}
178
185{
186 Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr.GetAddressAsString());
187}
188
std::vector< NetworkAddress > NetworkAddressList
Type for a list of addresses.
Definition address.h:20
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
Definition address.h:28
int GetAddressLength()
Get the (valid) length of the address.
Definition address.h:98
bool IsFamily(int family)
Checks of this address is of the given family.
Definition address.cpp:132
const sockaddr_storage * GetAddress()
Get the address in its internal representation.
Definition address.cpp:113
std::string GetAddressAsString(bool with_family=true)
Get the address as a string, e.g.
Definition address.cpp:94
const std::string & AsString() const
Get the string representation of the error message.
static NetworkError GetLast()
Get the last network error.
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition core.h:74
void Reopen()
Reopen the socket so we can send/receive stuff again.
Definition core.h:79
void CloseSocket()
Close the actual UDP socket.
Definition udp.cpp:59
bool Listen()
Start listening on the given host and port.
Definition udp.cpp:44
SocketList sockets
The opened sockets.
Definition udp.h:31
void SendPacket(Packet &p, NetworkAddress &recv, bool all=false, bool broadcast=false)
Send a packet over UDP.
Definition udp.cpp:74
void ReceivePackets()
Receive a packet at UDP level.
Definition udp.cpp:110
NetworkUDPSocketHandler(NetworkAddressList *bind=nullptr)
Create an UDP socket but don't listen yet.
Definition udp.cpp:24
virtual void Receive_CLIENT_FIND_SERVER(Packet &p, NetworkAddress &client_addr)
Queries to the server for information about the game.
Definition udp.cpp:189
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress &client_addr)
Helper for logging receiving invalid packets.
Definition udp.cpp:184
NetworkAddressList bind
The address to bind to.
Definition udp.h:29
virtual void Receive_SERVER_RESPONSE(Packet &p, NetworkAddress &client_addr)
Response to a query letting the client know we are here.
Definition udp.cpp:190
void HandleUDPPacket(Packet &p, NetworkAddress &client_addr)
Handle an incoming packets by sending it to the correct function.
Definition udp.cpp:156
static const size_t UDP_MTU
Number of bytes we can pack in a single UDP packet.
Definition config.h:28
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
Internal entity of a packet.
Definition packet.h:42
size_t Size() const
Get the number of bytes in the packet.
Definition packet.cpp:250
bool PrepareToRead()
Prepares the packet so it can be read.
Definition packet.cpp:278
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:318
bool ParsePacketSize()
Reads the packet size from the raw packet and stores it in the packet->size.
Definition packet.cpp:259
ssize_t TransferIn(F transfer_function, S source, Args &&... args)
Transfer data from the given function into the packet.
Definition packet.h:174
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition packet.cpp:66
ssize_t TransferOut(F transfer_function, D destination, Args &&... args)
Transfer data from the packet to the given function.
Definition packet.h:139
Basic functions to receive and send UDP packets.
PacketUDPType
Enum with all types of UDP packets.
Definition udp.h:19
@ PACKET_UDP_CLIENT_FIND_SERVER
Queries a game server for game information.
Definition udp.h:20
@ PACKET_UDP_SERVER_RESPONSE
Reply of the game server with game information.
Definition udp.h:21
@ PACKET_UDP_END
Must ALWAYS be on the end of this list!! (period)
Definition udp.h:22