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 
8 /**
9  * @file packet.h Basic functions to create, fill and read packets.
10  */
11 
12 #ifndef NETWORK_CORE_PACKET_H
13 #define NETWORK_CORE_PACKET_H
14 
15 #include "os_abstraction.h"
16 #include "config.h"
17 #include "core.h"
18 #include "../../string_type.h"
19 #include <functional>
20 #include <limits>
21 
22 typedef uint16 PacketSize; ///< Size of the whole packet.
23 typedef uint8  PacketType; ///< Identifier for the packet
24 
25 /**
26  * Internal entity of a packet. As everything is sent as a packet,
27  * all network communication will need to call the functions that
28  * populate the packet.
29  * Every packet can be at most a limited number bytes set in the
30  * constructor. Overflowing this limit will give an assertion when
31  * sending (i.e. writing) the packet. Reading past the size of the
32  * packet when receiving will return all 0 values and "" in case of
33  * the string.
34  *
35  * --- Points of attention ---
36  *  - all > 1 byte integral values are written in little endian,
37  *    unless specified otherwise.
38  *      Thus, 0x01234567 would be sent as {0x67, 0x45, 0x23, 0x01}.
39  *  - all sent strings are of variable length and terminated by a '\0'.
40  *      Thus, the length of the strings is not sent.
41  *  - years that are leap years in the 'days since X' to 'date' calculations:
42  *     (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
43  */
44 struct Packet {
45 private:
46 	/** The next packet. Used for queueing packets before sending. */
47 	Packet *next;
48 	/** The current read/write position in the packet */
49 	PacketSize pos;
50 	/** The buffer of this packet. */
51 	std::vector<byte> buffer;
52 	/** The limit for the packet size. */
53 	size_t limit;
54 
55 	/** Socket we're associated with. */
56 	NetworkSocketHandler *cs;
57 
58 public:
59 	Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = sizeof(PacketSize));
60 	Packet(PacketType type, size_t limit = COMPAT_MTU);
61 
62 	static void AddToQueue(Packet **queue, Packet *packet);
63 	static Packet *PopFromQueue(Packet **queue);
64 
65 	/* Sending/writing of packets */
66 	void PrepareToSend();
67 
68 	bool   CanWriteToPacket(size_t bytes_to_write);
69 	void   Send_bool  (bool   data);
70 	void   Send_uint8 (uint8  data);
71 	void   Send_uint16(uint16 data);
72 	void   Send_uint32(uint32 data);
73 	void   Send_uint64(uint64 data);
74 	void   Send_string(const std::string_view data);
75 	size_t Send_bytes (const byte *begin, const byte *end);
76 
77 	/* Reading/receiving of packets */
78 	bool HasPacketSizeData() const;
79 	bool ParsePacketSize();
80 	size_t Size() const;
81 	void PrepareToRead();
82 	PacketType GetPacketType() const;
83 
84 	bool   CanReadFromPacket(size_t bytes_to_read, bool close_connection = false);
85 	bool   Recv_bool  ();
86 	uint8  Recv_uint8 ();
87 	uint16 Recv_uint16();
88 	uint32 Recv_uint32();
89 	uint64 Recv_uint64();
90 	std::string Recv_string(size_t length, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK);
91 
92 	size_t RemainingBytesToTransfer() const;
93 
94 	/**
95 	 * Transfer data from the packet to the given function. It starts reading at the
96 	 * position the last transfer stopped.
97 	 * See Packet::TransferIn for more information about transferring data to functions.
98 	 * @param transfer_function The function to pass the buffer as second parameter and the
99 	 *                          amount to write as third parameter. It returns the amount that
100 	 *                          was written or -1 upon errors.
101 	 * @param limit             The maximum amount of bytes to transfer.
102 	 * @param destination       The first parameter of the transfer function.
103 	 * @param args              The fourth and further parameters to the transfer function, if any.
104 	 * @return The return value of the transfer_function.
105 	 */
106 	template <
107 		typename A = size_t, ///< The type for the amount to be passed, so it can be cast to the right type.
108 		typename F,          ///< The type of the function.
109 		typename D,          ///< The type of the destination.
110 		typename ... Args>   ///< The types of the remaining arguments to the function.
TransferOutWithLimitPacket111 	ssize_t TransferOutWithLimit(F transfer_function, size_t limit, D destination, Args&& ... args)
112 	{
113 		size_t amount = std::min(this->RemainingBytesToTransfer(), limit);
114 		if (amount == 0) return 0;
115 
116 		assert(this->pos < this->buffer.size());
117 		assert(this->pos + amount <= this->buffer.size());
118 		/* Making buffer a char means casting a lot in the Recv/Send functions. */
119 		const char *output_buffer = reinterpret_cast<const char*>(this->buffer.data() + this->pos);
120 		ssize_t bytes = transfer_function(destination, output_buffer, static_cast<A>(amount), std::forward<Args>(args)...);
121 		if (bytes > 0) this->pos += bytes;
122 		return bytes;
123 	}
124 
125 	/**
126 	 * Transfer data from the packet to the given function. It starts reading at the
127 	 * position the last transfer stopped.
128 	 * See Packet::TransferIn for more information about transferring data to functions.
129 	 * @param transfer_function The function to pass the buffer as second parameter and the
130 	 *                          amount to write as third parameter. It returns the amount that
131 	 *                          was written or -1 upon errors.
132 	 * @param destination       The first parameter of the transfer function.
133 	 * @param args              The fourth and further parameters to the transfer function, if any.
134 	 * @tparam A    The type for the amount to be passed, so it can be cast to the right type.
135 	 * @tparam F    The type of the transfer_function.
136 	 * @tparam D    The type of the destination.
137 	 * @tparam Args The types of the remaining arguments to the function.
138 	 * @return The return value of the transfer_function.
139 	 */
140 	template <typename A = size_t, typename F, typename D, typename ... Args>
TransferOutPacket141 	ssize_t TransferOut(F transfer_function, D destination, Args&& ... args)
142 	{
143 		return TransferOutWithLimit<A>(transfer_function, std::numeric_limits<size_t>::max(), destination, std::forward<Args>(args)...);
144 	}
145 
146 	/**
147 	 * Transfer data from the given function into the packet. It starts writing at the
148 	 * position the last transfer stopped.
149 	 *
150 	 * Examples of functions that can be used to transfer data into a packet are TCP's
151 	 * recv and UDP's recvfrom functions. They will directly write their data into the
152 	 * packet without an intermediate buffer.
153 	 * Examples of functions that can be used to transfer data from a packet are TCP's
154 	 * send and UDP's sendto functions. They will directly read the data from the packet's
155 	 * buffer without an intermediate buffer.
156 	 * These are functions are special in a sense as even though the packet can send or
157 	 * receive an amount of data, those functions can say they only processed a smaller
158 	 * amount, so special handling is required to keep the position pointers correct.
159 	 * Most of these transfer functions are in the form function(source, buffer, amount, ...),
160 	 * so the template of this function will assume that as the base parameter order.
161 	 *
162 	 * This will attempt to write all the remaining bytes into the packet. It updates the
163 	 * position based on how many bytes were actually written by the called transfer_function.
164 	 * @param transfer_function The function to pass the buffer as second parameter and the
165 	 *                          amount to read as third parameter. It returns the amount that
166 	 *                          was read or -1 upon errors.
167 	 * @param source            The first parameter of the transfer function.
168 	 * @param args              The fourth and further parameters to the transfer function, if any.
169 	 * @tparam A    The type for the amount to be passed, so it can be cast to the right type.
170 	 * @tparam F    The type of the transfer_function.
171 	 * @tparam S    The type of the source.
172 	 * @tparam Args The types of the remaining arguments to the function.
173 	 * @return The return value of the transfer_function.
174 	 */
175 	template <typename A = size_t, typename F, typename S, typename ... Args>
TransferInPacket176 	ssize_t TransferIn(F transfer_function, S source, Args&& ... args)
177 	{
178 		size_t amount = this->RemainingBytesToTransfer();
179 		if (amount == 0) return 0;
180 
181 		assert(this->pos < this->buffer.size());
182 		assert(this->pos + amount <= this->buffer.size());
183 		/* Making buffer a char means casting a lot in the Recv/Send functions. */
184 		char *input_buffer = reinterpret_cast<char*>(this->buffer.data() + this->pos);
185 		ssize_t bytes = transfer_function(source, input_buffer, static_cast<A>(amount), std::forward<Args>(args)...);
186 		if (bytes > 0) this->pos += bytes;
187 		return bytes;
188 	}
189 };
190 
191 #endif /* NETWORK_CORE_PACKET_H */
192