IPXMGR.CPP 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972
  1. /*
  2. ** Command & Conquer(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\ipxmgr.cpv 1.9 16 Oct 1995 16:48:22 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 : IPXMGR.CPP *
  26. * *
  27. * Programmer : Bill Randolph *
  28. * *
  29. * Start Date : December 20, 1994 *
  30. * *
  31. * Last Update : May 4, 1995 [BRR] *
  32. * *
  33. *-------------------------------------------------------------------------*
  34. * Functions: *
  35. * IPXManagerClass::IPXManagerClass -- class constructor *
  36. * IPXManagerClass::~IPXManagerClass -- class destructor *
  37. * IPXManagerClass::Init -- initialization routine *
  38. * IPXManagerClass::Is_IPX -- tells if IPX is installed or not *
  39. * IPXManagerClass::Set_Timing -- sets timing for all connections *
  40. * IPXManagerClass::Create_Connection -- creates a new connection *
  41. * IPXManagerClass::Delete_Connection -- deletes a connection *
  42. * IPXManagerClass::Num_Connections -- gets the # of connections *
  43. * IPXManagerClass::Connection_ID -- gets the given connection's ID *
  44. * IPXManagerClass::Connection_Name -- gets name for given connection *
  45. * IPXManagerClass::Connection_Address -- retrieves connection's address *
  46. * IPXManagerClass::Connection_Index -- gets given connection's index *
  47. * IPXManagerClass::Send_Global_Message -- sends a Global Message *
  48. * IPXManagerClass::Get_Global_Message -- polls the Global Message queue *
  49. * IPXManagerClass::Send_Private_Message -- Sends a Private Message *
  50. * IPXManagerClass::Get_Private_Message -- Polls Private Message queue *
  51. * IPXManagerClass::Service -- main polling routine for IPX Connections *
  52. * IPXManagerClass::Get_Bad_Connection -- returns bad connection ID *
  53. * IPXManagerClass::Global_Num_Send -- gets # entries in send queue *
  54. * IPXManagerClass::Global_Num_Receive -- gets # entries in recv queue *
  55. * IPXManagerClass::Private_Num_Send -- gets # entries in send queue *
  56. * IPXManagerClass::Private_Num_Receive -- gets # entries in recv queue *
  57. * IPXManagerClass::Set_Bridge -- prepares to cross a bridge *
  58. * IPXManagerClass::Set_Socket -- sets socket ID for all connections *
  59. * IPXManagerClass::Response_Time -- Returns largest Avg Response Time *
  60. * IPXManagerClass::Global_Response_Time -- Returns Avg Response Time *
  61. * IPXManagerClass::Reset_Response_Time -- Reset response time *
  62. * IPXManagerClass::Oldest_Send -- gets ptr to oldest send buf *
  63. * IPXManagerClass::Mono_Debug_Print -- debug output routine *
  64. * IPXManagerClass::Alloc_RealMode_Mem -- allocates real-mode memory *
  65. * IPXManagerClass::Free_RealMode_Mem -- frees real-mode memory *
  66. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  67. #include "function.h"
  68. #include "ipx95.h"
  69. #include "tcpip.h"
  70. /***************************************************************************
  71. * IPXManagerClass::IPXManagerClass -- class constructor *
  72. * *
  73. * INPUT: *
  74. * glb_maxlen Global Channel maximum packet length *
  75. * pvt_maxlen Private Channel maximum packet length *
  76. * socket socket ID to use *
  77. * product_id a unique numerical ID for this product *
  78. * *
  79. * OUTPUT: *
  80. * none. *
  81. * *
  82. * WARNINGS: *
  83. * The socket number is byte-swapped, since IPX requires socket ID's *
  84. * to be stored high/low. *
  85. * *
  86. * HISTORY: *
  87. * 12/20/1994 BR : Created. *
  88. *=========================================================================*/
  89. IPXManagerClass::IPXManagerClass (int glb_maxlen, int pvt_maxlen,
  90. int glb_num_packets, int pvt_num_packets, unsigned short socket,
  91. unsigned short product_id)
  92. {
  93. int i;
  94. /*------------------------------------------------------------------------
  95. Initialize data members
  96. ------------------------------------------------------------------------*/
  97. /*........................................................................
  98. IPXStatus = 1 if IPX is installed, 0 if not
  99. ........................................................................*/
  100. if (IPX_SPX_Installed()==0) {
  101. IPXStatus = 0;
  102. } else {
  103. IPXStatus = 1;
  104. }
  105. /*........................................................................
  106. Set listening state flag to off
  107. ........................................................................*/
  108. Listening = 0;
  109. /*........................................................................
  110. No memory has been alloc'd yet
  111. ........................................................................*/
  112. RealMemAllocd = 0;
  113. /*........................................................................
  114. Set max packet sizes, for allocating real-mode memory
  115. ........................................................................*/
  116. Glb_MaxPacketLen = glb_maxlen;
  117. Glb_NumPackets = glb_num_packets;
  118. Pvt_MaxPacketLen = pvt_maxlen;
  119. Pvt_NumPackets = pvt_num_packets;
  120. /*........................................................................
  121. Save the app's product ID
  122. ........................................................................*/
  123. ProductID = product_id;
  124. /*........................................................................
  125. Save our socket ID number
  126. ........................................................................*/
  127. Socket = (unsigned short)( (((unsigned long)socket & 0x00ff) << 8) |
  128. (((unsigned long)socket & 0xff00) >> 8));
  129. /*........................................................................
  130. Get the user's IPX local connection number
  131. ........................................................................*/
  132. if (IPXStatus) {
  133. ConnectionNum = IPX_Get_Connection_Number();
  134. } else {
  135. ConnectionNum = 0;
  136. }
  137. /*........................................................................
  138. Init connection states
  139. ........................................................................*/
  140. NumConnections = 0;
  141. CurConnection = 0;
  142. for (i = 0; i < CONNECT_MAX; i++)
  143. Connection[i] = 0;
  144. GlobalChannel = 0;
  145. SendOverflows = 0;
  146. ReceiveOverflows = 0;
  147. BadConnection = IPXConnClass::CONNECTION_NONE;
  148. /*........................................................................
  149. Init timing parameters
  150. ........................................................................*/
  151. RetryDelta = 2; // 2 ticks between retries
  152. MaxRetries = -1; // disregard # retries
  153. Timeout = 60; // report bad connection after 1 second
  154. } /* end of IPXManagerClass */
  155. /***************************************************************************
  156. * IPXManagerClass::~IPXManagerClass -- class destructor *
  157. * *
  158. * INPUT: *
  159. * none. *
  160. * *
  161. * OUTPUT: *
  162. * none. *
  163. * *
  164. * WARNINGS: *
  165. * none. *
  166. * *
  167. * HISTORY: *
  168. * 12/20/1994 BR : Created. *
  169. *=========================================================================*/
  170. IPXManagerClass::~IPXManagerClass()
  171. {
  172. int i;
  173. /*------------------------------------------------------------------------
  174. Stop all IPX events
  175. ------------------------------------------------------------------------*/
  176. if (Listening) {
  177. IPXConnClass::Stop_Listening();
  178. Listening = 0;
  179. }
  180. /*------------------------------------------------------------------------
  181. Free all protected-mode memory
  182. ------------------------------------------------------------------------*/
  183. if (GlobalChannel) {
  184. delete GlobalChannel;
  185. GlobalChannel = 0;
  186. }
  187. for (i = 0; i < NumConnections; i++) {
  188. delete Connection[i];
  189. Connection[i] = 0;
  190. }
  191. NumConnections = 0;
  192. /*------------------------------------------------------------------------
  193. Free all real-mode memory
  194. ------------------------------------------------------------------------*/
  195. if (RealMemAllocd) {
  196. Free_RealMode_Mem();
  197. RealMemAllocd = 0;
  198. }
  199. } /* end of ~IPXManagerClass */
  200. /***************************************************************************
  201. * IPXManagerClass::Init -- initialization routine *
  202. * *
  203. * This routine allocates memory,
  204. * *
  205. * INPUT: *
  206. * none. *
  207. * *
  208. * OUTPUT: *
  209. * 1 = OK, 0 = error *
  210. * *
  211. * WARNINGS: *
  212. * none. *
  213. * *
  214. * HISTORY: *
  215. * 12/20/1994 BR : Created. *
  216. *=========================================================================*/
  217. int IPXManagerClass::Init()
  218. {
  219. int i;
  220. if (!(GameToPlay == GAME_INTERNET)){
  221. /*
  222. ----------------------- Error if IPX not installed -----------------------
  223. */
  224. if (!IPXStatus) {
  225. return(false);
  226. }
  227. /*------------------------------------------------------------------------
  228. Stop Listening
  229. ------------------------------------------------------------------------*/
  230. if (Listening) {
  231. IPXConnClass::Stop_Listening();
  232. Listening = 0;
  233. }
  234. /*------------------------------------------------------------------------
  235. Free Real-mode memory
  236. ------------------------------------------------------------------------*/
  237. if (RealMemAllocd) {
  238. Free_RealMode_Mem();
  239. RealMemAllocd = 0;
  240. }
  241. }else{
  242. /*
  243. ** Pretend IPX is available for Internet games whether it is or not
  244. */
  245. IPXStatus = 1;
  246. }
  247. /*------------------------------------------------------------------------
  248. Free protected-mode memory
  249. ------------------------------------------------------------------------*/
  250. if (GlobalChannel) {
  251. delete GlobalChannel;
  252. GlobalChannel = 0;
  253. }
  254. for (i = 0; i < NumConnections; i++) {
  255. delete Connection[i];
  256. Connection[i] = 0;
  257. }
  258. NumConnections = 0;
  259. if (!(GameToPlay == GAME_INTERNET)){
  260. /*------------------------------------------------------------------------
  261. Allocate real-mode memory
  262. ------------------------------------------------------------------------*/
  263. if (!Alloc_RealMode_Mem()) return(false);
  264. RealMemAllocd = 1;
  265. }
  266. /*------------------------------------------------------------------------
  267. Allocate the Global Channel
  268. ------------------------------------------------------------------------*/
  269. GlobalChannel = new IPXGlobalConnClass (Glb_NumPackets, Glb_NumPackets,
  270. Glb_MaxPacketLen, ProductID);
  271. if (!GlobalChannel)
  272. return(false);
  273. GlobalChannel->Init();
  274. GlobalChannel->Set_Retry_Delta (RetryDelta);
  275. GlobalChannel->Set_Max_Retries (MaxRetries);
  276. GlobalChannel->Set_TimeOut (Timeout);
  277. /*------------------------------------------------------------------------
  278. Configure the IPX Connections
  279. ------------------------------------------------------------------------*/
  280. IPXConnClass::Configure(Socket, ConnectionNum, ListenECB, SendECB,
  281. FirstHeaderBuf, SendHeader, FirstDataBuf, SendBuf, Handler, PacketLen);
  282. /*------------------------------------------------------------------------
  283. Start Listening
  284. ------------------------------------------------------------------------*/
  285. if (!(GameToPlay == GAME_INTERNET)){
  286. if (!IPXConnClass::Start_Listening()) return(false);
  287. }
  288. Listening = 1;
  289. return(true);
  290. }
  291. /***************************************************************************
  292. * IPXManagerClass::Is_IPX -- tells if IPX is installed or not *
  293. * *
  294. * INPUT: *
  295. * none. *
  296. * *
  297. * OUTPUT: *
  298. * 1 = IPX is installed; 0 = isn't *
  299. * *
  300. * WARNINGS: *
  301. * none. *
  302. * *
  303. * HISTORY: *
  304. * 12/20/1994 BR : Created. *
  305. *=========================================================================*/
  306. int IPXManagerClass::Is_IPX(void)
  307. {
  308. return(IPXStatus);
  309. } /* end of Is_IPX */
  310. /***************************************************************************
  311. * IPXManagerClass::Set_Timing -- sets timing for all connections *
  312. * *
  313. * This will set the timing parameters for all existing connections, and *
  314. * all connections created from now on. This allows an application to *
  315. * measure the Response_Time while running, and adjust timing accordingly. *
  316. * *
  317. * INPUT: *
  318. * retrydelta value to set for retry delta *
  319. * maxretries value to set for max # retries *
  320. * timeout value to set for connection timeout *
  321. * *
  322. * OUTPUT: *
  323. * none. *
  324. * *
  325. * WARNINGS: *
  326. * none. *
  327. * *
  328. * HISTORY: *
  329. * 07/02/1995 BR : Created. *
  330. *=========================================================================*/
  331. void IPXManagerClass::Set_Timing (unsigned long retrydelta,
  332. unsigned long maxretries, unsigned long timeout)
  333. {
  334. int i;
  335. RetryDelta = retrydelta;
  336. MaxRetries = maxretries;
  337. Timeout = timeout;
  338. if (GlobalChannel) {
  339. GlobalChannel->Set_Retry_Delta (RetryDelta);
  340. GlobalChannel->Set_Max_Retries (MaxRetries);
  341. GlobalChannel->Set_TimeOut (Timeout);
  342. }
  343. for (i = 0; i < NumConnections; i++) {
  344. Connection[i]->Set_Retry_Delta (RetryDelta);
  345. Connection[i]->Set_Max_Retries (MaxRetries);
  346. Connection[i]->Set_TimeOut (Timeout);
  347. }
  348. } /* end of Set_Timing */
  349. /***************************************************************************
  350. * IPXManagerClass::Create_Connection -- creates a new connection *
  351. * *
  352. * INPUT: *
  353. * id application-specific numerical ID for this connection *
  354. * node ptr to IPXNodeIDType (name & address) *
  355. * address IPX address for this connection *
  356. * *
  357. * OUTPUT: *
  358. * 1 = OK, 0 = error *
  359. * *
  360. * WARNINGS: *
  361. * Never create a connection with an 'id' of -1. *
  362. * *
  363. * HISTORY: *
  364. * 12/20/1994 BR : Created. *
  365. *=========================================================================*/
  366. bool IPXManagerClass::Create_Connection(int id, char *name, IPXAddressClass *address)
  367. {
  368. #if (0)
  369. char temp[80];
  370. NetNumType num;
  371. NetNodeType node;
  372. address->Get_Address (num, node);
  373. sprintf (temp, "Address:%02x %02x %02x %02x %02x %02x\n", node[0],
  374. node[1],
  375. node[2],
  376. node[3],
  377. node[4],
  378. node[5]);
  379. CCDebugString (temp);
  380. sprintf (temp, "Network:%02x %02x %02x %02x\n", num[0],
  381. num[1],
  382. num[2],
  383. num[3]);
  384. CCDebugString (temp);
  385. #endif //(0)
  386. /*
  387. ----------------------- Error if IPX not installed -----------------------
  388. */
  389. if (!IPXStatus)
  390. return(false);
  391. /*
  392. ------------------------- Error if no more room --------------------------
  393. */
  394. if (NumConnections==CONNECT_MAX)
  395. return(false);
  396. /*
  397. ------------------------- Create new connection --------------------------
  398. */
  399. Connection[NumConnections] = new IPXConnClass(Pvt_NumPackets,
  400. Pvt_NumPackets, Pvt_MaxPacketLen, ProductID, address, id, name);
  401. if (!Connection[NumConnections])
  402. return(false);
  403. Connection[NumConnections]->Init ();
  404. Connection[NumConnections]->Set_Retry_Delta (RetryDelta);
  405. Connection[NumConnections]->Set_Max_Retries (MaxRetries);
  406. Connection[NumConnections]->Set_TimeOut (Timeout);
  407. NumConnections++;
  408. return(true);
  409. } /* end of Create_Connection */
  410. /***************************************************************************
  411. * IPXManagerClass::Delete_Connection -- deletes a connection *
  412. * *
  413. * INPUT: *
  414. * id ID of connection to delete *
  415. * *
  416. * OUTPUT: *
  417. * 1 = OK, 0 = error *
  418. * *
  419. * WARNINGS: *
  420. * none. *
  421. * *
  422. * HISTORY: *
  423. * 12/20/1994 BR : Created. *
  424. *=========================================================================*/
  425. bool IPXManagerClass::Delete_Connection(int id)
  426. {
  427. int i,j;
  428. /*
  429. ----------------------- Error if IPX not installed -----------------------
  430. */
  431. if (!IPXStatus)
  432. return(false);
  433. /*
  434. ------------------- Error if no connections to delete --------------------
  435. */
  436. if (NumConnections==0)
  437. return(false);
  438. /*
  439. ---------------------- Loop through all connections ----------------------
  440. */
  441. for (i = 0; i < NumConnections; i++) {
  442. /*
  443. ........................ If a match, delete it ........................
  444. */
  445. if (Connection[i]->ID==id) {
  446. delete Connection[i];
  447. /*
  448. ................ Move array elements back one index ................
  449. */
  450. for (j = i; j < NumConnections - 1; j++) {
  451. Connection[j] = Connection[j+1];
  452. }
  453. /*
  454. ......................... Adjust counters ..........................
  455. */
  456. NumConnections--;
  457. if (CurConnection >= NumConnections)
  458. CurConnection = 0;
  459. return(true);
  460. }
  461. }
  462. /*
  463. ---------------------------- No match; error -----------------------------
  464. */
  465. return(false);
  466. } /* end of Delete_Connection */
  467. /***************************************************************************
  468. * IPXManagerClass::Num_Connections -- gets the # of connections *
  469. * *
  470. * INPUT: *
  471. * none. *
  472. * *
  473. * OUTPUT: *
  474. * # of connections *
  475. * *
  476. * WARNINGS: *
  477. * none. *
  478. * *
  479. * HISTORY: *
  480. * 01/25/1995 BR : Created. *
  481. *=========================================================================*/
  482. int IPXManagerClass::Num_Connections(void)
  483. {
  484. #ifdef VIRTUAL_SUBNET_SERVER
  485. /*
  486. ** If we are connected to the VSS then dont coumt that in the number of connections.
  487. */
  488. if (Connection_Index (VSS_ID) == IPXConnClass::CONNECTION_NONE){
  489. return(NumConnections);
  490. }else{
  491. return(NumConnections -1);
  492. }
  493. #else // VIRTUAL_SUBNET_SERVER
  494. return(NumConnections);
  495. #endif //VIRTUAL_SUBNET_SERVER
  496. } /* end of Num_Connections */
  497. /***************************************************************************
  498. * IPXManagerClass::Connection_ID -- gets the given connection's ID *
  499. * *
  500. * INPUT: *
  501. * index index of connection to retrieve *
  502. * *
  503. * OUTPUT: *
  504. * ID for that connection, CONNECTION_NONE if invalid index *
  505. * *
  506. * WARNINGS: *
  507. * none. *
  508. * *
  509. * HISTORY: *
  510. * 01/25/1995 BR : Created. *
  511. *=========================================================================*/
  512. int IPXManagerClass::Connection_ID(int index)
  513. {
  514. if (index >= 0 && index < NumConnections) {
  515. return(Connection[index]->ID);
  516. } else {
  517. return(IPXConnClass::CONNECTION_NONE);
  518. }
  519. }
  520. /***************************************************************************
  521. * IPXManagerClass::Connection_Name -- retrieves name for given connection *
  522. * *
  523. * INPUT: *
  524. * id ID of connection to get name of *
  525. * *
  526. * OUTPUT: *
  527. * ptr to connection's name, NULL if not found *
  528. * *
  529. * WARNINGS: *
  530. * none. *
  531. * *
  532. * HISTORY: *
  533. * 01/19/1995 BR : Created. *
  534. *=========================================================================*/
  535. char *IPXManagerClass::Connection_Name(int id)
  536. {
  537. int i;
  538. for (i = 0; i < NumConnections; i++) {
  539. if (Connection[i]->ID==id) {
  540. return(Connection[i]->Name);
  541. }
  542. }
  543. return(NULL);
  544. } /* end of Connection_Name */
  545. /***************************************************************************
  546. * IPXManagerClass::Connection_Address -- retrieves connection's address *
  547. * *
  548. * INPUT: *
  549. * id ID of connection to get address for *
  550. * *
  551. * OUTPUT: *
  552. * pointer to IXPAddressClass, NULL if not found *
  553. * *
  554. * WARNINGS: *
  555. * none. *
  556. * *
  557. * HISTORY: *
  558. * 01/19/1995 BR : Created. *
  559. *=========================================================================*/
  560. IPXAddressClass * IPXManagerClass::Connection_Address(int id)
  561. {
  562. int i;
  563. for (i = 0; i < NumConnections; i++) {
  564. if (Connection[i]->ID==id) {
  565. return(&Connection[i]->Address);
  566. }
  567. }
  568. return(NULL);
  569. } /* end of Connection_Address */
  570. /***************************************************************************
  571. * IPXManagerClass::Connection_Index -- gets given connection's index *
  572. * *
  573. * INPUT: *
  574. * ID to retrieve index for *
  575. * *
  576. * OUTPUT: *
  577. * index for this connection, CONNECTION_NONE if not found *
  578. * *
  579. * WARNINGS: *
  580. * none. *
  581. * *
  582. * HISTORY: *
  583. * 01/25/1995 BR : Created. *
  584. *=========================================================================*/
  585. int IPXManagerClass::Connection_Index(int id)
  586. {
  587. int i;
  588. for (i = 0; i < NumConnections; i++) {
  589. if (Connection[i]->ID==id)
  590. return(i);
  591. }
  592. return(IPXConnClass::CONNECTION_NONE);
  593. } /* end of Connection_Index */
  594. /***************************************************************************
  595. * IPXManagerClass::Send_Global_Message -- sends a Global Message *
  596. * *
  597. * INPUT: *
  598. * buf buffer to send *
  599. * buflen length of buf *
  600. * ack_req 1 = ACK required; 0 = no ACK required *
  601. * address address to send to; NULL = broadcast *
  602. * *
  603. * OUTPUT: *
  604. * 1 = OK, 0 = error *
  605. * *
  606. * WARNINGS: *
  607. * none. *
  608. * *
  609. * HISTORY: *
  610. * 01/25/1995 BR : Created. *
  611. *=========================================================================*/
  612. int IPXManagerClass::Send_Global_Message(void *buf, int buflen,
  613. int ack_req, IPXAddressClass *address)
  614. {
  615. int rc;
  616. /*
  617. ------------ Error if IPX not installed or not Listening -----------------
  618. */
  619. if (!IPXStatus || !Listening) return(false);
  620. rc = GlobalChannel->Send_Packet (buf, buflen, address, ack_req);
  621. if (!rc)
  622. SendOverflows++;
  623. return(rc);
  624. }
  625. /***************************************************************************
  626. * IPXManagerClass::Get_Global_Message -- polls the Global Message queue *
  627. * *
  628. * INPUT: *
  629. * buf buffer to store received packet *
  630. * buflen length of data placed in 'buf' *
  631. * address IPX address of sender *
  632. * product_id product ID of sender *
  633. * *
  634. * OUTPUT: *
  635. * 1 = OK, 0 = error *
  636. * *
  637. * WARNINGS: *
  638. * none. *
  639. * *
  640. * HISTORY: *
  641. * 01/25/1995 BR : Created. *
  642. *=========================================================================*/
  643. int IPXManagerClass::Get_Global_Message(void *buf, int *buflen,
  644. IPXAddressClass *address, unsigned short *product_id)
  645. {
  646. /*
  647. ------------ Error if IPX not installed or not Listening -----------------
  648. */
  649. if (!IPXStatus || !Listening) return(false);
  650. return(GlobalChannel->Get_Packet (buf, buflen, address, product_id));
  651. }
  652. /***************************************************************************
  653. * IPXManagerClass::Send_Private_Message -- Sends a Private Message *
  654. * *
  655. * INPUT: *
  656. * buf buffer to send *
  657. * buflen length of 'buf' *
  658. * conn_id connection ID to send to (CONNECTION_NONE = all) *
  659. * ack_req 1 = ACK required; 0 = no ACK required *
  660. * *
  661. * OUTPUT: *
  662. * 1 = OK, 0 = error *
  663. * *
  664. * WARNINGS: *
  665. * none. *
  666. * *
  667. * HISTORY: *
  668. * 01/25/1995 BR : Created. *
  669. *=========================================================================*/
  670. int IPXManagerClass::Send_Private_Message(void *buf, int buflen, int ack_req,
  671. int conn_id)
  672. {
  673. int i; // loop counter
  674. int connect_idx; // index of channel to send to, if specified
  675. /*
  676. ------------ Error if IPX not installed or not Listening -----------------
  677. */
  678. if (!IPXStatus || !Listening || (NumConnections==0)) return(false);
  679. /*------------------------------------------------------------------------
  680. Send the message to all connections
  681. ------------------------------------------------------------------------*/
  682. if (conn_id==IPXConnClass::CONNECTION_NONE) {
  683. /*
  684. ** If this is an internet game and no ack is reqired then we only need to send
  685. ** the packet to the VSS and it will forward it to all the other players.
  686. */
  687. #ifdef VIRTUAL_SUBNET_SERVER
  688. if (ack_req || (!Winsock.Get_Connected() || !UseVirtualSubnetServer)){
  689. #endif //VIRTUAL_SUBNET_SERVER
  690. /*.....................................................................
  691. Check for room in all connections
  692. .....................................................................*/
  693. for (i = 0; i < NumConnections; i++) {
  694. #ifdef VIRTUAL_SUBNET_SERVER
  695. if (Connection[i]->ID != VSS_ID){
  696. #endif //VIRTUAL_SUBNET_SERVER
  697. if (Connection[i]->Queue->Num_Send()==Connection[i]->Queue->Max_Send()) {
  698. SendOverflows++;
  699. return(false);
  700. }
  701. #ifdef VIRTUAL_SUBNET_SERVER
  702. }
  703. #endif // VIRTUAL_SUBNET_SERVER
  704. }
  705. /*.....................................................................
  706. Send packet to all connections
  707. .....................................................................*/
  708. for (i = 0; i < NumConnections; i++) {
  709. #ifdef VIRTUAL_SUBNET_SERVER
  710. if (Connection[i]->ID != VSS_ID){
  711. #endif //VIRTUAL_SUBNET_SERVER
  712. Connection[i]->Send_Packet (buf, buflen, ack_req);
  713. #ifdef VIRTUAL_SUBNET_SERVER
  714. }
  715. #endif //VIRTUAL_SUBNET_SERVER
  716. }
  717. #ifdef VIRTUAL_SUBNET_SERVER
  718. }else{
  719. /*
  720. ** Send the packet to the VSS with a 0 header so it gets forwarded to all players.
  721. */
  722. if (Connection[ Connection_Index(VSS_ID) ]->Queue->Num_Send() == Connection[ Connection_Index(VSS_ID) ]->Queue->Max_Send()) {
  723. SendOverflows++;
  724. return(false);
  725. }
  726. Connection[ Connection_Index(VSS_ID) ]->Send_Packet (buf, buflen, 0);
  727. }
  728. #endif // VIRTUAL_SUBNET_SERVER
  729. return(true);
  730. } else {
  731. /*------------------------------------------------------------------------
  732. Send the message to the specified connection
  733. ------------------------------------------------------------------------*/
  734. connect_idx = Connection_Index (conn_id);
  735. if (connect_idx == IPXConnClass::CONNECTION_NONE) {
  736. SendOverflows++;
  737. return(false);
  738. }
  739. /*.....................................................................
  740. Check for room in the connection
  741. .....................................................................*/
  742. if (Connection[connect_idx]->Queue->Num_Send() ==
  743. Connection[connect_idx]->Queue->Max_Send()) {
  744. SendOverflows++;
  745. return(false);
  746. }
  747. /*.....................................................................
  748. Send the packet to that connection
  749. .....................................................................*/
  750. Connection[connect_idx]->Send_Packet (buf, buflen, ack_req);
  751. return(true);
  752. }
  753. }
  754. /***************************************************************************
  755. * IPXManagerClass::Get_Private_Message -- Polls the Private Message queue *
  756. * *
  757. * INPUT: *
  758. * buf buffer to store incoming packet *
  759. * buflen length of data placed in 'buf' *
  760. * conn_id filled in with connection ID of sender *
  761. * *
  762. * OUTPUT: *
  763. * 1 = OK, 0 = error *
  764. * *
  765. * WARNINGS: *
  766. * none. *
  767. * *
  768. * HISTORY: *
  769. * 01/25/1995 BR : Created. *
  770. *=========================================================================*/
  771. int IPXManagerClass::Get_Private_Message(void *buf, int *buflen, int *conn_id)
  772. {
  773. int i;
  774. int rc;
  775. int c_id;
  776. #ifdef VIRTUAL_SUBNET_SERVER
  777. int vss = 0;
  778. #endif // VIRTUAL_SUBNET_SERVER
  779. /*
  780. ------------ Error if IPX not installed or not Listening -----------------
  781. */
  782. if (!IPXStatus || !Listening || (NumConnections==0)) return(false);
  783. #ifdef VIRTUAL_SUBNET_SERVER
  784. if (Winsock.Get_Connected()){
  785. vss = (int) UseVirtualSubnetServer;
  786. }
  787. #endif //VIRTUAL_SUBNET_SERVER
  788. /*------------------------------------------------------------------------
  789. Safety check: ensure CurConnection is in range.
  790. ------------------------------------------------------------------------*/
  791. #ifdef VIRTUAL_SUBNET_SERVER
  792. if (CurConnection >= NumConnections - vss)
  793. #else // VIRTUAL_SUBNET_SERVER
  794. if (CurConnection >= NumConnections)
  795. #endif //VIRTUAL_SUBNET_SERVER
  796. CurConnection = 0;
  797. /*------------------------------------------------------------------------
  798. Scan all connections for a received packet, starting with 'CurConnection'
  799. ------------------------------------------------------------------------*/
  800. #ifdef VIRTUAL_SUBNET_SERVER
  801. for (i = 0; i < NumConnections - vss; i++) {
  802. #else // VIRTUAL_SUBNET_SERVER
  803. for (i = 0; i < NumConnections; i++) {
  804. #endif // VIRTUAL_SUBNET_SERVER
  805. /*.....................................................................
  806. Check this connection for a packet
  807. .....................................................................*/
  808. rc = Connection[CurConnection]->Get_Packet (buf, buflen);
  809. c_id = Connection[CurConnection]->ID;
  810. /*.....................................................................
  811. Increment CurConnection to the next connection index
  812. .....................................................................*/
  813. CurConnection++;
  814. #ifdef VIRTUAL_SUBNET_SERVER
  815. if (CurConnection >= NumConnections - vss)
  816. #else // VIRTUAL_SUBNET_SERVER
  817. if (CurConnection >= NumConnections)
  818. #endif // VIRTUAL_SUBNET_SERVER
  819. CurConnection = 0;
  820. /*.....................................................................
  821. If we got a packet, return the connection ID
  822. .....................................................................*/
  823. if (rc) {
  824. (*conn_id) = c_id;
  825. return(true);
  826. }
  827. }
  828. return(false);
  829. }
  830. /***************************************************************************
  831. * IPXManagerClass::Service -- main polling routine for IPX Connections *
  832. * *
  833. * INPUT: *
  834. * none. *
  835. * *
  836. * OUTPUT: *
  837. * 1 = OK, 0 = error *
  838. * *
  839. * WARNINGS: *
  840. * none. *
  841. * *
  842. * HISTORY: *
  843. * 01/25/1995 BR : Created. *
  844. *=========================================================================*/
  845. int IPXManagerClass::Service(void)
  846. {
  847. int rc = 1;
  848. int i;
  849. CommHeaderType *packet;
  850. int packetlen;
  851. IPXAddressClass address;
  852. #ifndef NOT_FOR_WIN95
  853. unsigned char temp_receive_buffer[1024];
  854. int recv_length;
  855. if (Winsock.Get_Connected()){
  856. while ((recv_length = Winsock.Read(temp_receive_buffer, 1024))!=0){
  857. #ifdef VIRTUAL_SUBNET_SERVER
  858. /*
  859. ** Get a pointer to the data header and swap the bit mask
  860. */
  861. CurHeaderBuf = (IPXHEADER*)&temp_receive_buffer[0]; //NULL;
  862. unsigned short *swapptr = (unsigned short*)CurHeaderBuf;
  863. *swapptr = ntohs (*swapptr);
  864. CurDataBuf = (char*)&temp_receive_buffer[2];
  865. /*.....................................................................
  866. Compute the length of the packet (byte-swap the length in the IPX hdr)
  867. .....................................................................*/
  868. packetlen = recv_length-2;
  869. #else //VIRTUAL_SUBNET_SERVER
  870. CurHeaderBuf = NULL;
  871. CurDataBuf = (char*)&temp_receive_buffer[0];
  872. /*.....................................................................
  873. Compute the length of the packet (byte-swap the length in the IPX hdr)
  874. .....................................................................*/
  875. packetlen = recv_length;
  876. #endif //VIRTUAL_SUBNET_SERVER
  877. /*.....................................................................
  878. Extract the sender's address from the IPX header
  879. .....................................................................*/
  880. address.Set_Address (CurHeaderBuf);
  881. /*.....................................................................
  882. Examine the Magic Number of the received packet to determine if this
  883. packet goes into the Global Queue, or into one of the Private Queues
  884. .....................................................................*/
  885. packet = (CommHeaderType *)CurDataBuf;
  886. #if (0)
  887. char tempbuf[256];
  888. static char pcode [4][18]={
  889. "PACKET_DATA_ACK", // this is a data packet requiring an ACK
  890. "PACKET_DATA_NOACK", // this is a data packet not requiring an ACK
  891. "PACKET_ACK", // this is an ACK for a packet
  892. "PACKET_COUNT" // for computational purposes
  893. };
  894. sprintf (tempbuf, "Received packet type %d, ID=%d, code=%s, length=%d \n", CurDataBuf[sizeof(CommHeaderType)],
  895. packet->PacketID,
  896. pcode[packet->Code],
  897. recv_length);
  898. CCDebugString (tempbuf);
  899. #endif //(0)
  900. if (packet->MagicNumber == GlobalChannel->Magic_Num()) {
  901. /*..................................................................
  902. Put the packet in the Global Queue
  903. ..................................................................*/
  904. if (!GlobalChannel->Receive_Packet (packet, packetlen, &address))
  905. ReceiveOverflows++;
  906. } else {
  907. if (packet->MagicNumber == ProductID) {
  908. /*..................................................................
  909. Find the Private Queue that this packet is for
  910. ..................................................................*/
  911. for (i = 0; i < NumConnections; i++) {
  912. #ifdef VIRTUAL_SUBNET_SERVER
  913. if (Connection[i]->Address == address && Connection[i]->ID != VSS_ID) {
  914. #else //VIRTUAL_SUBNET_SERVER
  915. if (Connection[i]->Address == address) {
  916. #endif //VIRTUAL_SUBNET_SERVER
  917. if (!Connection[i]->Receive_Packet (packet, packetlen))
  918. ReceiveOverflows++;
  919. break;
  920. }
  921. }
  922. }
  923. }
  924. }
  925. }else{
  926. while (IPX_Get_Outstanding_Buffer95(&temp_receive_buffer[0])){
  927. CurHeaderBuf = (IPXHEADER*)&temp_receive_buffer[0];
  928. CurDataBuf = (char*)&temp_receive_buffer[sizeof(IPXHeaderType)];
  929. /*.....................................................................
  930. Compute the length of the packet (byte-swap the length in the IPX hdr)
  931. .....................................................................*/
  932. packetlen = ((CurHeaderBuf->Length & 0xff) << 8) |
  933. (CurHeaderBuf->Length >> 8);
  934. packetlen -= sizeof(IPXHeaderType);
  935. /*.....................................................................
  936. Extract the sender's address from the IPX header
  937. .....................................................................*/
  938. address.Set_Address (CurHeaderBuf);
  939. /*.....................................................................
  940. Examine the Magic Number of the received packet to determine if this
  941. packet goes into the Global Queue, or into one of the Private Queues
  942. .....................................................................*/
  943. packet = (CommHeaderType *)CurDataBuf;
  944. if (packet->MagicNumber == GlobalChannel->Magic_Num()) {
  945. /*..................................................................
  946. Put the packet in the Global Queue
  947. ..................................................................*/
  948. if (!GlobalChannel->Receive_Packet (packet, packetlen, &address))
  949. ReceiveOverflows++;
  950. } else {
  951. if (packet->MagicNumber == ProductID) {
  952. /*..................................................................
  953. Find the Private Queue that this packet is for
  954. ..................................................................*/
  955. for (i = 0; i < NumConnections; i++) {
  956. if (Connection[i]->Address == address) {
  957. if (!Connection[i]->Receive_Packet (packet, packetlen))
  958. ReceiveOverflows++;
  959. break;
  960. }
  961. }
  962. }
  963. }
  964. }
  965. }
  966. //IPX_Start_Listening95();
  967. #else //NOT_FOR_WIN95
  968. /*
  969. ------------ Error if IPX not installed or not Listening -----------------
  970. */
  971. if (!IPXStatus || !Listening)
  972. return(false);
  973. /*------------------------------------------------------------------------
  974. Loop until there are no more packets to process.
  975. ------------------------------------------------------------------------*/
  976. for (;;) {
  977. /*.....................................................................
  978. Check the BufferFlags for the "current" buffer; if it's empty,
  979. break; out of the loop.
  980. .....................................................................*/
  981. if (BufferFlags[CurIndex]==0)
  982. break;
  983. /*.....................................................................
  984. Compute the length of the packet (byte-swap the length in the IPX hdr)
  985. .....................................................................*/
  986. packetlen = ((CurHeaderBuf->Length & 0xff) << 8) |
  987. (CurHeaderBuf->Length >> 8);
  988. packetlen -= sizeof(IPXHeaderType);
  989. /*.....................................................................
  990. Extract the sender's address from the IPX header
  991. .....................................................................*/
  992. address.Set_Address (CurHeaderBuf);
  993. /*.....................................................................
  994. Examine the Magic Number of the received packet to determine if this
  995. packet goes into the Global Queue, or into one of the Private Queues
  996. .....................................................................*/
  997. packet = (CommHeaderType *)CurDataBuf;
  998. if (packet->MagicNumber == GlobalChannel->Magic_Num()) {
  999. /*..................................................................
  1000. Put the packet in the Global Queue
  1001. ..................................................................*/
  1002. if (!GlobalChannel->Receive_Packet (packet, packetlen, &address))
  1003. ReceiveOverflows++;
  1004. } else {
  1005. if (packet->MagicNumber == ProductID) {
  1006. /*..................................................................
  1007. Find the Private Queue that this packet is for
  1008. ..................................................................*/
  1009. for (i = 0; i < NumConnections; i++) {
  1010. if (Connection[i]->Address == address) {
  1011. if (!Connection[i]->Receive_Packet (packet, packetlen))
  1012. ReceiveOverflows++;
  1013. break;
  1014. }
  1015. }
  1016. }
  1017. }
  1018. /*.....................................................................
  1019. Set the current BufferFlags to 0 (since we've cleaned out this buffer)
  1020. .....................................................................*/
  1021. BufferFlags[CurIndex] = 0;
  1022. /*.....................................................................
  1023. Go to the next packet buffer
  1024. .....................................................................*/
  1025. CurIndex++;
  1026. CurHeaderBuf = (IPXHeaderType *)(((char *)CurHeaderBuf) + FullPacketLen);
  1027. CurDataBuf = ((char *)CurDataBuf) + FullPacketLen;
  1028. if (CurIndex >= NumBufs) {
  1029. CurHeaderBuf = FirstHeaderBuf;
  1030. CurDataBuf = FirstDataBuf;
  1031. CurIndex = 0;
  1032. }
  1033. }
  1034. #endif //NOT_FOR_WIN95
  1035. /*------------------------------------------------------------------------
  1036. Service all connections. If a connection reports that it's gone "bad",
  1037. report an error to the caller. If it's the Global Channel, un-queue the
  1038. send entry that's holding things up. This will keep the Global Channel
  1039. from being clogged by one un-ACK'd outgoing packet.
  1040. ------------------------------------------------------------------------*/
  1041. if (GlobalChannel) {
  1042. if (!GlobalChannel->Service()) {
  1043. GlobalChannel->Queue->UnQueue_Send (NULL, NULL, 0);
  1044. rc = 0;
  1045. }
  1046. }
  1047. for (i = 0; i < NumConnections; i++) {
  1048. if (!Connection[i]->Service()) {
  1049. #ifdef VIRTUAL_SUBNET_SERVER
  1050. if (Connection[i]->ID != VSS_ID){
  1051. #endif //VIRTUAL_SUBNET_SERVER
  1052. rc = 0;
  1053. BadConnection = Connection[i]->ID;
  1054. #ifdef VIRTUAL_SUBNET_SERVER
  1055. }
  1056. #endif //VIRTUAL_SUBNET_SERVER
  1057. }
  1058. }
  1059. if (rc)
  1060. BadConnection = IPXConnClass::CONNECTION_NONE;
  1061. return(rc);
  1062. } /* end of Service */
  1063. /***************************************************************************
  1064. * IPXManagerClass::Get_Bad_Connection -- returns bad connection ID *
  1065. * *
  1066. * INPUT: *
  1067. * none. *
  1068. * *
  1069. * OUTPUT: *
  1070. * ID of bad connection; CONNECTION_NONE if none. *
  1071. * *
  1072. * WARNINGS: *
  1073. * none. *
  1074. * *
  1075. * HISTORY: *
  1076. * 05/04/1995 BRR : Created. *
  1077. *=========================================================================*/
  1078. int IPXManagerClass::Get_Bad_Connection(void)
  1079. {
  1080. return(BadConnection);
  1081. } /* end of Get_Bad_Connection */
  1082. /***************************************************************************
  1083. * IPXManagerClass::Global_Num_Send -- reports # entries in send queue *
  1084. * *
  1085. * INPUT: *
  1086. * none. *
  1087. * *
  1088. * OUTPUT: *
  1089. * # entries in the Global Send Queue *
  1090. * *
  1091. * WARNINGS: *
  1092. * none. *
  1093. * *
  1094. * HISTORY: *
  1095. * 01/25/1995 BR : Created. *
  1096. *=========================================================================*/
  1097. int IPXManagerClass::Global_Num_Send(void)
  1098. {
  1099. /*
  1100. ------------ Error if IPX not installed or not Listening -----------------
  1101. */
  1102. if (!IPXStatus || !Listening)
  1103. return(0);
  1104. return(GlobalChannel->Queue->Num_Send());
  1105. } /* end of Global_Num_Send */
  1106. /***************************************************************************
  1107. * IPXManagerClass::Global_Num_Receive -- reports # entries in recv queue *
  1108. * *
  1109. * INPUT: *
  1110. * none. *
  1111. * *
  1112. * OUTPUT: *
  1113. * # entries in the Global Receive Queue *
  1114. * *
  1115. * WARNINGS: *
  1116. * none. *
  1117. * *
  1118. * HISTORY: *
  1119. * 01/25/1995 BR : Created. *
  1120. *=========================================================================*/
  1121. int IPXManagerClass::Global_Num_Receive(void)
  1122. {
  1123. /*
  1124. ------------ Error if IPX not installed or not Listening -----------------
  1125. */
  1126. if (!IPXStatus || !Listening)
  1127. return(0);
  1128. return(GlobalChannel->Queue->Num_Receive());
  1129. } /* end of Global_Num_Receive */
  1130. /***************************************************************************
  1131. * IPXManagerClass::Private_Num_Send -- reports # entries in send queue *
  1132. * *
  1133. * INPUT: *
  1134. * # entries in the Private Send Queue *
  1135. * *
  1136. * OUTPUT: *
  1137. * 1 = OK, 0 = error *
  1138. * *
  1139. * WARNINGS: *
  1140. * none. *
  1141. * *
  1142. * HISTORY: *
  1143. * 01/25/1995 BR : Created. *
  1144. *=========================================================================*/
  1145. int IPXManagerClass::Private_Num_Send(int id)
  1146. {
  1147. int i;
  1148. int maxnum;
  1149. /*
  1150. ------------ Error if IPX not installed or not Listening -----------------
  1151. */
  1152. if (!IPXStatus || !Listening || (NumConnections==0)) return(false);
  1153. /*------------------------------------------------------------------------
  1154. If connection ID specified, return that connection's # of packets
  1155. ------------------------------------------------------------------------*/
  1156. if (id != IPXConnClass::CONNECTION_NONE) {
  1157. i = Connection_Index(id);
  1158. if (i != IPXConnClass::CONNECTION_NONE) {
  1159. return(Connection[i]->Queue->Num_Send());
  1160. } else {
  1161. return(false);
  1162. }
  1163. } else {
  1164. /*------------------------------------------------------------------------
  1165. Otherwise, return the max # of all connections
  1166. ------------------------------------------------------------------------*/
  1167. maxnum = 0;
  1168. for (i = 0; i < NumConnections; i++) {
  1169. if (Connection[i]->Queue->Num_Send() > maxnum) {
  1170. maxnum = Connection[i]->Queue->Num_Send();
  1171. }
  1172. }
  1173. return(maxnum);
  1174. }
  1175. }
  1176. /***************************************************************************
  1177. * IPXManagerClass::Private_Num_Receive -- reports # entries in recv queue *
  1178. * *
  1179. * INPUT: *
  1180. * id ID of connection to query *
  1181. * *
  1182. * OUTPUT: *
  1183. * # entries in the Private Receive Queue *
  1184. * *
  1185. * WARNINGS: *
  1186. * none. *
  1187. * *
  1188. * HISTORY: *
  1189. * 01/25/1995 BR : Created. *
  1190. *=========================================================================*/
  1191. int IPXManagerClass::Private_Num_Receive(int id)
  1192. {
  1193. int i;
  1194. int maxnum;
  1195. /*
  1196. ------------ Error if IPX not installed or not Listening -----------------
  1197. */
  1198. if (!IPXStatus || !Listening || (NumConnections==0))
  1199. return(0);
  1200. /*------------------------------------------------------------------------
  1201. If connection ID specified, return that connection's # of packets
  1202. ------------------------------------------------------------------------*/
  1203. if (id != IPXConnClass::CONNECTION_NONE) {
  1204. i = Connection_Index(id);
  1205. if (i != IPXConnClass::CONNECTION_NONE) {
  1206. return(Connection[i]->Queue->Num_Receive());
  1207. } else {
  1208. return(0);
  1209. }
  1210. } else {
  1211. /*------------------------------------------------------------------------
  1212. Otherwise, return the max # of all connections
  1213. ------------------------------------------------------------------------*/
  1214. maxnum = 0;
  1215. for (i = 0; i < NumConnections; i++) {
  1216. if (Connection[i]->Queue->Num_Receive() > maxnum)
  1217. maxnum = Connection[i]->Queue->Num_Receive();
  1218. }
  1219. return(maxnum);
  1220. }
  1221. }
  1222. /***************************************************************************
  1223. * IPXManagerClass::Set_Socket -- sets socket ID for all connections *
  1224. * *
  1225. * INPUT: *
  1226. * socket new socket ID to use *
  1227. * *
  1228. * OUTPUT: *
  1229. * none. *
  1230. * *
  1231. * WARNINGS: *
  1232. * Do not call this function after communications have started; you *
  1233. * must call it before calling Init(). *
  1234. * The socket number is byte-swapped, since IPX requires socket ID's *
  1235. * to be stored high/low. *
  1236. * *
  1237. * HISTORY: *
  1238. * 01/25/1995 BR : Created. *
  1239. *=========================================================================*/
  1240. void IPXManagerClass::Set_Socket(unsigned short socket)
  1241. {
  1242. Socket = (unsigned short)( (((unsigned long)socket & 0x00ff) << 8) |
  1243. (((unsigned long)socket & 0xff00) >> 8));
  1244. } /* end of Set_Socket */
  1245. /***************************************************************************
  1246. * IPXManagerClass::Response_Time -- Returns largest Avg Response Time *
  1247. * *
  1248. * INPUT: *
  1249. * none. *
  1250. * *
  1251. * OUTPUT: *
  1252. * largest avg response time *
  1253. * *
  1254. * WARNINGS: *
  1255. * none. *
  1256. * *
  1257. * HISTORY: *
  1258. * 05/04/1995 BRR : Created. *
  1259. *=========================================================================*/
  1260. unsigned long IPXManagerClass::Response_Time(void)
  1261. {
  1262. unsigned long resp;
  1263. unsigned long maxresp = 0;
  1264. int i;
  1265. #ifdef VIRTUAL_SUBNET_SERVER
  1266. int vss=0;
  1267. if (Winsock.Get_Connected()){
  1268. vss = (int) UseVirtualSubnetServer;
  1269. }
  1270. for (i = 0; i < NumConnections - vss; i++) {
  1271. #else //VIRTUAL_SUBNET_SERVER
  1272. for (i = 0; i < NumConnections; i++) {
  1273. #endif // VIRTUAL_SUBNET_SERVER
  1274. resp = Connection[i]->Queue->Avg_Response_Time();
  1275. if (resp > maxresp)
  1276. maxresp = resp;
  1277. }
  1278. return(maxresp);
  1279. }
  1280. /***************************************************************************
  1281. * IPXManagerClass::Global_Response_Time -- Returns Avg Response Time *
  1282. * *
  1283. * INPUT: *
  1284. * none. *
  1285. * *
  1286. * OUTPUT: *
  1287. * avg global channel response time *
  1288. * *
  1289. * WARNINGS: *
  1290. * none. *
  1291. * *
  1292. * HISTORY: *
  1293. * 05/04/1995 BRR : Created. *
  1294. *=========================================================================*/
  1295. unsigned long IPXManagerClass::Global_Response_Time(void)
  1296. {
  1297. if (GlobalChannel) {
  1298. return (GlobalChannel->Queue->Avg_Response_Time());
  1299. } else {
  1300. return (0);
  1301. }
  1302. }
  1303. /***************************************************************************
  1304. * IPXManagerClass::Reset_Response_Time -- Reset response time *
  1305. * *
  1306. * INPUT: *
  1307. * none. *
  1308. * *
  1309. * OUTPUT: *
  1310. * none. *
  1311. * *
  1312. * WARNINGS: *
  1313. * none. *
  1314. * *
  1315. * HISTORY: *
  1316. * 05/04/1995 BRR : Created. *
  1317. *=========================================================================*/
  1318. void IPXManagerClass::Reset_Response_Time(void)
  1319. {
  1320. int i;
  1321. for (i = 0; i < NumConnections; i++) {
  1322. Connection[i]->Queue->Reset_Response_Time();
  1323. }
  1324. if (GlobalChannel)
  1325. GlobalChannel->Queue->Reset_Response_Time();
  1326. } /* end of Reset_Response_Time */
  1327. /***************************************************************************
  1328. * IPXManagerClass::Oldest_Send -- gets ptr to oldest send buf *
  1329. * *
  1330. * INPUT: *
  1331. * none. *
  1332. * *
  1333. * OUTPUT: *
  1334. * buf ptr *
  1335. * *
  1336. * WARNINGS: *
  1337. * none. *
  1338. * *
  1339. * HISTORY: *
  1340. * 05/04/1995 BRR : Created. *
  1341. *=========================================================================*/
  1342. void * IPXManagerClass::Oldest_Send(void)
  1343. {
  1344. int i,j;
  1345. unsigned long time;
  1346. unsigned long mintime = 0xffffffff;
  1347. SendQueueType *send_entry; // ptr to send entry header
  1348. CommHeaderType *packet;
  1349. void *buf = NULL;
  1350. for (i = 0; i < NumConnections; i++) {
  1351. send_entry = NULL;
  1352. for (j = 0; j < Connection[i]->Queue->Num_Send(); j++) {
  1353. send_entry = Connection[i]->Queue->Get_Send(j);
  1354. if (send_entry) {
  1355. packet = (CommHeaderType *)send_entry->Buffer;
  1356. if (packet->Code == ConnectionClass::PACKET_DATA_ACK && send_entry->IsACK == 0) {
  1357. break;
  1358. } else {
  1359. send_entry = NULL;
  1360. }
  1361. }
  1362. }
  1363. if (send_entry!=NULL) {
  1364. time = send_entry->FirstTime;
  1365. if (time < mintime) {
  1366. mintime = time;
  1367. buf = send_entry->Buffer;
  1368. }
  1369. }
  1370. }
  1371. return(buf);
  1372. } /* end of Oldest_Send */
  1373. /***************************************************************************
  1374. * IPXManagerClass::Set_Bridge -- prepares to cross a bridge *
  1375. * *
  1376. * This routine is designed to prevent the connection from having to *
  1377. * call Get_Local_Target, except the minimum number of times, since that *
  1378. * routine is buggy & goes away for long periods sometimes. *
  1379. * *
  1380. * INPUT: *
  1381. * bridge network number of the destination bridge *
  1382. * *
  1383. * OUTPUT: *
  1384. * none *
  1385. * *
  1386. * WARNINGS: *
  1387. * none *
  1388. * *
  1389. * HISTORY: *
  1390. * 07/06/1995 BRR : Created. *
  1391. *=========================================================================*/
  1392. void IPXManagerClass::Set_Bridge(NetNumType bridge)
  1393. {
  1394. if (GlobalChannel) {
  1395. GlobalChannel->Set_Bridge(bridge);
  1396. }
  1397. }
  1398. /***************************************************************************
  1399. * IPXManagerClass::Configure_Debug -- sets up special debug values *
  1400. * *
  1401. * Mono_Debug_Print2() can look into a packet to pull out a particular *
  1402. * ID, and can print both that ID and a string corresponding to *
  1403. * that ID. This routine configures these values so it can find *
  1404. * and decode the ID. This ID is used in addition to the normal *
  1405. * CommHeaderType values. *
  1406. * *
  1407. * INPUT: *
  1408. * index connection index to configure (-1 = Global Channel) *
  1409. * offset ID's byte offset into packet *
  1410. * size size of ID, in bytes; 0 if none *
  1411. * names ptr to array of names; use ID as an index into this *
  1412. * maxnames max # in the names array; 0 if none. *
  1413. * *
  1414. * OUTPUT: *
  1415. * none. *
  1416. * *
  1417. * WARNINGS: *
  1418. * Names shouldn't be longer than 12 characters. *
  1419. * *
  1420. * HISTORY: *
  1421. * 05/31/1995 BRR : Created. *
  1422. *=========================================================================*/
  1423. void IPXManagerClass::Configure_Debug(int index, int offset, int size,
  1424. char **names, int maxnames)
  1425. {
  1426. if (index == -1) {
  1427. GlobalChannel->Queue->Configure_Debug (offset, size, names, maxnames);
  1428. } else {
  1429. if (Connection[index]) {
  1430. Connection[index]->Queue->Configure_Debug (offset, size, names, maxnames);
  1431. }
  1432. }
  1433. }
  1434. /***************************************************************************
  1435. * IPXManagerClass::Mono_Debug_Print -- debug output routine *
  1436. * *
  1437. * INPUT: *
  1438. * index index of connection to display (-1 = Global Channel) *
  1439. * refresh 1 = complete screen refresh *
  1440. * *
  1441. * OUTPUT: *
  1442. * 1 = OK, 0 = error *
  1443. * *
  1444. * WARNINGS: *
  1445. * none. *
  1446. * *
  1447. * HISTORY: *
  1448. * 01/25/1995 BR : Created. *
  1449. *=========================================================================*/
  1450. void IPXManagerClass::Mono_Debug_Print(int index, int refresh)
  1451. {
  1452. #ifdef WWLIB32_H
  1453. char txt[80];
  1454. int i;
  1455. if (index == -1)
  1456. GlobalChannel->Queue->Mono_Debug_Print (refresh);
  1457. else if (Connection[index])
  1458. Connection[index]->Queue->Mono_Debug_Print (refresh);
  1459. if (refresh) {
  1460. Mono_Set_Cursor (20,1);
  1461. Mono_Printf ("IPX Queue:");
  1462. Mono_Set_Cursor (9,2);
  1463. Mono_Printf ("Average Response Time:");
  1464. Mono_Set_Cursor (43,1);
  1465. Mono_Printf ("Send Overflows:");
  1466. Mono_Set_Cursor (40,2);
  1467. Mono_Printf ("Receive Overflows:");
  1468. }
  1469. Mono_Set_Cursor (32,1);
  1470. Mono_Printf ("%d",index);
  1471. Mono_Set_Cursor (32,2);
  1472. if (index == -1) {
  1473. Mono_Printf ("%d ", GlobalChannel->Queue->Avg_Response_Time());
  1474. } else {
  1475. Mono_Printf ("%d ", Connection[index]->Queue->Avg_Response_Time());
  1476. }
  1477. Mono_Set_Cursor (59,1);
  1478. Mono_Printf ("%d ", SendOverflows);
  1479. Mono_Set_Cursor (59,2);
  1480. Mono_Printf ("%d ", ReceiveOverflows);
  1481. for (i = 0; i < NumBufs; i++) {
  1482. if (BufferFlags[i]) {
  1483. txt[i] = 'X';
  1484. } else {
  1485. txt[i] = '_';
  1486. }
  1487. }
  1488. txt[i] = 0;
  1489. Mono_Set_Cursor ((80-NumBufs)/2,3);
  1490. Mono_Printf ("%s",txt);
  1491. #else
  1492. index = index;
  1493. refresh = refresh;
  1494. #endif
  1495. } /* end of Mono_Debug_Print */
  1496. /***************************************************************************
  1497. * IPXManagerClass::Alloc_RealMode_Mem -- allocates real-mode memory *
  1498. * *
  1499. * INPUT: *
  1500. * none. *
  1501. * *
  1502. * OUTPUT: *
  1503. * 1 = OK, 0 = error *
  1504. * *
  1505. * WARNINGS: *
  1506. * none. *
  1507. * *
  1508. * HISTORY: *
  1509. * 12/20/1994 BR : Created. *
  1510. *=========================================================================*/
  1511. int IPXManagerClass::Alloc_RealMode_Mem(void)
  1512. {
  1513. #ifdef NOT_FOR_WIN95
  1514. union REGS regs;
  1515. struct SREGS sregs;
  1516. int size; // required size of allocation
  1517. unsigned char *realmode; // start addresses of real-mode data
  1518. int realmodelen; // length of real-mode data
  1519. unsigned long func_val;
  1520. char *p; // for parsing buffer
  1521. int i;
  1522. /*------------------------------------------------------------------------
  1523. Compute # of buffers we need to allocate, & the max size of each one
  1524. ------------------------------------------------------------------------*/
  1525. NumBufs = Glb_NumPackets + (Pvt_NumPackets * CONNECT_MAX);
  1526. PacketLen = Glb_MaxPacketLen + sizeof (GlobalHeaderType);
  1527. if (Pvt_MaxPacketLen + sizeof (CommHeaderType) > PacketLen)
  1528. PacketLen = Pvt_MaxPacketLen + sizeof (CommHeaderType);
  1529. FullPacketLen = PacketLen + sizeof(IPXHeaderType);
  1530. /*------------------------------------------------------------------------
  1531. Compute the size of everything we'll ever need, allocate it in one big
  1532. chunk. The memory is used as follows:
  1533. - Real-mode assembly IPX callback routine, plus its data,
  1534. (which includes the ListenECB)
  1535. - Array of IPX Packet buffers (IPXHeader plus data buffer)
  1536. - SendECB: ECB for sending
  1537. - SendHeader: IPX Header for sending
  1538. - SendBuf: Packet buffer for sending
  1539. - BufferFlags: 1 byte for each incoming packet buffer; 1=in use, 0=free
  1540. ------------------------------------------------------------------------*/
  1541. realmode = (unsigned char *)Get_RM_IPX_Address();
  1542. realmodelen = Get_RM_IPX_Size();
  1543. size = realmodelen + // assembly routine & its data
  1544. (FullPacketLen * NumBufs) + // array of packet buffers
  1545. sizeof(ECBType) + // SendECB
  1546. FullPacketLen + // SendHeader & SendBuf
  1547. NumBufs; // BufferFlags
  1548. if (size > 65535)
  1549. return(false);
  1550. /*------------------------------------------------------------------------
  1551. Allocate DOS memory for the ECB, IPXHeader & packet buffers:
  1552. AX = 0x100
  1553. BX = # paragraphs to allocate
  1554. - if Success, AX = real-mode segment, DX = selector
  1555. - if Failure, carry flag is set
  1556. ------------------------------------------------------------------------*/
  1557. memset (&regs, 0 ,sizeof(regs));
  1558. segread (&sregs);
  1559. regs.x.eax = DPMI_ALLOC_DOS_MEM; // DPMI function to call
  1560. regs.x.ebx = ((size + 15) >> 4); // # paragraphs to allocate
  1561. int386x (DPMI_INT, &regs, &regs, &sregs); // allocate the memory
  1562. /*........................................................................
  1563. If the carry flag is set, DPMI is indicating an error.
  1564. ........................................................................*/
  1565. if (regs.x.cflag) {
  1566. return(false);
  1567. }
  1568. /*........................................................................
  1569. Save the values of the returned segment & selector
  1570. ........................................................................*/
  1571. Selector = regs.w.dx;
  1572. Segment = regs.w.ax;
  1573. RealMemSize = size;
  1574. RealModeData = (RealModeDataType *)(((long)Segment) << 4);
  1575. /*------------------------------------------------------------------------
  1576. Lock the memory (since we're servicing interrupts with it)
  1577. AX = 0x600
  1578. BX:CX = starting linear address of memory to lock
  1579. SI:DI = size of region to lock (in bytes)
  1580. - If Failure, carry flag is set.
  1581. ------------------------------------------------------------------------*/
  1582. memset (&regs, 0 ,sizeof(regs));
  1583. segread (&sregs);
  1584. regs.x.eax = DPMI_LOCK_MEM; // DPMI function to call
  1585. regs.x.ebx = ((long)RealModeData & 0xffff0000) >> 16;
  1586. regs.x.ecx = ((long)RealModeData & 0x0000ffff);
  1587. regs.x.esi = ((long)RealMemSize & 0xffff0000) >> 16;
  1588. regs.x.edi = ((long)RealMemSize & 0x0000ffff);
  1589. int386x (DPMI_INT, &regs, &regs, &sregs); // call DPMI
  1590. /*........................................................................
  1591. If the carry flag is set, DPMI is indicating an error.
  1592. ........................................................................*/
  1593. if (regs.x.cflag) {
  1594. memset (&regs, 0 ,sizeof(regs));
  1595. segread (&sregs);
  1596. regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
  1597. regs.x.edx = Selector; // ptr to free
  1598. int386x (DPMI_INT, &regs, &regs, &sregs); // free the memory
  1599. return(false);
  1600. }
  1601. /*------------------------------------------------------------------------
  1602. Copy the Real-mode code into our memory buffer
  1603. ------------------------------------------------------------------------*/
  1604. p = (char *)(((long)Segment) << 4);
  1605. memcpy (p,realmode,realmodelen);
  1606. p += realmodelen;
  1607. /*------------------------------------------------------------------------
  1608. Compute & save the entry point for the real-mode packet handler
  1609. ------------------------------------------------------------------------*/
  1610. func_val = (unsigned long)RealModeData;
  1611. Handler = (((func_val & 0xffff0) << 12) |
  1612. ((func_val & 0x000f) + RealModeData->FuncOffset));
  1613. /*------------------------------------------------------------------------
  1614. Fill in buffer pointers
  1615. ------------------------------------------------------------------------*/
  1616. ListenECB = &(RealModeData->ListenECB);
  1617. FirstHeaderBuf = (IPXHeaderType *)p;
  1618. FirstDataBuf = (((char *)FirstHeaderBuf) + sizeof(IPXHeaderType));
  1619. CurIndex = 0;
  1620. CurHeaderBuf = FirstHeaderBuf;
  1621. CurDataBuf = FirstDataBuf;
  1622. p += FullPacketLen * NumBufs;
  1623. SendECB = (ECBType *)p;
  1624. p += sizeof (ECBType);
  1625. SendHeader = (IPXHeaderType *)p;
  1626. p += sizeof (IPXHeaderType);
  1627. SendBuf = (char *)p;
  1628. p += PacketLen;
  1629. BufferFlags = (char *)p;
  1630. /*------------------------------------------------------------------------
  1631. Fill in the real-mode routine's data (The ECB will be filled in when we
  1632. command IPX to Listen).
  1633. ------------------------------------------------------------------------*/
  1634. RealModeData->NumBufs = (short)NumBufs;
  1635. RealModeData->BufferFlags = (char *)
  1636. ((((long)BufferFlags & 0xffff0) << 12) |
  1637. ((long)BufferFlags & 0x0000f));
  1638. RealModeData->PacketSize = (short)FullPacketLen;
  1639. RealModeData->FirstPacketBuf = (IPXHeaderType *)
  1640. ((((long)FirstHeaderBuf & 0xffff0) << 12) |
  1641. ((long)FirstHeaderBuf & 0x0000f));
  1642. RealModeData->CurIndex = 0;
  1643. RealModeData->CurPacketBuf = RealModeData->FirstPacketBuf;
  1644. RealModeData->Semaphore = 0;
  1645. RealModeData->ReEntrantCount = 0;
  1646. /*------------------------------------------------------------------------
  1647. Init state of all buffers to empty
  1648. ------------------------------------------------------------------------*/
  1649. for (i = 0; i < NumBufs; i++)
  1650. BufferFlags[i] = 0;
  1651. /*------------------------------------------------------------------------
  1652. Check the start & end markers in the real-mode memory area
  1653. ------------------------------------------------------------------------*/
  1654. if (RealModeData->Marker1 != 0x1111 ||
  1655. RealModeData->Marker2 != 0x2222) {
  1656. Free_RealMode_Mem();
  1657. return(false);
  1658. } else {
  1659. return(true);
  1660. }
  1661. #else //NOT_FOR_WIN95
  1662. return (TRUE);
  1663. #endif //NOT_FOR_WIN95
  1664. }
  1665. /***************************************************************************
  1666. * IPXManagerClass::Free_RealMode_Mem -- frees real-mode memory *
  1667. * *
  1668. * INPUT: *
  1669. * none. *
  1670. * *
  1671. * OUTPUT: *
  1672. * 1 = OK, 0 = error *
  1673. * *
  1674. * WARNINGS: *
  1675. * none. *
  1676. * *
  1677. * HISTORY: *
  1678. * 12/20/1994 BR : Created. *
  1679. *=========================================================================*/
  1680. int IPXManagerClass::Free_RealMode_Mem(void)
  1681. {
  1682. #ifdef NOT_FOR_WIN95
  1683. union REGS regs;
  1684. struct SREGS sregs;
  1685. int rc = 1;
  1686. /*------------------------------------------------------------------------
  1687. Unlock the memory
  1688. ------------------------------------------------------------------------*/
  1689. memset (&regs, 0 ,sizeof(regs));
  1690. segread (&sregs);
  1691. regs.x.eax = DPMI_UNLOCK_MEM; // DPMI function to call
  1692. regs.x.ebx = ((long)RealModeData & 0xffff0000) >> 16;
  1693. regs.x.ecx = ((long)RealModeData & 0x0000ffff);
  1694. regs.x.esi = ((long)RealMemSize & 0xffff0000) >> 16;
  1695. regs.x.edi = ((long)RealMemSize & 0x0000ffff);
  1696. int386x (DPMI_INT, &regs, &regs, &sregs); // call DPMI
  1697. /*........................................................................
  1698. If the carry flag is set, DPMI is indicating an error.
  1699. ........................................................................*/
  1700. if (regs.x.cflag) {
  1701. rc = 0;
  1702. }
  1703. /*------------------------------------------------------------------------
  1704. Free DOS memory
  1705. ------------------------------------------------------------------------*/
  1706. memset (&regs, 0 ,sizeof(regs));
  1707. segread (&sregs);
  1708. regs.x.eax = DPMI_FREE_DOS_MEM; // DPMI function to call
  1709. regs.x.edx = Selector; // ptr to free
  1710. int386x (DPMI_INT, &regs, &regs, &sregs); // free the memory
  1711. return(rc);
  1712. #else // NOT_FOR_WIN95
  1713. return (1);
  1714. #endif // NOT_FOR_WIN95
  1715. } /* end of Free_RealMode_Mem */