IPX.CPP 52 KB

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