IPX.CPP 52 KB

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