OpenTTD Source 20250524-master-gc366e6a48e
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([&](std::span<const uint8_t> buffer) {
98 return sendto(s.first, reinterpret_cast<const char *>(buffer.data()), static_cast<int>(buffer.size()), 0, reinterpret_cast<const struct sockaddr *>(send.GetAddress()), send.GetAddressLength());
99 });
100 Debug(net, 7, "sendto({})", send.GetAddressAsString());
101
102 /* Check for any errors, but ignore it otherwise */
103 if (res == -1) Debug(net, 1, "sendto({}) failed: {}", send.GetAddressAsString(), NetworkError::GetLast().AsString());
104
105 if (!all) break;
106 }
107}
108
113{
114 for (auto &s : this->sockets) {
115 for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP
116 struct sockaddr_storage client_addr{};
117
118 /* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */
119 Packet p(this, UDP_MTU, UDP_MTU);
120 socklen_t client_len = sizeof(client_addr);
121
122 /* Try to receive anything */
123 SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket
124 ssize_t nbytes = p.TransferIn([&](std::span<uint8_t> buffer) {
125 return recvfrom(s.first, reinterpret_cast<char *>(buffer.data()), static_cast<int>(buffer.size()), 0, reinterpret_cast<struct sockaddr *>(&client_addr), &client_len);
126 });
127
128 /* Did we get the bytes for the base header of the packet? */
129 if (nbytes <= 0) break; // No data, i.e. no packet
130 if (nbytes <= 2) continue; // Invalid data; try next packet
131#ifdef __EMSCRIPTEN__
132 client_len = FixAddrLenForEmscripten(client_addr);
133#endif
134
135 NetworkAddress address(client_addr, client_len);
136
137 /* If the size does not match the packet must be corrupted.
138 * Otherwise it will be marked as corrupted later on. */
139 if (!p.ParsePacketSize() || static_cast<size_t>(nbytes) != p.Size()) {
140 Debug(net, 1, "Received a packet with mismatching size from {}", address.GetAddressAsString());
141 continue;
142 }
143 if (!p.PrepareToRead()) {
144 Debug(net, 1, "Invalid packet received (too small / decryption error)");
145 continue;
146 }
147
148 /* Handle the packet */
149 this->HandleUDPPacket(p, address);
150 }
151 }
152}
153
160{
161 PacketUDPType type;
162
163 /* New packet == new client, which has not quit yet */
164 this->Reopen();
165
166 type = (PacketUDPType)p.Recv_uint8();
167
168 switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
169 case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
170 case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
171
172 default:
173 if (this->HasClientQuit()) {
174 Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr.GetAddressAsString());
175 } else {
176 Debug(net, 0, "[udp] Received illegal packet from {}", client_addr.GetAddressAsString());
177 }
178 break;
179 }
180}
181
188{
189 Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr.GetAddressAsString());
190}
191
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:95
bool IsFamily(int family)
Checks of this address is of the given family.
Definition address.cpp:133
const sockaddr_storage * GetAddress()
Get the address in its internal representation.
Definition address.cpp:114
std::string GetAddressAsString(bool with_family=true)
Get the address as a string, e.g.
Definition address.cpp:95
std::string_view 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:112
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:192
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress &client_addr)
Helper for logging receiving invalid packets.
Definition udp.cpp:187
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:193
void HandleUDPPacket(Packet &p, NetworkAddress &client_addr)
Handle an incoming packets by sending it to the correct function.
Definition udp.cpp:159
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,...)
Output 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:43
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
ssize_t TransferIn(F transfer_function)
Transfer data from the given function into the packet.
Definition packet.h:157
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
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition packet.cpp:66
ssize_t TransferOut(F transfer_function)
Transfer data from the packet to the given function.
Definition packet.h:128
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