// ipxnet.c #include #include #include #include #include #include #include "ipxnet.h" /* ============================================================================= IPX PACKET DRIVER ============================================================================= */ packet_t packets[NUMPACKETS]; nodeadr_t nodeadr[MAXNETNODES+1]; // first is local, last is broadcast nodeadr_t remoteadr; // set by each GetPacket localadr_t localadr; // set at startup int socketid = 0x869c; // 0x869c is the official DOOM socket union REGS regs; // scratch for int86 calls struct SREGS sregs; unsigned short enteripx[2]; long localtime; // for time stamp in packets long remotetime; //=========================================================================== char *hex = "0123456789abcdef"; void PrintAddress (nodeadr_t *adr, char *str) { int i; for (i=0 ; i<6 ; i++) { *str++ = hex[adr->node[i]>>4]; *str++ = hex[adr->node[i]&15]; } *str = 0; } int OpenSocket(short socketNumber) { regs.x.bx = 0; regs.h.al = 0; // longevity regs.x.dx = socketNumber; int86(0x7A,®s,®s); if (regs.h.al) Error ("OpenSocket: 0x%x",regs.h.al); return regs.x.dx; } void CloseSocket(short socketNumber) { regs.x.bx = 1; regs.x.dx = socketNumber; int86(0x7A,®s,®s); } void ListenForPacket(ECB *ecb) { regs.x.si = FP_OFF(ecb); sregs.es = FP_SEG(ecb); regs.x.bx = 4; int86x (0x7a,®s,®s,&sregs); if (regs.h.al) Error ("ListenForPacket: 0x%x",regs.h.al); } void GetLocalAddress (void) { regs.x.si = FP_OFF(&localadr); sregs.es = FP_SEG(&localadr); regs.x.bx = 9; int86x (0x7a,®s,®s,&sregs); if (regs.h.al) Error ("Get inet addr: 0x%x",regs.h.al); } /* ==================== = = InitNetwork = ==================== */ void InitNetwork (void) { int i,j; // // get IPX function address // regs.x.ax = 0x7a00; int86x (0x2f,®s,®s,&sregs); if ( regs.h.al != 0xff) Error ("IPX not detected\n"); enteripx[0] = regs.x.di; enteripx[1] = sregs.es; // // allocate a socket for sending and receiving // i = CheckParm ("-port"); if (i>0 && i<_argc-1) { socketid = atoi (_argv[i+1]); printf ("Using alternate port %i for network\n",socketid); } socketid = OpenSocket ( (socketid>>8) + ((socketid&255)<<8) ); GetLocalAddress (); // // set up several receiving ECBs // memset (packets,0,NUMPACKETS*sizeof(packet_t)); for (i=1 ; i>8; // 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; } /* ==================== = = ShutdownNetwork = ==================== */ void ShutdownNetwork (void) { CloseSocket (socketid); } /* ============== = = SendPacket = = A destination of MAXNETNODES is a broadcast ============== */ void SendPacket (int destination) { int j; // find a free packet buffer to use while (packets[0].ecb.InUseFlag) { } // set the time packets[0].time = localtime; // 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 + doomcom.datalength + 4; // put the data into an ipx packet memcpy (&packets[0].data, &doomcom.data, doomcom.datalength); // send the packet regs.x.si = FP_OFF(&packets[0]); sregs.es = FP_SEG(&packets[0]); regs.x.bx = 3; int86x (0x7a, ®s, ®s, &sregs); if (regs.h.al) Error ("SendPacket: 0x%x",regs.h.al); } 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, j; long besttic; packet_t *packet; // if multiple packets are waiting, return them in order by time besttic = MAXLONG; packetnum = -1; doomcom.remotenode = -1; for ( i = 1 ; i < NUMPACKETS ; 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 && localtime != -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 ; iecb); return 0; } } // copy out the data doomcom.datalength = ShortSwap(packet->ipx.PacketLength) - 38; memcpy (&doomcom.data, &packet->data, doomcom.datalength); // repost the ECB ListenForPacket (&packet->ecb); return 1; }