IPXMGR.CPP 80 KB

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