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