IPX.CPP 53 KB

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