CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

IPX.CPP (54213B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header: /CounterStrike/IPX.CPP 1     3/03/97 10:24a Joe_bostic $ */
     17 /***************************************************************************
     18  **   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        **
     19  ***************************************************************************
     20  *                                                                         *
     21  *                 Project Name : Command & Conquer                        *
     22  *                                                                         *
     23  *                    File Name : IPX.CPP                                  *
     24  *                                                                         *
     25  *                   Programmer : Barry Nance										*
     26  * 										 from Client/Server LAN Programming			*
     27  *											 Westwood-ized by Bill Randolph				*
     28  *                                                                         *
     29  *                   Start Date : December 14, 1994                        *
     30  *                                                                         *
     31  *                  Last Update : December 15, 1994   [BR]                 *
     32  *                                                                         *
     33  *-------------------------------------------------------------------------*
     34  * Pitfalls:																					*
     35  * - Never try to use a closed socket; always check the return code from	*
     36  *   IPX_Open_Socket().																		*
     37  * - Always give IPX an outstanding ECB for listening, before you send.		*
     38  * - It turns out that IPX is pretty bad about saving registers, so if		*
     39  *   you have any register variables in your program, they may get			*
     40  *   trashed.  To circumvent this, all functions in this module save &		*
     41  *   restore the registers before invoking any IPX or NETX function.			*
     42  *                                                                         *
     43  *-------------------------------------------------------------------------*
     44  * Functions:                                                              *
     45  *   IPX_SPX_Installed -- checks for installation of IPX/SPX               *
     46  *   IPX_Open_Socket -- opens an IPX socket for sending or receiving       *
     47  *   IPX_Close_Socket -- closes an open socket                             *
     48  *   IPX_Get_Connection_Number -- gets local Connection Number					*
     49  *   IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user  *
     50  *   IPX_Get_Internet_Address -- gets Network Number & Node Address			*
     51  *   IPX_Get_User_ID -- gets user ID from Connection Number                *
     52  *   IPX_Listen_For_Packet -- commands IPX to listen for a packet          *
     53  *   IPX_Send_Packet -- commands IPX to send a packet                      *
     54  *   IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB        *
     55  *   IPX_Cancel_Event -- cancels an operation in progress                  *
     56  *   Let_IPX_Breath -- gives IPX some CPU time                             *
     57  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     58 
     59 #include "function.h"
     60 #include <stdio.h>
     61 //#include <mem.h>
     62 //#include <i86.h>
     63 #include "ipx.h"
     64 
     65 #ifdef WIN32
     66 #include "ipx95.h"
     67 #endif	//WIN32
     68 
     69 
     70 // Turn off "expression is not meaningful".
     71 //#pragma warning 628 9
     72 
     73 
     74 /***************************************************************************
     75  * IPX_SPX_Installed -- checks for installation of IPX/SPX                 *
     76  *                                                                         *
     77  * INPUT:                                                                  *
     78  *		none.																						*
     79  *                                                                         *
     80  * OUTPUT:                                                                 *
     81  *		0 = not installed; 1 = IPX only, 2 = IPX and SPX are installed			*
     82  *                                                                         *
     83  * WARNINGS:                                                               *
     84  *		none.																						*
     85  *                                                                         *
     86  * HISTORY:                                                                *
     87  *   12/14/1994 BR : Created.                                              *
     88  *=========================================================================*/
     89 int IPX_SPX_Installed(void)
     90 {
     91 	return false;
     92 #ifdef WIN32
     93 
     94 #ifdef TIBERIAN_SUN
     95 	return(false);
     96 #else
     97 #if (0)//PG
     98 	if ( Load_IPX_Dll () ){
     99 		return ( IPX_Initialise() );
    100 	}else{
    101 		return(false);
    102 	}
    103 #endif
    104 #endif
    105 
    106 #else	//WIN32
    107 
    108 	union REGS regs;
    109 	struct SREGS sregs;
    110 	RMIType rmi;
    111 
    112 	//------------------------------------------------------------------------
    113 	//	Init all registers to 0's
    114 	//------------------------------------------------------------------------
    115 	memset (&regs, 0, sizeof(regs));
    116 	segread (&sregs);
    117 	memset (&rmi, 0, sizeof(rmi));
    118 
    119 	//------------------------------------------------------------------------
    120 	//	Fill in registers for the DPMI call, function 0x300
    121 	//------------------------------------------------------------------------
    122 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    123 	regs.w.bx = 0x002f;					// interrupt # to invoke
    124 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    125 	regs.x.edi = FP_OFF(&rmi);
    126 
    127 	//------------------------------------------------------------------------
    128 	//	Fill in registers for the real-mode interrupt handler.
    129 	//	To test for the presence of IPX, set AH to 0x7a, AL to 0, and invoke
    130 	//	interrupt 0x2f (the "multiplex" interrupt).  If IPX is installed,
    131 	//	AL will be 0xff, and ES:DI will contain the IPX/SPX function address.
    132 	//------------------------------------------------------------------------
    133 	rmi.eax = 0x00007a00;
    134 
    135 	//------------------------------------------------------------------------
    136 	//	call DPMI
    137 	//------------------------------------------------------------------------
    138 	int386x(DPMI_INT, &regs, &regs, &sregs);
    139 
    140 	//------------------------------------------------------------------------
    141 	//	If IPX isn't there, return 0
    142 	//------------------------------------------------------------------------
    143 	if ( (rmi.eax & 0x00ff) != 0xff) {
    144 		return(0);
    145 	}
    146 
    147 	//------------------------------------------------------------------------
    148 	//	Test for SPX by invoking the IPX_SPX function with BX = 0x10, and AL = 0.
    149 	//	If SPX is present, AL will be 0xff.
    150 	//------------------------------------------------------------------------
    151 	//........................................................................
    152 	//	Fill in registers for the DPMI call
    153 	//........................................................................
    154 	memset (&regs, 0 ,sizeof(regs));
    155 	segread (&sregs);
    156 	memset (&rmi, 0 ,sizeof(rmi));
    157 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    158 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    159 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    160 	regs.x.edi = FP_OFF(&rmi);
    161 
    162 	//........................................................................
    163 	//	Fill in registers for the interrupt call
    164 	//........................................................................
    165 	rmi.ebx = 0x00000010;
    166 
    167 	//........................................................................
    168 	//	call DPMI
    169 	//........................................................................
    170 	int386x(DPMI_INT, &regs, &regs, &sregs);
    171 
    172 	//------------------------------------------------------------------------
    173 	//	SPX is installed; return '2'
    174 	//------------------------------------------------------------------------
    175 	if ( (rmi.eax & 0x00ff) == 0xff) {
    176 		return(2);
    177 	}
    178 
    179 	//------------------------------------------------------------------------
    180 	//	SPX is not installed; return '1'
    181 	//------------------------------------------------------------------------
    182 	return(1);
    183 #endif	//WIN32
    184 
    185 }	/* end of IPX_SPX_Installed */
    186 
    187 
    188 /***************************************************************************
    189  * IPX_Open_Socket -- opens an IPX socket for sending or receiving         *
    190  *                                                                         *
    191  * INPUT:                                                                  *
    192  *		socket		the socket number to open											*
    193  *                                                                         *
    194  * OUTPUT:                                                                 *
    195  *		0 = OK																					*
    196  *		-1 = IPX not installed																*
    197  *		0xfe = socket table is full														*
    198  *		0xff = socket is already open														*
    199  *                                                                         *
    200  * WARNINGS:                                                               *
    201  *		The application must define its socket number carefully.  Use			*
    202  *		values from 0x4000 to 0x8000 for custom socket numbers.  The app		*
    203  *		must know its own socket number as well as the socket number of		*
    204  *		a destination workstation.															*
    205  *                                                                         *
    206  * HISTORY:                                                                *
    207  *   12/15/1994 BR : Created.                                              *
    208  *=========================================================================*/
    209 
    210 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    211 
    212 int IPX_Open_Socket(unsigned short socket)
    213 {
    214 	union REGS regs;
    215 	struct SREGS sregs;
    216 	RMIType rmi;
    217 	int rc;
    218 
    219 	//------------------------------------------------------------------------
    220 	//	Open the socket:
    221 	//	DX = socket number
    222 	//	AL = 0 for short-lived socket, 0xff for long-lived socket
    223 	//------------------------------------------------------------------------
    224 	//........................................................................
    225 	//	Fill in registers for the DPMI call
    226 	//........................................................................
    227 	memset (&regs, 0 ,sizeof(regs));
    228 	segread (&sregs);
    229 	memset (&rmi, 0 ,sizeof(rmi));
    230 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    231 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    232 	sregs.es = FP_SEG (&rmi);			// tell DPMI where the RMI is
    233 	regs.x.edi = FP_OFF (&rmi);
    234 
    235 	//........................................................................
    236 	//	Fill in registers for the interrupt call
    237 	//........................................................................
    238 	rmi.ebx = IPX_OPEN_SOCKET;			// function code
    239 	rmi.edx = socket;						// desired socket #
    240 	rmi.eax = 0x00ff;						// make this a long-lived socket
    241 
    242 	//........................................................................
    243 	//	call DPMI
    244 	//........................................................................
    245 	int386x (DPMI_INT, &regs, &regs, &sregs);
    246 
    247 	rc = (rmi.eax & 0xff);
    248 
    249 	return(rc);
    250 
    251 }	/* end of IPX_Open_Socket */
    252 #endif	//WIN32
    253 
    254 /***************************************************************************
    255  * IPX_Close_Socket -- closes an open socket                               *
    256  *                                                                         *
    257  * INPUT:                                                                  *
    258  *		socket		socket number to close												*
    259  *                                                                         *
    260  * OUTPUT:                                                                 *
    261  *		0 = ok, -1 = error																	*
    262  *                                                                         *
    263  * WARNINGS:                                                               *
    264  *		none.																						*
    265  *                                                                         *
    266  * HISTORY:                                                                *
    267  *   12/15/1994 BR : Created.                                              *
    268  *=========================================================================*/
    269 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    270 
    271 int IPX_Close_Socket(unsigned short socket)
    272 {
    273 	union REGS regs;
    274 	struct SREGS sregs;
    275 	RMIType rmi;
    276 
    277 	//------------------------------------------------------------------------
    278 	//	Close the socket:
    279 	//	DX = socket number
    280 	//------------------------------------------------------------------------
    281 	//........................................................................
    282 	//	Fill in registers for the DPMI call
    283 	//........................................................................
    284 	memset (&regs, 0 ,sizeof(regs));
    285 	segread (&sregs);
    286 	memset (&rmi, 0 ,sizeof(rmi));
    287 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    288 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    289 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    290 	regs.x.edi = FP_OFF(&rmi);
    291 
    292 	//........................................................................
    293 	//	Fill in registers for the interrupt call
    294 	//........................................................................
    295 	rmi.ebx = IPX_CLOSE_SOCKET;
    296 	rmi.edx = socket;
    297 
    298 	//........................................................................
    299 	//	call DPMI
    300 	//........................................................................
    301 	int386x(DPMI_INT, &regs, &regs, &sregs);
    302 
    303 	return(0);
    304 
    305 }	/* end of IPX_Close_Socket */
    306 #endif		//WIN32
    307 
    308 
    309 /***************************************************************************
    310  * IPX_Get_Connection_Number -- gets local Connection Number					*
    311  *                                                                         *
    312  * This Novell call will the return the user's local "Connection Number".	*
    313  * This value will be 0 if the user isn't logged into Novell, so this		*
    314  * routine can be used to detect if other calls (such as Get_Local_Target)	*
    315  * will be OK.																					*
    316  *                                                                         *
    317  * INPUT:                                                                  *
    318  *		none.																						*
    319  *                                                                         *
    320  * OUTPUT:                                                                 *
    321  *		Connection Number, 0 = none														*
    322  *                                                                         *
    323  * WARNINGS:                                                               *
    324  *		none.																						*
    325  *                                                                         *
    326  * HISTORY:                                                                *
    327  *   12/15/1994 BR : Created.                                              *
    328  *=========================================================================*/
    329 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    330 int IPX_Get_Connection_Number(void)
    331 {
    332 	union REGS regs;
    333 	struct SREGS sregs;
    334 	RMIType rmi;
    335 	int num;
    336 
    337 	//------------------------------------------------------------------------
    338 	//	Call Interrupt 0x21, with AH = 0xdc.  This tells Novell to put the local
    339 	//	connection number into AL.
    340 	//------------------------------------------------------------------------
    341 	//........................................................................
    342 	//	Fill in registers for the DPMI call
    343 	//........................................................................
    344 	memset (&regs, 0 ,sizeof(regs));
    345 	segread (&sregs);
    346 	memset (&rmi, 0 ,sizeof(rmi));
    347 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    348 	regs.w.bx = 0x21;						// interrupt # to invoke
    349 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    350 	regs.x.edi = FP_OFF(&rmi);
    351 
    352 	//........................................................................
    353 	//	Fill in registers for the interrupt call
    354 	//........................................................................
    355 	rmi.eax = 0x0000dc00;
    356 
    357 	//........................................................................
    358 	//	call DPMI
    359 	//........................................................................
    360 	int386x(DPMI_INT, &regs, &regs, &sregs);
    361 
    362 	num = rmi.eax & 0x00ff;
    363 
    364 	return(num);
    365 
    366 }	/* end of IPX_Get_Connection_Number */
    367 #endif	//WIN32
    368 
    369 
    370 /***************************************************************************
    371  * IPX_Get_1st_Connection_Num -- gets 1st Connect Number for given user    *
    372  *                                                                         *
    373  * This gets the Connection Number for the given User ID.  Since a user		*
    374  * may be logged in more than once, this just returns the first connection	*
    375  * found and ignores the others.															*
    376  *                                                                         *
    377  * INPUT:                                                                  *
    378  *		username		name of the user to get the Connection Number for			*
    379  *                                                                         *
    380  * OUTPUT:                                                                 *
    381  *		first-found Connection Number for that user, 0 if user not logged in	*
    382  *                                                                         *
    383  * WARNINGS:                                                               *
    384  *                                                                         *
    385  * HISTORY:                                                                *
    386  *   12/15/1994 BR : Created.                                              *
    387  *=========================================================================*/
    388 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    389 int IPX_Get_1st_Connection_Num (char * username)
    390 {
    391 	struct request_buffer {
    392 		unsigned short len;							// username length + 5
    393 		unsigned char buffer_type;					// ConnectionNum = 0x15
    394 		unsigned short object_type;				// set ot 0x0100
    395 		unsigned char name_len;						// length of username
    396 		char name [48];								// copy of username
    397 		unsigned short reserved;
    398 	};
    399 	struct reply_buffer {
    400 		unsigned short  len;
    401 		unsigned char   number_connections;		// will be 0 - 100
    402 		unsigned char   connection_num [100];	// array of connection numbers
    403 		unsigned short  reserved[2];
    404 	};
    405 	union REGS regs;
    406 	struct SREGS sregs;
    407 	RMIType rmi;
    408 	struct request_buffer * reqbuf;
    409 	struct reply_buffer * replybuf;
    410 	unsigned short segment;							// for DOS allocation
    411 	unsigned short selector;						// for DOS allocation
    412 	int num_conns;										// # connections returned
    413 	int conn_num;										// connection number
    414 	int rc;
    415 
    416 	//------------------------------------------------------------------------
    417 	//	Allocate DOS memory to store the buffers passed to the interrupt
    418 	//------------------------------------------------------------------------
    419 	memset (&regs, 0 ,sizeof(regs));
    420 	segread (&sregs);
    421 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    422 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    423 		sizeof(struct reply_buffer) + 15) >> 4;
    424 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    425 
    426 	//------------------------------------------------------------------------
    427 	//	If the carry flag is set, DPMI is indicating an error.
    428 	//------------------------------------------------------------------------
    429 	if (regs.x.cflag) {
    430 		return(0);
    431 	}
    432 
    433 	//------------------------------------------------------------------------
    434 	//	Get pointers to allocated memory.
    435 	//	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    436 	//	'replybuf' is an offset from 'reqbuf'.
    437 	//------------------------------------------------------------------------
    438 	segment = regs.w.ax;
    439 	selector = regs.w.dx;
    440 	reqbuf = (struct request_buffer *)(segment << 4);
    441 	replybuf = (struct reply_buffer *)
    442 		(((char *)reqbuf) + sizeof (struct request_buffer));
    443 
    444 	//------------------------------------------------------------------------
    445 	//	Init the contents of the request & reply buffers
    446 	//------------------------------------------------------------------------
    447 	reqbuf->len = (unsigned short)(strlen(username) + 5);
    448 	reqbuf->buffer_type = 0x15;
    449 	reqbuf->object_type = 0x0100;
    450 	reqbuf->name_len    = (unsigned char) strlen(username);
    451 	strcpy(reqbuf->name, username);
    452 	reqbuf->reserved = reqbuf->reserved;				// prevent compiler warning
    453 	replybuf->len = 101;
    454 	replybuf->reserved[0] = replybuf->reserved[0];	// prevent compiler warning
    455 	replybuf->reserved[0] = replybuf->reserved[1];	// prevent compiler warning
    456 
    457 	//------------------------------------------------------------------------
    458 	//	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    459 	//------------------------------------------------------------------------
    460 	//........................................................................
    461 	//	Fill in registers for the DPMI call
    462 	//........................................................................
    463 	memset (&regs, 0 ,sizeof(regs));
    464 	segread (&sregs);
    465 	memset (&rmi, 0 ,sizeof(rmi));
    466 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    467 	regs.w.bx = 0x21;						// interrupt # to invoke
    468 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    469 	regs.x.edi = FP_OFF(&rmi);
    470 
    471 	//........................................................................
    472 	//	Fill in registers for the interrupt call
    473 	//........................................................................
    474 	rmi.eax = 0x0000e300;
    475 	rmi.ds = segment;
    476 	rmi.esi = 0;
    477 	rmi.es = segment;
    478 	rmi.edi = sizeof(struct request_buffer);
    479 
    480 	//........................................................................
    481 	//	call DPMI
    482 	//........................................................................
    483 	int386x(DPMI_INT, &regs, &regs, &sregs);
    484 
    485 	//------------------------------------------------------------------------
    486 	//	Stash the 1st connection number
    487 	//------------------------------------------------------------------------
    488 	rc = (rmi.eax & 0x00ff);								// if AL !=0, error
    489 	num_conns = replybuf->number_connections;			// # times user is logged in
    490 	conn_num = (int )replybuf->connection_num[0];	// 1st connection #
    491 
    492 	//------------------------------------------------------------------------
    493 	//	Free DOS memory
    494 	//------------------------------------------------------------------------
    495 	memset (&regs, 0 ,sizeof(regs));
    496 	segread (&sregs);
    497 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    498 	regs.x.edx = selector;									// ptr to free
    499 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    500 
    501 	//------------------------------------------------------------------------
    502 	//	Return error if function failed, or user not logged in
    503 	//------------------------------------------------------------------------
    504 	if (rc != 0 || num_conns==0) {
    505 		return(0);
    506 	}
    507 	else {
    508 		return(conn_num);
    509 	}
    510 
    511 }	/* end of IPX_Get_1st_Connection_Num */
    512 
    513 #endif	//WIN32
    514 
    515 /***************************************************************************
    516  * IPX_Get_Internet_Address -- gets Network Number & Node Address				*
    517  *                                                                         *
    518  * Once you've obtained a Connection Number from IPX_Get_Connection_Number	*
    519  * or IPX_Get_1st_Connection_Num, use this function to translate it into	*
    520  * a Network Number and Node Address; then, place those numbers in the		*
    521  * IPX header for outgoing packets.														*
    522  *                                                                         *
    523  * INPUT:                                                                  *
    524  *		connection_number		Connection Number to translate						*
    525  *		network_number			ptr: will hold Network Number							*
    526  *		physical_node			ptr: will hold Node Address							*
    527  *                                                                         *
    528  * OUTPUT:                                                                 *
    529  *		0 = OK, -1 = error																	*
    530  *                                                                         *
    531  * WARNINGS:                                                               *
    532  *		If connection_number is 0 and NETX isn't running, this routine			*
    533  *		will just put garbage into the network_number and physical_node.		*
    534  *                                                                         *
    535  * HISTORY:                                                                *
    536  *   12/15/1994 BR : Created.                                              *
    537  *=========================================================================*/
    538 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    539 int IPX_Get_Internet_Address(int connection_number,
    540 	unsigned char * network_number, unsigned char * physical_node)
    541 {
    542 	struct request_buffer {
    543 		unsigned short  len;
    544 		unsigned char   buffer_type;				// Internet = 0x13
    545 		unsigned char   connection_number;		// Conn. Number to translate
    546 	};
    547 	struct reply_buffer {
    548 		unsigned short  len;
    549 		unsigned char   network_number [4];		// filled in by IPX
    550 		unsigned char   physical_node  [6];		// filled in by IPX
    551 		unsigned short  server_socket;			// filled in by IPX, but don't use!
    552 	};
    553 	union REGS regs;
    554 	struct SREGS sregs;
    555 	RMIType rmi;
    556 	struct request_buffer * reqbuf;
    557 	struct reply_buffer * replybuf;
    558 	unsigned short segment;							// for DOS allocation
    559 	unsigned short selector;						// for DOS allocation
    560 
    561 	//------------------------------------------------------------------------
    562 	//	Error if invalid connection is given
    563 	//------------------------------------------------------------------------
    564 	if (connection_number==0) {
    565 		return(-1);
    566 	}
    567 
    568 	//------------------------------------------------------------------------
    569 	//	Allocate DOS memory to store the buffers passed to the interrupt
    570 	//------------------------------------------------------------------------
    571 	memset (&regs, 0 ,sizeof(regs));
    572 	segread (&sregs);
    573 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    574 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    575 		sizeof(struct reply_buffer) + 15) >> 4;
    576 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    577 
    578 	//------------------------------------------------------------------------
    579 	//	If the carry flag is set, DPMI is indicating an error.
    580 	//------------------------------------------------------------------------
    581 	if (regs.x.cflag) {
    582 		return(-1);
    583 	}
    584 
    585 	//------------------------------------------------------------------------
    586 	//	Get pointers to allocated memory.
    587 	//	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    588 	//	'replybuf' is an offset from 'reqbuf'.
    589 	//------------------------------------------------------------------------
    590 	segment = regs.w.ax;
    591 	selector = regs.w.dx;
    592 	reqbuf = (struct request_buffer *)(segment << 4);
    593 	replybuf = (struct reply_buffer *)
    594 		(((char *)reqbuf) + sizeof (struct request_buffer));
    595 
    596 	//------------------------------------------------------------------------
    597 	//	Init the contents of the request & reply buffers
    598 	//------------------------------------------------------------------------
    599 	reqbuf->len = 2;
    600 	reqbuf->buffer_type = 0x13;
    601 	reqbuf->connection_number = (unsigned char)connection_number;
    602 	replybuf->len = 12;
    603 	replybuf->network_number[0] = replybuf->network_number[0];	// suppress warning
    604 	replybuf->physical_node[0] = replybuf->physical_node[0];		// suppress warning
    605 	replybuf->server_socket = replybuf->server_socket;				// suppress warning
    606 
    607 	//------------------------------------------------------------------------
    608 	//	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    609 	//------------------------------------------------------------------------
    610 	//........................................................................
    611 	//	Fill in registers for the DPMI call
    612 	//........................................................................
    613 	memset (&regs, 0 ,sizeof(regs));
    614 	segread (&sregs);
    615 	memset (&rmi, 0 ,sizeof(rmi));
    616 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    617 	regs.w.bx = 0x21;						// interrupt # to invoke
    618 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    619 	regs.x.edi = FP_OFF(&rmi);
    620 
    621 	//........................................................................
    622 	//	Fill in registers for the interrupt call
    623 	//........................................................................
    624 	rmi.eax = 0x0000e300;
    625 	rmi.ds = segment;
    626 	rmi.esi = 0;
    627 	rmi.es = segment;
    628 	rmi.edi = sizeof(struct request_buffer);
    629 
    630 	//........................................................................
    631 	//	call DPMI
    632 	//........................................................................
    633 	int386x(DPMI_INT, &regs, &regs, &sregs);
    634 
    635 	memcpy(network_number, replybuf->network_number, 4);
    636 	memcpy(physical_node,  replybuf->physical_node,  6);
    637 
    638 	//------------------------------------------------------------------------
    639 	//	Free DOS memory
    640 	//------------------------------------------------------------------------
    641 	memset (&regs, 0 ,sizeof(regs));
    642 	segread (&sregs);
    643 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    644 	regs.x.edx = selector;									// ptr to free
    645 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    646 
    647 	return(0);
    648 
    649 }	/* end of IPX_Get_Internet_Address */
    650 #endif	//WIN32
    651 
    652 /***************************************************************************
    653  * IPX_Get_User_ID -- gets user ID from Connection Number                  *
    654  *                                                                         *
    655  * INPUT:                                                                  *
    656  *		connection_number		Connection Number to get User ID for				*
    657  *		user_id					ptr to buffer to put User ID into; 					*
    658  *									size must be >= 48 chars								*
    659  *                                                                         *
    660  * OUTPUT:                                                                 *
    661  *		0 = OK, -1 = error																	*
    662  *                                                                         *
    663  * WARNINGS:                                                               *
    664  *		none.																						*
    665  *                                                                         *
    666  * HISTORY:                                                                *
    667  *   12/15/1994 BR : Created.                                              *
    668  *=========================================================================*/
    669 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    670 int IPX_Get_User_ID(int connection_number, char * user_id)
    671 {
    672 	struct request_buffer {
    673 		unsigned short  len;
    674 		unsigned char   buffer_type;			// 0x16 = UserID buffer type
    675 		unsigned char   connection_number;	// Connection Number to get ID for
    676 	};
    677 	struct reply_buffer {
    678 		unsigned short  len;
    679 		unsigned char   object_id[4];
    680 		unsigned char   object_type[2];
    681 		char            object_name[48];
    682 		char            login_time[7];
    683 		unsigned short  reserved;
    684 	};
    685 	union REGS      regs;
    686 	struct SREGS    sregs;
    687 	RMIType rmi;
    688 	struct request_buffer * reqbuf;
    689 	struct reply_buffer * replybuf;
    690 	unsigned short segment;							// for DOS allocation
    691 	unsigned short selector;						// for DOS allocation
    692 
    693 	//------------------------------------------------------------------------
    694 	//	Error if invalid connection is given
    695 	//------------------------------------------------------------------------
    696 	if (connection_number==0) {
    697 		return(-1);
    698 	}
    699 
    700 	//------------------------------------------------------------------------
    701 	//	Allocate DOS memory to store the buffers passed to the interrupt
    702 	//------------------------------------------------------------------------
    703 	memset (&regs, 0 ,sizeof(regs));
    704 	segread (&sregs);
    705 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    706 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    707 		sizeof(struct reply_buffer) + 15) >> 4;
    708 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    709 
    710 	//------------------------------------------------------------------------
    711 	//	If the carry flag is set, DPMI is indicating an error.
    712 	//------------------------------------------------------------------------
    713 	if (regs.x.cflag) {
    714 		return(-1);
    715 	}
    716 
    717 	//------------------------------------------------------------------------
    718 	//	Get pointers to allocated memory.
    719 	//	'reqbuf' is just the returned real-mode segment, multiplied by 16.
    720 	//	'replybuf' is an offset from 'reqbuf'.
    721 	//------------------------------------------------------------------------
    722 	segment = regs.w.ax;
    723 	selector = regs.w.dx;
    724 	reqbuf = (struct request_buffer *)(segment << 4);
    725 	replybuf = (struct reply_buffer *)
    726 		(((char *)reqbuf) + sizeof (struct request_buffer));
    727 
    728 	//------------------------------------------------------------------------
    729 	//	Init the contents of the request & reply buffers
    730 	//------------------------------------------------------------------------
    731 	reqbuf->len = 2;
    732 	reqbuf->buffer_type = 0x16;
    733 	reqbuf->connection_number = (unsigned char)connection_number;
    734 	replybuf->len = sizeof(struct reply_buffer) - 2;
    735 	replybuf->object_id[0] = replybuf->object_id[0];		// suppress warnings
    736 	replybuf->object_type[0] = replybuf->object_type[0];	// suppress warnings
    737 	replybuf->login_time[0] = replybuf->login_time[0];		// suppress warnings
    738 	replybuf->reserved = replybuf->reserved;					// suppress warnings
    739 
    740 	//------------------------------------------------------------------------
    741 	//	Invoke Int 21 with AH=0xe3, DS:SI=&request_buffer, ES:DI=&reply_buffer
    742 	//------------------------------------------------------------------------
    743 	//........................................................................
    744 	//	Fill in registers for the DPMI call
    745 	//........................................................................
    746 	memset (&regs, 0 ,sizeof(regs));
    747 	segread (&sregs);
    748 	memset (&rmi, 0 ,sizeof(rmi));
    749 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    750 	regs.w.bx = 0x21;						// interrupt # to invoke
    751 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    752 	regs.x.edi = FP_OFF(&rmi);
    753 
    754 	//........................................................................
    755 	//	Fill in registers for the interrupt call
    756 	//........................................................................
    757 	rmi.eax = 0x0000e300;
    758 	rmi.ds = segment;
    759 	rmi.esi = 0;
    760 	rmi.es = segment;
    761 	rmi.edi = sizeof(struct request_buffer);
    762 
    763 	//........................................................................
    764 	//	call DPMI
    765 	//........................................................................
    766 	int386x(DPMI_INT, &regs, &regs, &sregs);
    767 
    768 	//------------------------------------------------------------------------
    769 	//	Fill in the caller's buffer with the user name
    770 	//------------------------------------------------------------------------
    771 	strncpy(user_id, replybuf->object_name, 48);
    772 
    773 	//------------------------------------------------------------------------
    774 	//	Free DOS memory
    775 	//------------------------------------------------------------------------
    776 	memset (&regs, 0 ,sizeof(regs));
    777 	segread (&sregs);
    778 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
    779 	regs.x.edx = selector;									// ptr to free
    780 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    781 
    782 	return(0);
    783 
    784 }	/* end of IPX_Get_User_ID */
    785 #endif	//WIN32
    786 
    787 /***************************************************************************
    788  * IPX_Listen_For_Packet -- commands IPX to listen for a packet            *
    789  *                                                                         *
    790  * Before calling this function, you must fill in an ECB:						*
    791  *		SocketNumber:				must contain the socket you've opened,			*
    792  *										and are "listening" on								*
    793  *		Event_Service_Routine:	optionally points to a callback routine		*
    794  *		PacketCount:				set to 2, to tell IPX there are 2 areas to	*
    795  *										store the incoming data in							*
    796  *		Packet[0].Address:		set to the address of an IPXHeaderType			*
    797  *		Packet[0].Length:			sizeof(IPXHeaderType)								*
    798  *		Packet[1].Address:		address of data buffer, for the packet			*
    799  *		Packet[1].Length:			size of the data buffer								*
    800  *                                                                         *
    801  * When the packet is received, ECBType.CompletionCode will be 0 if 			*
    802  * successful.  Otherwise, some error occurred.										*
    803  *                                                                         *
    804  * You should initialize the ECB to 0's before filling it in.					*
    805  *                                                                         *
    806  * INPUT:                                                                  *
    807  *		ecb_ptr		pointer to a filled-in ECB; MUST be real-mode memory		*
    808  *                                                                         *
    809  * OUTPUT:                                                                 *
    810  *		0 = OK, IPX error otherwise														*
    811  *                                                                         *
    812  * WARNINGS:                                                               *
    813  *		The ECB must be located in real-mode memory, as well as the values	*
    814  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
    815  *                                                                         *
    816  * HISTORY:                                                                *
    817  *   12/15/1994 BR : Created.                                              *
    818  *=========================================================================*/
    819 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    820 int IPX_Listen_For_Packet(struct ECB *ecb_ptr)
    821 {
    822 	union REGS      regs;
    823 	struct SREGS    sregs;
    824 	RMIType rmi;
    825 
    826 	//------------------------------------------------------------------------
    827 	//	Call IPX with ES:SI=ecb_ptr
    828 	//------------------------------------------------------------------------
    829 	//........................................................................
    830 	//	Fill in registers for the DPMI call
    831 	//........................................................................
    832 	memset (&regs, 0 ,sizeof(regs));
    833 	segread (&sregs);
    834 	memset (&rmi, 0 ,sizeof(rmi));
    835 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    836 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    837 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    838 	regs.x.edi = FP_OFF(&rmi);
    839 
    840 	//........................................................................
    841 	//	Fill in registers for the interrupt call
    842 	//........................................................................
    843 	rmi.ebx = IPX_LISTEN_FOR_PACKET;
    844 	rmi.es = (short)((long)ecb_ptr >> 4);
    845 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
    846 
    847 	//........................................................................
    848 	//	call DPMI
    849 	//........................................................................
    850 	int386x(DPMI_INT, &regs, &regs, &sregs);
    851 
    852 	return(rmi.eax & 0x00ff);
    853 
    854 }	/* end of IPX_Listen_For_Packet */
    855 #endif	//WIN32
    856 
    857 /***************************************************************************
    858  * IPX_Send_Packet -- commands IPX to send a packet                        *
    859  *                                                                         *
    860  * Before calling this function, you must fill in an ECB:						*
    861  *		SocketNumber:				must contain the socket you've opened,			*
    862  *										and are sending on									*
    863  *		Event_Service_Routine:	optionally points to a callback routine		*
    864  *		PacketCount:				set to 2, to tell IPX there are 2 areas the	*
    865  *										outgoing data is stored in							*
    866  *		Packet[0].Address:		set to the address of an IPXHeaderType			*
    867  *		Packet[0].Length:			sizeof(IPXHeaderType)								*
    868  *		Packet[1].Address:		address of buffer containing data to send		*
    869  *		Packet[1].Length:			size of the data buffer								*
    870  *		ImmediateAddress:			must be filled in with the node address of	*
    871  *										the bridge that will route the message;		*
    872  *										fill this in by calling IPX_Get_Local_Target	*
    873  *                                                                         *
    874  * Also, you must fill in the IPXHeaderType with certain values:				*
    875  *		PacketType:					set to 4 for IPX										*
    876  *		DestNetworkNumber:		Network Number of the destination system		*
    877  *		DestNetworkNode:			Node Address of the destination system			*
    878  *		DestNetworkSocket:		the destination system's socket to send to;	*
    879  *										this doesn't have to be the same as the		*
    880  *										socket opened on the local machine.				*
    881  *                                                                         *
    882  * You should initialize the ECB & IPXHeader to 0's before filling them in.*
    883  *                                                                         *
    884  * INPUT:                                                                  *
    885  *		ecb_ptr		pointer to a filled-in ECB											*
    886  *                                                                         *
    887  * OUTPUT:                                                                 *
    888  *		none.  This function doesn't return anything; the caller must check	*
    889  *    its ECB.CompletionCode for: 0 = OK, IPX Error otherwise.					*
    890  *                                                                         *
    891  * WARNINGS:                                                               *
    892  *		The ECB must be located in real-mode memory, as well as the values	*
    893  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
    894  *                                                                         *
    895  * HISTORY:                                                                *
    896  *   12/15/1994 BR : Created.                                              *
    897  *=========================================================================*/
    898 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    899 void IPX_Send_Packet(struct ECB *ecb_ptr)
    900 {
    901 	union REGS      regs;
    902 	struct SREGS    sregs;
    903 	RMIType rmi;
    904 
    905 	//------------------------------------------------------------------------
    906 	//	Call IPX with ES:SI=ecb_ptr
    907 	//------------------------------------------------------------------------
    908 	//........................................................................
    909 	//	Fill in registers for the DPMI call
    910 	//........................................................................
    911 	memset (&regs, 0 ,sizeof(regs));
    912 	segread (&sregs);
    913 	memset (&rmi, 0 ,sizeof(rmi));
    914 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
    915 	regs.w.bx = IPX_INT;					// interrupt # to invoke
    916 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
    917 	regs.x.edi = FP_OFF(&rmi);
    918 
    919 	//........................................................................
    920 	//	Fill in registers for the interrupt call
    921 	//........................................................................
    922 	rmi.ebx = IPX_SEND_PACKET;
    923 	rmi.es = (short)((long)ecb_ptr >> 4);
    924 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
    925 
    926 	//........................................................................
    927 	//	call DPMI
    928 	//........................................................................
    929 	int386x(DPMI_INT, &regs, &regs, &sregs);
    930 
    931 }	/* end of IPX_Send_Packet */
    932 #endif	//WIN32
    933 
    934 /***************************************************************************
    935  * IPX_Get_Local_Target -- fills in ImmediateAddress field of ECB          *
    936  *                                                                         *
    937  * Use this function to fill in the ECB's ImmediateAddress field when		*
    938  * sending a packet.  The Immediate Address is the node address of the		*
    939  * bridge that must route the message.  If there is no bridge, it's 			*
    940  * filled in with the destination Node Address.  In either case, it			*
    941  * will contain the proper value for sending.										*
    942  *                                                                         *
    943  * INPUT:                                                                  *
    944  *		dest_network			destination Network Number								*
    945  *		dest_node				destination Node Address								*
    946  *		dest_socket				destination Socket Number								*
    947  *		bridge_address			field to fill in with Immediate Address			*
    948  *                                                                         *
    949  * OUTPUT:                                                                 *
    950  *		0 = OK, error otherwise																*
    951  *                                                                         *
    952  * WARNINGS:                                                               *
    953  *		If the Connection Number is 0 (user not logged in), dest_network		*
    954  *		and dest_node will be garbage, and this routine will probably crash.	*
    955  *                                                                         *
    956  * HISTORY:                                                                *
    957  *   12/15/1994 BR : Created.                                              *
    958  *=========================================================================*/
    959 #ifndef WIN32		// WIN32 version is in IPX95.CPP
    960 int IPX_Get_Local_Target(unsigned char *dest_network, unsigned char *dest_node,
    961 	unsigned short dest_socket, unsigned char *bridge_address)
    962 {
    963 	struct request_buffer {
    964 		unsigned char   network_number [4];
    965 		unsigned char   physical_node  [6];
    966 		unsigned short  socket;
    967 	};
    968 	struct reply_buffer {
    969 		unsigned char   local_target [6];
    970 	};
    971 	unsigned int rc;
    972 	union REGS regs;
    973 	struct SREGS sregs;
    974 	RMIType rmi;
    975 	struct request_buffer *reqbuf;
    976 	struct reply_buffer *replybuf;
    977 	unsigned short segment;							// for DOS allocation
    978 	unsigned short selector;						// for DOS allocation
    979 
    980 	//------------------------------------------------------------------------
    981 	//	Allocate DOS memory to store the buffers passed to the interrupt
    982 	//------------------------------------------------------------------------
    983 	memset (&regs, 0 ,sizeof(regs));
    984 	segread (&sregs);
    985 	regs.x.eax = DPMI_ALLOC_DOS_MEM;						// DPMI function to call
    986 	regs.x.ebx = (sizeof(struct request_buffer) + 	// # paragraphs to allocate
    987 		sizeof(struct reply_buffer) + 15) >> 4;
    988 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
    989 
    990 	//------------------------------------------------------------------------
    991 	//	If the carry flag is set, DPMI is indicating an error.
    992 	//------------------------------------------------------------------------
    993 	if (regs.x.cflag) {
    994 		return(-1);
    995 	}
    996 
    997 	//------------------------------------------------------------------------
    998 	//	Get pointers to allocated memory.
    999 	//	'reqbuf' is just the returned real-mode segment, multiplied by 16.
   1000 	//	'replybuf' is an offset from 'reqbuf'.
   1001 	//------------------------------------------------------------------------
   1002 	segment = regs.w.ax;
   1003 	selector = regs.w.dx;
   1004 	reqbuf = (struct request_buffer *)(segment << 4);
   1005 	replybuf = (struct reply_buffer *)
   1006 		(((char *)reqbuf) + sizeof (struct request_buffer));
   1007 
   1008 	//------------------------------------------------------------------------
   1009 	//	Init the contents of the request & reply buffers
   1010 	//------------------------------------------------------------------------
   1011 	memcpy(reqbuf->network_number, dest_network, 4);
   1012 	memcpy(reqbuf->physical_node, dest_node, 6);
   1013 	reqbuf->socket = dest_socket;
   1014 
   1015 	//------------------------------------------------------------------------
   1016 	//	Invoke IPX with DS:SI=&request_buffer, ES:DI=&reply_buffer
   1017 	//------------------------------------------------------------------------
   1018 	//........................................................................
   1019 	//	Fill in registers for the DPMI call
   1020 	//........................................................................
   1021 	memset (&regs, 0 ,sizeof(regs));
   1022 	segread (&sregs);
   1023 	memset (&rmi, 0 ,sizeof(rmi));
   1024 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
   1025 	regs.w.bx = IPX_INT;					// interrupt # to invoke
   1026 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
   1027 	regs.x.edi = FP_OFF(&rmi);
   1028 
   1029 	//........................................................................
   1030 	//	Fill in registers for the interrupt call
   1031 	//........................................................................
   1032 	rmi.ebx = IPX_GET_LOCAL_TARGET;
   1033 	rmi.ds = segment;
   1034 	rmi.esi = 0;
   1035 	rmi.es = segment;
   1036 	rmi.edi = sizeof(struct request_buffer);
   1037 	//........................................................................
   1038 	//	call DPMI
   1039 	//........................................................................
   1040 	int386x(DPMI_INT, &regs, &regs, &sregs);
   1041 
   1042 	rc = (rmi.eax & 0x00ff);
   1043 	memcpy(bridge_address, replybuf->local_target, 6);
   1044 
   1045 	//------------------------------------------------------------------------
   1046 	//	Free DOS memory
   1047 	//------------------------------------------------------------------------
   1048 	memset (&regs, 0 ,sizeof(regs));
   1049 	segread (&sregs);
   1050 	regs.x.eax = DPMI_FREE_DOS_MEM;						// DPMI function to call
   1051 	regs.x.edx = selector;									// ptr to free
   1052 	int386x (DPMI_INT, &regs, &regs, &sregs);			// allocate the memory
   1053 
   1054 	return(rc);
   1055 
   1056 }	/* end of IPX_Get_Local_Target */
   1057 #endif	//WIN32
   1058 
   1059 /***************************************************************************
   1060  * IPX_Cancel_Event -- cancels an operation in progress                    *
   1061  *                                                                         *
   1062  * INPUT:                                                                  *
   1063  *		ecb_ptr		pointer to ECB event to cancel									*
   1064  *                                                                         *
   1065  * OUTPUT:                                                                 *
   1066  *		???																						*
   1067  *                                                                         *
   1068  * WARNINGS:                                                               *
   1069  *		The ECB must be located in real-mode memory, as well as the values	*
   1070  *		pointed to in the ECB (the IPX Header, the buffer to send, etc.)		*
   1071  *                                                                         *
   1072  * HISTORY:                                                                *
   1073  *   12/15/1994 BR : Created.                                              *
   1074  *=========================================================================*/
   1075 #ifndef WIN32		// WIN32 version is in IPX95.CPP
   1076 int IPX_Cancel_Event(struct ECB *ecb_ptr)
   1077 {
   1078 	union REGS      regs;
   1079 	struct SREGS    sregs;
   1080 	RMIType rmi;
   1081 	unsigned int rc;
   1082 
   1083 	//------------------------------------------------------------------------
   1084 	//	Fill in registers for the DPMI call
   1085 	//------------------------------------------------------------------------
   1086 	memset (&regs, 0 ,sizeof(regs));
   1087 	segread (&sregs);
   1088 	memset (&rmi, 0 ,sizeof(rmi));
   1089 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
   1090 	regs.w.bx = IPX_INT;					// interrupt # to invoke
   1091 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
   1092 	regs.x.edi = FP_OFF(&rmi);
   1093 
   1094 	//------------------------------------------------------------------------
   1095 	//	Fill in registers for the interrupt call
   1096 	//------------------------------------------------------------------------
   1097 	rmi.ebx = IPX_CANCEL_EVENT;
   1098 	rmi.es = (short)((long)ecb_ptr >> 4);
   1099 	rmi.esi = (long)((long)ecb_ptr & 0x000f);
   1100 
   1101 	//------------------------------------------------------------------------
   1102 	//	call DPMI
   1103 	//------------------------------------------------------------------------
   1104 	int386x(DPMI_INT, &regs, &regs, &sregs);
   1105 
   1106 	rc = (rmi.eax & 0x00ff);
   1107 
   1108 	return(rc);
   1109 
   1110 }	/* end of IPX_Cancel_Event */
   1111 #endif	//WIN32
   1112 
   1113 /***************************************************************************
   1114  * Let_IPX_Breath -- gives IPX some CPU time                               *
   1115  *                                                                         *
   1116  * Use this function if you're polling the ECB's InUse flag, waiting			*
   1117  * for it to go to 0:																		*
   1118  *                                                                         *
   1119  *		while ECBType.InUse																	*
   1120  *			Let_IPX_Breath();																	*
   1121  *                                                                         *
   1122  * INPUT:                                                                  *
   1123  *		none.																						*
   1124  *                                                                         *
   1125  * OUTPUT:                                                                 *
   1126  *		none.																						*
   1127  *                                                                         *
   1128  * WARNINGS:                                                               *
   1129  *		none.																						*
   1130  *                                                                         *
   1131  * HISTORY:                                                                *
   1132  *   12/15/1994 BR : Created.                                              *
   1133  *=========================================================================*/
   1134 #ifndef WIN32		// WIN32 version is in IPX95.CPP
   1135 void Let_IPX_Breath(void)
   1136 {
   1137 	union REGS      regs;
   1138 	struct SREGS    sregs;
   1139 	RMIType rmi;
   1140 
   1141 	//------------------------------------------------------------------------
   1142 	//	Fill in registers for the DPMI call
   1143 	//------------------------------------------------------------------------
   1144 	memset (&regs, 0 ,sizeof(regs));
   1145 	segread (&sregs);
   1146 	memset (&rmi, 0 ,sizeof(rmi));
   1147 	regs.w.ax = DPMI_CALL_REAL_INT;	// DPMI function to call
   1148 	regs.w.bx = IPX_INT;					// interrupt # to invoke
   1149 	sregs.es = FP_SEG(&rmi);			// tell DPMI where the RMI is
   1150 	regs.x.edi = FP_OFF(&rmi);
   1151 
   1152 	//------------------------------------------------------------------------
   1153 	//	Fill in registers for the interrupt call
   1154 	//------------------------------------------------------------------------
   1155 	rmi.ebx = IPX_RELINQUISH_CONTROL;
   1156 
   1157 	//------------------------------------------------------------------------
   1158 	//	call DPMI
   1159 	//------------------------------------------------------------------------
   1160 	int386x(DPMI_INT, &regs, &regs, &sregs);
   1161 
   1162 }	/* end of Let_IPX_Breath */
   1163 #endif	//WIN32
   1164 /**************************** end of ipx.cpp *******************************/