FS2_Open
Open source remastering of the Freespace 2 engine
multi_sexp.cpp
Go to the documentation of this file.
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 "network/psnet2.h"
9 #include "network/multimsgs.h"
10 #include "parse/sexp.h"
11 #include "network/multi.h"
12 #include "network/multiutil.h"
13 
14 #define CALLBACK_TERMINATOR 255
15 int TEMP_DATA_SIZE = -1;
16 
17 #define TYPE_NOT_DATA 255
18 #define TYPE_SEXP_OPERATOR 0
19 #define TYPE_ARGUMENT_COUNT 1
20 #define TYPE_DATA_TERMINATES 2
21 #define TYPE_INT 3
22 #define TYPE_SHIP 4
23 #define TYPE_STRING 5
24 #define TYPE_PARSE_OBJECT 6
25 #define TYPE_BOOLEAN 7
26 #define TYPE_FLOAT 8
27 #define TYPE_SHORT 9
28 #define TYPE_USHORT 10
29 #define TYPE_OBJECT 11
30 
31 
32 // the type array holds information on the type of date held at the same index of the data array
33 // types are not sent to the client and the entire array could be replaced with a couple of variables indexing the end of
34 // the previous SEXP. However it is much more helpful when debugging to have the array
36 int argument_count_index = -1; // index in the type and data arrays for the argument count
37 int current_argument_count = 0; // number of bytes the data for this SEXP currently takes up
38 
39 // these 3 variable names must remain the same as those used in multimsgs.h in order for the macros to work
41 int packet_size = 0;
42 int offset = 0;
43 
44 bool callback_started = false;
45 
46 int Multi_sexp_bytes_left = 0; // number of bytes in incoming packet that still require processing
47 
48 int op_num = -1;
50 
51 //forward declarations
52 void multi_sexp_ensure_space_remains(int data_size);
53 
54 
55 /**************************
56  HOST SIDE PACKET FUNCTIONS
57  *************************/
58 
63 {
64  if (!MULTIPLAYER_MASTER) {
65  return;
66  }
67 
68  memset(data, 0, MAX_PACKET_SIZE);
69  memset(type, -1, MAX_PACKET_SIZE);
70 
71  packet_size = 0;
74 }
75 
80 {
81  if (!MULTIPLAYER_MASTER) {
82  return;
83  }
84 
85  // 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
86  // 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!
87  multi_sexp_ensure_space_remains(sizeof(int)*2);
88 
89  callback_started = true;
90 
91  //Write OP into the Type buffer.
93  //Write the SEXP_Operator number into the data buffer.
94  Assert (!Current_sexp_operator.empty());
96 
97  //Store the next data index as we'll need it later to write the COUNT.
99  // store an invalid count, we'll come back and store the correct value once we know what it is.
102 }
103 
108 {
109  if (!MULTIPLAYER_MASTER) {
110  return;
111  }
112 
113  // 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!
115 
116  callback_started = false;
117 
118  // something is wrong with the packet, blast it clean and start again
121  packet_flagged_invalid = false;
122  return;
123  }
124 
125  //write TERMINATOR into the Type and data buffers
128  ADD_DATA(b);
129 
130  //Write the COUNT into the data buffer at the index we saved earlier.
131  int temp_packet_size = packet_size;
134  packet_size = temp_packet_size;
135 
137 }
143 {
146 }
147 
155 {
156  if (!MULTIPLAYER_MASTER) {
157  return;
158  }
159 
160  int packet_end = 0;
161  int sub_packet_size = 0;
162  int i, j;
163 
164  //If the index of the data buffer isn't high enough yet, bail
165  if (packet_size + data_size + HEADER_LENGTH < MAX_PACKET_SIZE) {
166  return;
167  }
168 
169  //iterate back through the types array until we find a TERMINATOR and store the corresponding data index
170  for (i = packet_size-1; i > 0; i--) {
171  if ( type[i] == TYPE_DATA_TERMINATES) {
172  packet_end = i;
173  break;
174  }
175  }
176 
177  // we want the number of bytes not the index of the last one
178  sub_packet_size = packet_end + 1;
179 
180  // At very least must include OP, COUNT, TERMINATOR
181  if (packet_end < 9 && !packet_flagged_invalid) {
182  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 );
183  packet_flagged_invalid = true;
184  return;
185  }
186 
187  send_sexp_packet(data, sub_packet_size);
188 
189  j = 0;
190  //Slide down any entries after the stored index to the start of the array.
191  for (i = sub_packet_size; i < packet_size; i++) {
192  data[j] = data[i];
193  type[j] = type[i];
194  j++;
195  }
196 
197  packet_size = j;
198 
199  // flush the remaining type buffer
200  for (i = j ; i < MAX_PACKET_SIZE ; i++) {
201  type[i] = (ubyte) -1;
202  }
203 
204  // if we have an existing argument count we need to update where to put it too
206  argument_count_index = argument_count_index - sub_packet_size;
207  }
208 
210 }
211 
216 {
217  if (!MULTIPLAYER_MASTER) {
218  return;
219  }
220 
221  // possible to get here when there is nothing in the packet to send
222  if (packet_size == 0){
223  return;
224  }
227 
229 
231 }
232 
237 {
239  return true;
240  }
241 
242  if (!callback_started) {
243  Warning (LOCATION, "Attempt to send data in multi_sexp.cpp without first starting a callback");
244  return true;
245  }
246 
247  return false;
248 }
249 
250 /********************************
251  HOST SIDE DATA WRAPPER FUNCTIONS
252  *******************************/
253 
258 {
259  if (cannot_send_data()) {
260  return;
261  }
262 
263  multi_sexp_ensure_space_remains(sizeof(value));
264 
265  //Write INT into the Type buffer.
267  //Write the int into the data buffer
268  ADD_INT(value);
269  //Increment the COUNT by 4 (i.e the size of an int).
270  current_argument_count += sizeof(int);
271 }
272 
276 void multi_send_ship(int shipnum)
277 {
278  if (cannot_send_data()) {
279  return;
280  }
281 
282  multi_sexp_ensure_space_remains(sizeof(shipnum));
283 
284  multi_send_ship(&Ships[shipnum]);
285 }
286 
291 {
292  if (cannot_send_data()) {
293  return;
294  }
295 
297 
298  //write into the Type buffer.
300  //write the into the data buffer
302  current_argument_count += sizeof(ushort);
303 }
304 
308 void multi_send_object(object *objp)
309 {
310  if (cannot_send_data()) {
311  return;
312  }
313 
315 
316  //write into the Type buffer.
318  //write the into the data buffer
319  ADD_USHORT(objp->net_signature);
320  current_argument_count += sizeof(ushort);
321 }
322 
327 {
328  if (cannot_send_data()) {
329  return;
330  }
331 
333 
334  //write into the Type buffer.
336  //write the into the data buffer
337  ADD_USHORT(pobjp->net_signature);
338  current_argument_count += sizeof(ushort);
339 }
340 
344 void multi_send_string(char *string)
345 {
346  if (cannot_send_data()) {
347  return;
348  }
349 
350  multi_sexp_ensure_space_remains(strlen(string)+4);
351 
352  int start_size = packet_size;
353  //write into the Type buffer.
355  //write the into the data buffer
356  ADD_STRING(string);
357  current_argument_count += packet_size - start_size;
358 }
359 
360 void multi_send_string(const SCP_string &string)
361 {
362  if (cannot_send_data()) {
363  return;
364  }
365 
367 
368  int start_size = packet_size;
369  //write into the Type buffer.
371  //write the into the data buffer
372  ADD_STRING(string.c_str());
373  current_argument_count += packet_size - start_size;
374 }
375 
380 {
381  if (cannot_send_data()) {
382  return;
383  }
384 
385  multi_sexp_ensure_space_remains(sizeof(value));
386 
387  //write into the Type buffer.
389  //Write the value into the data buffer
390  ADD_DATA(value);
391  //Increment the COUNT
392  current_argument_count += sizeof(value);
393 }
394 
399 {
400  if (cannot_send_data()) {
401  return;
402  }
403 
404  multi_sexp_ensure_space_remains(sizeof(value));
405 
406  //write into the Type buffer.
408  //Write the value into the data buffer
409  ADD_FLOAT(value);
410  //Increment the COUNT
411  current_argument_count += sizeof(float);
412 }
413 
418 {
419  if (cannot_send_data()) {
420  return;
421  }
422 
423  multi_sexp_ensure_space_remains(sizeof(value));
424 
425  //Write the type into the Type buffer.
427  //Write the value into the data buffer
428  ADD_SHORT(value);
429  //Increment the COUNT
430  current_argument_count += sizeof(short);
431 }
432 
437 {
438  if (cannot_send_data()) {
439  return;
440  }
441 
442  multi_sexp_ensure_space_remains(sizeof(value));
443 
444  //Write the type into the Type buffer.
446  //Write the value into the data buffer
447  ADD_USHORT(value);
448  //Increment the COUNT
449  current_argument_count += sizeof(ushort);
450 }
451 
452 
453 /****************************
454  CLIENT SIDE PACKET FUNCTIONS
455  ***************************/
456 
461 void sexp_packet_received(ubyte *received_packet, int num_ubytes)
462 {
463  int i;
464 
465  offset = 0;
466  op_num = -1;
467 
468  for (i=0; i < MAX_PACKET_SIZE; i++) {
469  data[i] = received_packet[i];
470  }
471 
472  Multi_sexp_bytes_left = num_ubytes;
473  // start working through the packet
474  multi_sexp_eval();
475 }
476 
481 {
482  if (current_argument_count != 0) {
483  // we have a problem here, either the argument count is wrong or the last SEXP didn't remove all its data from the packet
484  ubyte possible_terminator;
485  bool terminator_found = false;
486  for (int i=0; i < current_argument_count ; i++) {
487  GET_DATA(possible_terminator);
489 
490  if (possible_terminator == CALLBACK_TERMINATOR) {
491  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, current_argument_count, i);
492  terminator_found = true;
493  break;
494  }
495  }
496 
497  // if we still haven't found the terminator it probably means the last SEXP didn't remove all its data from the packet
498  if (!terminator_found) {
499  GET_DATA(possible_terminator);
501 
502  if (possible_terminator != CALLBACK_TERMINATOR) {
503  // discard remainder of packet if we still haven't found the terminator as it is hopelessly corrupt
504  Warning(LOCATION, "%s has returned to multi_sexp_eval() without finding the terminator. Discarding packet! Trace out and fix this!", Operators[op_num].text);
506  return false;
507  }
508  else {
509  // the previous SEXP hasn't removed all it's data from the packet correctly but it appears we've managed to fix it
510  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);
511  op_num = -1;
512  }
513  }
514  }
515 
516  return true;
517 }
518 
524 {
525  if (!argument_count_is_valid()) {
526  return -1;
527  }
528 
529  GET_INT(op_num);
530  Multi_sexp_bytes_left -= sizeof(int);
532  Multi_sexp_bytes_left -= sizeof(int);
533 
535  return op_num;
536 }
537 
542 {
543  return op_num;
544 }
545 
549 void multi_reduce_counts(int amount)
550 {
551  Multi_sexp_bytes_left -= amount;
552  current_argument_count -= amount;
553 
555  Warning(LOCATION, "multi_get_x function call has read an invalid amount of data. Trace out and fix this!");
556  }
557 }
558 
563 {
564  ubyte terminator;
565 
567 
568  // read in the terminator
569  GET_DATA(terminator);
570  if (terminator != CALLBACK_TERMINATOR) {
571  Warning(LOCATION, "multi_get_x function call has been called on an improperly terminated callback. Trace out and fix this!");
572  // discard remainder of packet
574  return;
575  }
577  op_num = -1;
578 }
579 
584 {
585  int i;
586  ubyte dummy;
587  ubyte terminator;
588 
589  // read in a number of bytes equal to the count
590  for (i=0; i<current_argument_count; i++) {
591  GET_DATA(dummy);
593  }
594 
595  GET_DATA(terminator);
597  op_num = -1;
598 
599  // the operation terminated correctly, probably a new SEXP that this version doesn't support.
600  if (terminator == CALLBACK_TERMINATOR)
601  return true;
602 
603  // packet is probably corrupt
604  else
605  return false;
606 
607 }
608 
609 /**********************************
610  CLIENT SIDE DATA WRAPPER FUNCTIONS
611  *********************************/
612 
617 {
619  return false;
620  }
621 
622  GET_INT(value);
623  multi_reduce_counts(sizeof(int));
624 
625  return true;
626 }
627 
633 {
634  ushort netsig;
635  object *objp;
636 
638  return false;
639  }
640 
641  // get the net signature of the ship
642  GET_USHORT(netsig);
643  multi_reduce_counts(sizeof(ushort));
644 
645  // lookup the object
646  objp = multi_get_network_object(netsig);
647  if((objp != NULL) && (objp->type == OBJ_SHIP) && (objp->instance >=0)){
648  value = objp->instance;
649  return true;
650  }
651 
652  Warning(LOCATION, "multi_get_ship called for object %d even though it is not a ship", objp->instance);
653  return false;
654 }
655 
661 {
662  int shipnum;
663 
664  if (multi_get_ship(shipnum)) {
665  shipp = &Ships[shipnum];
666  return true;
667  }
668 
669  return false;
670 }
671 
676 bool multi_get_object(object*& objp)
677 {
678  ushort netsig;
679 
681  return false;
682  }
683 
684  // get the net signature of the ship
685  GET_USHORT(netsig);
686  multi_reduce_counts(sizeof(ushort));
687 
688  // lookup the object
689  objp = multi_get_network_object(netsig);
690  if((objp != NULL) && (objp->instance >=0)){
691  return true;
692  }
693 
694  Warning(LOCATION, "multi_get_object called for non-existent object");
695  return false;
696 }
697 
703 {
704  ushort netsig;
705 
707  return false;
708  }
709 
710  // get the net signature of the ship
711  GET_USHORT(netsig);
712  multi_reduce_counts(sizeof(ushort));
713 
714  // lookup the object
715  pobjp = mission_parse_get_arrival_ship(netsig);
716  if(pobjp != NULL){
717  return true;
718  }
719 
720  return false;
721 }
722 
727 {
728  int starting_offset = offset;
729 
731  return false;
732  }
733 
734  GET_STRING(buffer);
735  multi_reduce_counts(offset - starting_offset);
736 
737  return true;
738 }
739 
741 {
742  char tempstring[TOKEN_LENGTH];
743  int starting_offset = offset;
744 
746  return false;
747  }
748 
749  GET_STRING(tempstring);
750  buffer = tempstring;
751  multi_reduce_counts(offset - starting_offset);
752 
753  return true;
754 }
755 
760 {
762  return false;
763  }
764 
765  GET_DATA(value);
766  multi_reduce_counts(sizeof(value));
767 
768  return true;
769 }
770 
774 bool multi_get_float(float &value)
775 {
777  return false;
778  }
779 
780  GET_FLOAT(value);
781  multi_reduce_counts(sizeof(float));
782 
783  return true;
784 }
785 
789 bool multi_get_short(short &value)
790 {
792  return false;
793  }
794 
795  GET_SHORT(value);
796  multi_reduce_counts(sizeof(short));
797 
798  return true;
799 }
800 
805 {
807  return false;
808  }
809 
810  GET_USHORT(value);
811  multi_reduce_counts(sizeof(ushort));
812 
813  return true;
814 }
815 
820 {
822  Warning(LOCATION, "Attempt to discard remaining data failed! Callback lacks proper termination. Entire packet may be corrupt. Discarding remaining packet");
823  }
824 }
int i
Definition: multi_pxo.cpp:466
#define GET_DATA(d)
Definition: multimsgs.h:47
void sexp_packet_received(ubyte *received_packet, int num_ubytes)
Definition: multi_sexp.cpp:461
int objnum
Definition: ship.h:537
#define TYPE_INT
Definition: multi_sexp.cpp:21
void multi_finished_callback()
Definition: multi_sexp.cpp:562
GLsizei const GLfloat * value
Definition: Glext.h:5646
void multi_send_object(object *objp)
Definition: multi_sexp.cpp:308
#define TYPE_SHORT
Definition: multi_sexp.cpp:27
#define ADD_DATA(d)
Definition: multimsgs.h:37
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
Assert(pm!=NULL)
#define ADD_STRING(s)
Definition: multimsgs.h:43
ushort net_signature
Definition: object.h:163
#define TYPE_SEXP_OPERATOR
Definition: multi_sexp.cpp:18
int offset
Definition: multi_sexp.cpp:42
#define TYPE_PARSE_OBJECT
Definition: multi_sexp.cpp:24
bool multi_sexp_discard_operator()
Definition: multi_sexp.cpp:583
#define TYPE_BOOLEAN
Definition: multi_sexp.cpp:25
std::basic_string< char, std::char_traits< char >, std::allocator< char > > SCP_string
Definition: vmallocator.h:21
object * objp
Definition: lua.cpp:3105
ushort net_signature
Definition: missionparse.h:413
void multi_start_callback()
Definition: multi_sexp.cpp:79
ship * shipp
Definition: lua.cpp:9162
int packet_size
Definition: multi_sexp.cpp:41
void multi_sexp_flush_packet()
Definition: multi_sexp.cpp:215
#define TYPE_STRING
Definition: multi_sexp.cpp:23
int current_argument_count
Definition: multi_sexp.cpp:37
GLenum type
Definition: Gl.h:1492
bool multi_get_bool(bool &value)
Definition: multi_sexp.cpp:759
#define GET_FLOAT(d)
Definition: multimsgs.h:52
#define ADD_INT(d)
Definition: multimsgs.h:40
#define MAX_PACKET_SIZE
Definition: psnet2.h:34
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int instance
Definition: object.h:150
GLintptr offset
Definition: Glext.h:5497
p_object * mission_parse_get_arrival_ship(const char *name)
Returns the parse object on the ship arrival list associated with the given name. ...
#define ADD_FLOAT(d)
Definition: multimsgs.h:42
int Multi_sexp_bytes_left
Definition: multi_sexp.cpp:46
void multi_reduce_counts(int amount)
Definition: multi_sexp.cpp:549
#define TYPE_DATA_TERMINATES
Definition: multi_sexp.cpp:20
bool multi_get_int(int &value)
Definition: multi_sexp.cpp:616
void multi_sexp_eval()
Definition: sexp.cpp:25196
void multi_send_string(char *string)
Definition: multi_sexp.cpp:344
#define TYPE_USHORT
Definition: multi_sexp.cpp:28
bool cannot_send_data()
Definition: multi_sexp.cpp:236
void multi_discard_remaining_callback_data()
Definition: multi_sexp.cpp:819
bool multi_get_string(char *buffer)
Definition: multi_sexp.cpp:726
void multi_send_ship(int shipnum)
Definition: multi_sexp.cpp:276
bool argument_count_is_valid()
Definition: multi_sexp.cpp:480
#define TYPE_SHIP
Definition: multi_sexp.cpp:22
GLuint buffer
Definition: Glext.h:5492
void multi_send_short(short value)
Definition: multi_sexp.cpp:417
void multi_send_parse_object(p_object *pobjp)
Definition: multi_sexp.cpp:326
#define ADD_SHORT(d)
Definition: multimsgs.h:38
int op_num
Definition: multi_sexp.cpp:48
#define TYPE_OBJECT
Definition: multi_sexp.cpp:29
Definition: ship.h:534
void send_sexp_packet(ubyte *sexp_packet, int num_ubytes)
Definition: multimsgs.cpp:8701
void multi_send_ushort(ushort value)
Definition: multi_sexp.cpp:436
sexp_oper Operators[]
Definition: sexp.cpp:118
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
unsigned char ubyte
Definition: pstypes.h:62
bool packet_flagged_invalid
Definition: multi_sexp.cpp:49
#define CALLBACK_TERMINATOR
Definition: multi_sexp.cpp:14
#define OBJ_SHIP
Definition: object.h:32
void multi_sexp_ensure_space_remains(int data_size)
Definition: multi_sexp.cpp:154
#define TYPE_FLOAT
Definition: multi_sexp.cpp:26
#define ADD_USHORT(d)
Definition: multimsgs.h:39
void multi_send_float(float value)
Definition: multi_sexp.cpp:398
#define TOKEN_LENGTH
Definition: globals.h:41
int multi_sexp_get_operator()
Definition: multi_sexp.cpp:541
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
bool multi_get_parse_object(p_object *&pobjp)
Definition: multi_sexp.cpp:702
#define TYPE_ARGUMENT_COUNT
Definition: multi_sexp.cpp:19
#define GET_USHORT(d)
Definition: multimsgs.h:49
bool multi_get_float(float &value)
Definition: multi_sexp.cpp:774
void multi_end_callback()
Definition: multi_sexp.cpp:107
unsigned short ushort
Definition: pstypes.h:63
void multi_do_callback()
Definition: multi_sexp.cpp:142
int HEADER_LENGTH
Definition: multi.cpp:106
bool callback_started
Definition: multi_sexp.cpp:44
bool multi_get_ship(int &value)
Definition: multi_sexp.cpp:632
#define MULTIPLAYER_MASTER
Definition: multi.h:130
#define LOCATION
Definition: pstypes.h:245
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
void multi_send_int(int value)
Definition: multi_sexp.cpp:257
object * multi_get_network_object(ushort net_signature)
Definition: multiutil.cpp:220
GLenum GLuint GLenum GLsizei length
Definition: Glext.h:5156
#define GET_SHORT(d)
Definition: multimsgs.h:48
int TEMP_DATA_SIZE
Definition: multi_sexp.cpp:15
void multi_send_bool(bool value)
Definition: multi_sexp.cpp:379
#define GET_INT(d)
Definition: multimsgs.h:50
bool multi_get_ushort(ushort &value)
Definition: multi_sexp.cpp:804
char * text
Definition: sexp.h:1020
char type
Definition: object.h:146
#define GET_STRING(s)
Definition: multimsgs.h:53
int multi_sexp_get_next_operator()
Definition: multi_sexp.cpp:523
int argument_count_index
Definition: multi_sexp.cpp:36
SCP_vector< int > Current_sexp_operator
Definition: sexp.cpp:851
void initalise_sexp_packet()
Definition: multi_sexp.cpp:62
bool multi_get_object(object *&objp)
Definition: multi_sexp.cpp:676
bool multi_get_short(short &value)
Definition: multi_sexp.cpp:789