4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
11 * @file packet.cpp Basic functions to create, fill and read packets.
16 #include "../../stdafx.h"
17 #include "../../string_func.h"
18 #include "../../command_type.h"
22 #include "../../safeguards.h"
25 * Create a packet that is used to read from a network socket
26 * @param cs the socket handler associated with the socket we are reading from
28 Packet::Packet(NetworkSocketHandler
*cs
)
34 this->pos
= 0; // We start reading from here
36 this->buffer
= MallocT
<byte
>(SHRT_MAX
);
40 * Creates a packet to send
41 * @param type of the packet to send
43 Packet::Packet(PacketType type
)
48 /* Skip the size so we can write that in before sending the packet */
50 this->size
= sizeof(PacketSize
);
51 this->buffer
= MallocT
<byte
>(SHRT_MAX
);
52 this->buffer
[this->size
++] = type
;
56 * Free the buffer of this packet.
64 * Writes the packet size from the raw packet from packet->size
66 void Packet::PrepareToSend()
68 assert(this->cs
== NULL
&& this->next
== NULL
);
70 this->buffer
[0] = GB(this->size
, 0, 8);
71 this->buffer
[1] = GB(this->size
, 8, 8);
73 this->pos
= 0; // We start reading from here
77 * The next couple of functions make sure we can send
78 * uint8, uint16, uint32 and uint64 endian-safe
79 * over the network. The least significant bytes are
82 * So 0x01234567 would be sent as 67 45 23 01.
84 * A bool is sent as a uint8 where zero means false
85 * and non-zero means true.
89 * Package a boolean in the packet.
90 * @param data The data to send.
92 void Packet::Send_bool(bool data
)
94 this->Send_uint8(data
? 1 : 0);
98 * Package a 8 bits integer in the packet.
99 * @param data The data to send.
101 void Packet::Send_uint8(uint8 data
)
103 assert(this->size
< SHRT_MAX
- sizeof(data
));
104 this->buffer
[this->size
++] = data
;
108 * Package a 16 bits integer in the packet.
109 * @param data The data to send.
111 void Packet::Send_uint16(uint16 data
)
113 assert(this->size
< SHRT_MAX
- sizeof(data
));
114 this->buffer
[this->size
++] = GB(data
, 0, 8);
115 this->buffer
[this->size
++] = GB(data
, 8, 8);
119 * Package a 32 bits integer in the packet.
120 * @param data The data to send.
122 void Packet::Send_uint32(uint32 data
)
124 assert(this->size
< SHRT_MAX
- sizeof(data
));
125 this->buffer
[this->size
++] = GB(data
, 0, 8);
126 this->buffer
[this->size
++] = GB(data
, 8, 8);
127 this->buffer
[this->size
++] = GB(data
, 16, 8);
128 this->buffer
[this->size
++] = GB(data
, 24, 8);
132 * Package a 64 bits integer in the packet.
133 * @param data The data to send.
135 void Packet::Send_uint64(uint64 data
)
137 assert(this->size
< SHRT_MAX
- sizeof(data
));
138 this->buffer
[this->size
++] = GB(data
, 0, 8);
139 this->buffer
[this->size
++] = GB(data
, 8, 8);
140 this->buffer
[this->size
++] = GB(data
, 16, 8);
141 this->buffer
[this->size
++] = GB(data
, 24, 8);
142 this->buffer
[this->size
++] = GB(data
, 32, 8);
143 this->buffer
[this->size
++] = GB(data
, 40, 8);
144 this->buffer
[this->size
++] = GB(data
, 48, 8);
145 this->buffer
[this->size
++] = GB(data
, 56, 8);
149 * Sends a string over the network. It sends out
150 * the string + '\0'. No size-byte or something.
151 * @param data The string to send
153 void Packet::Send_string(const char *data
)
155 assert(data
!= NULL
);
156 /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */
157 assert(this->size
+ strlen(data
) + 1 <= SHRT_MAX
);
158 while ((this->buffer
[this->size
++] = *data
++) != '\0') {}
162 * Sends a binary data over the network.
163 * @param data The data to send
165 void Packet::Send_binary(const char *data
, const size_t size
)
167 assert(data
!= NULL
);
168 assert(size
< MAX_CMD_TEXT_LENGTH
);
169 memcpy(&this->buffer
[this->size
], data
, size
);
170 this->size
+= (PacketSize
) size
;
176 * Again, the next couple of functions are endian-safe
177 * see the comment before Send_bool for more info.
182 * Is it safe to read from the packet, i.e. didn't we run over the buffer ?
183 * @param bytes_to_read The amount of bytes we want to try to read.
184 * @return True if that is safe, otherwise false.
186 bool Packet::CanReadFromPacket(uint bytes_to_read
)
188 /* Don't allow reading from a quit client/client who send bad data */
189 if (this->cs
->HasClientQuit()) return false;
191 /* Check if variable is within packet-size */
192 if (this->pos
+ bytes_to_read
> this->size
) {
193 this->cs
->NetworkSocketHandler::CloseConnection();
201 * Reads the packet size from the raw packet and stores it in the packet->size
203 void Packet::ReadRawPacketSize()
205 assert(this->cs
!= NULL
&& this->next
== NULL
);
206 this->size
= (PacketSize
)this->buffer
[0];
207 this->size
+= (PacketSize
)this->buffer
[1] << 8;
211 * Prepares the packet so it can be read
213 void Packet::PrepareToRead()
215 this->ReadRawPacketSize();
217 /* Put the position on the right place */
218 this->pos
= sizeof(PacketSize
);
222 * Read a boolean from the packet.
223 * @return The read data.
225 bool Packet::Recv_bool()
227 return this->Recv_uint8() != 0;
231 * Read a 8 bits integer from the packet.
232 * @return The read data.
234 uint8
Packet::Recv_uint8()
238 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
240 n
= this->buffer
[this->pos
++];
245 * Read a 16 bits integer from the packet.
246 * @return The read data.
248 uint16
Packet::Recv_uint16()
252 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
254 n
= (uint16
)this->buffer
[this->pos
++];
255 n
+= (uint16
)this->buffer
[this->pos
++] << 8;
260 * Read a 32 bits integer from the packet.
261 * @return The read data.
263 uint32
Packet::Recv_uint32()
267 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
269 n
= (uint32
)this->buffer
[this->pos
++];
270 n
+= (uint32
)this->buffer
[this->pos
++] << 8;
271 n
+= (uint32
)this->buffer
[this->pos
++] << 16;
272 n
+= (uint32
)this->buffer
[this->pos
++] << 24;
277 * Read a 64 bits integer from the packet.
278 * @return The read data.
280 uint64
Packet::Recv_uint64()
284 if (!this->CanReadFromPacket(sizeof(n
))) return 0;
286 n
= (uint64
)this->buffer
[this->pos
++];
287 n
+= (uint64
)this->buffer
[this->pos
++] << 8;
288 n
+= (uint64
)this->buffer
[this->pos
++] << 16;
289 n
+= (uint64
)this->buffer
[this->pos
++] << 24;
290 n
+= (uint64
)this->buffer
[this->pos
++] << 32;
291 n
+= (uint64
)this->buffer
[this->pos
++] << 40;
292 n
+= (uint64
)this->buffer
[this->pos
++] << 48;
293 n
+= (uint64
)this->buffer
[this->pos
++] << 56;
298 * Reads a string till it finds a '\0' in the stream.
299 * @param buffer The buffer to put the data into.
300 * @param size The size of the buffer.
301 * @param settings The string validation settings.
303 void Packet::Recv_string(char *buffer
, size_t size
, StringValidationSettings settings
)
307 const char *last
= buffer
+ size
- 1;
309 /* Don't allow reading from a closed socket */
310 if (cs
->HasClientQuit()) return;
313 while (--size
> 0 && pos
< this->size
&& (*buffer
++ = this->buffer
[pos
++]) != '\0') {}
315 if (size
== 0 || pos
== this->size
) {
317 /* If size was sooner to zero then the string in the stream
318 * skip till the \0, so than packet can be read out correctly for the rest */
319 while (pos
< this->size
&& this->buffer
[pos
] != '\0') pos
++;
324 str_validate(bufp
, last
, settings
);
329 * @param buffer The buffer to put the data into.
330 * @param size The size of the buffer.
332 void Packet::Recv_binary(char *buffer
, size_t size
)
334 /* Don't allow reading from a closed socket */
335 if (cs
->HasClientQuit()) return;
337 memcpy(buffer
, &this->buffer
[this->pos
], size
);
338 this->pos
+= (PacketSize
) size
;
341 #endif /* ENABLE_NETWORK */