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