389 lines
7.5 KiB
C
389 lines
7.5 KiB
C
/*
|
|
Copyright (C) 1994-1995 Apogee Software, Ltd.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
// ipxnet.c
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dos.h>
|
|
#include <string.h>
|
|
#include <process.h>
|
|
#include <values.h>
|
|
|
|
#include "..\rottnet.h"
|
|
#include "ipxnet.h"
|
|
#include "ipxsetup.h"
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
IPX PACKET DRIVER
|
|
|
|
=============================================================================
|
|
*/
|
|
|
|
|
|
packet_t * packets[MAXPACKETS];
|
|
|
|
nodeadr_t nodeadr[MAXNETNODES+1]; // first is local, last is broadcast
|
|
|
|
nodeadr_t remoteadr; // set by each GetPacket
|
|
|
|
localadr_t localadr; // set at startup
|
|
|
|
void far (*IPX)(void);
|
|
|
|
long ipxlocaltime; // for time stamp in packets
|
|
long remotetime;
|
|
int numnetpackets=NUMPACKETS;
|
|
|
|
//===========================================================================
|
|
void AllocatePackets( void )
|
|
{
|
|
int i;
|
|
|
|
if (server==true)
|
|
numnetpackets=NUMPACKETSPERPLAYER*numnetnodes;
|
|
else
|
|
numnetpackets=NUMPACKETS;
|
|
|
|
if (numnetpackets>MAXPACKETS)
|
|
numnetpackets=MAXPACKETS;
|
|
|
|
for (i=0;i<numnetpackets;i++)
|
|
{
|
|
packets[i]=(packet_t *)malloc(sizeof(packet_t));
|
|
if (packets[i]==NULL)
|
|
Error("Failed on allocation of packet %d\n",i);
|
|
memset (packets[i],0,sizeof(packet_t));
|
|
}
|
|
}
|
|
|
|
void DeAllocatePackets ( void )
|
|
{
|
|
int i;
|
|
|
|
for (i=0;i<numnetpackets;i++)
|
|
{
|
|
if (packets[i])
|
|
free(packets[i]);
|
|
}
|
|
}
|
|
|
|
int OpenSocket(short socketNumber)
|
|
{
|
|
_DX = socketNumber;
|
|
_BX = 0;
|
|
_AL = 0;
|
|
IPX();
|
|
if(_AL)
|
|
Error ("OpenSocket: 0x%x", _AL);
|
|
return _DX;
|
|
}
|
|
|
|
|
|
void CloseSocket(short socketNumber)
|
|
{
|
|
_DX = socketNumber;
|
|
_BX = 1;
|
|
IPX();
|
|
}
|
|
|
|
void ListenForPacket(ECB *ecb)
|
|
{
|
|
_SI = FP_OFF(ecb);
|
|
_ES = FP_SEG(ecb);
|
|
_BX = 4;
|
|
IPX();
|
|
if(_AL)
|
|
Error ("ListenForPacket: 0x%x", _AL);
|
|
}
|
|
|
|
|
|
void GetLocalAddress (void)
|
|
{
|
|
_SI = FP_OFF(&localadr);
|
|
_ES = FP_SEG(&localadr);
|
|
_BX = 9;
|
|
IPX();
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
====================
|
|
=
|
|
= InitNetwork
|
|
=
|
|
====================
|
|
*/
|
|
|
|
void InitNetwork (void)
|
|
{
|
|
int i,j;
|
|
long socket;
|
|
|
|
//
|
|
// get IPX function address
|
|
//
|
|
_AX = 0x7a00;
|
|
geninterrupt(0x2f);
|
|
if(_AL != 0xff)
|
|
Error ("IPX not detected\n");
|
|
IPX = MK_FP(_ES, _DI);
|
|
|
|
AllocatePackets();
|
|
|
|
//
|
|
// allocate a socket for sending and receiving
|
|
//
|
|
socketid = OpenSocket ( (socketid>>8) + ((socketid&255)<<8) );
|
|
|
|
GetLocalAddress();
|
|
|
|
for (i=1 ; i<numnetpackets ; i++)
|
|
{
|
|
packets[i]->ecb.ECBSocket = socketid;
|
|
packets[i]->ecb.FragmentCount = 1;
|
|
packets[i]->ecb.fAddress[0] = FP_OFF(&(packets[i]->ipx));
|
|
packets[i]->ecb.fAddress[1] = FP_SEG(&(packets[i]->ipx));
|
|
packets[i]->ecb.fSize = sizeof(packet_t)-sizeof(ECB);
|
|
|
|
ListenForPacket (&(packets[i]->ecb));
|
|
}
|
|
|
|
//
|
|
// set up a sending ECB
|
|
//
|
|
|
|
packets[0]->ecb.ECBSocket = socketid;
|
|
packets[0]->ecb.FragmentCount = 2;
|
|
packets[0]->ecb.fAddress[0] = FP_OFF(&(packets[0]->ipx));
|
|
packets[0]->ecb.fAddress[1] = FP_SEG(&(packets[0]->ipx));
|
|
for (j=0 ; j<4 ; j++)
|
|
packets[0]->ipx.dNetwork[j] = localadr.network[j];
|
|
packets[0]->ipx.dSocket[0] = socketid&255;
|
|
packets[0]->ipx.dSocket[1] = socketid>>8;
|
|
packets[0]->ecb.f2Address[0] = FP_OFF(&rottcom.data);
|
|
packets[0]->ecb.f2Address[1] = FP_SEG(&rottcom.data);
|
|
|
|
// known local node at 0
|
|
for (i=0 ; i<6 ; i++)
|
|
nodeadr[0].node[i] = localadr.node[i];
|
|
|
|
// broadcast node at MAXNETNODES
|
|
for (j=0 ; j<6 ; j++)
|
|
nodeadr[MAXNETNODES].node[j] = 0xff;
|
|
printf("\nIPX Network Initialized\n");
|
|
socket=(unsigned)socketid;
|
|
socket=(socket>>8) + ((socket&255)<<8);
|
|
printf("Using socket number 0x%x\n\n", socket );
|
|
}
|
|
|
|
|
|
/*
|
|
====================
|
|
=
|
|
= ShutdownNetwork
|
|
=
|
|
====================
|
|
*/
|
|
|
|
void ShutdownNetwork (void)
|
|
{
|
|
if (IPX)
|
|
CloseSocket (socketid);
|
|
DeAllocatePackets ();
|
|
}
|
|
|
|
|
|
/*
|
|
==============
|
|
=
|
|
= SendPacket
|
|
=
|
|
= A destination of MAXNETNODES is a broadcast
|
|
==============
|
|
*/
|
|
|
|
void SendPacket (int destination)
|
|
{
|
|
int j;
|
|
|
|
// set the time
|
|
packets[0]->time = ipxlocaltime;
|
|
|
|
// set the address
|
|
for (j=0 ; j<6 ; j++)
|
|
packets[0]->ipx.dNode[j] =
|
|
packets[0]->ecb.ImmediateAddress[j] =
|
|
nodeadr[destination].node[j];
|
|
|
|
// set the length (ipx + time + datalength)
|
|
packets[0]->ecb.fSize = sizeof(IPXPacket) + 4;
|
|
packets[0]->ecb.f2Size = rottcom.datalength + 4;
|
|
|
|
// send the packet
|
|
_SI = FP_OFF(packets[0]);
|
|
_ES = FP_SEG(packets[0]);
|
|
_BX = 3;
|
|
IPX();
|
|
if (_AL)
|
|
Error("SendPacket: 0x%x", _AL);
|
|
|
|
while(packets[0]->ecb.InUseFlag != 0)
|
|
{
|
|
// IPX Relinquish Control - polled drivers MUST have this here!
|
|
_BX = 10;
|
|
IPX();
|
|
}
|
|
}
|
|
|
|
|
|
unsigned short ShortSwap (unsigned short i)
|
|
{
|
|
return ((i&255)<<8) + ((i>>8)&255);
|
|
}
|
|
|
|
/*
|
|
==============
|
|
=
|
|
= GetPacket
|
|
=
|
|
= Returns false if no packet is waiting
|
|
=
|
|
==============
|
|
*/
|
|
|
|
int GetPacket (void)
|
|
{
|
|
int packetnum;
|
|
int i;
|
|
long besttic;
|
|
packet_t *packet;
|
|
|
|
// if multiple packets are waiting, return them in order by time
|
|
|
|
besttic = MAXLONG;
|
|
packetnum = -1;
|
|
rottcom.remotenode = -1;
|
|
|
|
for ( i = 1 ; i < numnetpackets ; i++)
|
|
{
|
|
if (packets[i]->ecb.InUseFlag)
|
|
continue;
|
|
|
|
if (packets[i]->time < besttic)
|
|
{
|
|
besttic = packets[i]->time;
|
|
packetnum = i;
|
|
}
|
|
}
|
|
|
|
if (besttic == MAXLONG)
|
|
return 0; // no packets
|
|
|
|
packet = packets[packetnum];
|
|
|
|
if (besttic == -1 && ipxlocaltime != -1)
|
|
{
|
|
ListenForPacket (&packet->ecb);
|
|
return 0; // setup broadcast from other game
|
|
}
|
|
|
|
remotetime = besttic;
|
|
|
|
//
|
|
// got a good packet
|
|
//
|
|
if (packet->ecb.CompletionCode)
|
|
Error ("GetPacket: ecb.ComletionCode = 0x%x",packet->ecb.CompletionCode);
|
|
|
|
// set remoteadr to the sender of the packet
|
|
memcpy (&remoteadr, packet->ipx.sNode, sizeof(remoteadr));
|
|
for (i=0 ; i<=rottcom.numplayers ; i++)
|
|
if (!memcmp(&remoteadr, &nodeadr[i], sizeof(remoteadr)))
|
|
break;
|
|
if (i <= rottcom.numplayers)
|
|
rottcom.remotenode = i;
|
|
else
|
|
{
|
|
if (ipxlocaltime != -1)
|
|
{ // this really shouldn't happen
|
|
ListenForPacket (&packet->ecb);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// copy out the data
|
|
rottcom.datalength = ShortSwap(packet->ipx.PacketLength) - 38;
|
|
memcpy (&rottcom.data, &packet->data, rottcom.datalength);
|
|
|
|
// repost the ECB
|
|
ListenForPacket (&packet->ecb);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|