1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- //
- // 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: F:\projects\c&c\vcs\code\ipx.cpv 2.17 16 Oct 1995 16:49:34 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 "ipx95.h"
- /***************************************************************************
- * 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)
- {
- #ifndef NOT_FOR_WIN95
- return (IPX_Initialise());
- #else //NOT_FOR_WIN95
- union REGS regs;
- struct SREGS sregs;
- RMIType rmi;
- /*------------------------------------------------------------------------
- Init all registers to 0's
- ------------------------------------------------------------------------*/
- memset (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &sregs);
- /*------------------------------------------------------------------------
- SPX is installed; return '2'
- ------------------------------------------------------------------------*/
- if ( (rmi.eax & 0x00ff) == 0xff) {
- return(2);
- }
- /*------------------------------------------------------------------------
- SPX is not installed; return '1'
- ------------------------------------------------------------------------*/
- return(1);
- #endif //NOT_FOR_WIN95
- } /* 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- rc = (rmi.eax & 0xff);
- return(rc);
- } /* end of IPX_Open_Socket */
- #endif
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- return(0);
- } /* end of IPX_Close_Socket */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- num = rmi.eax & 0x00ff;
- return(num);
- } /* end of IPX_Get_Connection_Number */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &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);
- }
- }
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &sregs);
- memcpy(network_number, replybuf->network_number, 4);
- memcpy(physical_node, replybuf->physical_node, 6);
- /*------------------------------------------------------------------------
- Free DOS memory
- ------------------------------------------------------------------------*/
- memset (®s, 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, ®s, ®s, &sregs); // allocate the memory
- return(0);
- } /* end of IPX_Get_Internet_Address */
- #endif // NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &sregs);
- /*------------------------------------------------------------------------
- Fill in the caller's buffer with the user name
- ------------------------------------------------------------------------*/
- strncpy(user_id, replybuf->object_name, 48);
- /*------------------------------------------------------------------------
- Free DOS memory
- ------------------------------------------------------------------------*/
- memset (®s, 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, ®s, ®s, &sregs); // allocate the memory
- return(0);
- } /* end of IPX_Get_User_ID */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- return(rmi.eax & 0x00ff);
- } /* end of IPX_Listen_For_Packet */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- } /* end of IPX_Send_Packet */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &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 (®s, 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, ®s, ®s, &sregs);
- rc = (rmi.eax & 0x00ff);
- memcpy(bridge_address, replybuf->local_target, 6);
- /*------------------------------------------------------------------------
- Free DOS memory
- ------------------------------------------------------------------------*/
- memset (®s, 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, ®s, ®s, &sregs); // allocate the memory
- return(rc);
- } /* end of IPX_Get_Local_Target */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- 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 (®s, 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, ®s, ®s, &sregs);
- rc = (rmi.eax & 0x00ff);
- return(rc);
- } /* end of IPX_Cancel_Event */
- #endif //NOT_FOR_WIN95
- /***************************************************************************
- * 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. *
- *=========================================================================*/
- #ifdef NOT_FOR_WIN95
- void Let_IPX_Breath(void)
- {
- union REGS regs;
- struct SREGS sregs;
- RMIType rmi;
- /*........................................................................
- Fill in registers for the DPMI call
- ........................................................................*/
- memset (®s, 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, ®s, ®s, &sregs);
- } /* end of Let_IPX_Breath */
- #endif //NOT_FOR_WIN95
|