OpenTTD Source 20260206-master-g4d4e37dbf1
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "../../stdafx.h"
12#include "../../debug.h"
13#include "network_game_info.h"
14#include "udp.h"
15
16#include "../../safeguards.h"
17
23{
24 if (bind != nullptr) {
25 for (NetworkAddress &addr : *bind) {
26 this->bind.push_back(addr);
27 }
28 } else {
29 /* As an empty hostname and port 0 don't go well when
30 * resolving it we need to add an address for each of
31 * the address families we support. */
32 this->bind.emplace_back("", 0, AF_INET);
33 this->bind.emplace_back("", 0, AF_INET6);
34 }
35}
36
37
43{
44 /* Make sure socket is closed */
45 this->CloseSocket();
46
47 for (NetworkAddress &addr : this->bind) {
48 addr.Listen(SOCK_DGRAM, &this->sockets);
49 }
50
51 return !this->sockets.empty();
52}
53
58{
59 for (auto &s : this->sockets) {
60 closesocket(s.first);
61 }
62 this->sockets.clear();
63}
64
72void NetworkUDPSocketHandler::SendPacket(Packet &p, NetworkAddress &recv, bool all, bool broadcast)
73{
74 if (this->sockets.empty()) this->Listen();
75
76 for (auto &s : this->sockets) {
77 /* Make a local copy because if we resolve it we cannot
78 * easily unresolve it so we can resolve it later again. */
79 NetworkAddress send(recv);
80
81 /* Not the same type */
82 if (!send.IsFamily(s.second.GetAddress()->ss_family)) continue;
83
84 p.PrepareToSend();
85
86 if (broadcast) {
87 /* Enable broadcast */
88 unsigned long val = 1;
89 if (setsockopt(s.first, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) {
90 Debug(net, 1, "Setting broadcast mode failed: {}", NetworkError::GetLast().AsString());
91 }
92 }
93
94 /* Send the buffer */
95 ssize_t res = p.TransferOut([&](std::span<const uint8_t> buffer) {
96 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());
97 });
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
116 /* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */
117 Packet p(this, UDP_MTU, UDP_MTU);
118 socklen_t client_len = sizeof(client_addr);
119
120 /* Try to receive anything */
121 SetNonBlocking(s.first); // Some OSes seem to lose the non-blocking status of the socket
122 ssize_t nbytes = p.TransferIn([&](std::span<uint8_t> buffer) {
123 return recvfrom(s.first, reinterpret_cast<char *>(buffer.data()), static_cast<int>(buffer.size()), 0, reinterpret_cast<struct sockaddr *>(&client_addr), &client_len);
124 });
125
126 /* Did we get the bytes for the base header of the packet? */
127 if (nbytes <= 0) break; // No data, i.e. no packet
128 if (nbytes <= 2) continue; // Invalid data; try next packet
129#ifdef __EMSCRIPTEN__
130 client_len = FixAddrLenForEmscripten(client_addr);
131#endif
132
133 NetworkAddress address(client_addr, client_len);
134
135 /* If the size does not match the packet must be corrupted.
136 * Otherwise it will be marked as corrupted later on. */
137 if (!p.ParsePacketSize() || static_cast<size_t>(nbytes) != p.Size()) {
138 Debug(net, 1, "Received a packet with mismatching size from {}", address.GetAddressAsString());
139 continue;
140 }
141 if (!p.PrepareToRead()) {
142 Debug(net, 1, "Invalid packet received (too small / decryption error)");
143 continue;
144 }
145
146 /* Handle the packet */
147 this->HandleUDPPacket(p, address);
148 }
149 }
150}
151
158{
159 PacketUDPType type;
160
161 /* New packet == new client, which has not quit yet */
162 this->Reopen();
163
164 type = (PacketUDPType)p.Recv_uint8();
165
166 switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
167 case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
168 case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
169
170 default:
171 if (this->HasClientQuit()) {
172 Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr.GetAddressAsString());
173 } else {
174 Debug(net, 0, "[udp] Received illegal packet from {}", client_addr.GetAddressAsString());
175 }
176 break;
177 }
178}
179
186{
187 Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr.GetAddressAsString());
188}
189
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
static NetworkError GetLast()
Get the last network error.
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition core.h:72
void Reopen()
Reopen the socket so we can send/receive stuff again.
Definition core.h:77
void CloseSocket()
Close the actual UDP socket.
Definition udp.cpp:57
bool Listen()
Start listening on the given host and port.
Definition udp.cpp:42
SocketList sockets
The opened sockets.
Definition udp.h:29
void SendPacket(Packet &p, NetworkAddress &recv, bool all=false, bool broadcast=false)
Send a packet over UDP.
Definition udp.cpp:72
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:22
virtual void Receive_CLIENT_FIND_SERVER(Packet &p, NetworkAddress &client_addr)
Queries to the server for information about the game.
Definition udp.cpp:190
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress &client_addr)
Helper for logging receiving invalid packets.
Definition udp.cpp:185
NetworkAddressList bind
The address to bind to.
Definition udp.h:27
virtual void Receive_SERVER_RESPONSE(Packet &p, NetworkAddress &client_addr)
Response to a query letting the client know we are here.
Definition udp.cpp:191
void HandleUDPPacket(Packet &p, NetworkAddress &client_addr)
Handle an incoming packets by sending it to the correct function.
Definition udp.cpp:157
static const size_t UDP_MTU
Number of bytes we can pack in a single UDP packet.
Definition config.h:26
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Convert NetworkGameInfo to Packet and back.
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
size_t Size() const
Get the number of bytes in the packet.
Definition packet.cpp:248
bool PrepareToRead()
Prepares the packet so it can be read.
Definition packet.cpp:276
ssize_t TransferIn(F transfer_function)
Transfer data from the given function into the packet.
Definition packet.h:155
uint8_t Recv_uint8()
Read a 8 bits integer from the packet.
Definition packet.cpp:316
bool ParsePacketSize()
Reads the packet size from the raw packet and stores it in the packet->size.
Definition packet.cpp:257
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition packet.cpp:64
ssize_t TransferOut(F transfer_function)
Transfer data from the packet to the given function.
Definition packet.h:126
Definition of the game-calendar-timer.
Basic functions to receive and send UDP packets.
PacketUDPType
Enum with all types of UDP packets.
Definition udp.h:17
@ PACKET_UDP_CLIENT_FIND_SERVER
Queries a game server for game information.
Definition udp.h:18
@ PACKET_UDP_SERVER_RESPONSE
Reply of the game server with game information.
Definition udp.h:19
@ PACKET_UDP_END
Must ALWAYS be on the end of this list!! (period).
Definition udp.h:20