/* 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 #include #include #include #include #include #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>8) + ((socketid&255)<<8) ); GetLocalAddress(); for (i=1 ; iecb.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; }