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.cpp Basic functions to create, fill and read packets.
12 #include "../../stdafx.h"
13 #include "../../string_func.h"
17 #include "../../safeguards.h"
20 * Create a packet that is used to read from a network socket
21 * @param cs the socket handler associated with the socket we are reading from
23 Packet::Packet(NetworkSocketHandler
*cs
)
25 assert(cs
!= nullptr);
29 this->pos
= 0; // We start reading from here
31 this->buffer
= MallocT
<byte
>(SEND_MTU
);
35 * Creates a packet to send
36 * @param type of the packet to send
38 Packet::Packet(PacketType type
)
43 /* Skip the size so we can write that in before sending the packet */
45 this->size
= sizeof(PacketSize
);
46 this->buffer
= MallocT
<byte
>(SEND_MTU
);
47 this->buffer
[this->size
++] = type
;
51 * Free the buffer of this packet.
59 * Writes the packet size from the raw packet from packet->size
61 void Packet::PrepareToSend()
63 assert(this->cs
== nullptr && this->next
== nullptr);
65 this->buffer
[0] = GB(this->size
, 0, 8);
66 this->buffer
[1] = GB(this->size
, 8, 8);
68 this->pos
= 0; // We start reading from here
72 * The next couple of functions make sure we can send
73 * uint8, uint16, uint32 and uint64 endian-safe
74 * over the network. The least significant bytes are
77 * So 0x01234567 would be sent as 67 45 23 01.
79 * A bool is sent as a uint8 where zero means false
80 * and non-zero means true.
84 * Package a boolean in the packet.
85 * @param data The data to send.
87 void Packet::Send_bool(bool data
)
89 this->Send_uint8(data
? 1 : 0);
93 * Package a 8 bits integer in the packet.
94 * @param data The data to send.
96 void Packet::Send_uint8(uint8 data
)
98 assert(this->size
< SEND_MTU
- sizeof(data
));
99 this->buffer
[this->size
++] = data
;
103 * Package a 16 bits integer in the packet.
104 * @param data The data to send.
106 void Packet::Send_uint16(uint16 data
)
108 assert(this->size
< SEND_MTU
- sizeof(data
));
109 this->buffer
[this->size
++] = GB(data
, 0, 8);
110 this->buffer
[this->size
++] = GB(data
, 8, 8);
114 * Package a 32 bits integer in the packet.
115 * @param data The data to send.
117 void Packet::Send_uint32(uint32 data
)
119 assert(this->size
< SEND_MTU
- sizeof(data
));
120 this->buffer
[this->size
++] = GB(data
, 0, 8);
121 this->buffer
[this->size
++] = GB(data
, 8, 8);
122 this->buffer
[this->size
++] = GB(data
, 16, 8);
123 this->buffer
[this->size
++] = GB(data
, 24, 8);
127 * Package a 64 bits integer in the packet.
128 * @param data The data to send.
130 void Packet::Send_uint64(uint64 data
)
132 assert(this->size
< SEND_MTU
- sizeof(data
));
133 this->buffer
[this->size
++] = GB(data
, 0, 8);
134 this->buffer
[this->size
++] = GB(data
, 8, 8);
135 this->buffer
[this->size
++] = GB(data
, 16, 8);
136 this->buffer
[this->size
++] = GB(data
, 24, 8);
137 this->buffer
[this->size
++] = GB(data
, 32, 8);
138 this->buffer
[this->size
++] = GB(data
, 40, 8);
139 this->buffer
[this->size
++] = GB(data
, 48, 8);
140 this->buffer
[this->size
++] = GB(data
, 56, 8);
144 * Sends a string over the network. It sends out
145 * the string + '\0'. No size-byte or something.
146 * @param data The string to send
148 void Packet::Send_string(const char *data
)
150 assert(data
!= nullptr);
151 /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */
152 assert(this->size
+ strlen(data
) + 1 <= SEND_MTU
);
153 while ((this->buffer
[this->size
++] = *data
++) != '\0') {}
159 * Again, the next couple of functions are endian-safe
160 * see the comment before Send_bool for more info.
165 * Is it safe to read from the packet, i.e. didn't we run over the buffer ?
166 * @param bytes_to_read The amount of bytes we want to try to read.
167 * @return True if that is safe, otherwise false.
169 bool Packet::CanReadFromPacket(uint bytes_to_read
)
171 /* Don't allow reading from a quit client/client who send bad data */
172 if (this->cs
->HasClientQuit()) return false;
174 /* Check if variable is within packet-size */
175 if (this->pos
+ bytes_to_read
> this->size
) {
176 this->cs
->NetworkSocketHandler::CloseConnection();
184 * Reads the packet size from the raw packet and stores it in the packet->size
186 void Packet::ReadRawPacketSize()
188 assert(this->cs
!= nullptr && this->next
== nullptr);
189 this->size
= (PacketSize
)this->buffer
[0];
190 this->size
+= (PacketSize
)this->buffer
[1] << 8;
194 * Prepares the packet so it can be read
196 void Packet::PrepareToRead()
198 this->ReadRawPacketSize();
200 /* Put the position on the right place */
201 this->pos
= sizeof(PacketSize
);
205 * Read a boolean from the packet.
206 * @return The read data.
208 bool Packet::Recv_bool()
210 return this->Recv_uint8() != 0;
214 * Read a 8 bits integer from the packet.
215 * @return The read data.
217 uint8
Packet::Recv_uint8()
221 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
223 n
= this->buffer
[this->pos
++];
228 * Read a 16 bits integer from the packet.
229 * @return The read data.
231 uint16
Packet::Recv_uint16()
235 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
237 n
= (uint16
)this->buffer
[this->pos
++];
238 n
+= (uint16
)this->buffer
[this->pos
++] << 8;
243 * Read a 32 bits integer from the packet.
244 * @return The read data.
246 uint32
Packet::Recv_uint32()
250 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
252 n
= (uint32
)this->buffer
[this->pos
++];
253 n
+= (uint32
)this->buffer
[this->pos
++] << 8;
254 n
+= (uint32
)this->buffer
[this->pos
++] << 16;
255 n
+= (uint32
)this->buffer
[this->pos
++] << 24;
260 * Read a 64 bits integer from the packet.
261 * @return The read data.
263 uint64
Packet::Recv_uint64()
267 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
269 n
= (uint64
)this->buffer
[this->pos
++];
270 n
+= (uint64
)this->buffer
[this->pos
++] << 8;
271 n
+= (uint64
)this->buffer
[this->pos
++] << 16;
272 n
+= (uint64
)this->buffer
[this->pos
++] << 24;
273 n
+= (uint64
)this->buffer
[this->pos
++] << 32;
274 n
+= (uint64
)this->buffer
[this->pos
++] << 40;
275 n
+= (uint64
)this->buffer
[this->pos
++] << 48;
276 n
+= (uint64
)this->buffer
[this->pos
++] << 56;
281 * Reads a string till it finds a '\0' in the stream.
282 * @param buffer The buffer to put the data into.
283 * @param size The size of the buffer.
284 * @param settings The string validation settings.
286 void Packet::Recv_string(char *buffer
, size_t size
, StringValidationSettings settings
)
290 const char *last
= buffer
+ size
- 1;
292 /* Don't allow reading from a closed socket */
293 if (cs
->HasClientQuit()) return;
296 while (--size
> 0 && pos
< this->size
&& (*buffer
++ = this->buffer
[pos
++]) != '\0') {}
298 if (size
== 0 || pos
== this->size
) {
300 /* If size was sooner to zero then the string in the stream
301 * skip till the \0, so than packet can be read out correctly for the rest */
302 while (pos
< this->size
&& this->buffer
[pos
] != '\0') pos
++;
307 str_validate(bufp
, last
, settings
);