1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26
27 #ifdef DOS
28 #include <conio.h>
29 #include <dos.h>
30 #include <process.h>
31 #include <bios.h>
32 #endif
33
34 #include "rt_def.h"
35 #include "_rt_com.h"
36 #include "rt_com.h"
37 #include "rt_util.h"
38 #include "rt_in.h"
39 #include "rt_crc.h"
40 #include "rt_playr.h"
41 #include "isr.h"
42 #include "rt_msg.h"
43 #include "rottnet.h"
44 #include "rt_main.h"
45 #include "rt_net.h"
46 #include "rt_draw.h"
47 //#include "rt_ser.h"
48 //MED
49 #include "memcheck.h"
50
51 // GLOBAL VARIABLES
52
53 // Same as in real mode
54 rottcom_t * rottcom;
55 int badpacket;
56 int consoleplayer;
57 byte ROTTpacket[MAXCOMBUFFERSIZE];
58 int controlsynctime;
59
60 // LOCAL VARIABLES
61 #ifdef DOS
62 static union REGS comregs;
63 #endif
64
65 static int ComStarted=false;
66 static int transittimes[MAXPLAYERS];
67
68 void SyncTime( int client );
69 void SetTransitTime( int client, int time );
70
71 #ifdef PLATFORM_UNIX
72
73 static int sock = -1;
74
ReadUDPPacket()75 static void ReadUDPPacket()
76 {
77 rottcom->remotenode = -1;
78 }
79
WriteUDPPacket()80 static void WriteUDPPacket()
81 {
82 }
83
84 #endif
85
86 /*
87 ===============
88 =
89 = InitROTTNET
90 =
91 ===============
92 */
93
InitROTTNET(void)94 void InitROTTNET (void)
95 {
96 int netarg;
97 long netaddress;
98
99 if (ComStarted==true)
100 return;
101 ComStarted=true;
102
103 #ifdef DOS
104 netarg=CheckParm ("net");
105 netarg++;
106
107 netaddress=atol(_argv[netarg]);
108 rottcom=(rottcom_t *)netaddress;
109 #elif defined(PLATFORM_UNIX)
110 /*
111 server-specific options:
112 -net: enables netplay
113 -server: run as rott server (default port 34858)
114 -port: select a non-default port for server
115 -host: select a non-default ip address to bind to
116 -standalone: run as standalone server
117 -remoteridicule: enable remote ridicule
118 -players: number of players to expect
119
120 client-specific options:
121 -master: request to have control
122 -net: specifies the host to connect to
123 -port: select a non-default port to connect to
124 */
125
126 rottcom = (rottcom_t *) malloc (sizeof(rottcom_t));
127 memset(rottcom, 0, sizeof(rottcom_t));
128
129 rottcom->ticstep = 1;
130 rottcom->gametype = 1;
131 rottcom->remotenode = -1;
132
133 if (CheckParm("server")) {
134 if (CheckParm("standalone")) {
135 rottcom->consoleplayer = 0;
136 } else {
137 rottcom->consoleplayer = 1;
138 }
139
140 if (CheckParm("remoteridicule")) {
141 rottcom->remoteridicule = 1;
142 } else {
143 rottcom->remoteridicule = 0;
144 }
145
146 netarg = CheckParm("players");
147 if (netarg && netarg < _argc-1) {
148 rottcom->numplayers = atoi(_argv[netarg+1]);
149 } else {
150 rottcom->numplayers = 2;
151 }
152
153 rottcom->client = 0;
154 } else {
155 rottcom->client = 1;
156
157 /* consoleplayer will be initialized after connecting */
158 /* numplayers will be initialized after connecting */
159 /* remoteridicule will be initialized after connecting */
160 }
161
162 /* client-server negotiation protocol, as inspired by ipxsetup.c */
163 /*
164 Best case:
165 client sends a HereIAm packet.
166 server replies with a YouAre packet, and broadcasts an Info packet
167 to the rest, indicating that the new player has joined.
168 client replies with an IAm packet
169 until all players have joined, the server broadcasts an Info packet
170 to the rest, indicating that another player is needed.
171 once server has enough players, it broadcasts an AllDone packet.
172
173 In detail:
174 Client state: HereIAm (initial connection)
175 Client sends HereIAm packet, waits for YouAre from server.
176 At timeout, Client resends HereIam
177 When client receives YouAre, client switches to IAm state
178
179 Client state: IAm
180 Client sends IAm packet, waits for IAmAck from server.
181 At timeout, Client resends IAm
182 When client receives IAmAck, client switches to WaitForDone state.
183
184 Client state: WaitForDone
185 Client waits for AllDone packet.
186 When client receives AllDone, it sends an AllDoneAck.
187 */
188
189 #endif
190
191 remoteridicule = false;
192 remoteridicule = rottcom->remoteridicule;
193 if (rottcom->ticstep != 1)
194 remoteridicule = false;
195 if (remoteridicule == true)
196 {
197 if (!quiet)
198 printf("ROTTNET: LIVE Remote Ridicule Enabled\n");
199 }
200
201 if (!quiet)
202 {
203 #ifdef DOS
204 printf("ROTTNET: Communicating on vector %ld\n",(long int)rottcom->intnum);
205 #endif
206 printf("ROTTNET: consoleplayer=%ld\n",(long int)rottcom->consoleplayer);
207 }
208 }
209
210 /*
211 ================
212 =
213 = ReadPacket
214 =
215 ================
216 */
217
ReadPacket(void)218 boolean ReadPacket (void)
219 {
220 word crc;
221 word sentcrc;
222
223 // Set command (Get Packet)
224 rottcom->command=CMD_GET;
225
226 badpacket = 0;
227
228 // Check to see if a packet is ready
229
230 #ifdef DOS
231 int386(rottcom->intnum,&comregs,&comregs);
232 #elif PLATFORM_UNIX
233 ReadUDPPacket();
234 #endif
235
236 // Is it ready?
237
238 if (rottcom->remotenode!=-1)
239 {
240 // calculate crc on packet
241 crc=CalculateCRC (&rottcom->data[0], rottcom->datalength-sizeof(word));
242
243 // get crc inside packet
244 sentcrc=*((word *)(&rottcom->data[rottcom->datalength-sizeof(word)]));
245
246 // are the crcs the same?
247 if (crc!=sentcrc)
248 {
249 badpacket=1;
250 SoftError("BADPKT at %ld\n",GetTicCount());
251 }
252 if (networkgame==false)
253 {
254 rottcom->remotenode=server;
255 }
256 else
257 {
258 if ((IsServer==true) && (rottcom->remotenode>0))
259 rottcom->remotenode--;
260 }
261 memcpy(&ROTTpacket[0], &rottcom->data[0], rottcom->datalength);
262
263 // SoftError( "ReadPacket: time=%ld size=%ld src=%ld type=%d\n",GetTicCount(), rottcom->datalength,rottcom->remotenode,rottcom->data[0]);
264
265 #if 0
266 rottcom->command=CMD_OUTQUEBUFFERSIZE;
267 int386(rottcom->intnum,&comregs,&comregs);
268 SoftError( "outque size=%ld\n",*((short *)&(rottcom->data[0])));
269 rottcom->command=CMD_INQUEBUFFERSIZE;
270 int386(rottcom->intnum,&comregs,&comregs);
271 SoftError( "inque size=%ld\n",*((short *)&(rottcom->data[0])));
272 #endif
273 return true;
274 }
275 else // Not ready yet....
276 return false;
277 }
278
279
280 /*
281 =============
282 =
283 = WritePacket
284 =
285 =============
286 */
287
WritePacket(void * buffer,int len,int destination)288 void WritePacket (void * buffer, int len, int destination)
289 {
290 word crc;
291
292 // set send command
293 rottcom->command=CMD_SEND;
294
295 // set destination
296 rottcom->remotenode=destination;
297
298 if (len>(int)(MAXCOMBUFFERSIZE-sizeof(word)))
299 {
300 Error("WritePacket: Overflowed buffer\n");
301 }
302
303 // copy local buffer into realmode buffer
304 memcpy((byte *)&(rottcom->data[0]),(byte *)buffer,len);
305
306 // calculate CRC
307 crc=CalculateCRC (buffer, len);
308
309 // put CRC into realmode buffer packet
310 *((word *)&rottcom->data[len])=crc;
311
312 // set size of realmode packet including crc
313 rottcom->datalength=len+sizeof(word);
314
315 if (*((byte *)buffer)==0)
316 Error("Packet type = 0\n");
317
318 if (networkgame==true)
319 {
320 if (IsServer==true)
321 rottcom->remotenode++; // server fix-up
322 }
323
324 // SoftError( "WritePacket: time=%ld size=%ld src=%ld type=%d\n",GetTicCount(),rottcom->datalength,rottcom->remotenode,rottcom->data[0]);
325 // Send It !
326 #ifdef DOS
327 int386(rottcom->intnum,&comregs,&comregs);
328 #elif PLATFORM_UNIX
329 WriteUDPPacket();
330 #endif
331
332 #if 0
333 rottcom->command=CMD_OUTQUEBUFFERSIZE;
334 int386(rottcom->intnum,&comregs,&comregs);
335 SoftError( "outque size=%ld\n",*((short *)&(rottcom->data[0])));
336 rottcom->command=CMD_INQUEBUFFERSIZE;
337 int386(rottcom->intnum,&comregs,&comregs);
338 SoftError( "inque size=%ld\n",*((short *)&(rottcom->data[0])));
339 #endif
340 }
341
342
343
344
345 /*
346 =============
347 =
348 = ValidSyncPacket
349 =
350 =============
351 */
ValidSyncPacket(synctype * sync)352 boolean ValidSyncPacket ( synctype * sync )
353 {
354 if (ReadPacket() && (badpacket==0))
355 {
356 if (((syncpackettype *)&(ROTTpacket[0]))->type==COM_SYNC)
357 {
358 memcpy(&(sync->pkt),&(ROTTpacket[0]),sizeof(sync->pkt));
359 return true;
360 }
361 }
362 return false;
363 }
364
365 /*
366 =============
367 =
368 = SendSyncPacket
369 =
370 =============
371 */
SendSyncPacket(synctype * sync,int dest)372 void SendSyncPacket ( synctype * sync, int dest)
373 {
374 sync->pkt.type=COM_SYNC;
375 sync->sendtime=GetTicCount();
376 WritePacket( &(sync->pkt.type) , sizeof(syncpackettype) , dest );
377 }
378
379
380 /*
381 =============
382 =
383 = SlavePhaseHandler
384 =
385 =============
386 */
387
SlavePhaseHandler(synctype * sync)388 boolean SlavePhaseHandler( synctype * sync )
389 {
390 boolean done;
391
392 done=false;
393
394 switch (sync->pkt.phase)
395 {
396 case SYNC_PHASE1:
397 break;
398 case SYNC_PHASE2:
399 ISR_SetTime(sync->pkt.clocktime);
400 break;
401 case SYNC_PHASE3:
402 sync->pkt.clocktime=GetTicCount();
403 break;
404 case SYNC_PHASE4:
405 ISR_SetTime(GetTicCount()-sync->pkt.delta);
406 sync->pkt.clocktime=GetTicCount();
407 break;
408 case SYNC_PHASE5:
409 ISR_SetTime(GetTicCount()-sync->pkt.delta);
410 sync->sendtime=sync->pkt.clocktime;
411 done=true;
412 break;
413 }
414 return done;
415 }
416
417
418
419 /*
420 =============
421 =
422 = MasterPhaseHandler
423 =
424 =============
425 */
426
MasterPhaseHandler(synctype * sync)427 boolean MasterPhaseHandler( synctype * sync )
428 {
429 boolean done;
430
431 done=false;
432
433 switch (sync->pkt.phase)
434 {
435 case SYNC_PHASE1:
436 sync->pkt.phase=SYNC_PHASE2;
437 sync->pkt.clocktime=GetTicCount()+(sync->deltatime>>1);
438 break;
439 case SYNC_PHASE2:
440 sync->pkt.phase=SYNC_PHASE3;
441 break;
442 case SYNC_PHASE3:
443 sync->pkt.delta=sync->pkt.clocktime-GetTicCount()+(sync->deltatime>>1);
444 sync->pkt.phase=SYNC_PHASE4;
445 break;
446 case SYNC_PHASE4:
447 sync->pkt.phase=SYNC_PHASE5;
448 sync->pkt.delta=sync->pkt.clocktime-GetTicCount()+(sync->deltatime>>1);
449 sync->sendtime=GetTicCount()+SYNCTIME;
450 sync->pkt.clocktime=sync->sendtime;
451 done=true;
452 break;
453 }
454 return done;
455 }
456
457
458 /*
459 =============
460 =
461 = ComSetTime
462 =
463 =============
464 */
465
ComSetTime(void)466 void ComSetTime ( void )
467 {
468 int i;
469 syncpackettype * syncpacket;
470 boolean done=false;
471
472 syncpacket=(syncpackettype *)SafeMalloc(sizeof(syncpackettype));
473
474
475 // Sync clocks
476
477 if (networkgame==true)
478 {
479 if (IsServer==true)
480 {
481 for (i=0;i<numplayers;i++)
482 {
483 if (PlayerInGame(i)==false)
484 continue;
485 if (standalone==true)
486 SyncTime(i);
487 else if (i!=consoleplayer)
488 SyncTime(i);
489 if (standalone==true)
490 printf("ComSetTime: player#%ld\n",(long int)i);
491 }
492 }
493 else
494 {
495 SyncTime(0);
496 }
497 }
498 else // Modem 2-player game
499 {
500 if (consoleplayer==0)
501 SyncTime(server);
502 else
503 SyncTime(server);
504 }
505
506 if ( ( (networkgame==true) && (IsServer==true) ) ||
507 ( (networkgame==false) && (consoleplayer==0) )
508 ) // Master/Server
509 {
510 int nump;
511 int time;
512
513 syncpacket->type=COM_START;
514 syncpacket->clocktime=GetTicCount();
515 controlsynctime=syncpacket->clocktime;
516 if (networkgame==true)
517 nump=numplayers;
518 else
519 nump=1;
520
521 time = GetTicCount();
522
523 for (i=0;i<nump;i++)
524 {
525 WritePacket( &(syncpacket->type) , sizeof(syncpackettype) , i );
526 }
527
528 while (GetTicCount()<time+(VBLCOUNTER/4)) ;
529
530 for (i=0;i<nump;i++)
531 {
532 WritePacket( &(syncpacket->type) , sizeof(syncpackettype) , i );
533 }
534
535 if (standalone==true)
536 printf("ComSetTime: Start packets sent\n");
537 }
538 else // Slave/Client
539 {
540 while (done==false)
541 {
542 AbortCheck("ComSetTime aborted as client");
543
544 if (ReadPacket() && (badpacket==0))
545 {
546 memcpy(syncpacket,&(ROTTpacket[0]),sizeof(syncpackettype));
547 if (syncpacket->type==COM_START)
548 {
549 controlsynctime=syncpacket->clocktime;
550 done=true;
551 }
552 }
553 }
554 }
555 if (standalone==false)
556 {
557 AddMessage("All players synched.",MSG_SYSTEM);
558 ThreeDRefresh();
559 }
560 SafeFree(syncpacket);
561
562 //
563 // flush out any extras
564 //
565 while (GetTicCount()<controlsynctime+VBLCOUNTER)
566 {
567 ReadPacket ();
568 }
569 }
570
571 /*
572 =============
573 =
574 = InitialMasterSync
575 =
576 =============
577 */
InitialMasterSync(synctype * sync,int client)578 void InitialMasterSync ( synctype * sync, int client )
579 {
580 boolean done=false;
581 int i;
582
583 if (networkgame==true)
584 {
585 for (i=0;i<numplayers;i++)
586 {
587 if (i<=client)
588 continue;
589 sync->pkt.type=COM_SYNC;
590 sync->pkt.phase=SYNC_MEMO;
591 sync->pkt.clocktime=client;
592 SendSyncPacket(sync,i);
593 }
594 }
595
596 // Initialize send time so as soon as we enter the loop, we send
597
598 sync->sendtime=GetTicCount()-SYNCTIME;
599
600 while (done==false)
601 {
602 sync->pkt.phase=SYNC_PHASE0;
603
604 AbortCheck("Initial sync aborted as master");
605 if ((sync->sendtime+SYNCTIME) <= GetTicCount())
606 SendSyncPacket(sync,client);
607 if (ValidSyncPacket(sync)==true)
608 {
609 if (sync->pkt.phase==SYNC_PHASE0)
610 {
611 int time=GetTicCount();
612
613 while (time+SYNCTIME>GetTicCount())
614 {
615 ReadPacket();
616 }
617 time=GetTicCount();
618 while (time+SYNCTIME>GetTicCount()) {}
619 done=true;
620 }
621 }
622 }
623 }
624
625 /*
626 =============
627 =
628 = InitialSlaveSync
629 =
630 =============
631 */
InitialSlaveSync(synctype * sync)632 void InitialSlaveSync ( synctype * sync )
633 {
634 boolean done=false;
635
636 while (done==false)
637 {
638 AbortCheck("Initial sync aborted as slave");
639 if (ValidSyncPacket(sync)==true)
640 {
641 if (sync->pkt.phase==SYNC_MEMO)
642 {
643 char str[50]="Server is synchronizing player ";
644 char str2[10];
645
646 strcat(str,itoa(sync->pkt.clocktime+1,str2,10));
647 AddMessage(str,MSG_SYSTEM);
648 ThreeDRefresh();
649 }
650 if (sync->pkt.phase==SYNC_PHASE0)
651 {
652 int time=GetTicCount();
653
654 SendSyncPacket(sync,server);
655 while (time+SYNCTIME>GetTicCount())
656 {
657 ReadPacket();
658 }
659 done=true;
660 }
661 }
662 }
663 AddMessage("Server is synchronizing your system",MSG_SYSTEM);
664 ThreeDRefresh();
665 }
666
667
668 /*
669 =============
670 =
671 = SyncTime
672 =
673 =============
674 */
675
SyncTime(int client)676 void SyncTime( int client )
677 {
678 int dtime[NUMSYNCPHASES];
679 boolean done;
680 int i;
681 synctype * sync;
682
683 sync=(synctype *)SafeMalloc(sizeof(synctype));
684
685 if ( ((networkgame==true) && (IsServer==true)) ||
686 ((networkgame==false) && (consoleplayer==0)) )
687 {
688 // Master
689
690 InitialMasterSync ( sync, client );
691
692 done=false;
693
694 // Initial setup for Master
695 // Initialize send time so as soon as we enter the loop, we send
696
697 sync->pkt.phase=SYNC_PHASE1;
698 sync->sendtime=GetTicCount()-SYNCTIME;
699
700 while (done==false)
701 {
702 // Master
703
704 AbortCheck("SyncTime aborted as master");
705
706 if ((sync->sendtime+SYNCTIME) <= GetTicCount())
707 SendSyncPacket(sync,client);
708
709 while (ValidSyncPacket(sync)==true)
710 {
711
712 // find average delta
713
714 sync->deltatime=0;
715
716 // calculate last delta
717
718 dtime[sync->pkt.phase]=GetTicCount()-sync->sendtime;
719
720 for (i=0;i<=sync->pkt.phase;i++)
721 sync->deltatime+=dtime[i];
722 if (i!=0)
723 sync->deltatime/=i;
724 else
725 Error("SyncTime: this should not happen\n");
726
727 done = MasterPhaseHandler( sync );
728
729 SendSyncPacket(sync,client);
730
731 }
732 }
733 }
734 else
735 {
736 // Slave
737
738 InitialSlaveSync ( sync );
739
740 done=false;
741
742 while (done==false)
743 {
744 // Slave
745
746 AbortCheck("SyncTime aborted as slave");
747
748 while (ValidSyncPacket(sync)==true)
749 {
750 done = SlavePhaseHandler( sync );
751
752 if (done==false)
753 SendSyncPacket(sync,server);
754
755 }
756 }
757 }
758
759 while (sync->sendtime > GetTicCount())
760 {
761 while (ReadPacket()) {}
762 }
763 while ((sync->sendtime+SYNCTIME) > GetTicCount())
764 {
765 }
766
767 if ( ((networkgame==true) && (IsServer==true)) ||
768 ((networkgame==false) && (consoleplayer==0)) )
769 SetTransitTime( client, (sync->deltatime>>1));
770
771 SafeFree(sync);
772 }
773
774 /*
775 =============
776 =
777 = SetTransitTime
778 =
779 =============
780 */
781
SetTransitTime(int client,int time)782 void SetTransitTime( int client, int time )
783 {
784 transittimes[client]=time;
785 }
786
787 /*
788 =============
789 =
790 = GetTransitTime
791 =
792 =============
793 */
794
GetTransitTime(int client)795 int GetTransitTime( int client )
796 {
797 return transittimes[client];
798 }
799
800