1 /***************************************************************************
2
3 network.c
4
5 ***************************************************************************/
6
7
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #ifdef MAME_NET
12
13 #include "network.h"
14 #include "osdepend.h"
15 #include "mame.h"
16 #include "common.h" /* Machine struct */
17 #include "driver.h" /* GameDriver struct */
18
19
20 /* Uncomment to turn on printf code */
21 /* #define NET_DEBUG */
22
23 #ifdef NET_DEBUG
24 #include <ctype.h>
25
26 #define dprintf(x) printf x;
27 #else
28 #define dprintf(x)
29 #endif
30
31 /* private funcs */
32 static int _real_net_sync( int first, char type );
33 static void net_packet_type_to_string( char type, char packet_type_str[] );
34
35 static int vercmp(char *str_a, char *str_b);
36
37 /* private vars */
38 static char netversion[] = "Rev7.3 ()"; /* RevX.Y X = Protocol version, Y = Tweak/Bug fix revision */
39 static char *mameversion = build_version; /* from mame.h and version.c */
40 static int is_active = 0; /* Set to true if the net has been initialized */
41 static int in_game = 0; /* Set to true if we are in a game */
42 static int is_client = 1;
43 static int num_clients = 0;
44
45 /*******************************************************************
46 external functions
47 *******************************************************************/
48
net_init()49 int net_init()
50 {
51 dprintf(("net_init() called\n"))
52 in_game = 0;
53 /* TODO: move is_client setting into os-dependent settings?
54 should os-independent stuff know about this at all?
55 */
56 if ( ( is_client = osd_net_init() ) == NET_ERROR )
57 {
58 dprintf(("osd_net_init() - FAILED\n"))
59 return 1;
60 }
61
62 is_active = 1; /* we're using network */
63
64 /* if we're the client we can do the version checking now
65 server checks in net_add_player
66 */
67 if ( is_client )
68 {
69 if ( net_vers_check( 0 ) )
70 {
71 dprintf(("net_version_check() - FAILED\n"))
72 return 1;
73 }
74 }
75
76 dprintf(("net_init() - SUCCESS\n"))
77 /* made it this far, must be ok */
78 return 0;
79 }
80
81
net_exit(char type)82 int net_exit( char type )
83 {
84 dprintf(("net_exit() called\n"))
85
86 /* guard to make sure we're still active */
87 if (!is_active)
88 return 0;
89
90 /* what kind of exit are we experiencing */
91 switch ( type )
92 {
93 /* if we initiate we'll need to send */
94 case NET_QUIT_QUIT:
95 case NET_QUIT_ABRT:
96 net_sync( type );
97 break;
98
99 /* if its peer initiated we just handle it w/o sending */
100 case NET_QUIT_OKAY:
101 break;
102 }
103
104 is_active = 0;
105 dprintf(("net_exit() returning osd_net_exit()\n"))
106 return osd_net_exit();
107 }
108
net_game_init()109 int net_game_init()
110 {
111 dprintf(("net_game_init() called\n"))
112 if (osd_net_game_init() != 0)
113 {
114 dprintf(("net_game_init - FAILED\n"))
115 return 1;
116 }
117
118 /* we can do the game checking now */
119 if ( is_client )
120 {
121 if ( net_game_check( 0 ) )
122 {
123 dprintf(("net_game_check - FAILED\n"))
124 return 1;
125 }
126 dprintf(("net_game_check - SUCCESS\n"))
127 }
128 else
129 {
130 int i;
131
132 for (i = 0; i < num_clients; i++)
133 {
134 if ( net_game_check( i ) )
135 {
136 dprintf(("net_game_init player (%d) - FAILED\n", i))
137 return 1;
138 }
139 dprintf(("net_game_init player (%d) - SUCCESS\n", i))
140 }
141 }
142 in_game = is_active = 1;
143 dprintf(("net_game_init() return\n"))
144 return 0;
145 }
146
net_game_exit()147 int net_game_exit()
148 {
149 in_game = 0;
150 dprintf(("net_game_exit called - returning osd_net_game_exit()\n"))
151 return osd_net_game_exit();
152 }
153
154 /*
155 do consistency check of mame/netmame support and prompt user for input on failure
156 */
net_vers_check(int player)157 int net_vers_check( int player )
158 {
159 char szVerSelf[NET_MAX_DATA];
160 char szVerPeer[NET_MAX_DATA];
161 char cAck = 1; /* assuming false */
162
163 /* setup app and network support version info */
164 memset( szVerSelf, 0, sizeof(szVerSelf) ); /* zero out array first */
165 strcpy( szVerSelf, build_version );
166 strcpy( (szVerSelf+25), netversion );
167
168 dprintf(("net_vers_check()\n"))
169
170 /* do comparisons */
171 if ( is_client )
172 {
173 net_send( 0, NET_INIT_VERS, szVerSelf, NET_MAX_DATA );
174 net_recv( 0, NET_INIT_VERS, &cAck, 1 );
175 }
176 else /* server */
177 {
178 /* Clients send to us and we check versions */
179 net_recv( player, NET_INIT_VERS, szVerPeer, NET_MAX_DATA );
180
181 /* Check the app version */
182 if ( vercmp( szVerSelf, szVerPeer ) != 0 )
183 {
184 printf("Client %d does not match MAME version"
185 "\nServer:%s"
186 "\nClient:%s\n"
187 , player, szVerSelf, szVerPeer );
188 }
189
190 /* Check the network version */
191 else if ( vercmp( (szVerSelf+25), (szVerPeer+25) ) != 0 )
192 {
193 printf("Client %d does not match network support version"
194 "\nServer:%s"
195 "\nClient:%s"
196 , player, (szVerSelf+25), (szVerPeer+25) );
197 /* TODO:some sort of prompt for return value...??? */
198 }
199
200 /* else we are successful */
201 else
202 cAck = 0;
203
204 /* let client know results of version check */
205 net_send( player, NET_INIT_VERS, &cAck, 1 );
206 }
207
208 dprintf(("net_vers_check() - %s\n", (cAck) ? "FAILED" : "SUCCESS"))
209
210 return cAck;
211 }
212
213
214 /*
215 *** rjr *** Compare versions; ignore dates (in parentheses)
216 So recompiling doesn't bring the world to a screeching halt!
217 */
vercmp(char * str_a,char * str_b)218 static int vercmp(char *str_a, char *str_b)
219 {
220 char string_a[NET_MAX_DATA];
221 char string_b[NET_MAX_DATA];
222
223 char *p;
224
225 strcpy(string_a, str_a);
226 strcpy(string_b, str_b);
227
228 if (p = strchr(string_a, '('))
229 *p = '\0';
230
231 if (p = strchr(string_b, '('))
232 *p = '\0';
233
234 dprintf(("vercmp(%s,%s)\n", string_a, string_b))
235
236 return strcmp(string_a, string_b);
237 }
238
239
240 #ifdef NET_DEBUG
241 /* Dump a packet in hex and ascii */
array_to_string(int len,char * array)242 char * array_to_string(int len, char *array)
243 {
244 static char str[500] = "";
245 char temp[50];
246 char *ptr = array;
247 int i;
248
249 for (i = 0; i < len; i++, ptr++)
250 {
251 if (i)
252 strcat(str,",");
253 sprintf(temp,"%02x,'%c'", *ptr & 0xFF, (isalnum(*ptr)) ? *ptr : '.');
254 strcat(str, temp);
255 }
256 return str;
257 }
258
259 #endif
260 /*
261 do consistency check of game/roms and prompt user for input on failure
262 */
net_game_check(int player)263 int net_game_check( int player )
264 {
265 char szVerSelf[NET_MAX_DATA];
266 char szVerPeer[NET_MAX_DATA];
267 char cAck = 1; /* assuming false */
268
269 dprintf(("net_game_check (%d) as %s, Game('%s')\n",
270 player, (is_client) ? "Client" : "Server", Machine->gamedrv->name))
271 /* Setup rom version info */
272 strcpy( szVerSelf, Machine->gamedrv->name );
273 /* TODO: strcpy checksum info? */
274
275 /* do comparisons */
276 if ( is_client )
277 {
278 net_send( 0, NET_INIT_GAME, szVerSelf, strlen(szVerSelf));
279 net_recv( 0, NET_INIT_GAME, &cAck, 1 );
280 }
281 else /* server */
282 {
283 /* Clients send to us and we check versions */
284 memset(szVerPeer, '\0', sizeof(szVerPeer));
285 net_recv( player, NET_INIT_GAME, szVerPeer, NET_MAX_DATA);
286
287 dprintf(("Server NET_INIT_GAME: %s\n", array_to_string(8, szVerPeer)))
288 if ( strcmp( (szVerSelf), (szVerPeer)) != 0 )
289 {
290 printf("Client %d does not match rom name"
291 "\nServer:%s"
292 "\nClient:%s"
293 , player, (szVerSelf), (szVerPeer) );
294 }
295
296 /* else we are successful */
297 else
298 cAck = 0;
299
300 /* let client know results of version check */
301 net_send( player, NET_INIT_GAME, &cAck, 1 );
302 }
303 dprintf(("net_game_check (%d) - %s\n", player, (cAck) ? "FAILED" : "SUCCESS"))
304 return cAck;
305 }
306
net_sync(char type)307 int net_sync( char type )
308 {
309 dprintf(("net_sync() called\n"))
310 switch ( type )
311 {
312 case NET_SYNC_INIT:
313 case NET_SYNC_REDO:
314 return _real_net_sync( is_client, type );
315 break;
316
317 case NET_QUIT_QUIT:
318 case NET_QUIT_ABRT:
319 /* we still sync first if we've decided to exit */
320 return _real_net_sync( 1, type );
321 break;
322
323 default:
324 printf("net_sync: asked to sync a type we don't recognize at this point\n");
325 }
326 return 1; /* error shouldn't reach this far */
327 }
328
_real_net_sync(int first,char type)329 static int _real_net_sync( int first, char type )
330 {
331 static NET_BYTE szMsg[] = "PeterAndMichael";
332 static int size = 16;
333
334 dprintf(("_real_net_sync() called as %d - first is %s\n",
335 (is_client) ? "Client" : "Server",
336 (first) ? "TRUE" : "FALSE"))
337
338 if ( is_client )
339 {
340 if ( first )
341 {
342 net_send( 0, type, szMsg, size );
343 net_recv( 0, type, szMsg, NET_MAX_DATA );
344 }
345 else
346 {
347 net_recv( 0, type, szMsg, NET_MAX_DATA );
348 net_send( 0, type, szMsg, size );
349 }
350 }
351
352 else
353 {
354 int i;
355 if ( first )
356 {
357 for ( i=0; i < num_clients; i++)
358 {
359 net_send( 0, type, szMsg, size );
360 net_recv( 0, type, szMsg, NET_MAX_DATA );
361 }
362 }
363 else
364 {
365 for ( i=0; i < num_clients; i++)
366 {
367 net_recv( 0, type, szMsg, NET_MAX_DATA );
368 net_send( 0, type, szMsg, size );
369 }
370 }
371 }
372
373 /* error checking? */
374 dprintf(("_real_net_sync() called\n"))
375 return 0;
376 }
377
net_analog_sync(unsigned char input_port_value[],int port,int analog_player_port[],int default_player)378 int net_analog_sync(unsigned char input_port_value[], int port,
379 int analog_player_port[], int default_player)
380 {
381 unsigned char junk[MAX_INPUT_PORTS]; /* used just for synchronizing - values don't matter */
382
383 dprintf(("net_analog_sync() called\n"))
384 if ( is_client )
385 {
386 if ( analog_player_port[port] == default_player ) /* we control this port */
387 {
388 /* we tell the server our input */
389 net_send( 0, NET_SYNC_ANLG, &input_port_value[port], 1 );
390 net_recv( 0, NET_SYNC_ANLG, &junk[port], 1 );
391 }
392 else
393 {
394 /* we receive the correct input from the server */
395 net_send( 0, NET_SYNC_ANLG, &junk[port], 1 );
396 net_recv( 0, NET_SYNC_ANLG, &input_port_value[port], 1 );
397 }
398 }
399 else
400 {
401 if ( analog_player_port[port] == default_player ) /* we control this port */
402 {
403 /* we tell the client our input */
404 net_recv( 0, NET_SYNC_ANLG, &junk[port], 1 );
405 net_send( 0, NET_SYNC_ANLG, &input_port_value[port], 1 );
406 }
407 else
408 {
409 /* we receive the correct input from the client */
410 net_recv( 0, NET_SYNC_ANLG, &input_port_value[port], 1 );
411 net_send( 0, NET_SYNC_ANLG, &junk[port], 1 );
412 }
413 }
414 dprintf(("net_analog_sync() return\n"))
415
416 return 0;
417 }
418
419
net_input_sync(unsigned char input_port_value[],unsigned char input_port_default[],int num_ports)420 int net_input_sync( unsigned char input_port_value[], unsigned char input_port_default[], int num_ports )
421 {
422 int port;
423
424 dprintf(("net_input_sync() called\n"))
425 if ( is_client )
426 {
427 /* mark default bits */
428 for(port=0; port < num_ports; port++)
429 input_port_value[port] ^= input_port_default[port];
430
431 /* send our changes to server for merging */
432 net_send( 0, NET_SYNC_INPT, input_port_value, num_ports );
433
434 /* receive final merged input from server */
435 net_recv( 0, NET_SYNC_INPT, input_port_value, num_ports );
436 }
437
438 else /* server */
439 {
440 int client;
441 static unsigned char changed_input_port_value[MAX_INPUT_PORTS];
442 static unsigned char old_input_port_value[MAX_INPUT_PORTS]; /* used by server in case network dies */
443
444 /* save values incase network dies */
445 memcpy(old_input_port_value, input_port_value, num_ports);
446
447 /* receive input from client and merge */
448 for (client=0; client < num_clients; client++)
449 {
450 /* mark default bits */
451 for(port=0; port < num_ports; port++)
452 input_port_value[port] ^= input_port_default[port];
453
454 net_recv( client, NET_SYNC_INPT, changed_input_port_value, num_ports );
455
456 for( port=0; port < num_ports; port++ )
457 {
458 /* merge this clients changes */
459 input_port_value[port] |= changed_input_port_value[port]; /* or local and remote changes */
460 input_port_value[port] ^= input_port_default[port]; /* toggle changed bits */
461 }
462 }
463
464 /* now check if clients still exist */
465 if ( is_active )
466 {
467 for (client=0; client < num_clients; client++) /* send final input to client */
468 net_send( client, NET_SYNC_INPT, input_port_value, num_ports );
469 }
470 else /* net connection is now down, restore our values */
471 {
472 memcpy(input_port_value, old_input_port_value, num_ports);
473 }
474 }
475 dprintf(("net_input_sync() return\n"))
476
477 /* TODO: error checking */
478 return 0;
479 }
480
481 /* format packet and pass to os-specific sender */
net_send(int player,char type,unsigned char * msg,int size)482 int net_send( int player, char type, unsigned char *msg, int size )
483 {
484 /* format packet */
485 static unsigned char buf[NET_MAX_PACKET];
486 int new_size = size + NET_MAX_HEADER;
487 int error = 0;
488 #ifdef NET_DEBUG
489 char packet_str[14];
490 net_packet_type_to_string( type, packet_str );
491 if (type == NET_INIT_GAME && size > 1)
492 {
493 dprintf(("net_send: %s data(%s), len(%d)\n", packet_str, msg, size))
494 }
495 else
496 dprintf(("net_send: %s, size(%d)\n", packet_str, size ))
497 #endif
498 memset( buf, '\0', NET_MAX_PACKET ); /* clear full buffer */
499 memcpy( buf, &type, NET_MAX_HEAD_TYPE );
500 memcpy( (buf + NET_MAX_HEAD_TYPE), &size, NET_MAX_HEAD_SIZE );
501 memcpy( (buf + NET_MAX_HEADER), msg, size );
502
503 error = osd_net_send( player, buf, &new_size );
504
505 if ( new_size != size + (int)NET_MAX_HEADER )
506 {
507 printf( "net_send: detected error while attempting to send\n" );
508 printf( "net_send: newsize:%d size+header:%d\n",new_size,size+NET_MAX_HEADER );
509 error = 1;
510 }
511
512 return error;
513 }
514
515 /* receive from os-specific sender and check packet format */
net_recv(int player,char type,unsigned char * msg,int size)516 int net_recv( int player, char type, unsigned char *msg, int size )
517 {
518 /* decode packet and check against expected*/
519 static unsigned char buf[NET_MAX_PACKET];
520 int error;
521 char new_type;
522 int new_size;
523
524 /* clear buffer before receiving */
525 net_recv_again:
526 error = 0;
527 new_type = 0;
528 new_size = size + NET_MAX_HEADER;
529 memset( buf, 0, NET_MAX_PACKET );
530 error = osd_net_recv( player, buf, &new_size );
531
532 #ifdef NET_DEBUG
533 {
534 char packet_str[14];
535 net_packet_type_to_string( type, packet_str );
536 dprintf(("net_recv: %s, size(%d)\n", packet_str, new_size ))
537 }
538 #endif
539
540 memcpy( &new_type, buf, NET_MAX_HEAD_TYPE );
541
542 /* also check packet type to see that we got what we wanted*/
543 if ( new_type != type )
544 {
545 /* if we initiated a quit, we don't care about what we received */
546 /* TODO: check type against a mask to see if we care instead of long if block... */
547 if ( ( type == NET_QUIT_QUIT ) || ( type == NET_QUIT_ABRT ) || ( type == NET_QUIT_OKAY ) )
548 {
549 return 0; /* leave buffer alone */
550 }
551
552 /* error condition, see if we can handle new_type and recover */
553 error = 1;
554 switch ( new_type )
555 {
556 /* check for reset */
557 case NET_SYNC_INIT:
558 case NET_SYNC_REDO:
559 /* TODO: reset */
560 return 0;
561
562 /* check for pause */
563 case NET_SYNC_PAWS:
564 /* TODO: wait for another paws */
565 goto net_recv_again;
566
567 /* quit conditions */
568 case NET_QUIT_QUIT:
569 case NET_QUIT_ABRT:
570 case NET_QUIT_OKAY:
571 printf( "we've detected a quit or abort\n" );
572 /* leave buffer alone - do not use merged buffer*/
573 return net_remove_player( player );
574
575 /* this should never happen - but does */
576 /*TODO: handle this instead of dropping player */
577 case NET_0NOT_USED:
578 printf( "bad data received - aborting player\n" );
579 {
580 char expected_packet_str[14];
581 char received_packet_str[14];
582 net_packet_type_to_string( type, expected_packet_str );
583 net_packet_type_to_string( new_type, received_packet_str );
584 dprintf(("net_recv: received packet:%s not expected:%s\n", received_packet_str, expected_packet_str ))
585 }
586 /* leave buffer alone - do not use merged buffer*/
587 return net_remove_player( player );
588
589 default:
590 {
591 char expected_packet_str[14];
592 char received_packet_str[14];
593 net_packet_type_to_string( type, expected_packet_str );
594 net_packet_type_to_string( new_type, received_packet_str );
595 printf( "net_recv: received packet:%s not expected:%s\n", received_packet_str, expected_packet_str );
596 /* leave buffer alone - do not use merged buffer*/
597 return error;
598 }
599 }
600 }
601
602 /* copy received buffer back into expected location */
603 memcpy( msg, (buf+NET_MAX_HEADER), (new_size-NET_MAX_HEADER) );
604
605 return error;
606
607 }
608
net_add_player()609 int net_add_player()
610 {
611 dprintf(("net_add_player()\n"))
612 /* TODO: make this also work for client for consistency */
613
614 /* check if osd adding a client failed */
615 if ( ( num_clients = osd_net_add_player() ) < 0 )
616 {
617 dprintf(("osd_net_add_player() - FAILED\n"))
618 return -1;
619 }
620
621 /* if it succeeded then we check the version */
622 if ( net_vers_check( num_clients-1 ) )
623 {
624 dprintf(("net_vers_check() - FAILED\n"))
625 return -1;
626 }
627
628 /* TODO: need to shift player info around (currently just sockets - eventually input assignments too ) */
629 /* TODO: setup player names and such */
630 dprintf(("net_add_player() num_clients = %d\n", num_clients))
631 return num_clients; /* we return the new total number of clients */
632 }
633
net_remove_player(int player)634 int net_remove_player( int player )
635 {
636 dprintf(("net_remove_player(%d)\n", player ))
637
638 /* TODO: need to shift player info around (currently just sockets - eventually input assignments too ) */
639 if ( is_client )
640 {
641 net_exit( NET_QUIT_OKAY );
642 return 0;
643 }
644 else
645 {
646 int new_players = osd_net_remove_player( player );
647 /* TODO: need to allow server to remain active */
648 if ( new_players == 0 )
649 net_exit( NET_QUIT_OKAY );
650
651 return new_players;
652 }
653 }
654
655 /* Only returns true if the net is initialized and we are playing a game */
net_active()656 int net_active()
657 {
658 #ifdef NET_DEBUG
659 static int last = 0;
660 static int iactive = 0;
661 static int igame = 0;
662
663 if (iactive != is_active || igame != in_game)
664 {
665 iactive = is_active;
666 igame = in_game;
667 last = (iactive && igame);
668 dprintf(("net_active() = %s is_active = %s, in_game = %s\n",
669 (last) ? "TRUE" : "FALSE",
670 (iactive) ? "TRUE" : "FALSE",
671 (igame) ? "TRUE" : "FALSE"))
672 }
673 #endif
674 return (is_active && in_game);
675 }
676
net_packet_type_to_string(char type,char packet_type_str[])677 static void net_packet_type_to_string( char type, char packet_type_str[] )
678 {
679 switch ( type )
680 {
681 case NET_INIT_INIT:
682 strcpy( packet_type_str, "NET_INIT_INIT" );
683 break;
684 case NET_INIT_VERS:
685 strcpy( packet_type_str, "NET_INIT_VERS" );
686 break;
687 case NET_INIT_GAME:
688 strcpy( packet_type_str, "NET_INIT_GAME" );
689 break;
690 case NET_SYNC_INIT:
691 strcpy( packet_type_str, "NET_SYNC_INIT" );
692 break;
693 case NET_SYNC_INPT:
694 strcpy( packet_type_str, "NET_SYNC_INPT" );
695 break;
696 case NET_SYNC_ANLG:
697 strcpy( packet_type_str, "NET_SYNC_ANLG" );
698 break;
699 case NET_SYNC_USER:
700 strcpy( packet_type_str, "NET_SYNC_USER" );
701 break;
702 case NET_SYNC_BOOM:
703 strcpy( packet_type_str, "NET_SYNC_BOOM" );
704 break;
705 case NET_SYNC_REDO:
706 strcpy( packet_type_str, "NET_SYNC_REDO" );
707 break;
708 case NET_QUIT_QUIT:
709 strcpy( packet_type_str, "NET_QUIT_QUIT" );
710 break;
711 case NET_QUIT_ABRT:
712 strcpy( packet_type_str, "NET_QUIT_ABRT" );
713 break;
714 case NET_QUIT_OKAY:
715 strcpy( packet_type_str, "NET_QUIT_OKAY" );
716 break;
717 case NET_CHAT_INIT:
718 strcpy( packet_type_str, "NET_CHAT_INIT" );
719 break;
720 case NET_CHAT_CHAT:
721 strcpy( packet_type_str, "NET_CHAT_CHAT" );
722 break;
723 case NET_CHAT_QUIT:
724 strcpy( packet_type_str, "NET_CHAT_QUIT" );
725 break;
726 case NET_0NOT_USED:
727 strcpy( packet_type_str, "NET_0NOT_USED" );
728 break;
729 default:
730 strcpy( packet_type_str, "UNRECOGNIZED!" );
731 break;
732 }
733 }
734
net_chat_send(unsigned char * msg,int * size)735 int net_chat_send( unsigned char *msg, int *size )
736 {
737 net_send( 0, NET_CHAT_CHAT, msg, *size );
738 return 0;
739 }
740
net_chat_recv(int player,unsigned char * msg,int * size)741 int net_chat_recv(int player, unsigned char *msg, int *size )
742 {
743 net_recv( player, NET_CHAT_CHAT, msg, *size );
744 return 0;
745 }
746
747 #endif /* MAME_NET */
748