OpenTTD Source  20241121-master-g67a0fccfad
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 
74 void 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:19
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([[maybe_unused]] 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