IPX.CPP 53 KB

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