1 /*
2 * Created by Hassan "Karajorma" Kazmi for the FreeSpace2 Source Code Project.
3 * You may not sell or otherwise commercially exploit the source or things you
4 * create based on the source.
5 */
6
7 #include "network/multi_sexp.h"
8 #include "parse/sexp.h"
9 #include "network/multi.h"
10 #include "network/multiutil.h"
11
12 static const std::uint8_t CALLBACK_TERMINATOR = 255;
13 static const std::int16_t TEMP_DATA_SIZE = -1;
14
15 sexp_network_packet Current_sexp_network_packet;
16
17 /****************************
18 CLIENT SIDE PACKET FUNCTIONS
19 ***************************/
20
21 /**
22 * Called when the client recieves a SEXP packet from the server. Removes the data from the packet that underlying code uses and puts
23 * into a new array that will work with the rest of the client-side code.
24 */
sexp_packet_received(ubyte * received_packet,int num_ubytes)25 void sexp_packet_received(ubyte *received_packet, int num_ubytes)
26 {
27 Current_sexp_network_packet.set_data(received_packet, num_ubytes);
28
29 // start working through the packet
30 multi_sexp_eval();
31 }
32
ensure_space_remains(size_t data_size)33 void sexp_network_packet::ensure_space_remains(size_t data_size)
34 {
35 if (!MULTIPLAYER_MASTER) {
36 return;
37 }
38
39 int packet_end = 0;
40 int sub_packet_size = 0;
41 int i, j;
42
43 // If the index of the data buffer isn't high enough yet, bail
44 if (packet_size + static_cast<int>(data_size) < SEXP_MAX_PACKET_SIZE) {
45 return;
46 }
47
48 //iterate back through the types array until we find a TERMINATOR and store the corresponding data index
49 for (i = packet_size - 1; i > 0; i--) {
50 if (type[i] == packet_data_type::DATA_TERMINATES) {
51 packet_end = i;
52 break;
53 }
54 }
55
56 // we want the number of bytes not the index of the last one
57 sub_packet_size = packet_end + 1;
58
59 // At very least must include OP, COUNT, TERMINATOR
60 if (packet_end < MIN_SEXP_PACKET_SIZE && !packet_flagged_invalid) {
61 Warning(LOCATION, "Sexp %s has attempted to write too much data to a single packet. It is advised that you split this SEXP up into smaller ones", Operators[Current_sexp_operator.back()].text.c_str());
62 packet_flagged_invalid = true;
63 return;
64 }
65
66 send_sexp_packet(data, sub_packet_size);
67
68 j = 0;
69 //Slide down any entries after the stored index to the start of the array.
70 for (i = sub_packet_size; i < packet_size; i++) {
71 data[j] = data[i];
72 type[j] = type[i];
73 j++;
74 }
75
76 packet_size = j;
77
78 // flush the remaining type buffer
79 for (i = j; i < SEXP_MAX_PACKET_SIZE; i++) {
80 type[i] = packet_data_type::NOT_DATA;
81 }
82
83 // if we have an existing argument count we need to update where to put it too
84 if (current_argument_count) {
85 argument_count_index = argument_count_index - sub_packet_size;
86 }
87
88 Assert(argument_count_index >= 0);
89 }
90
reduce_counts(int amount)91 void sexp_network_packet::reduce_counts(int amount)
92 {
93 sexp_bytes_left -= amount;
94 current_argument_count -= amount;
95
96 if (sexp_bytes_left < 0 || current_argument_count < 0) {
97 Warning(LOCATION, "multi_get_x function call has read an invalid amount of data. Trace out and fix this!");
98 }
99 }
100
argument_count_is_valid()101 bool sexp_network_packet::argument_count_is_valid()
102 {
103 if (current_argument_count != 0) {
104 // we have a problem here, either the argument count is wrong or the last SEXP didn't remove all its data from the packet
105 ubyte possible_terminator;
106 bool terminator_found = false;
107 for (int i = 0; i < current_argument_count; i++) {
108 GET_DATA(possible_terminator);
109 sexp_bytes_left--;
110
111 if (possible_terminator == CALLBACK_TERMINATOR) {
112 Warning(LOCATION, "%s has returned to multi_sexp_eval() claiming %d arguments left. %d actually found. Trace out and fix this!", Operators[op_num].text.c_str(), current_argument_count, i);
113 terminator_found = true;
114 break;
115 }
116 }
117
118 // if we still haven't found the terminator it probably means the last SEXP didn't remove all its data from the packet
119 if (!terminator_found) {
120 GET_DATA(possible_terminator);
121 sexp_bytes_left--;
122
123 if (possible_terminator != CALLBACK_TERMINATOR) {
124 // discard remainder of packet if we still haven't found the terminator as it is hopelessly corrupt
125 Warning(LOCATION, "%s has returned to multi_sexp_eval() without finding the terminator. Discarding packet! Trace out and fix this!", Operators[op_num].text.c_str());
126 sexp_bytes_left = 0;
127 return false;
128 }
129 else {
130 // the previous SEXP hasn't removed all it's data from the packet correctly but it appears we've managed to fix it
131 Warning(LOCATION, "%s has returned to multi_sexp_eval() without removing all the data the server wrote during its callback. Trace out and fix this!", Operators[op_num].text.c_str());
132 op_num = -1;
133 }
134 }
135 }
136
137 return true;
138 }
139
set_data(ubyte * received_packet,int num_ubytes)140 void sexp_network_packet::set_data(ubyte * received_packet, int num_ubytes)
141 {
142 offset = 0;
143 op_num = -1;
144
145 const auto r_data_size = std::min(SEXP_MAX_PACKET_SIZE, num_ubytes);
146 memcpy(data, received_packet, static_cast<size_t>(r_data_size));
147
148 sexp_bytes_left = r_data_size;
149 }
150
initialize()151 void sexp_network_packet::initialize()
152 {
153 if (!MULTIPLAYER_MASTER) {
154 return;
155 }
156
157 for (int i = 0; i < SEXP_MAX_PACKET_SIZE; ++i) {
158 data[i] = 0;
159 type[i] = packet_data_type::NOT_DATA;
160 }
161
162 packet_size = 0;
163 argument_count_index = -1;
164 current_argument_count = 0;
165 }
166
start_callback()167 void sexp_network_packet::start_callback()
168 {
169 if (!MULTIPLAYER_MASTER) {
170 return;
171 }
172
173 // Ensure that there is enough space in the packet. At present the function writes the Operator number and the argument count into the packet. Both are ints
174 // so we must ensure we have space left to write two ints. If this function is changed to write other data, this line MUST be updated too!
175 ensure_space_remains(sizeof(int) * 2);
176
177 callback_started = true;
178
179 //Write OP into the Type buffer.
180 type[packet_size] = packet_data_type::SEXP_OPERATOR;
181 //Write the SEXP_Operator number into the data buffer.
182 Assert(!Current_sexp_operator.empty());
183 ADD_INT(Current_sexp_operator.back());
184
185 //Store the next data index as we'll need it later to write the COUNT.
186 argument_count_index = packet_size;
187 // store an invalid count, we'll come back and store the correct value once we know what it is.
188 type[packet_size] = packet_data_type::ARGUMENT_COUNT;
189 ADD_SHORT(TEMP_DATA_SIZE);
190 }
191
end_callback()192 void sexp_network_packet::end_callback()
193 {
194 if (!MULTIPLAYER_MASTER) {
195 return;
196 }
197
198 // ensure that there is enough space in the packet. If this function is ever updated to write anything other than the terminator, this MUST be taken into account here!
199 ensure_space_remains(sizeof(ubyte));
200
201 callback_started = false;
202
203 // something is wrong with the packet, blast it clean and start again
204 if (packet_flagged_invalid) {
205 initialize();
206 packet_flagged_invalid = false;
207 return;
208 }
209
210 //write TERMINATOR into the Type and data buffers
211 type[packet_size] = packet_data_type::DATA_TERMINATES;
212 ADD_DATA(CALLBACK_TERMINATOR);
213
214 //Write the COUNT into the data buffer at the index we saved earlier.
215 int temp_packet_size = packet_size;
216 packet_size = argument_count_index;
217 ADD_SHORT(static_cast<short>(current_argument_count));
218 packet_size = temp_packet_size;
219
220 current_argument_count = 0;
221 }
222
do_callback()223 void sexp_network_packet::do_callback()
224 {
225 start_callback();
226 end_callback();
227 }
228
sexp_flush_packet()229 void sexp_network_packet::sexp_flush_packet()
230 {
231 if (!MULTIPLAYER_MASTER) {
232 return;
233 }
234
235 // possible to get here when there is nothing in the packet to send
236 if (packet_size == 0) {
237 return;
238 }
239 Assert(type[packet_size - 1] == packet_data_type::DATA_TERMINATES);
240 Assert(!packet_flagged_invalid);
241
242 send_sexp_packet(data, packet_size);
243
244 initialize();
245 }
246
cannot_send_data()247 bool sexp_network_packet::cannot_send_data()
248 {
249 if (!MULTIPLAYER_MASTER || packet_flagged_invalid) {
250 return true;
251 }
252
253 if (!callback_started) {
254 Warning(LOCATION, "Attempt to send data in multi_sexp.cpp without first starting a callback");
255 return true;
256 }
257
258 return false;
259 }
260
send_int(int value)261 void sexp_network_packet::send_int(int value)
262 {
263 if (cannot_send_data()) {
264 return;
265 }
266
267 ensure_space_remains(sizeof(value));
268
269 //Write INT into the Type buffer.
270 type[packet_size] = packet_data_type::INT;
271 //Write the int into the data buffer
272 ADD_INT(value);
273 //Increment the COUNT by 4 (i.e the size of an int).
274 current_argument_count += sizeof(int);
275 }
276
send_wing(wing * wingp)277 void sexp_network_packet::send_wing(wing * wingp)
278 {
279 if (cannot_send_data()) {
280 return;
281 }
282
283 ensure_space_remains(sizeof(ushort));
284
285 //write into the Type buffer.
286 type[packet_size] = packet_data_type::WING;
287 //write the into the data buffer
288 ADD_USHORT(wingp->net_signature);
289 current_argument_count += sizeof(ushort);
290 }
291
send_ship(ship * shipp)292 void sexp_network_packet::send_ship(ship * shipp)
293 {
294 if (cannot_send_data()) {
295 return;
296 }
297
298 ensure_space_remains(sizeof(ushort));
299
300 //write into the Type buffer.
301 type[packet_size] = packet_data_type::SHIP;
302 //write the into the data buffer
303 ADD_USHORT(Objects[shipp->objnum].net_signature);
304 current_argument_count += sizeof(ushort);
305 }
306
send_object(object * objp)307 void sexp_network_packet::send_object(object * objp)
308 {
309 if (cannot_send_data()) {
310 return;
311 }
312
313 ensure_space_remains(sizeof(ushort));
314
315 //write into the Type buffer.
316 type[packet_size] = packet_data_type::OBJECT;
317 //write the into the data buffer
318 ADD_USHORT(objp->net_signature);
319 current_argument_count += sizeof(ushort);
320 }
321
send_parse_object(p_object * pobjp)322 void sexp_network_packet::send_parse_object(p_object * pobjp)
323 {
324 if (cannot_send_data()) {
325 return;
326 }
327
328 ensure_space_remains(sizeof(ushort));
329
330 //write into the Type buffer.
331 type[packet_size] = packet_data_type::PARSE_OBJECT;
332 //write the into the data buffer
333 ADD_USHORT(pobjp->net_signature);
334 current_argument_count += sizeof(ushort);
335 }
336
send_string(char * string)337 void sexp_network_packet::send_string(char * string)
338 {
339 if (cannot_send_data()) {
340 return;
341 }
342
343 ensure_space_remains(strlen(string) + sizeof(uint16_t));
344
345 int start_size = packet_size;
346 //write into the Type buffer.
347 type[packet_size] = packet_data_type::STRING;
348 //write the into the data buffer
349 ADD_STRING_16(string);
350 current_argument_count += packet_size - start_size;
351 }
352
send_string(const SCP_string & string)353 void sexp_network_packet::send_string(const SCP_string & string)
354 {
355 if (cannot_send_data()) {
356 return;
357 }
358
359 ensure_space_remains(string.length() + sizeof(uint16_t));
360
361 int start_size = packet_size;
362 //write into the Type buffer.
363 type[packet_size] = packet_data_type::STRING;
364 //write the into the data buffer
365 ADD_STRING_16(string.c_str());
366 current_argument_count += packet_size - start_size;
367 }
368
send_bool(bool value)369 void sexp_network_packet::send_bool(bool value)
370 {
371 if (cannot_send_data()) {
372 return;
373 }
374
375 ensure_space_remains(sizeof(value));
376
377 //write into the Type buffer.
378 type[packet_size] = packet_data_type::BOOLEAN;
379 //Write the value into the data buffer
380 ADD_DATA(value);
381 //Increment the COUNT
382 current_argument_count += sizeof(value);
383 }
384
send_float(float value)385 void sexp_network_packet::send_float(float value)
386 {
387 if (cannot_send_data()) {
388 return;
389 }
390
391 ensure_space_remains(sizeof(value));
392
393 //write into the Type buffer.
394 type[packet_size] = packet_data_type::FLOAT;
395 //Write the value into the data buffer
396 ADD_FLOAT(value);
397 //Increment the COUNT
398 current_argument_count += sizeof(float);
399 }
400
send_vec3d(vec3d * value)401 void sexp_network_packet::send_vec3d(vec3d *value)
402 {
403 for (int i = 0; i < 3; ++i) // NOLINT
404 send_float(value->a1d[i]);
405 }
406
send_matrix(matrix * value)407 void sexp_network_packet::send_matrix(matrix *value)
408 {
409 for (int i = 0; i < 9; ++i) // NOLINT
410 send_float(value->a1d[i]);
411 }
412
send_short(short value)413 void sexp_network_packet::send_short(short value)
414 {
415 if (cannot_send_data()) {
416 return;
417 }
418
419 ensure_space_remains(sizeof(value));
420
421 //Write the type into the Type buffer.
422 type[packet_size] = packet_data_type::SHORT;
423 //Write the value into the data buffer
424 ADD_SHORT(value);
425 //Increment the COUNT
426 current_argument_count += sizeof(short);
427 }
428
send_ushort(ushort value)429 void sexp_network_packet::send_ushort(ushort value)
430 {
431 if (cannot_send_data()) {
432 return;
433 }
434
435 ensure_space_remains(sizeof(value));
436
437 //Write the type into the Type buffer.
438 type[packet_size] = packet_data_type::USHORT;
439 //Write the value into the data buffer
440 ADD_USHORT(value);
441 //Increment the COUNT
442 current_argument_count += sizeof(ushort);
443 }
444
get_int(int & value)445 bool sexp_network_packet::get_int(int & value)
446 {
447 if (!sexp_bytes_left || !current_argument_count) {
448 return false;
449 }
450
451 GET_INT(value);
452 reduce_counts(sizeof(int));
453
454 return true;
455 }
456
get_ship(int & value)457 bool sexp_network_packet::get_ship(int & value)
458 {
459 ushort netsig;
460 object *objp;
461
462 if (!sexp_bytes_left || !current_argument_count) {
463 return false;
464 }
465
466 // get the net signature of the ship
467 GET_USHORT(netsig);
468 reduce_counts(sizeof(ushort));
469
470 // lookup the object
471 objp = multi_get_network_object(netsig);
472 if ((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >= 0)) {
473 value = objp->instance;
474 return true;
475 }
476
477 Warning(LOCATION, "Current_sexp_network_packet.get_ship called for net signature %d even though it is not a ship", netsig);
478 return false;
479 }
480
get_ship(ship * & shipp)481 bool sexp_network_packet::get_ship(ship *& shipp)
482 {
483 int shipnum;
484
485 if (get_ship(shipnum)) {
486 shipp = &Ships[shipnum];
487 return true;
488 }
489
490 return false;
491 }
492
get_wing(wing * & wingp)493 bool sexp_network_packet::get_wing(wing *& wingp)
494 {
495 int i;
496 ushort netsig;
497
498 if (!sexp_bytes_left || !current_argument_count) {
499 return false;
500 }
501
502 // get the net signature of the wing
503 GET_USHORT(netsig);
504 reduce_counts(sizeof(ushort));
505
506 // lookup the wing
507 for (i = 0; i < Num_wings; i++) {
508 if (Wings[i].net_signature == netsig) {
509 wingp = &Wings[i];
510 return true;
511 }
512 }
513
514 Warning(LOCATION, "Current_sexp_network_packet.get_wing called for net signature %d even though it is not a ship", netsig);
515 return false;
516 }
517
get_object(object * & value)518 bool sexp_network_packet::get_object(object *& value)
519 {
520 ushort netsig;
521
522 if (!sexp_bytes_left || !current_argument_count) {
523 return false;
524 }
525
526 // get the net signature of the ship
527 GET_USHORT(netsig);
528 reduce_counts(sizeof(ushort));
529
530 // lookup the object
531 value = multi_get_network_object(netsig);
532 if ((value != NULL) && (value->instance >= 0)) {
533 return true;
534 }
535
536 Warning(LOCATION, "multi_get_object called for non-existent object");
537 return false;
538 }
539
get_parse_object(p_object * & pobjp)540 bool sexp_network_packet::get_parse_object(p_object *& pobjp)
541 {
542 ushort netsig;
543
544 if (!sexp_bytes_left || !current_argument_count) {
545 return false;
546 }
547
548 // get the net signature of the ship
549 GET_USHORT(netsig);
550 reduce_counts(sizeof(ushort));
551
552 // lookup the object
553 pobjp = mission_parse_get_arrival_ship(netsig);
554 if (pobjp != NULL) {
555 return true;
556 }
557
558 return false;
559 }
560
get_string(char * buffer,const size_t buf_len)561 bool sexp_network_packet::get_string(char * buffer, const size_t buf_len)
562 {
563 char tempstring[SEXP_MAX_PACKET_SIZE];
564 int starting_offset = offset;
565
566 if (!sexp_bytes_left || !current_argument_count) {
567 return false;
568 }
569
570 GET_STRING_16(tempstring);
571 strcpy_s(buffer, buf_len, tempstring);
572 reduce_counts(offset - starting_offset);
573
574 return true;
575 }
576
get_string(SCP_string & buffer)577 bool sexp_network_packet::get_string(SCP_string & buffer)
578 {
579 char tempstring[SEXP_MAX_PACKET_SIZE];
580 int starting_offset = offset;
581
582 if (!sexp_bytes_left || !current_argument_count) {
583 return false;
584 }
585
586 GET_STRING_16(tempstring);
587 buffer = tempstring;
588 reduce_counts(offset - starting_offset);
589
590 return true;
591 }
592
get_bool(bool & value)593 bool sexp_network_packet::get_bool(bool & value)
594 {
595 if (!sexp_bytes_left || !current_argument_count) {
596 return false;
597 }
598
599 GET_DATA(value);
600 reduce_counts(sizeof(value));
601
602 return true;
603 }
604
get_float(float & value)605 bool sexp_network_packet::get_float(float & value)
606 {
607 if (!sexp_bytes_left || !current_argument_count) {
608 return false;
609 }
610
611 GET_FLOAT(value);
612 reduce_counts(sizeof(float));
613
614 return true;
615 }
616
get_vec3d(vec3d * value)617 bool sexp_network_packet::get_vec3d(vec3d *value)
618 {
619 for (int i = 0; i < 3; ++i) // NOLINT
620 {
621 if (!get_float(value->a1d[i]))
622 return false;
623 }
624 return true;
625 }
626
get_matrix(matrix * value)627 bool sexp_network_packet::get_matrix(matrix *value)
628 {
629 for (int i = 0; i < 9; ++i) // NOLINT
630 {
631 if (!get_float(value->a1d[i]))
632 return false;
633 }
634 return true;
635 }
636
get_short(short & value)637 bool sexp_network_packet::get_short(short & value)
638 {
639 if (!sexp_bytes_left || !current_argument_count) {
640 return false;
641 }
642
643 GET_SHORT(value);
644 reduce_counts(sizeof(short));
645
646 return true;
647 }
648
get_ushort(ushort & value)649 bool sexp_network_packet::get_ushort(ushort & value)
650 {
651 if (!sexp_bytes_left || !current_argument_count) {
652 return false;
653 }
654
655 GET_USHORT(value);
656 reduce_counts(sizeof(ushort));
657
658 return true;
659 }
660
get_next_operator()661 int sexp_network_packet::get_next_operator()
662 {
663 if (!argument_count_is_valid()) {
664 return -1;
665 }
666
667 short count;
668
669 GET_INT(op_num);
670 sexp_bytes_left -= sizeof(int);
671 GET_SHORT(count);
672 current_argument_count = count;
673 sexp_bytes_left -= sizeof(short);
674
675 Assert(sexp_bytes_left);
676 return op_num;
677
678 }
679
get_operator()680 int sexp_network_packet::get_operator()
681 {
682 return op_num;
683 }
684
finished_callback()685 void sexp_network_packet::finished_callback()
686 {
687 ubyte terminator;
688
689 Assert(current_argument_count == 0);
690
691 // read in the terminator
692 GET_DATA(terminator);
693 if (terminator != CALLBACK_TERMINATOR) {
694 Warning(LOCATION, "multi_get_x function call has been called on an improperly terminated callback. Trace out and fix this!");
695 // discard remainder of packet
696 sexp_bytes_left = 0;
697 return;
698 }
699 sexp_bytes_left--;
700 op_num = -1;
701 }
702
sexp_discard_operator()703 bool sexp_network_packet::sexp_discard_operator()
704 {
705 int i;
706 ubyte dummy;
707 ubyte terminator;
708
709 // read in a number of bytes equal to the count
710 for (i = 0; i<current_argument_count; i++) {
711 GET_DATA(dummy);
712 sexp_bytes_left--;
713 }
714
715 GET_DATA(terminator);
716 sexp_bytes_left--;
717 op_num = -1;
718
719 // the operation terminated correctly, probably a new SEXP that this version doesn't support.
720 if (terminator == CALLBACK_TERMINATOR)
721 return true;
722
723 // packet is probably corrupt
724 else
725 return false;
726 }
727
discard_remaining_callback_data()728 void sexp_network_packet::discard_remaining_callback_data()
729 {
730 if (!sexp_discard_operator()) {
731 Warning(LOCATION, "Attempt to discard remaining data failed! Callback lacks proper termination. Entire packet may be corrupt. Discarding remaining packet");
732 }
733 }
734