IPXCONN.CPP 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  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\ipxconn.cpv 1.9 16 Oct 1995 16:50:52 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 : IPXCONN.CPP *
  26. * *
  27. * Programmer : Bill Randolph *
  28. * *
  29. * Start Date : December 20, 1994 *
  30. * *
  31. * Last Update : April 9, 1995 [BRR] *
  32. * *
  33. *-------------------------------------------------------------------------*
  34. * Functions: *
  35. * IPXConnClass::IPXConnClass -- class constructor *
  36. * IPXConnClass::~IPXConnClass -- class destructor *
  37. * IPXConnClass::Init -- hardware-specific initialization routine *
  38. * IPXConnClass::Configure -- One-time initialization routine *
  39. * IPXConnClass::Start_Listening -- commands IPX to listen *
  40. * IPXConnClass::Stop_Listening -- commands IPX to stop listen *
  41. * IPXConnClass::Send -- sends a packet; invoked by SequencedConnection *
  42. * IPXConnClass::Open_Socket -- opens communications socket *
  43. * IPXConnClass::Close_Socket -- closes the socket *
  44. * IPXConnClass::Send_To -- sends the packet to the given address *
  45. * IPXConnClass::Broadcast -- broadcasts the given packet *
  46. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  47. #include "function.h"
  48. #include "ipx95.h"
  49. #include "tcpip.h"
  50. /*
  51. ********************************* Globals ***********************************
  52. */
  53. unsigned short IPXConnClass::Socket;
  54. int IPXConnClass::ConnectionNum;
  55. ECBType * IPXConnClass::ListenECB;
  56. IPXHeaderType * IPXConnClass::ListenHeader;
  57. char * IPXConnClass::ListenBuf;
  58. ECBType * IPXConnClass::SendECB;
  59. IPXHeaderType * IPXConnClass::SendHeader;
  60. char * IPXConnClass::SendBuf;
  61. long IPXConnClass::Handler;
  62. int IPXConnClass::Configured = 0;
  63. int IPXConnClass::SocketOpen = 0;
  64. int IPXConnClass::Listening = 0;
  65. int IPXConnClass::PacketLen;
  66. /***************************************************************************
  67. * IPXConnClass::IPXConnClass -- class constructor *
  68. * *
  69. * INPUT: *
  70. * numsend desired # of entries for the send queue *
  71. * numreceive desired # of entries for the recieve queue *
  72. * maxlen max length of an application packet *
  73. * magicnum the packet "magic number" for this connection *
  74. * address address of destination (NULL = no address) *
  75. * id connection's unique numerical ID *
  76. * name connection's name *
  77. * *
  78. * OUTPUT: *
  79. * none. *
  80. * *
  81. * WARNINGS: *
  82. * none. *
  83. * *
  84. * HISTORY: *
  85. * 12/20/1994 BR : Created. *
  86. *=========================================================================*/
  87. IPXConnClass::IPXConnClass (int numsend, int numreceive, int maxlen,
  88. unsigned short magicnum, IPXAddressClass *address, int id, char *name) :
  89. #ifdef SEQ_NET
  90. SequencedConnClass (numsend, numreceive, maxlen, magicnum,
  91. #else
  92. NonSequencedConnClass (numsend, numreceive, maxlen, magicnum,
  93. #endif
  94. 2, // retry delta
  95. -1, // max retries
  96. 60) // timeout
  97. {
  98. NetNumType net;
  99. NetNodeType node;
  100. /*------------------------------------------------------------------------
  101. Save the values passed in
  102. ------------------------------------------------------------------------*/
  103. if (address)
  104. Address = (*address);
  105. ID = id;
  106. strcpy (Name, name);
  107. if (!Winsock.Get_Connected()){
  108. /*------------------------------------------------------------------------
  109. If our Address field is an actual address (ie NULL wasn't passed to the
  110. constructor), pre-compute the ImmediateAddress value for the SendECB.
  111. This allows pre-computing of the ImmediateAddress for all connections
  112. created after Configure() is called.
  113. ------------------------------------------------------------------------*/
  114. if (!Address.Is_Broadcast() && Configured==1) {
  115. Address.Get_Address(net,node);
  116. /*.....................................................................
  117. If the user is logged in & has a valid Novell Connection Number, get the
  118. bridge address the "official" way
  119. .....................................................................*/
  120. if (ConnectionNum != 0) {
  121. if (IPX_Get_Local_Target (net, node, Socket, ImmediateAddress)!=0)
  122. memcpy(ImmediateAddress,node,6);
  123. } else {
  124. /*.....................................................................
  125. Otherwise, use the destination node address as the ImmediateAddress, and
  126. just hope there's no network bridge in the path.
  127. .....................................................................*/
  128. memcpy(ImmediateAddress,node,6);
  129. }
  130. Immed_Set = 1;
  131. } else {
  132. memset (ImmediateAddress, 0, 6);
  133. Immed_Set = 0;
  134. }
  135. }
  136. } /* end of IPXConnClass */
  137. /***************************************************************************
  138. * IPXConnClass::Init -- hardware-specific initialization routine *
  139. * *
  140. * INPUT: *
  141. * none. *
  142. * *
  143. * OUTPUT: *
  144. * none. *
  145. * *
  146. * WARNINGS: *
  147. * none. *
  148. * *
  149. * HISTORY: *
  150. * 12/20/1994 BR : Created. *
  151. *=========================================================================*/
  152. void IPXConnClass::Init (void)
  153. {
  154. /*------------------------------------------------------------------------
  155. Invoke the parent's Init routine
  156. ------------------------------------------------------------------------*/
  157. #ifdef SEQ_NET
  158. SequencedConnClass::Init();
  159. #else
  160. NonSequencedConnClass::Init();
  161. #endif
  162. }
  163. /***************************************************************************
  164. * IPXConnClass::Configure -- One-time initialization routine *
  165. * *
  166. * This routine sets up static members that are shared by all IPX *
  167. * connections (ie those variables used by the Send/Listen/Broadcast *
  168. * routines). *
  169. * *
  170. * INPUT: *
  171. * socket socket ID for sending & receiving *
  172. * conn_num local IPX Connection Number (0 = not logged in) *
  173. * listen_ecb ptr to ECBType for listening *
  174. * send_ecb ptr to ECBType for sending *
  175. * listen_header ptr to IPXHeaderType for listening *
  176. * send_header ptr to IPXHeaderType for sending *
  177. * listen_buf ptr to buffer for listening *
  178. * send_buf ptr to buffer for sending *
  179. * handler_rm_ptr REAL-MODE pointer to event service routine *
  180. * (high word = segment, low word = offset) *
  181. * maxpacketlen max packet size to listen for *
  182. * *
  183. * OUTPUT: *
  184. * none. *
  185. * *
  186. * WARNINGS: *
  187. * - All pointers must be protected-mode pointers, but must point to *
  188. * DOS real-mode memory (except the Handler segment/offset) *
  189. * *
  190. * HISTORY: *
  191. * 12/20/1994 BR : Created. *
  192. *=========================================================================*/
  193. void IPXConnClass::Configure (unsigned short socket, int conn_num,
  194. ECBType *listen_ecb, ECBType *send_ecb, IPXHeaderType *listen_header,
  195. IPXHeaderType *send_header, char *listen_buf, char *send_buf,
  196. long handler_rm_ptr, int maxpacketlen)
  197. {
  198. /*------------------------------------------------------------------------
  199. Save the values passed in
  200. ------------------------------------------------------------------------*/
  201. Socket = socket;
  202. ConnectionNum = conn_num;
  203. ListenECB = listen_ecb;
  204. SendECB = send_ecb;
  205. ListenHeader = listen_header;
  206. SendHeader = send_header;
  207. ListenBuf = listen_buf;
  208. SendBuf = send_buf;
  209. Handler = handler_rm_ptr;
  210. PacketLen = maxpacketlen;
  211. Configured = 1;
  212. } /* end of Configure */
  213. /***************************************************************************
  214. * IPXConnClass::Start_Listening -- commands IPX to listen *
  215. * *
  216. * This routine may be used to start listening in polled mode (if the *
  217. * ECB's Event_Service_Routine is NULL), or in interrupt mode; it's *
  218. * up to the caller to fill the ECB in. If in polled mode, Listening *
  219. * must be restarted every time a packet comes in. *
  220. * *
  221. * INPUT: *
  222. * none. *
  223. * *
  224. * OUTPUT: *
  225. * none. *
  226. * *
  227. * WARNINGS: *
  228. * - The ListenECB must have been properly filled in by the IPX Manager.*
  229. * - Configure must be called before calling this routine. *
  230. * *
  231. * HISTORY: *
  232. * 12/16/1994 BR : Created. *
  233. *=========================================================================*/
  234. bool IPXConnClass::Start_Listening(void)
  235. {
  236. #ifndef NOT_FOR_WIN95
  237. if (Winsock.Get_Connected()) return (true);
  238. /*------------------------------------------------------------------------
  239. Open the Socket
  240. ------------------------------------------------------------------------*/
  241. if (!Open_Socket(Socket))
  242. return(false);
  243. if (IPX_Start_Listening95()){
  244. Listening =1;
  245. return (TRUE);
  246. }else{
  247. return (FALSE);
  248. }
  249. #else
  250. void *hdr_ptr;
  251. unsigned long hdr_val;
  252. void *buf_ptr;
  253. unsigned long buf_val;
  254. int rc;
  255. /*------------------------------------------------------------------------
  256. Don't do a thing unless we've been configured, and we're not listening.
  257. ------------------------------------------------------------------------*/
  258. if (Configured==0 || Listening==1)
  259. return(false);
  260. /*------------------------------------------------------------------------
  261. Open the Socket
  262. ------------------------------------------------------------------------*/
  263. if (!Open_Socket(Socket))
  264. return(false);
  265. /*------------------------------------------------------------------------
  266. Clear the ECB & header
  267. ------------------------------------------------------------------------*/
  268. memset(ListenECB, 0, sizeof(ECBType));
  269. memset(ListenHeader, 0, sizeof(IPXHeaderType));
  270. /*------------------------------------------------------------------------
  271. Convert protected-mode ptrs to real-mode ptrs
  272. ------------------------------------------------------------------------*/
  273. hdr_val = (unsigned long)ListenHeader;
  274. hdr_ptr = (void *)(((hdr_val & 0xffff0) << 12) | (hdr_val & 0x000f));
  275. buf_val = (unsigned long)ListenBuf;
  276. buf_ptr = (void *)(((buf_val & 0xffff0) << 12) | (buf_val & 0x000f));
  277. /*------------------------------------------------------------------------
  278. Fill in the ECB
  279. ------------------------------------------------------------------------*/
  280. ListenECB->SocketNumber = Socket;
  281. ListenECB->PacketCount = 2;
  282. ListenECB->Packet[0].Address = hdr_ptr;
  283. ListenECB->Packet[0].Length = sizeof(IPXHeaderType);
  284. ListenECB->Packet[1].Address = buf_ptr;
  285. ListenECB->Packet[1].Length = (unsigned short)PacketLen;
  286. ((long &)ListenECB->Event_Service_Routine) = Handler;
  287. /*------------------------------------------------------------------------
  288. Command IPX to listen
  289. ------------------------------------------------------------------------*/
  290. rc = IPX_Listen_For_Packet(ListenECB);
  291. if (rc!=0) {
  292. Close_Socket(Socket);
  293. return(false);
  294. } else {
  295. Listening = 1;
  296. return(true);
  297. }
  298. #endif //NOT_FOR_WIN95
  299. } /* end of Start_Listening */
  300. /***************************************************************************
  301. * IPXConnClass::Stop_Listening -- commands IPX to stop listen *
  302. * *
  303. * INPUT: *
  304. * none. *
  305. * *
  306. * OUTPUT: *
  307. * none. *
  308. * *
  309. * WARNINGS: *
  310. * - This routine MUST NOT be called if IPX is not listening already! *
  311. * *
  312. * HISTORY: *
  313. * 12/16/1994 BR : Created. *
  314. *=========================================================================*/
  315. bool IPXConnClass::Stop_Listening(void)
  316. {
  317. /*------------------------------------------------------------------------
  318. Don't do anything unless we're already Listening.
  319. ------------------------------------------------------------------------*/
  320. if (Listening==0)
  321. return(false);
  322. #ifndef NOT_FOR_WIN95
  323. if (Winsock.Get_Connected()){
  324. Listening = 0;
  325. return (true);
  326. }else{
  327. IPX_Shut_Down95();
  328. Close_Socket(Socket);
  329. }
  330. #else //NOT_FOR_WIN95
  331. /*------------------------------------------------------------------------
  332. Shut IPX down.
  333. ------------------------------------------------------------------------*/
  334. IPX_Cancel_Event(ListenECB);
  335. Close_Socket(Socket);
  336. #endif //NOT_FOR_WIN95
  337. Listening = 0;
  338. /*------------------------------------------------------------------------
  339. All done.
  340. ------------------------------------------------------------------------*/
  341. return(true);
  342. } /* end of Stop_Listening */
  343. /***************************************************************************
  344. * IPXConnClass::Send -- sends a packet; invoked by SequencedConnection *
  345. * *
  346. * INPUT: *
  347. * socket desired socket ID number *
  348. * *
  349. * OUTPUT: *
  350. * 1 = OK, 0 = error *
  351. * *
  352. * WARNINGS: *
  353. * none. *
  354. * *
  355. * HISTORY: *
  356. * 12/16/1994 BR : Created. *
  357. *=========================================================================*/
  358. int IPXConnClass::Send(char *buf, int buflen)
  359. {
  360. /*------------------------------------------------------------------------
  361. Invoke our own Send_To routine, filling in our Address as the destination.
  362. ------------------------------------------------------------------------*/
  363. if (Immed_Set) {
  364. return(Send_To (buf, buflen, &Address, ImmediateAddress));
  365. } else {
  366. return(Send_To (buf, buflen, &Address, NULL));
  367. }
  368. } /* end of Send */
  369. /***************************************************************************
  370. * IPXConnClass::Open_Socket -- opens communications socket *
  371. * *
  372. * INPUT: *
  373. * socket desired socket ID number *
  374. * *
  375. * OUTPUT: *
  376. * 1 = OK, 0 = error *
  377. * *
  378. * WARNINGS: *
  379. * none. *
  380. * *
  381. * HISTORY: *
  382. * 12/16/1994 BR : Created. *
  383. *=========================================================================*/
  384. int IPXConnClass::Open_Socket(unsigned short socket)
  385. {
  386. int rc;
  387. if (Winsock.Get_Connected()){
  388. SocketOpen = 1;
  389. return (true);
  390. }
  391. SocketOpen = 0;
  392. /*------------------------------------------------------------------------
  393. Try to open a listen socket. The socket may have been left open by
  394. a previously-crashed program, so ignore the state of the SocketOpen
  395. flag for this call; use IPX to determine if the socket was already open.
  396. ------------------------------------------------------------------------*/
  397. rc = IPX_Open_Socket(socket);
  398. if (rc) {
  399. /*
  400. ................. If already open, close & reopen it ..................
  401. */
  402. if (rc==IPXERR_SOCKET_ERROR) {
  403. IPX_Close_Socket(socket);
  404. rc = IPX_Open_Socket(socket);
  405. /*
  406. .................. Still can't open: return error ..................
  407. */
  408. if (rc) {
  409. return(false);
  410. }
  411. }
  412. }
  413. SocketOpen = 1;
  414. return(true);
  415. }
  416. /***************************************************************************
  417. * IPXConnClass::Close_Socket -- closes the socket *
  418. * *
  419. * INPUT: *
  420. * socket desired socket ID number *
  421. * *
  422. * OUTPUT: *
  423. * none. *
  424. * *
  425. * WARNINGS: *
  426. * Calling this routine when the sockets aren't open may crash! *
  427. * *
  428. * HISTORY: *
  429. * 12/16/1994 BR : Created. *
  430. *=========================================================================*/
  431. void IPXConnClass::Close_Socket(unsigned short socket)
  432. {
  433. if (Winsock.Get_Connected()){
  434. SocketOpen = 0;
  435. return;
  436. }
  437. /*------------------------------------------------------------------------
  438. Never, ever, ever, under any circumstances whatsoever, close a socket
  439. that isn't open. You'll regret it forever (or until at least until you're
  440. through rebooting, which, if you're on a Pentium is the same thing).
  441. ------------------------------------------------------------------------*/
  442. if (SocketOpen==1)
  443. IPX_Close_Socket(socket);
  444. SocketOpen = 0;
  445. } /* end of Close_Socket */
  446. /***************************************************************************
  447. * IPXConnClass::Send_To -- sends the packet to the given address *
  448. * *
  449. * The "ImmediateAddress" field of the SendECB must be filled in with the *
  450. * address of a bridge, or the node address of the destination if there *
  451. * is no bridge. The NETX call to find this address will always crash *
  452. * if NETX isn't loaded (ConnectionNum is 0), so this case is trapped & *
  453. * prevented. *
  454. * Also, if the address of this IPX connection is known when the *
  455. * constructor is called, and Configure has been called, Get_Local_Target *
  456. * is called to precompute the ImmediateAddress; this case is detected & *
  457. * if the value is already computed, it's just memcpy'd over. *
  458. * *
  459. * INPUT: *
  460. * buf buffer to send *
  461. * buflen length of buffer *
  462. * address Address to send to *
  463. * immed ImmediateAddress value, NULL if none *
  464. * *
  465. * OUTPUT: *
  466. * 1 = OK, 0 = error *
  467. * *
  468. * WARNINGS: *
  469. * none. *
  470. * *
  471. * HISTORY: *
  472. * 12/16/1994 BR : Created. *
  473. *=========================================================================*/
  474. #pragma off (unreferenced)
  475. int IPXConnClass::Send_To(char *buf, int buflen, IPXAddressClass *address,
  476. NetNodeType immed)
  477. {
  478. void *hdr_ptr;
  479. void *buf_ptr;
  480. unsigned long hdr_val;
  481. unsigned long buf_val;
  482. NetNumType net;
  483. NetNodeType node;
  484. int rc;
  485. unsigned short target_mask;
  486. unsigned char send_address[6];
  487. if (Winsock.Get_Connected()){
  488. #ifdef VIRTUAL_SUBNET_SERVER
  489. if (immed){
  490. memcpy(send_address, immed, 6);
  491. }else{
  492. address->Get_Address(net,node);
  493. memcpy (send_address, node, 6);
  494. }
  495. /*
  496. ** Use first two bytes of ipx address as target mask
  497. */
  498. unsigned short *maskptr = (unsigned short*)&send_address[0];
  499. target_mask = *maskptr;
  500. char *tempsend = new char [buflen + sizeof (target_mask)];
  501. *(unsigned short*)tempsend = htons(target_mask);
  502. memcpy (tempsend+2, buf, buflen);
  503. #if (0)
  504. char tempbuf[256];
  505. CommHeaderType *packet = (CommHeaderType *)(&tempsend[2]);
  506. static char pcode [4][18]={
  507. "PACKET_DATA_ACK", // this is a data packet requiring an ACK
  508. "PACKET_DATA_NOACK", // this is a data packet not requiring an ACK
  509. "PACKET_ACK", // this is an ACK for a packet
  510. "PACKET_COUNT" // for computational purposes
  511. };
  512. sprintf (tempbuf, "Sending unicast packet type %d, ID=%d, code=%s, length=%d\n", tempsend[sizeof(CommHeaderType)+2],
  513. packet->PacketID,
  514. pcode[packet->Code],
  515. buflen + sizeof (target_mask));
  516. CCDebugString (tempbuf);
  517. #endif //(0)
  518. Winsock.Write((void*)tempsend, buflen + sizeof (target_mask));
  519. delete [] tempsend;
  520. #else // VIRTUAL_SUBNET_SERVER
  521. Winsock.Write((void*)buf, buflen);
  522. #endif // VIRTUAL_SUBNET_SERVER
  523. return (true);
  524. }
  525. if (immed) {
  526. memcpy(send_address, immed, 6);
  527. //memcpy(node, immed, 6);
  528. //memset (net, 0, sizeof(net) );
  529. address->Get_Address(net,node);
  530. } else {
  531. address->Get_Address(net,node);
  532. /*.....................................................................
  533. If the user is logged in & has a valid Novell Connection Number, get the
  534. bridge address the "official" way
  535. .....................................................................*/
  536. if (ConnectionNum != 0) {
  537. rc = IPX_Get_Local_Target (net, node, Socket, &send_address[0]);
  538. if (rc!=0) {
  539. return(false);
  540. }
  541. } else {
  542. /*.....................................................................
  543. Otherwise, use the destination node address as the ImmediateAddress, and
  544. just hope there's no network bridge in the path.
  545. .....................................................................*/
  546. memcpy(send_address,node,6);
  547. }
  548. }
  549. return (IPX_Send_Packet95(&send_address[0], (unsigned char*)buf, buflen, (unsigned char*)net, (unsigned char*)node));
  550. }
  551. #pragma on (unreferenced)
  552. /***************************************************************************
  553. * IPXConnClass::Broadcast -- broadcasts the given packet *
  554. * *
  555. * INPUT: *
  556. * socket desired socket ID number *
  557. * *
  558. * OUTPUT: *
  559. * 1 = OK, 0 = error *
  560. * *
  561. * WARNINGS: *
  562. * none. *
  563. * *
  564. * HISTORY: *
  565. * 12/16/1994 BR : Created. *
  566. *=========================================================================*/
  567. int IPXConnClass::Broadcast(char *buf, int buflen)
  568. {
  569. if (Winsock.Get_Connected()){
  570. #ifdef VIRTUAL_SUBNET_SERVER
  571. char *tempsend = new char [buflen + sizeof (unsigned short)];
  572. memcpy (tempsend+2, buf, buflen);
  573. *tempsend = 0;
  574. *(tempsend+1) = 0;
  575. #if (0)
  576. char tempbuf[256];
  577. CommHeaderType *packet = (CommHeaderType *)(&tempsend[2]);
  578. static char pcode [4][18]={
  579. "PACKET_DATA_ACK", // this is a data packet requiring an ACK
  580. "PACKET_DATA_NOACK", // this is a data packet not requiring an ACK
  581. "PACKET_ACK", // this is an ACK for a packet
  582. "PACKET_COUNT" // for computational purposes
  583. };
  584. sprintf (tempbuf, "Sending multicast packet type %d, ID=%d, code=%s, length=%d\n", tempsend[sizeof(CommHeaderType)+2],
  585. packet->PacketID,
  586. pcode[packet->Code],
  587. buflen + sizeof (unsigned short));
  588. CCDebugString (tempbuf);
  589. #endif //(0)
  590. Winsock.Write((void*)tempsend, buflen + sizeof (unsigned short));
  591. delete [] tempsend;
  592. #else // VIRTUAL_SUBNET_SERVER
  593. Winsock.Write((void*)buf, buflen);
  594. #endif // VIRTUAL_SUBNET_SERVER
  595. return(true);
  596. }else{
  597. return (IPX_Broadcast_Packet95((unsigned char*)buf, buflen));
  598. }
  599. }