CnC_Remastered_Collection/REDALERT/IPX.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

1165 lines
53 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: /CounterStrike/IPX.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : IPX.CPP *
* *
* Programmer : Barry Nance *
* from Client/Server LAN Programming *
* Westwood-ized by Bill Randolph *
* *
* Start Date : December 14, 1994 *
* *
* Last Update : December 15, 1994 [BR] *
* *
*-------------------------------------------------------------------------*
* Pitfalls: *
* - Never try to use a closed socket; always check the return code from *
* IPX_Open_Socket(). *
* - Always give IPX an outstanding ECB for listening, before you send. *
* - It turns out that IPX is pretty bad about saving registers, so if *
* you have any register variables in your program, they may get *
* trashed. To circumvent this, all functions in this module save & *
* restore the registers before invoking any IPX or NETX function. *
* *
*-------------------------------------------------------------------------*
* Functions: *
* IPX_SPX_Installed -- checks for installation of IPX/SPX *
* IPX_Open_Socket -- opens an IPX socket for sending or receiving *
* IPX_Close_Socket -- closes an open socket *
* IPX_Get_Connection_Number -- gets local Connection Number *
* IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user *
* IPX_Get_Internet_Address -- gets Network Number & Node Address *
* IPX_Get_User_ID -- gets user ID from Connection Number *
* IPX_Listen_For_Packet -- commands IPX to listen for a packet *
* IPX_Send_Packet -- commands IPX to send a packet *
* IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB *
* IPX_Cancel_Event -- cancels an operation in progress *
* Let_IPX_Breath -- gives IPX some CPU time *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#include <stdio.h>
//#include <mem.h>
//#include <i86.h>
#include "ipx.h"
#ifdef WIN32
#include "ipx95.h"
#endif //WIN32
// Turn off "expression is not meaningful".
//#pragma warning 628 9
/***************************************************************************
* IPX_SPX_Installed -- checks for installation of IPX/SPX *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* 0 = not installed; 1 = IPX only, 2 = IPX and SPX are installed *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/14/1994 BR : Created. *
*=========================================================================*/
int IPX_SPX_Installed(void)
{
return false;
#ifdef WIN32
#ifdef TIBERIAN_SUN
return(false);
#else
#if (0)//PG
if ( Load_IPX_Dll () ){
return ( IPX_Initialise() );
}else{
return(false);
}
#endif
#endif
#else //WIN32
union REGS regs;
struct SREGS sregs;
RMIType rmi;
//------------------------------------------------------------------------
// Init all registers to 0's
//------------------------------------------------------------------------
memset (&regs, 0, sizeof(regs));
segread (&sregs);
memset (&rmi, 0, sizeof(rmi));
//------------------------------------------------------------------------
// Fill in registers for the DPMI call, function 0x300
//------------------------------------------------------------------------
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = 0x002f; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//------------------------------------------------------------------------
// Fill in registers for the real-mode interrupt handler.
// To test for the presence of IPX, set AH to 0x7a, AL to 0, and invoke
// interrupt 0x2f (the "multiplex" interrupt). If IPX is installed,
// AL will be 0xff, and ES:DI will contain the IPX/SPX function address.
//------------------------------------------------------------------------
rmi.eax = 0x00007a00;
//------------------------------------------------------------------------
// call DPMI
//------------------------------------------------------------------------
int386x(DPMI_INT, &regs, &regs, &sregs);
//------------------------------------------------------------------------
// If IPX isn't there, return 0
//------------------------------------------------------------------------
if ( (rmi.eax & 0x00ff) != 0xff) {
return(0);
}
//------------------------------------------------------------------------
// Test for SPX by invoking the IPX_SPX function with BX = 0x10, and AL = 0.
// If SPX is present, AL will be 0xff.
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = 0x00000010;
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
//------------------------------------------------------------------------
// SPX is installed; return '2'
//------------------------------------------------------------------------
if ( (rmi.eax & 0x00ff) == 0xff) {
return(2);
}
//------------------------------------------------------------------------
// SPX is not installed; return '1'
//------------------------------------------------------------------------
return(1);
#endif //WIN32
} /* end of IPX_SPX_Installed */
/***************************************************************************
* IPX_Open_Socket -- opens an IPX socket for sending or receiving *
* *
* INPUT: *
* socket the socket number to open *
* *
* OUTPUT: *
* 0 = OK *
* -1 = IPX not installed *
* 0xfe = socket table is full *
* 0xff = socket is already open *
* *
* WARNINGS: *
* The application must define its socket number carefully. Use *
* values from 0x4000 to 0x8000 for custom socket numbers. The app *
* must know its own socket number as well as the socket number of *
* a destination workstation. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Open_Socket(unsigned short socket)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
int rc;
//------------------------------------------------------------------------
// Open the socket:
// DX = socket number
// AL = 0 for short-lived socket, 0xff for long-lived socket
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG (&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF (&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = IPX_OPEN_SOCKET; // function code
rmi.edx = socket; // desired socket #
rmi.eax = 0x00ff; // make this a long-lived socket
//........................................................................
// call DPMI
//........................................................................
int386x (DPMI_INT, &regs, &regs, &sregs);
rc = (rmi.eax & 0xff);
return(rc);
} /* end of IPX_Open_Socket */
#endif //WIN32
/***************************************************************************
* IPX_Close_Socket -- closes an open socket *
* *
* INPUT: *
* socket socket number to close *
* *
* OUTPUT: *
* 0 = ok, -1 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Close_Socket(unsigned short socket)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
//------------------------------------------------------------------------
// Close the socket:
// DX = socket number
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = IPX_CLOSE_SOCKET;
rmi.edx = socket;
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
return(0);
} /* end of IPX_Close_Socket */
#endif //WIN32
/***************************************************************************
* IPX_Get_Connection_Number -- gets local Connection Number *
* *
* This Novell call will the return the user's local "Connection Number". *
* This value will be 0 if the user isn't logged into Novell, so this *
* routine can be used to detect if other calls (such as Get_Local_Target) *
* will be OK. *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* Connection Number, 0 = none *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Get_Connection_Number(void)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
int num;
//------------------------------------------------------------------------
// Call Interrupt 0x21, with AH = 0xdc. This tells Novell to put the local
// connection number into AL.
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = 0x21; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.eax = 0x0000dc00;
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
num = rmi.eax & 0x00ff;
return(num);
} /* end of IPX_Get_Connection_Number */
#endif //WIN32
/***************************************************************************
* IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user *
* *
* This gets the Connection Number for the given User ID. Since a user *
* may be logged in more than once, this just returns the first connection *
* found and ignores the others. *
* *
* INPUT: *
* username name of the user to get the Connection Number for *
* *
* OUTPUT: *
* first-found Connection Number for that user, 0 if user not logged in *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Get_1st_Connection_Num (char * username)
{
struct request_buffer {
unsigned short len; // username length + 5
unsigned char buffer_type; // ConnectionNum = 0x15
unsigned short object_type; // set ot 0x0100
unsigned char name_len; // length of username
char name [48]; // copy of username
unsigned short reserved;
};
struct reply_buffer {
unsigned short len;
unsigned char number_connections; // will be 0 - 100
unsigned char connection_num [100]; // array of connection numbers
unsigned short reserved[2];
};
union REGS regs;
struct SREGS sregs;
RMIType rmi;
struct request_buffer * reqbuf;
struct reply_buffer * replybuf;
unsigned short segment; // for DOS allocation
unsigned short selector; // for DOS allocation
int num_conns; // # connections returned
int conn_num; // connection number
int rc;
//------------------------------------------------------------------------
// Allocate DOS memory to store the buffers passed to the interrupt
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call
regs.x.ebx = (sizeof(struct request_buffer) + // # paragraphs to allocate
sizeof(struct reply_buffer) + 15) >> 4;
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
//------------------------------------------------------------------------
// If the carry flag is set, DPMI is indicating an error.
//------------------------------------------------------------------------
if (regs.x.cflag) {
return(0);
}
//------------------------------------------------------------------------
// Get pointers to allocated memory.
// 'reqbuf' is just the returned real-mode segment, multiplied by 16.
// 'replybuf' is an offset from 'reqbuf'.
//------------------------------------------------------------------------
segment = regs.w.ax;
selector = regs.w.dx;
reqbuf = (struct request_buffer *)(segment << 4);
replybuf = (struct reply_buffer *)
(((char *)reqbuf) + sizeof (struct request_buffer));
//------------------------------------------------------------------------
// Init the contents of the request & reply buffers
//------------------------------------------------------------------------
reqbuf->len = (unsigned short)(strlen(username) + 5);
reqbuf->buffer_type = 0x15;
reqbuf->object_type = 0x0100;
reqbuf->name_len = (unsigned char) strlen(username);
strcpy(reqbuf->name, username);
reqbuf->reserved = reqbuf->reserved; // prevent compiler warning
replybuf->len = 101;
replybuf->reserved[0] = replybuf->reserved[0]; // prevent compiler warning
replybuf->reserved[0] = replybuf->reserved[1]; // prevent compiler warning
//------------------------------------------------------------------------
// Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = 0x21; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.eax = 0x0000e300;
rmi.ds = segment;
rmi.esi = 0;
rmi.es = segment;
rmi.edi = sizeof(struct request_buffer);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
//------------------------------------------------------------------------
// Stash the 1st connection number
//------------------------------------------------------------------------
rc = (rmi.eax & 0x00ff); // if AL !=0, error
num_conns = replybuf->number_connections; // # times user is logged in
conn_num = (int )replybuf->connection_num[0]; // 1st connection #
//------------------------------------------------------------------------
// Free DOS memory
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
regs.x.edx = selector; // ptr to free
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
//------------------------------------------------------------------------
// Return error if function failed, or user not logged in
//------------------------------------------------------------------------
if (rc != 0 || num_conns==0) {
return(0);
}
else {
return(conn_num);
}
} /* end of IPX_Get_1st_Connection_Num */
#endif //WIN32
/***************************************************************************
* IPX_Get_Internet_Address -- gets Network Number & Node Address *
* *
* Once you've obtained a Connection Number from IPX_Get_Connection_Number *
* or IPX_Get_1st_Connection_Num, use this function to translate it into *
* a Network Number and Node Address; then, place those numbers in the *
* IPX header for outgoing packets. *
* *
* INPUT: *
* connection_number Connection Number to translate *
* network_number ptr: will hold Network Number *
* physical_node ptr: will hold Node Address *
* *
* OUTPUT: *
* 0 = OK, -1 = error *
* *
* WARNINGS: *
* If connection_number is 0 and NETX isn't running, this routine *
* will just put garbage into the network_number and physical_node. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Get_Internet_Address(int connection_number,
unsigned char * network_number, unsigned char * physical_node)
{
struct request_buffer {
unsigned short len;
unsigned char buffer_type; // Internet = 0x13
unsigned char connection_number; // Conn. Number to translate
};
struct reply_buffer {
unsigned short len;
unsigned char network_number [4]; // filled in by IPX
unsigned char physical_node [6]; // filled in by IPX
unsigned short server_socket; // filled in by IPX, but don't use!
};
union REGS regs;
struct SREGS sregs;
RMIType rmi;
struct request_buffer * reqbuf;
struct reply_buffer * replybuf;
unsigned short segment; // for DOS allocation
unsigned short selector; // for DOS allocation
//------------------------------------------------------------------------
// Error if invalid connection is given
//------------------------------------------------------------------------
if (connection_number==0) {
return(-1);
}
//------------------------------------------------------------------------
// Allocate DOS memory to store the buffers passed to the interrupt
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call
regs.x.ebx = (sizeof(struct request_buffer) + // # paragraphs to allocate
sizeof(struct reply_buffer) + 15) >> 4;
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
//------------------------------------------------------------------------
// If the carry flag is set, DPMI is indicating an error.
//------------------------------------------------------------------------
if (regs.x.cflag) {
return(-1);
}
//------------------------------------------------------------------------
// Get pointers to allocated memory.
// 'reqbuf' is just the returned real-mode segment, multiplied by 16.
// 'replybuf' is an offset from 'reqbuf'.
//------------------------------------------------------------------------
segment = regs.w.ax;
selector = regs.w.dx;
reqbuf = (struct request_buffer *)(segment << 4);
replybuf = (struct reply_buffer *)
(((char *)reqbuf) + sizeof (struct request_buffer));
//------------------------------------------------------------------------
// Init the contents of the request & reply buffers
//------------------------------------------------------------------------
reqbuf->len = 2;
reqbuf->buffer_type = 0x13;
reqbuf->connection_number = (unsigned char)connection_number;
replybuf->len = 12;
replybuf->network_number[0] = replybuf->network_number[0]; // suppress warning
replybuf->physical_node[0] = replybuf->physical_node[0]; // suppress warning
replybuf->server_socket = replybuf->server_socket; // suppress warning
//------------------------------------------------------------------------
// Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = 0x21; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.eax = 0x0000e300;
rmi.ds = segment;
rmi.esi = 0;
rmi.es = segment;
rmi.edi = sizeof(struct request_buffer);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
memcpy(network_number, replybuf->network_number, 4);
memcpy(physical_node, replybuf->physical_node, 6);
//------------------------------------------------------------------------
// Free DOS memory
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
regs.x.edx = selector; // ptr to free
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
return(0);
} /* end of IPX_Get_Internet_Address */
#endif //WIN32
/***************************************************************************
* IPX_Get_User_ID -- gets user ID from Connection Number *
* *
* INPUT: *
* connection_number Connection Number to get User ID for *
* user_id ptr to buffer to put User ID into; *
* size must be >= 48 chars *
* *
* OUTPUT: *
* 0 = OK, -1 = error *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Get_User_ID(int connection_number, char * user_id)
{
struct request_buffer {
unsigned short len;
unsigned char buffer_type; // 0x16 = UserID buffer type
unsigned char connection_number; // Connection Number to get ID for
};
struct reply_buffer {
unsigned short len;
unsigned char object_id[4];
unsigned char object_type[2];
char object_name[48];
char login_time[7];
unsigned short reserved;
};
union REGS regs;
struct SREGS sregs;
RMIType rmi;
struct request_buffer * reqbuf;
struct reply_buffer * replybuf;
unsigned short segment; // for DOS allocation
unsigned short selector; // for DOS allocation
//------------------------------------------------------------------------
// Error if invalid connection is given
//------------------------------------------------------------------------
if (connection_number==0) {
return(-1);
}
//------------------------------------------------------------------------
// Allocate DOS memory to store the buffers passed to the interrupt
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call
regs.x.ebx = (sizeof(struct request_buffer) + // # paragraphs to allocate
sizeof(struct reply_buffer) + 15) >> 4;
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
//------------------------------------------------------------------------
// If the carry flag is set, DPMI is indicating an error.
//------------------------------------------------------------------------
if (regs.x.cflag) {
return(-1);
}
//------------------------------------------------------------------------
// Get pointers to allocated memory.
// 'reqbuf' is just the returned real-mode segment, multiplied by 16.
// 'replybuf' is an offset from 'reqbuf'.
//------------------------------------------------------------------------
segment = regs.w.ax;
selector = regs.w.dx;
reqbuf = (struct request_buffer *)(segment << 4);
replybuf = (struct reply_buffer *)
(((char *)reqbuf) + sizeof (struct request_buffer));
//------------------------------------------------------------------------
// Init the contents of the request & reply buffers
//------------------------------------------------------------------------
reqbuf->len = 2;
reqbuf->buffer_type = 0x16;
reqbuf->connection_number = (unsigned char)connection_number;
replybuf->len = sizeof(struct reply_buffer) - 2;
replybuf->object_id[0] = replybuf->object_id[0]; // suppress warnings
replybuf->object_type[0] = replybuf->object_type[0]; // suppress warnings
replybuf->login_time[0] = replybuf->login_time[0]; // suppress warnings
replybuf->reserved = replybuf->reserved; // suppress warnings
//------------------------------------------------------------------------
// Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = 0x21; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.eax = 0x0000e300;
rmi.ds = segment;
rmi.esi = 0;
rmi.es = segment;
rmi.edi = sizeof(struct request_buffer);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
//------------------------------------------------------------------------
// Fill in the caller's buffer with the user name
//------------------------------------------------------------------------
strncpy(user_id, replybuf->object_name, 48);
//------------------------------------------------------------------------
// Free DOS memory
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
regs.x.edx = selector; // ptr to free
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
return(0);
} /* end of IPX_Get_User_ID */
#endif //WIN32
/***************************************************************************
* IPX_Listen_For_Packet -- commands IPX to listen for a packet *
* *
* Before calling this function, you must fill in an ECB: *
* SocketNumber: must contain the socket you've opened, *
* and are "listening" on *
* Event_Service_Routine: optionally points to a callback routine *
* PacketCount: set to 2, to tell IPX there are 2 areas to *
* store the incoming data in *
* Packet[0].Address: set to the address of an IPXHeaderType *
* Packet[0].Length: sizeof(IPXHeaderType) *
* Packet[1].Address: address of data buffer, for the packet *
* Packet[1].Length: size of the data buffer *
* *
* When the packet is received, ECBType.CompletionCode will be 0 if *
* successful. Otherwise, some error occurred. *
* *
* You should initialize the ECB to 0's before filling it in. *
* *
* INPUT: *
* ecb_ptr pointer to a filled-in ECB; MUST be real-mode memory *
* *
* OUTPUT: *
* 0 = OK, IPX error otherwise *
* *
* WARNINGS: *
* The ECB must be located in real-mode memory, as well as the values *
* pointed to in the ECB (the IPX Header, the buffer to send, etc.) *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Listen_For_Packet(struct ECB *ecb_ptr)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
//------------------------------------------------------------------------
// Call IPX with ES:SI=ecb_ptr
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = IPX_LISTEN_FOR_PACKET;
rmi.es = (short)((long)ecb_ptr >> 4);
rmi.esi = (long)((long)ecb_ptr & 0x000f);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
return(rmi.eax & 0x00ff);
} /* end of IPX_Listen_For_Packet */
#endif //WIN32
/***************************************************************************
* IPX_Send_Packet -- commands IPX to send a packet *
* *
* Before calling this function, you must fill in an ECB: *
* SocketNumber: must contain the socket you've opened, *
* and are sending on *
* Event_Service_Routine: optionally points to a callback routine *
* PacketCount: set to 2, to tell IPX there are 2 areas the *
* outgoing data is stored in *
* Packet[0].Address: set to the address of an IPXHeaderType *
* Packet[0].Length: sizeof(IPXHeaderType) *
* Packet[1].Address: address of buffer containing data to send *
* Packet[1].Length: size of the data buffer *
* ImmediateAddress: must be filled in with the node address of *
* the bridge that will route the message; *
* fill this in by calling IPX_Get_Local_Target *
* *
* Also, you must fill in the IPXHeaderType with certain values: *
* PacketType: set to 4 for IPX *
* DestNetworkNumber: Network Number of the destination system *
* DestNetworkNode: Node Address of the destination system *
* DestNetworkSocket: the destination system's socket to send to; *
* this doesn't have to be the same as the *
* socket opened on the local machine. *
* *
* You should initialize the ECB & IPXHeader to 0's before filling them in.*
* *
* INPUT: *
* ecb_ptr pointer to a filled-in ECB *
* *
* OUTPUT: *
* none. This function doesn't return anything; the caller must check *
* its ECB.CompletionCode for: 0 = OK, IPX Error otherwise. *
* *
* WARNINGS: *
* The ECB must be located in real-mode memory, as well as the values *
* pointed to in the ECB (the IPX Header, the buffer to send, etc.) *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
void IPX_Send_Packet(struct ECB *ecb_ptr)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
//------------------------------------------------------------------------
// Call IPX with ES:SI=ecb_ptr
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = IPX_SEND_PACKET;
rmi.es = (short)((long)ecb_ptr >> 4);
rmi.esi = (long)((long)ecb_ptr & 0x000f);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
} /* end of IPX_Send_Packet */
#endif //WIN32
/***************************************************************************
* IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB *
* *
* Use this function to fill in the ECB's ImmediateAddress field when *
* sending a packet. The Immediate Address is the node address of the *
* bridge that must route the message. If there is no bridge, it's *
* filled in with the destination Node Address. In either case, it *
* will contain the proper value for sending. *
* *
* INPUT: *
* dest_network destination Network Number *
* dest_node destination Node Address *
* dest_socket destination Socket Number *
* bridge_address field to fill in with Immediate Address *
* *
* OUTPUT: *
* 0 = OK, error otherwise *
* *
* WARNINGS: *
* If the Connection Number is 0 (user not logged in), dest_network *
* and dest_node will be garbage, and this routine will probably crash. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Get_Local_Target(unsigned char *dest_network, unsigned char *dest_node,
unsigned short dest_socket, unsigned char *bridge_address)
{
struct request_buffer {
unsigned char network_number [4];
unsigned char physical_node [6];
unsigned short socket;
};
struct reply_buffer {
unsigned char local_target [6];
};
unsigned int rc;
union REGS regs;
struct SREGS sregs;
RMIType rmi;
struct request_buffer *reqbuf;
struct reply_buffer *replybuf;
unsigned short segment; // for DOS allocation
unsigned short selector; // for DOS allocation
//------------------------------------------------------------------------
// Allocate DOS memory to store the buffers passed to the interrupt
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call
regs.x.ebx = (sizeof(struct request_buffer) + // # paragraphs to allocate
sizeof(struct reply_buffer) + 15) >> 4;
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
//------------------------------------------------------------------------
// If the carry flag is set, DPMI is indicating an error.
//------------------------------------------------------------------------
if (regs.x.cflag) {
return(-1);
}
//------------------------------------------------------------------------
// Get pointers to allocated memory.
// 'reqbuf' is just the returned real-mode segment, multiplied by 16.
// 'replybuf' is an offset from 'reqbuf'.
//------------------------------------------------------------------------
segment = regs.w.ax;
selector = regs.w.dx;
reqbuf = (struct request_buffer *)(segment << 4);
replybuf = (struct reply_buffer *)
(((char *)reqbuf) + sizeof (struct request_buffer));
//------------------------------------------------------------------------
// Init the contents of the request & reply buffers
//------------------------------------------------------------------------
memcpy(reqbuf->network_number, dest_network, 4);
memcpy(reqbuf->physical_node, dest_node, 6);
reqbuf->socket = dest_socket;
//------------------------------------------------------------------------
// Invoke IPX with DS:SI=&request_buffer, ES:DI=&reply_buffer
//------------------------------------------------------------------------
//........................................................................
// Fill in registers for the DPMI call
//........................................................................
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//........................................................................
// Fill in registers for the interrupt call
//........................................................................
rmi.ebx = IPX_GET_LOCAL_TARGET;
rmi.ds = segment;
rmi.esi = 0;
rmi.es = segment;
rmi.edi = sizeof(struct request_buffer);
//........................................................................
// call DPMI
//........................................................................
int386x(DPMI_INT, &regs, &regs, &sregs);
rc = (rmi.eax & 0x00ff);
memcpy(bridge_address, replybuf->local_target, 6);
//------------------------------------------------------------------------
// Free DOS memory
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
regs.x.edx = selector; // ptr to free
int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
return(rc);
} /* end of IPX_Get_Local_Target */
#endif //WIN32
/***************************************************************************
* IPX_Cancel_Event -- cancels an operation in progress *
* *
* INPUT: *
* ecb_ptr pointer to ECB event to cancel *
* *
* OUTPUT: *
* ??? *
* *
* WARNINGS: *
* The ECB must be located in real-mode memory, as well as the values *
* pointed to in the ECB (the IPX Header, the buffer to send, etc.) *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
int IPX_Cancel_Event(struct ECB *ecb_ptr)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
unsigned int rc;
//------------------------------------------------------------------------
// Fill in registers for the DPMI call
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//------------------------------------------------------------------------
// Fill in registers for the interrupt call
//------------------------------------------------------------------------
rmi.ebx = IPX_CANCEL_EVENT;
rmi.es = (short)((long)ecb_ptr >> 4);
rmi.esi = (long)((long)ecb_ptr & 0x000f);
//------------------------------------------------------------------------
// call DPMI
//------------------------------------------------------------------------
int386x(DPMI_INT, &regs, &regs, &sregs);
rc = (rmi.eax & 0x00ff);
return(rc);
} /* end of IPX_Cancel_Event */
#endif //WIN32
/***************************************************************************
* Let_IPX_Breath -- gives IPX some CPU time *
* *
* Use this function if you're polling the ECB's InUse flag, waiting *
* for it to go to 0: *
* *
* while ECBType.InUse *
* Let_IPX_Breath(); *
* *
* INPUT: *
* none. *
* *
* OUTPUT: *
* none. *
* *
* WARNINGS: *
* none. *
* *
* HISTORY: *
* 12/15/1994 BR : Created. *
*=========================================================================*/
#ifndef WIN32 // WIN32 version is in IPX95.CPP
void Let_IPX_Breath(void)
{
union REGS regs;
struct SREGS sregs;
RMIType rmi;
//------------------------------------------------------------------------
// Fill in registers for the DPMI call
//------------------------------------------------------------------------
memset (&regs, 0 ,sizeof(regs));
segread (&sregs);
memset (&rmi, 0 ,sizeof(rmi));
regs.w.ax = DPMI_CALL_REAL_INT; // DPMI function to call
regs.w.bx = IPX_INT; // interrupt # to invoke
sregs.es = FP_SEG(&rmi); // tell DPMI where the RMI is
regs.x.edi = FP_OFF(&rmi);
//------------------------------------------------------------------------
// Fill in registers for the interrupt call
//------------------------------------------------------------------------
rmi.ebx = IPX_RELINQUISH_CONTROL;
//------------------------------------------------------------------------
// call DPMI
//------------------------------------------------------------------------
int386x(DPMI_INT, &regs, &regs, &sregs);
} /* end of Let_IPX_Breath */
#endif //WIN32
/**************************** end of ipx.cpp *******************************/