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