OpenTTD Source 20260109-master-g241b5fcdfe
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
10#include "../../stdafx.h"
11#include "../../timer/timer_game_calendar.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
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: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
#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.
Internal entity of a packet.
Definition packet.h:41
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
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