OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

packet.cpp
Go to the documentation of this file.
1 /* $Id: packet.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2
3 /*
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/>.
8 */
9
14 #ifdef ENABLE_NETWORK
15
16 #include "../../stdafx.h"
17 #include "../../string_func.h"
18
19 #include "packet.h"
20
21 #include "../../safeguards.h"
22
27 Packet::Packet(NetworkSocketHandler *cs)
28 {
29 assert(cs != NULL);
30
31 this->cs = cs;
32 this->next = NULL;
33 this->pos = 0; // We start reading from here
34 this->size = 0;
35 this->buffer = MallocT<byte>(SEND_MTU);
36 }
37
42 Packet::Packet(PacketType type)
43 {
44 this->cs = NULL;
45 this->next = NULL;
46
47 /* Skip the size so we can write that in before sending the packet */
48 this->pos = 0;
49 this->size = sizeof(PacketSize);
50 this->buffer = MallocT<byte>(SEND_MTU);
51 this->buffer[this->size++] = type;
52 }
53
57 Packet::~Packet()
58 {
59 free(this->buffer);
60 }
61
65 void Packet::PrepareToSend()
66 {
67 assert(this->cs == NULL && this->next == NULL);
68
69 this->buffer[0] = GB(this->size, 0, 8);
70 this->buffer[1] = GB(this->size, 8, 8);
71
72 this->pos = 0; // We start reading from here
73 }
74
75 /*
76 * The next couple of functions make sure we can send
77 * uint8, uint16, uint32 and uint64 endian-safe
78 * over the network. The least significant bytes are
79 * sent first.
80 *
81 * So 0x01234567 would be sent as 67 45 23 01.
82 *
83 * A bool is sent as a uint8 where zero means false
84 * and non-zero means true.
85 */
86
91 void Packet::Send_bool(bool data)
92 {
93 this->Send_uint8(data ? 1 : 0);
94 }
95
100 void Packet::Send_uint8(uint8 data)
101 {
102 assert(this->size < SEND_MTU - sizeof(data));
103 this->buffer[this->size++] = data;
104 }
105
110 void Packet::Send_uint16(uint16 data)
111 {
112 assert(this->size < SEND_MTU - sizeof(data));
113 this->buffer[this->size++] = GB(data, 0, 8);
114 this->buffer[this->size++] = GB(data, 8, 8);
115 }
116
121 void Packet::Send_uint32(uint32 data)
122 {
123 assert(this->size < SEND_MTU - sizeof(data));
124 this->buffer[this->size++] = GB(data, 0, 8);
125 this->buffer[this->size++] = GB(data, 8, 8);
126 this->buffer[this->size++] = GB(data, 16, 8);
127 this->buffer[this->size++] = GB(data, 24, 8);
128 }
129
134 void Packet::Send_uint64(uint64 data)
135 {
136 assert(this->size < SEND_MTU - sizeof(data));
137 this->buffer[this->size++] = GB(data, 0, 8);
138 this->buffer[this->size++] = GB(data, 8, 8);
139 this->buffer[this->size++] = GB(data, 16, 8);
140 this->buffer[this->size++] = GB(data, 24, 8);
141 this->buffer[this->size++] = GB(data, 32, 8);
142 this->buffer[this->size++] = GB(data, 40, 8);
143 this->buffer[this->size++] = GB(data, 48, 8);
144 this->buffer[this->size++] = GB(data, 56, 8);
145 }
146
152 void Packet::Send_string(const char *data)
153 {
154 assert(data != NULL);
155 /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */
156 assert(this->size + strlen(data) + 1 <= SEND_MTU);
157 while ((this->buffer[this->size++] = *data++) != '\0') {}
158 }
159
160
161 /*
162 * Receiving commands
163 * Again, the next couple of functions are endian-safe
164 * see the comment before Send_bool for more info.
165 */
166
167
173 bool Packet::CanReadFromPacket(uint bytes_to_read)
174 {
175 /* Don't allow reading from a quit client/client who send bad data */
176 if (this->cs->HasClientQuit()) return false;
177
178 /* Check if variable is within packet-size */
179 if (this->pos + bytes_to_read > this->size) {
180 this->cs->NetworkSocketHandler::CloseConnection();
181 return false;
182 }
183
184 return true;
185 }
186
190 void Packet::ReadRawPacketSize()
191 {
192 assert(this->cs != NULL && this->next == NULL);
193 this->size = (PacketSize)this->buffer[0];
194 this->size += (PacketSize)this->buffer[1] << 8;
195 }
196
200 void Packet::PrepareToRead()
201 {
202 this->ReadRawPacketSize();
203
204 /* Put the position on the right place */
205 this->pos = sizeof(PacketSize);
206 }
207
212 bool Packet::Recv_bool()
213 {
214 return this->Recv_uint8() != 0;
215 }
216
221 uint8 Packet::Recv_uint8()
222 {
223 uint8 n;
224
225 if (!this->CanReadFromPacket(sizeof(n))) return 0;
226
227 n = this->buffer[this->pos++];
228 return n;
229 }
230
235 uint16 Packet::Recv_uint16()
236 {
237 uint16 n;
238
239 if (!this->CanReadFromPacket(sizeof(n))) return 0;
240
241 n = (uint16)this->buffer[this->pos++];
242 n += (uint16)this->buffer[this->pos++] << 8;
243 return n;
244 }
245
250 uint32 Packet::Recv_uint32()
251 {
252 uint32 n;
253
254 if (!this->CanReadFromPacket(sizeof(n))) return 0;
255
256 n = (uint32)this->buffer[this->pos++];
257 n += (uint32)this->buffer[this->pos++] << 8;
258 n += (uint32)this->buffer[this->pos++] << 16;
259 n += (uint32)this->buffer[this->pos++] << 24;
260 return n;
261 }
262
267 uint64 Packet::Recv_uint64()
268 {
269 uint64 n;
270
271 if (!this->CanReadFromPacket(sizeof(n))) return 0;
272
273 n = (uint64)this->buffer[this->pos++];
274 n += (uint64)this->buffer[this->pos++] << 8;
275 n += (uint64)this->buffer[this->pos++] << 16;
276 n += (uint64)this->buffer[this->pos++] << 24;
277 n += (uint64)this->buffer[this->pos++] << 32;
278 n += (uint64)this->buffer[this->pos++] << 40;
279 n += (uint64)this->buffer[this->pos++] << 48;
280 n += (uint64)this->buffer[this->pos++] << 56;
281 return n;
282 }
283
290 void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings settings)
291 {
292 PacketSize pos;
293 char *bufp = buffer;
294 const char *last = buffer + size - 1;
295
296 /* Don't allow reading from a closed socket */
297 if (cs->HasClientQuit()) return;
298
299 pos = this->pos;
300 while (--size > 0 && pos < this->size && (*buffer++ = this->buffer[pos++]) != '\0') {}
301
302 if (size == 0 || pos == this->size) {
303 *buffer = '\0';
304 /* If size was sooner to zero then the string in the stream
305 * skip till the \0, so than packet can be read out correctly for the rest */
306 while (pos < this->size && this->buffer[pos] != '\0') pos++;
307 pos++;
308 }
309 this->pos = pos;
310
311 str_validate(bufp, last, settings);
312 }
313
314 #endif /* ENABLE_NETWORK */