OpenTTD Source  12.0-beta2
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 "../../date_func.h"
14 #include "../../debug.h"
15 #include "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.size() != 0;
54 }
55 
60 {
61  for (auto &s : this->sockets) {
62  closesocket(s.second);
63  }
64  this->sockets.clear();
65 }
66 
74 void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast)
75 {
76  if (this->sockets.size() == 0) 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.first.GetAddress()->ss_family)) continue;
85 
86  p->PrepareToSend();
87 
88  if (broadcast) {
89  /* Enable broadcast */
90  unsigned long val = 1;
91  if (setsockopt(s.second, 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.second, 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.second); // Some OSes seem to lose the non-blocking status of the socket
123  ssize_t nbytes = p.TransferIn<int>(recvfrom, s.second, 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() || (size_t)nbytes != p.Size()) {
137  Debug(net, 1, "Received a packet with mismatching size from {}", address.GetAddressAsString());
138  continue;
139  }
140  p.PrepareToRead();
141 
142  /* Handle the packet */
143  this->HandleUDPPacket(&p, &address);
144  }
145  }
146 }
147 
154 {
155  PacketUDPType type;
156 
157  /* New packet == new client, which has not quit yet */
158  this->Reopen();
159 
160  type = (PacketUDPType)p->Recv_uint8();
161 
162  switch (this->HasClientQuit() ? PACKET_UDP_END : type) {
163  case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break;
164  case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break;
165 
166  default:
167  if (this->HasClientQuit()) {
168  Debug(net, 0, "[udp] Received invalid packet type {} from {}", type, client_addr->GetAddressAsString());
169  } else {
170  Debug(net, 0, "[udp] Received illegal packet from {}", client_addr->GetAddressAsString());
171  }
172  break;
173  }
174 }
175 
182 {
183  Debug(net, 0, "[udp] Received packet type {} on wrong port from {}", type, client_addr->GetAddressAsString());
184 }
185 
Packet::PrepareToSend
void PrepareToSend()
Writes the packet size from the raw packet from packet->size.
Definition: packet.cpp:83
Packet::Size
size_t Size() const
Get the number of bytes in the packet.
Definition: packet.cpp:249
NetworkAddress::GetAddress
const sockaddr_storage * GetAddress()
Get the address in its internal representation.
Definition: address.cpp:114
NetworkAddress::GetAddressLength
int GetAddressLength()
Get the (valid) length of the address.
Definition: address.h:100
PACKET_UDP_CLIENT_FIND_SERVER
@ PACKET_UDP_CLIENT_FIND_SERVER
Queries a game server for game information.
Definition: udp.h:20
Packet::TransferOut
ssize_t TransferOut(F transfer_function, D destination, Args &&... args)
Transfer data from the packet to the given function.
Definition: packet.h:141
NetworkUDPSocketHandler::CloseSocket
void CloseSocket()
Close the actual UDP socket.
Definition: udp.cpp:59
NetworkUDPSocketHandler::NetworkUDPSocketHandler
NetworkUDPSocketHandler(NetworkAddressList *bind=nullptr)
Create an UDP socket but don't listen yet.
Definition: udp.cpp:24
Packet::ParsePacketSize
bool ParsePacketSize()
Reads the packet size from the raw packet and stores it in the packet->size.
Definition: packet.cpp:258
NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER
virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr)
Queries to the server for information about the game.
Definition: udp.cpp:186
NetworkSocketHandler::Reopen
void Reopen()
Reopen the socket so we can send/receive stuff again.
Definition: core.h:73
NetworkAddressList
std::vector< NetworkAddress > NetworkAddressList
Type for a list of addresses.
Definition: address.h:21
Packet::PrepareToRead
void PrepareToRead()
Prepares the packet so it can be read.
Definition: packet.cpp:277
NetworkUDPSocketHandler::sockets
SocketList sockets
The opened sockets.
Definition: udp.h:31
NetworkError::GetLast
static NetworkError GetLast()
Get the last network error.
Definition: os_abstraction.cpp:116
PACKET_UDP_END
@ PACKET_UDP_END
Must ALWAYS be on the end of this list!! (period)
Definition: udp.h:22
NetworkUDPSocketHandler::bind
NetworkAddressList bind
The address to bind to.
Definition: udp.h:29
NetworkAddress::GetAddressAsString
std::string GetAddressAsString(bool with_family=true)
Get the address as a string, e.g.
Definition: address.cpp:94
Packet::TransferIn
ssize_t TransferIn(F transfer_function, S source, Args &&... args)
Transfer data from the given function into the packet.
Definition: packet.h:176
Packet
Internal entity of a packet.
Definition: packet.h:44
NetworkUDPSocketHandler::ReceiveInvalidPacket
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr)
Helper for logging receiving invalid packets.
Definition: udp.cpp:181
PACKET_UDP_SERVER_RESPONSE
@ PACKET_UDP_SERVER_RESPONSE
Reply of the game server with game information.
Definition: udp.h:21
NetworkSocketHandler::HasClientQuit
bool HasClientQuit() const
Whether the current client connected to the socket has quit.
Definition: core.h:68
NetworkAddress
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
Definition: address.h:30
NetworkUDPSocketHandler::HandleUDPPacket
void HandleUDPPacket(Packet *p, NetworkAddress *client_addr)
Handle an incoming packets by sending it to the correct function.
Definition: udp.cpp:153
UDP_MTU
static const uint16 UDP_MTU
Number of bytes we can pack in a single UDP packet.
Definition: config.h:32
NetworkError::AsString
const std::string & AsString() const
Get the string representation of the error message.
Definition: os_abstraction.cpp:79
NetworkUDPSocketHandler::Listen
bool Listen()
Start listening on the given host and port.
Definition: udp.cpp:44
game_info.h
udp.h
Packet::Recv_uint8
uint8 Recv_uint8()
Read a 8 bits integer from the packet.
Definition: packet.cpp:306
Debug
#define Debug(name, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
SetNonBlocking
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
Definition: os_abstraction.cpp:133
NetworkAddress::IsFamily
bool IsFamily(int family)
Checks of this address is of the given family.
Definition: address.cpp:133
NetworkUDPSocketHandler::ReceivePackets
void ReceivePackets()
Receive a packet at UDP level.
Definition: udp.cpp:110
NetworkUDPSocketHandler::Receive_SERVER_RESPONSE
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr)
Response to a query letting the client know we are here.
Definition: udp.cpp:187
PacketUDPType
PacketUDPType
Enum with all types of UDP packets.
Definition: udp.h:19
NetworkUDPSocketHandler::SendPacket
void SendPacket(Packet *p, NetworkAddress *recv, bool all=false, bool broadcast=false)
Send a packet over UDP.
Definition: udp.cpp:74