Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1572 lines
37 KiB

  1. #include "precomp.h"
  2. //
  3. // SC.CPP
  4. // Share Controller
  5. //
  6. // NOTE:
  7. // We must take the UTLOCK_AS every time we
  8. // * create/destroy the share object
  9. // * add/remove a person from the share
  10. //
  11. // Copyright(c) Microsoft 1997-
  12. //
  13. #define MLZ_FILE_ZONE ZONE_CORE
  14. //
  15. // SC_Init()
  16. // Initializes the share controller
  17. //
  18. BOOL SC_Init(void)
  19. {
  20. BOOL rc = FALSE;
  21. DebugEntry(SC_Init);
  22. ASSERT(!g_asSession.callID);
  23. ASSERT(!g_asSession.gccID);
  24. ASSERT(g_asSession.scState == SCS_TERM);
  25. //
  26. // Register as a Call Manager Secondary task
  27. //
  28. if (!CMS_Register(g_putAS, CMTASK_DCS, &g_pcmClientSc))
  29. {
  30. ERROR_OUT(( "Failed to register with CMS"));
  31. DC_QUIT;
  32. }
  33. g_asSession.scState = SCS_INIT;
  34. TRACE_OUT(("g_asSession.scState is SCS_INIT"));
  35. rc = TRUE;
  36. DC_EXIT_POINT:
  37. DebugExitBOOL(SC_Init, rc);
  38. return(rc);
  39. }
  40. //
  41. // SC_Term()
  42. //
  43. // See sc.h for description.
  44. //
  45. //
  46. void SC_Term(void)
  47. {
  48. DebugEntry(SC_Term);
  49. //
  50. // Clear up the core's state by generating appropriate PARTY_DELETED and
  51. // SHARE_ENDED events.
  52. //
  53. switch (g_asSession.scState)
  54. {
  55. case SCS_SHARING:
  56. case SCS_SHAREENDING:
  57. case SCS_SHAREPENDING:
  58. SC_End();
  59. break;
  60. }
  61. //
  62. // Deregister from the Call Manager
  63. //
  64. if (g_pcmClientSc)
  65. {
  66. CMS_Deregister(&g_pcmClientSc);
  67. }
  68. g_asSession.gccID = 0;
  69. g_asSession.callID = 0;
  70. g_asSession.scState = SCS_TERM;
  71. TRACE_OUT(("g_asSession.scState is SCS_TERM"));
  72. DebugExitVOID(SC_Term);
  73. }
  74. //
  75. // SC_CreateShare()
  76. // Creates a new share or joins an existing one
  77. //
  78. BOOL SC_CreateShare(UINT s20CreateOrJoin)
  79. {
  80. BOOL rc = FALSE;
  81. DebugEntry(SC_CreateShare);
  82. //
  83. // If we are initialised but there is no Call Manager call, return the
  84. // race condition.
  85. //
  86. if ((g_asSession.scState != SCS_INIT) && (g_asSession.scState != SCS_SHAREPENDING))
  87. {
  88. TRACE_OUT(("Ignoring SC_CreateShare() request; in bad state %d",
  89. g_asSession.scState));
  90. DC_QUIT;
  91. }
  92. if (!g_asSession.callID)
  93. {
  94. WARNING_OUT(("Ignoring SC_CreateShare() request; not in T120 call"));
  95. DC_QUIT;
  96. }
  97. //
  98. // Remember that we created this share.
  99. //
  100. g_asSession.fShareCreator = (s20CreateOrJoin == S20_CREATE);
  101. TRACE_OUT(("CreatedShare is %s", (s20CreateOrJoin == S20_CREATE) ?
  102. "TRUE" : "FALSE"));
  103. g_asSession.scState = SCS_SHAREPENDING;
  104. TRACE_OUT(("g_asSession.scState is SCS_SHAREPENDING"));
  105. rc = S20CreateOrJoinShare(s20CreateOrJoin, g_asSession.callID);
  106. if (!rc)
  107. {
  108. WARNING_OUT(("%s failed", (s20CreateOrJoin == S20_CREATE ? "S20_CREATE" : "S20_JOIN")));
  109. }
  110. DC_EXIT_POINT:
  111. DebugExitBOOL(SC_CreateShare, rc);
  112. return(rc);
  113. }
  114. //
  115. // SC_EndShare()
  116. // This will end a share if we are in one or in the middle of establishing
  117. // one, and clean up afterwards.
  118. //
  119. void SC_EndShare(void)
  120. {
  121. DebugEntry(SC_EndShare);
  122. if (g_asSession.scState <= SCS_SHAREENDING)
  123. {
  124. TRACE_OUT(("Ignoring SC_EndShare(); nothing to do in state %d", g_asSession.scState));
  125. }
  126. else
  127. {
  128. //
  129. // If we are in a share or in the middle of creating/joining one, stop
  130. // the process.
  131. //
  132. //
  133. // Kill the share
  134. // NOTE that this will call SC_End(), when we come back
  135. // from this function our g_asSession.scState() should be SCS_INIT.
  136. //
  137. g_asSession.scState = SCS_SHAREENDING;
  138. TRACE_OUT(("g_asSession.scState is SCS_SHAREENDING"));
  139. S20LeaveOrEndShare();
  140. g_asSession.scState = SCS_INIT;
  141. }
  142. DebugExitVOID(SC_EndShare);
  143. }
  144. //
  145. // SC_PersonFromNetID()
  146. //
  147. ASPerson * ASShare::SC_PersonFromNetID(MCSID mcsID)
  148. {
  149. ASPerson * pasPerson;
  150. DebugEntry(SC_PersonFromNetID);
  151. ASSERT(mcsID != MCSID_NULL);
  152. //
  153. // Search for the mcsID.
  154. //
  155. if (!SC_ValidateNetID(mcsID, &pasPerson))
  156. {
  157. ERROR_OUT(("Invalid [%u]", mcsID));
  158. }
  159. DebugExitPVOID(ASShare::SC_PersonFromNetID, pasPerson);
  160. return(pasPerson);
  161. }
  162. //
  163. // SC_ValidateNetID()
  164. //
  165. BOOL ASShare::SC_ValidateNetID
  166. (
  167. MCSID mcsID,
  168. ASPerson * * ppasPerson
  169. )
  170. {
  171. BOOL rc = FALSE;
  172. ASPerson * pasPerson;
  173. DebugEntry(ASShare::SC_ValidateNetID);
  174. // Init to empty
  175. pasPerson = NULL;
  176. //
  177. // MCSID_NULL matches no one.
  178. //
  179. if (mcsID == MCSID_NULL)
  180. {
  181. WARNING_OUT(("SC_ValidateNetID called with MCSID_NULL"));
  182. DC_QUIT;
  183. }
  184. //
  185. // Search for the mcsID.
  186. //
  187. for (pasPerson = m_pasLocal; pasPerson != NULL; pasPerson = pasPerson->pasNext)
  188. {
  189. ValidatePerson(pasPerson);
  190. if (pasPerson->mcsID == mcsID)
  191. {
  192. //
  193. // Found required person, set return values and quit
  194. //
  195. rc = TRUE;
  196. break;
  197. }
  198. }
  199. DC_EXIT_POINT:
  200. if (ppasPerson)
  201. {
  202. *ppasPerson = pasPerson;
  203. }
  204. DebugExitBOOL(ASShare::SC_ValidateNetID, rc);
  205. return(rc);
  206. }
  207. //
  208. // SC_PersonFromGccID()
  209. //
  210. ASPerson * ASShare::SC_PersonFromGccID(UINT gccID)
  211. {
  212. ASPerson * pasPerson;
  213. DebugEntry(ASShare::SC_PersonFromGccID);
  214. for (pasPerson = m_pasLocal; pasPerson != NULL; pasPerson = pasPerson->pasNext)
  215. {
  216. ValidatePerson(pasPerson);
  217. if (pasPerson->cpcCaps.share.gccID == gccID)
  218. {
  219. // Found it
  220. break;
  221. }
  222. }
  223. DebugExitPVOID(ASShare::SC_PersonFromGccID, pasPerson);
  224. return(pasPerson);
  225. }
  226. //
  227. // SC_Start()
  228. // Inits the share (if all is OK), and adds local person to it.
  229. //
  230. BOOL SC_Start(UINT mcsID)
  231. {
  232. BOOL rc = FALSE;
  233. ASShare * pShare;
  234. ASPerson * pasPerson;
  235. DebugEntry(SC_Start);
  236. ASSERT(g_asSession.callID);
  237. ASSERT(g_asSession.gccID);
  238. if ((g_asSession.scState != SCS_INIT) && (g_asSession.scState != SCS_SHAREPENDING))
  239. {
  240. WARNING_OUT(("Ignoring SC_Start(); in bad state"));
  241. DC_QUIT;
  242. }
  243. if (g_asSession.pShare)
  244. {
  245. WARNING_OUT(("Ignoring SC_Start(); have ASShare object already"));
  246. DC_QUIT;
  247. }
  248. g_asSession.scState = SCS_SHARING;
  249. TRACE_OUT(("g_asSession.scState is SCS_SHARING"));
  250. #ifdef _DEBUG
  251. //
  252. // Use this to calculate time between joining share and getting
  253. // first view
  254. //
  255. g_asSession.scShareTime = ::GetTickCount();
  256. #endif // _DEBUG
  257. //
  258. // Allocate the share object and add the local dude to the share.
  259. //
  260. pShare = new ASShare;
  261. if (pShare)
  262. {
  263. ZeroMemory(pShare, sizeof(*(pShare)));
  264. SET_STAMP(pShare, SHARE);
  265. rc = pShare->SC_ShareStarting();
  266. }
  267. UT_Lock(UTLOCK_AS);
  268. g_asSession.pShare = pShare;
  269. UT_Unlock(UTLOCK_AS);
  270. if (!rc)
  271. {
  272. ERROR_OUT(("Can't create/init ASShare"));
  273. DC_QUIT;
  274. }
  275. DCS_NotifyUI(SH_EVT_SHARE_STARTED, 0, 0);
  276. //
  277. // Join local dude into share. If that fails, also bail out.
  278. //
  279. pasPerson = g_asSession.pShare->SC_PartyJoiningShare(mcsID, g_asSession.achLocalName, sizeof(g_cpcLocalCaps), &g_cpcLocalCaps);
  280. if (!pasPerson)
  281. {
  282. ERROR_OUT(("Local person not joined into share successfully"));
  283. DC_QUIT;
  284. }
  285. //
  286. // Okay! We have a share, and it's set up.
  287. //
  288. //
  289. // Tell the UI that we're in the share.
  290. //
  291. DCS_NotifyUI(SH_EVT_PERSON_JOINED, pasPerson->cpcCaps.share.gccID, 0);
  292. //
  293. // Start periodic processing if ViewSelf or record/playback is on.
  294. //
  295. if (g_asSession.pShare->m_scfViewSelf)
  296. {
  297. SCH_ContinueScheduling(SCH_MODE_NORMAL);
  298. }
  299. rc = TRUE;
  300. DC_EXIT_POINT:
  301. DebugExitBOOL(SC_Start, rc);
  302. return(rc);
  303. }
  304. //
  305. // SC_End()
  306. // Removes any remotes from the share, removes the local person, and
  307. // cleans up after the fact.
  308. //
  309. void SC_End(void)
  310. {
  311. DebugEntry(SC_End);
  312. if (g_asSession.scState < SCS_SHAREENDING)
  313. {
  314. TRACE_OUT(("Ignoring SC_EVENT_SHAREENDED"));
  315. }
  316. else
  317. {
  318. if (g_asSession.pShare)
  319. {
  320. g_asSession.pShare->SC_ShareEnded();
  321. UT_Lock(UTLOCK_AS);
  322. delete g_asSession.pShare;
  323. g_asSession.pShare = NULL;
  324. UT_Unlock(UTLOCK_AS);
  325. DCS_NotifyUI(SH_EVT_SHARE_ENDED, 0, 0);
  326. }
  327. //
  328. // If the previous state was SCS_SHARE_PENDING then we
  329. // may have ended up here as the result of a 'back off' after
  330. // trying to create two shares. Let's try to join again...
  331. //
  332. if (g_asSession.fShareCreator)
  333. {
  334. g_asSession.fShareCreator = FALSE;
  335. TRACE_OUT(("CreatedShare is FALSE"));
  336. if (g_asSession.scState == SCS_SHAREPENDING)
  337. {
  338. WARNING_OUT(("Got share end while share pending - retry join"));
  339. UT_PostEvent(g_putAS, g_putAS, 0, CMS_NEW_CALL, 0, 0);
  340. }
  341. }
  342. g_asSession.scState = SCS_INIT;
  343. TRACE_OUT(("g_asSession.scState is SCS_INIT"));
  344. }
  345. g_s20ShareCorrelator = 0;
  346. //
  347. // Reset the queued control packets.
  348. //
  349. g_s20ControlPacketQHead = 0;
  350. g_s20ControlPacketQTail = 0;
  351. g_s20State = S20_NO_SHARE;
  352. TRACE_OUT(("g_s20State is S20_NO_SHARE"));
  353. DebugExitVOID(SC_End);
  354. }
  355. //
  356. // SC_PartyAdded()
  357. //
  358. BOOL ASShare::SC_PartyAdded
  359. (
  360. UINT mcsID,
  361. LPSTR szName,
  362. UINT cbCaps,
  363. LPVOID pCaps
  364. )
  365. {
  366. BOOL rc = FALSE;
  367. ASPerson * pasPerson;
  368. if (g_asSession.scState != SCS_SHARING)
  369. {
  370. WARNING_OUT(("Ignoring SC_EVENT_PARTYADDED; not in share"));
  371. DC_QUIT;
  372. }
  373. ASSERT(g_asSession.callID);
  374. ASSERT(g_asSession.gccID);
  375. //
  376. // A remote party is joining the share
  377. //
  378. //
  379. // Notify everybody
  380. //
  381. pasPerson = SC_PartyJoiningShare(mcsID, szName, cbCaps, pCaps);
  382. if (!pasPerson)
  383. {
  384. WARNING_OUT(("SC_PartyJoiningShare failed for remote [%d]", mcsID));
  385. DC_QUIT;
  386. }
  387. //
  388. // SYNC now
  389. // We should NEVER SEND ANY PACKETS when syncing. We aren't ready
  390. // because we haven't joined the person into the share. yet.
  391. // So we simply set variables for us to send data off the next
  392. // periodic schedule.
  393. //
  394. #ifdef _DEBUG
  395. m_scfInSync = TRUE;
  396. #endif // _DEBUG
  397. //
  398. // Stuff needed for being in the share, hosting or not
  399. //
  400. DCS_SyncOutgoing();
  401. OE_SyncOutgoing();
  402. if (m_pHost != NULL)
  403. {
  404. //
  405. // Common to both starting sharing and retransmitting sharing info
  406. //
  407. m_pHost->HET_SyncCommon();
  408. m_pHost->HET_SyncAlreadyHosting();
  409. m_pHost->CA_SyncAlreadyHosting();
  410. }
  411. #ifdef _DEBUG
  412. m_scfInSync = FALSE;
  413. #endif // _DEBUG
  414. //
  415. // DO THIS LAST -- tell the UI this person is in the share.
  416. //
  417. DCS_NotifyUI(SH_EVT_PERSON_JOINED, pasPerson->cpcCaps.share.gccID, 0);
  418. //
  419. // Start periodic processing
  420. //
  421. SCH_ContinueScheduling(SCH_MODE_NORMAL);
  422. rc = TRUE;
  423. DC_EXIT_POINT:
  424. DebugExitBOOL(ASShare::SC_PartyAdded, rc);
  425. return(rc);
  426. }
  427. //
  428. // SC_PartyDeleted()
  429. //
  430. void ASShare::SC_PartyDeleted(UINT mcsID)
  431. {
  432. if ((g_asSession.scState != SCS_SHARING) && (g_asSession.scState != SCS_SHAREENDING))
  433. {
  434. WARNING_OUT(("Ignoring SC_EVENT_PARTYDELETED; wrong state"));
  435. DC_QUIT;
  436. }
  437. SC_PartyLeftShare(mcsID);
  438. DC_EXIT_POINT:
  439. DebugExitVOID(ASShare::SC_PartyDeleted);
  440. }
  441. //
  442. // SC_ReceivedPacket()
  443. //
  444. void ASShare::SC_ReceivedPacket(PS20DATAPACKET pPacket)
  445. {
  446. ASPerson * pasPerson;
  447. PSNIPACKET pSNIPacket;
  448. DebugEntry(ASShare::SC_ReceivedPacket);
  449. if (g_asSession.scState != SCS_SHARING)
  450. {
  451. WARNING_OUT(("Ignoring received data because we're not in right state"));
  452. DC_QUIT;
  453. }
  454. //
  455. // Ignore packets on streams we don't know about.
  456. //
  457. if ((pPacket->stream < SC_STREAM_LOW) ||
  458. (pPacket->stream > SC_STREAM_HIGH))
  459. {
  460. TRACE_OUT(("Ignoring received data on unrecognized stream %d",
  461. pPacket->stream));
  462. DC_QUIT;
  463. }
  464. //
  465. // It is possible to get a packet from a person we do not know
  466. // about.
  467. //
  468. // This can happen if we join a conference that has an existing
  469. // share session. All existing parties will be sending data on
  470. // the channels we have joined but we will not yet have
  471. // received the events to add them to our share session.
  472. //
  473. // Data packets from unknown people are ignored (ignoring this
  474. // data is OK as we will resync with them when they are added
  475. // to our share session)
  476. //
  477. if (!SC_ValidateNetID(pPacket->header.user, &pasPerson))
  478. {
  479. WARNING_OUT(("Ignoring data packet from unknown person [%d]",
  480. pPacket->header.user));
  481. DC_QUIT;
  482. }
  483. if (pPacket->data.dataType == DT_SNI)
  484. {
  485. //
  486. // This is an SNI packet - handle it here.
  487. //
  488. pSNIPacket = (PSNIPACKET)pPacket;
  489. switch(pSNIPacket->message)
  490. {
  491. case SNI_MSG_SYNC:
  492. //
  493. // This is a sync message.
  494. //
  495. if (pSNIPacket->destination == m_pasLocal->mcsID)
  496. {
  497. //
  498. // This sync message is for us.
  499. //
  500. pasPerson->scSyncRecStatus[pPacket->stream-1] = SC_SYNCED;
  501. }
  502. else
  503. {
  504. TRACE_OUT(("Ignoring SYNC on stream %d for [%d] from [%d]",
  505. pPacket->stream, pSNIPacket->destination,
  506. pPacket->header.user));
  507. }
  508. break;
  509. default:
  510. ERROR_OUT(("Unknown SNI message %u", pSNIPacket->message));
  511. break;
  512. }
  513. }
  514. else if (pasPerson->scSyncRecStatus[pPacket->stream-1] == SC_SYNCED)
  515. {
  516. PS20DATAPACKET pPacketUse;
  517. UINT cbBufferSize;
  518. UINT compression;
  519. BOOL decompressed;
  520. UINT dictionary;
  521. //
  522. // Decompress the packet if necessary
  523. //
  524. //
  525. // Use the temporary buffer. This will never fail, so we don't
  526. // need to check the return value. THIS MEANS THAT THE HANDLING OF
  527. // INCOMING PACKETS CAN NEVER IMMEDIATELY TURN AROUND AND SEND AN
  528. // OUTGOING PACKET. Our scratch buffer is in use.
  529. //
  530. pPacketUse = (PS20DATAPACKET)m_ascTmpBuffer;
  531. TRACE_OUT(( "Got data pkt type %u from [%d], compression %u",
  532. pPacket->data.dataType, pasPerson->mcsID,
  533. pPacket->data.compressionType));
  534. //
  535. // If the packet has CT_OLD_COMPRESSED set, it has used simple PKZIP
  536. // compression
  537. //
  538. if (pPacket->data.compressionType & CT_OLD_COMPRESSED)
  539. {
  540. compression = CT_PKZIP;
  541. }
  542. else
  543. {
  544. compression = pPacket->data.compressionType;
  545. }
  546. TRACE_OUT(( "packet compressed with algorithm %u", compression));
  547. //
  548. // If the packet is compressed, decompress it now
  549. //
  550. if (compression)
  551. {
  552. PGDC_DICTIONARY pgdcDict = NULL;
  553. //
  554. // Copy the uncompressed packet header into the buffer.
  555. //
  556. memcpy(pPacketUse, pPacket, sizeof(*pPacket));
  557. cbBufferSize = TSHR_MAX_SEND_PKT - sizeof(*pPacket);
  558. if (compression == CT_PERSIST_PKZIP)
  559. {
  560. //
  561. // Figure out what dictionary to use based on stream priority
  562. //
  563. switch (pPacket->stream)
  564. {
  565. case PROT_STR_UPDATES:
  566. dictionary = GDC_DICT_UPDATES;
  567. break;
  568. case PROT_STR_MISC:
  569. dictionary = GDC_DICT_MISC;
  570. break;
  571. case PROT_STR_INPUT:
  572. dictionary = GDC_DICT_INPUT;
  573. break;
  574. default:
  575. ERROR_OUT(("Unrecognized stream ID"));
  576. break;
  577. }
  578. pgdcDict = pasPerson->adcsDict + dictionary;
  579. }
  580. else if (compression != CT_PKZIP)
  581. {
  582. //
  583. // If this isn't PKZIP or PERSIST_PKZIP, we don't know what the
  584. // heck it is (corrupted packet or incompatible T.128. Bail
  585. // out now.
  586. //
  587. WARNING_OUT(("SC_ReceivedPacket: ignoring packet, don't recognize compression type"));
  588. DC_QUIT;
  589. }
  590. //
  591. // Decompress the data following the packet header.
  592. // This should never fail - if it does, the data has probably been
  593. // corrupted.
  594. //
  595. decompressed = GDC_Decompress(pgdcDict, m_agdcWorkBuf,
  596. (LPBYTE)(pPacket + 1),
  597. pPacket->data.compressedLength - sizeof(DATAPACKETHEADER),
  598. (LPBYTE)(pPacketUse + 1),
  599. &cbBufferSize);
  600. if (!decompressed)
  601. {
  602. ERROR_OUT(( "Failed to decompress packet from [%d]!", pasPerson->mcsID));
  603. DC_QUIT;
  604. }
  605. }
  606. else
  607. {
  608. // We have received an uncompressed buffer. Since we may modify the
  609. // buffer's contents and what we have is an MCS buffer that may be
  610. // sent to other nodes, we copy the data.
  611. memcpy(pPacketUse, pPacket, pPacket->dataLength + sizeof(S20DATAPACKET)
  612. - sizeof(DATAPACKETHEADER));
  613. }
  614. // The packet (pPacketUse) is now decompressed
  615. //
  616. // ROUTE the packet
  617. //
  618. TRACE_OUT(("SC_ReceivedPacket: Received packet type %04d size %04d from [%d]",
  619. pPacketUse->data.dataType, pPacketUse->data.compressedLength,
  620. pPacketUse->header.user));
  621. switch (pPacketUse->data.dataType)
  622. {
  623. case DT_CA:
  624. CA_ReceivedPacket(pasPerson, pPacketUse);
  625. break;
  626. case DT_CA30:
  627. CA30_ReceivedPacket(pasPerson, pPacketUse);
  628. break;
  629. case DT_IM:
  630. IM_ReceivedPacket(pasPerson, pPacketUse);
  631. break;
  632. case DT_HET:
  633. case DT_HET30:
  634. HET_ReceivedPacket(pasPerson, pPacketUse);
  635. break;
  636. case DT_UP:
  637. UP_ReceivedPacket(pasPerson, pPacketUse);
  638. break;
  639. case DT_FH:
  640. FH_ReceivedPacket(pasPerson, pPacketUse);
  641. break;
  642. case DT_CM:
  643. CM_ReceivedPacket(pasPerson, pPacketUse);
  644. break;
  645. case DT_CPC:
  646. CPC_ReceivedPacket(pasPerson, pPacketUse);
  647. break;
  648. case DT_AWC:
  649. AWC_ReceivedPacket(pasPerson, pPacketUse);
  650. break;
  651. case DT_UNUSED_DS:
  652. TRACE_OUT(("Ignoring DS packet received from NM 2.x node"));
  653. break;
  654. case DT_UNUSED_USR_FH_11: // Old R.11 FH packets
  655. case DT_UNUSED_USR_FH_10: // Old R.10 FH packets
  656. case DT_UNUSED_HCA: // Old High-Level Control Arbiter
  657. case DT_UNUSED_SC: // Old R.11 SC packets
  658. default:
  659. ERROR_OUT(( "Invalid packet received %u",
  660. pPacketUse->data.dataType));
  661. break;
  662. }
  663. }
  664. DC_EXIT_POINT:
  665. DebugExitVOID(ASShare::SC_ReceivedPacket);
  666. }
  667. //
  668. // SC_ShareStarting()
  669. // Share initialization
  670. //
  671. // This in turn calls other component share starting
  672. //
  673. BOOL ASShare::SC_ShareStarting(void)
  674. {
  675. BOOL rc = FALSE;
  676. BOOL fViewSelf;
  677. DebugEntry(ASShare::SC_ShareStarting);
  678. //
  679. // SC specific init
  680. //
  681. // Find out whether to view own shared stuff (a handy debugging tool)
  682. COM_ReadProfInt(DBG_INI_SECTION_NAME, VIEW_INI_VIEWSELF, FALSE, &fViewSelf);
  683. m_scfViewSelf = (fViewSelf != FALSE);
  684. // Create scratch compression buffer for outgoing/incoming packets
  685. m_ascTmpBuffer = new BYTE[TSHR_MAX_SEND_PKT];
  686. if (!m_ascTmpBuffer)
  687. {
  688. ERROR_OUT(("SC_Init: couldn't allocate m_ascTmpBuffer"));
  689. DC_QUIT;
  690. }
  691. // Share version
  692. m_scShareVersion = CAPS_VERSION_CURRENT;
  693. //
  694. // Component inits
  695. //
  696. if (!BCD_ShareStarting())
  697. {
  698. ERROR_OUT(("BCD_ShareStarting failed"));
  699. DC_QUIT;
  700. }
  701. if (!IM_ShareStarting())
  702. {
  703. ERROR_OUT(("IM_ShareStarting failed"));
  704. DC_QUIT;
  705. }
  706. if (!CM_ShareStarting())
  707. {
  708. ERROR_OUT(("CM_ShareStarting failed"));
  709. DC_QUIT;
  710. }
  711. if (!USR_ShareStarting())
  712. {
  713. ERROR_OUT(("USR_ShareStarting failed"));
  714. DC_QUIT;
  715. }
  716. if (!VIEW_ShareStarting())
  717. {
  718. ERROR_OUT(("VIEW_ShareStarting failed"));
  719. DC_QUIT;
  720. }
  721. rc = TRUE;
  722. DC_EXIT_POINT:
  723. DebugExitBOOL(ASShare::SC_ShareStarting, rc);
  724. return(rc);
  725. }
  726. //
  727. // SC_ShareEnded()
  728. // Share cleanup
  729. //
  730. // This in turn calls other component share ended routines
  731. //
  732. void ASShare::SC_ShareEnded(void)
  733. {
  734. DebugEntry(ASShare::SC_ShareEnded);
  735. //
  736. // Delete remotes from share
  737. //
  738. if (m_pasLocal)
  739. {
  740. while (m_pasLocal->pasNext)
  741. {
  742. SC_PartyDeleted(m_pasLocal->pasNext->mcsID);
  743. }
  744. //
  745. // Delete local self from share
  746. //
  747. SC_PartyDeleted(m_pasLocal->mcsID);
  748. }
  749. //
  750. // Component Notifications
  751. //
  752. VIEW_ShareEnded();
  753. USR_ShareEnded();
  754. CM_ShareEnded();
  755. IM_ShareEnded();
  756. BCD_ShareEnded();
  757. //
  758. // SC specific term
  759. //
  760. // Free scratch buffer
  761. if (m_ascTmpBuffer)
  762. {
  763. delete[] m_ascTmpBuffer;
  764. m_ascTmpBuffer = NULL;
  765. }
  766. DebugExitVOID(ASShare::SC_ShareEnded);
  767. }
  768. //
  769. // SC_PartyJoiningShare()
  770. //
  771. // Called when a new party is joining the share. This is an internal
  772. // function because it is the SC which calls all these functions. The
  773. // processing done here relies on the capabilities - so it is in here as
  774. // this is called after CPC_PartyJoiningShare.
  775. //
  776. // RETURNS:
  777. //
  778. // TRUE if the party can join the share.
  779. //
  780. // FALSE if the party can NOT join the share.
  781. //
  782. //
  783. ASPerson * ASShare::SC_PartyJoiningShare
  784. (
  785. UINT mcsID,
  786. LPSTR szName,
  787. UINT cbCaps,
  788. LPVOID pCaps
  789. )
  790. {
  791. BOOL rc = FALSE;
  792. ASPerson * pasPerson = NULL;
  793. DebugEntry(ASShare::SC_PartyJoiningShare);
  794. //
  795. // Allocate an ASPerson for this dude. If this is the local person,
  796. // it gets stuck at the front. Otherwise it gets stuck just past
  797. // the front.
  798. //
  799. pasPerson = SC_PersonAllocate(mcsID, szName);
  800. if (!pasPerson)
  801. {
  802. ERROR_OUT(("SC_PartyAdded: can't allocate ASPerson for [%d]", mcsID));
  803. DC_QUIT;
  804. }
  805. //
  806. // DO THIS FIRST -- we need the person's caps set up
  807. //
  808. if (!CPC_PartyJoiningShare(pasPerson, cbCaps, pCaps))
  809. {
  810. ERROR_OUT(("CPC_PartyJoiningShare failed for [%d]", pasPerson->mcsID));
  811. DC_QUIT;
  812. }
  813. //
  814. // Call the component joined routines.
  815. //
  816. if (!DCS_PartyJoiningShare(pasPerson))
  817. {
  818. ERROR_OUT(("DCS_PartyJoiningShare failed for [%d]", pasPerson->mcsID));
  819. DC_QUIT;
  820. }
  821. if (!CM_PartyJoiningShare(pasPerson))
  822. {
  823. ERROR_OUT(("CM_PartyJoiningShare failed for [%d]", pasPerson->mcsID));
  824. DC_QUIT;
  825. }
  826. if (!HET_PartyJoiningShare(pasPerson))
  827. {
  828. ERROR_OUT(("HET_PartyJoiningShare failed for [%d]", pasPerson->mcsID));
  829. DC_QUIT;
  830. }
  831. //
  832. // NOW THE PERSON IS JOINED.
  833. // Recalculate capabilities of the share with this new person.
  834. //
  835. SC_RecalcCaps(TRUE);
  836. rc = TRUE;
  837. DC_EXIT_POINT:
  838. if (!rc)
  839. {
  840. //
  841. // Don't worry, this person object will still be cleaned up,
  842. // code at a higher layer will free by using the MCSID.
  843. //
  844. pasPerson = NULL;
  845. }
  846. DebugExitPVOID(ASShare::SC_PartyJoiningShare, pasPerson);
  847. return(pasPerson);
  848. }
  849. //
  850. // SC_RecalcCaps()
  851. //
  852. // Recalculates share capabilities after somebody has joined or left the
  853. // share.
  854. //
  855. void ASShare::SC_RecalcCaps(BOOL fJoiner)
  856. {
  857. ASPerson * pasT;
  858. DebugEntry(ASShare::SC_RecalcCaps);
  859. //
  860. // DO THIS FIRST -- recalculate the share version.
  861. //
  862. ValidatePerson(m_pasLocal);
  863. m_scShareVersion = m_pasLocal->cpcCaps.general.version;
  864. for (pasT = m_pasLocal->pasNext; pasT != NULL; pasT = pasT->pasNext)
  865. {
  866. ValidatePerson(pasT);
  867. m_scShareVersion = min(m_scShareVersion, pasT->cpcCaps.general.version);
  868. }
  869. //
  870. // Do viewing & hosting stuff first
  871. //
  872. DCS_RecalcCaps(fJoiner);
  873. OE_RecalcCaps(fJoiner);
  874. //
  875. // Do hosting stuff second
  876. //
  877. USR_RecalcCaps(fJoiner);
  878. CM_RecalcCaps(fJoiner);
  879. PM_RecalcCaps(fJoiner);
  880. SBC_RecalcCaps(fJoiner);
  881. SSI_RecalcCaps(fJoiner);
  882. DebugExitVOID(ASShare::SC_RecalcCaps);
  883. }
  884. //
  885. // FUNCTION: SC_PartyLeftShare()
  886. //
  887. // DESCRIPTION:
  888. //
  889. // Called when a party has left the share.
  890. //
  891. //
  892. void ASShare::SC_PartyLeftShare(UINT mcsID)
  893. {
  894. ASPerson * pasPerson;
  895. ASPerson * pasT;
  896. DebugEntry(SC_PartyLeftShare);
  897. if (!SC_ValidateNetID(mcsID, &pasPerson))
  898. {
  899. TRACE_OUT(("Couldn't find ASPerson for [%d]", mcsID));
  900. DC_QUIT;
  901. }
  902. // Tell the UI this dude is gone
  903. if (!pasPerson->cpcCaps.share.gccID)
  904. {
  905. WARNING_OUT(("Skipping PartyLeftShare for person [%d], no GCC id",
  906. pasPerson->mcsID));
  907. DC_QUIT;
  908. }
  909. DCS_NotifyUI(SH_EVT_PERSON_LEFT, pasPerson->cpcCaps.share.gccID, 0);
  910. //
  911. // Tell everybody this person is gone.
  912. //
  913. //
  914. // Notes on order of PartyLeftShare calls
  915. //
  916. // 1. HET must be called first, since that halts any sharing from this
  917. // person, before we kick the person out of the share.
  918. //
  919. // 2. CA must be called before IM (as CA calls IM functions)
  920. //
  921. //
  922. // This will stop hosting early
  923. HET_PartyLeftShare(pasPerson);
  924. CA_PartyLeftShare(pasPerson);
  925. CM_PartyLeftShare(pasPerson);
  926. VIEW_PartyLeftShare(pasPerson);
  927. PM_PartyLeftShare(pasPerson);
  928. RBC_PartyLeftShare(pasPerson);
  929. OD2_PartyLeftShare(pasPerson);
  930. OE_PartyLeftShare(pasPerson);
  931. DCS_PartyLeftShare(pasPerson);
  932. //
  933. // Free the person
  934. //
  935. SC_PersonFree(pasPerson);
  936. //
  937. // Recalculate the caps with him gone. But there's no point in doing
  938. // this if it's the local dude, since the share will exit imminently.
  939. //
  940. if (m_pasLocal)
  941. {
  942. SC_RecalcCaps(FALSE);
  943. }
  944. DC_EXIT_POINT:
  945. DebugExitVOID(ASShare::SC_PartyLeftShare);
  946. }
  947. //
  948. // FUNCTION: SCCheckForCMCall
  949. //
  950. // DESCRIPTION:
  951. //
  952. // This is called when we want to check if a CM call now exists (and do
  953. // whatever is appropriate to join it etc).
  954. //
  955. // PARAMETERS: NONE
  956. //
  957. // RETURNS: TRUE if success; otherwise, FALSE.
  958. //
  959. //
  960. void SCCheckForCMCall(void)
  961. {
  962. CM_STATUS cmStatus;
  963. DebugEntry(SCCheckForCMCall);
  964. ASSERT(g_asSession.scState == SCS_INIT);
  965. //
  966. // See if a call already exists
  967. //
  968. if (!g_asSession.callID)
  969. {
  970. if (CMS_GetStatus(&cmStatus))
  971. {
  972. //
  973. // The AS lock protects the g_asSession fields.
  974. //
  975. TRACE_OUT(("AS LOCK: SCCheckForCMCall"));
  976. UT_Lock(UTLOCK_AS);
  977. g_asSession.callID = cmStatus.callID;
  978. //
  979. // This is the time to update our local person name. It's
  980. // on our thread, but before the control packets exchange it
  981. //
  982. lstrcpy(g_asSession.achLocalName, cmStatus.localName);
  983. g_asSession.cchLocalName = lstrlen(g_asSession.achLocalName);
  984. TRACE_OUT(("Local Name is %s", g_asSession.achLocalName));
  985. g_asSession.gccID = cmStatus.localHandle;
  986. UT_Unlock(UTLOCK_AS);
  987. TRACE_OUT(("AS UNLOCK: SCCheckForCMCall"));
  988. }
  989. }
  990. if (g_asSession.callID)
  991. {
  992. SC_CreateShare(S20_JOIN);
  993. }
  994. DebugExitVOID(SCCheckForCMCall);
  995. }
  996. #ifdef _DEBUG
  997. void ASShare::ValidatePerson(ASPerson * pasPerson)
  998. {
  999. ASSERT(!IsBadWritePtr(pasPerson, sizeof(ASPerson)));
  1000. ASSERT(!lstrcmp(pasPerson->stamp.idStamp, "ASPerso"));
  1001. ASSERT(pasPerson->mcsID != MCSID_NULL);
  1002. }
  1003. void ASShare::ValidateView(ASPerson * pasPerson)
  1004. {
  1005. ValidatePerson(pasPerson);
  1006. ASSERT(!IsBadWritePtr(pasPerson->m_pView, sizeof(ASView)));
  1007. ASSERT(!lstrcmp(pasPerson->m_pView->stamp.idStamp, "ASVIEW"));
  1008. }
  1009. #endif // _DEBUG
  1010. //
  1011. // SC_PersonAllocate()
  1012. // This allocates a new ASPerson structure, fills in the debug/mcsID fields,
  1013. // and links it into the people-in-the-conference list.
  1014. //
  1015. // Eventually, all the PartyJoiningShare routines that simply init a field
  1016. // should go away and that info put here.
  1017. //
  1018. ASPerson * ASShare::SC_PersonAllocate(UINT mcsID, LPSTR szName)
  1019. {
  1020. ASPerson * pasNew;
  1021. DebugEntry(ASShare::SC_PersonAllocate);
  1022. pasNew = new ASPerson;
  1023. if (!pasNew)
  1024. {
  1025. ERROR_OUT(("Unable to allocate a new ASPerson"));
  1026. DC_QUIT;
  1027. }
  1028. ZeroMemory(pasNew, sizeof(*pasNew));
  1029. SET_STAMP(pasNew, Person);
  1030. //
  1031. // Set up mcsID and name
  1032. //
  1033. pasNew->mcsID = mcsID;
  1034. lstrcpyn(pasNew->scName, szName, TSHR_MAX_PERSON_NAME_LEN);
  1035. UT_Lock(UTLOCK_AS);
  1036. //
  1037. // Is this the local person?
  1038. //
  1039. if (!m_pasLocal)
  1040. {
  1041. m_pasLocal = pasNew;
  1042. }
  1043. else
  1044. {
  1045. UINT streamID;
  1046. //
  1047. // This is a remote. Set up the sync status right away in case
  1048. // the join process fails in the middle. Cleaning up will undo
  1049. // this always.
  1050. //
  1051. //
  1052. // Mark this person's streams as needing a sync from us before we
  1053. // can send data to him
  1054. // And and that we need a sync from him on each stream before we'll
  1055. // receive data from him
  1056. //
  1057. for (streamID = SC_STREAM_LOW; streamID <= SC_STREAM_HIGH; streamID++ )
  1058. {
  1059. //
  1060. // Set up the sync status.
  1061. //
  1062. ASSERT(pasNew->scSyncSendStatus[streamID-1] == SC_NOT_SYNCED);
  1063. ASSERT(pasNew->scSyncRecStatus[streamID-1] == SC_NOT_SYNCED);
  1064. m_ascSynced[streamID-1]++;
  1065. }
  1066. //
  1067. // Link into list
  1068. //
  1069. pasNew->pasNext = m_pasLocal->pasNext;
  1070. m_pasLocal->pasNext = pasNew;
  1071. }
  1072. UT_Unlock(UTLOCK_AS);
  1073. DC_EXIT_POINT:
  1074. DebugExitPVOID(ASShare::SC_PersonAllocate, pasNew);
  1075. return(pasNew);
  1076. }
  1077. //
  1078. // SC_PersonFree()
  1079. // This gets a person out of the linked list and frees the memory for them.
  1080. //
  1081. void ASShare::SC_PersonFree(ASPerson * pasFree)
  1082. {
  1083. ASPerson ** ppasPerson;
  1084. UINT streamID;
  1085. DebugEntry(ASShare::SC_PersonFree);
  1086. ValidatePerson(pasFree);
  1087. for (ppasPerson = &m_pasLocal; *(ppasPerson) != NULL; ppasPerson = &((*ppasPerson)->pasNext))
  1088. {
  1089. if ((*ppasPerson) == pasFree)
  1090. {
  1091. //
  1092. // Found it.
  1093. //
  1094. TRACE_OUT(("SC_PersonUnhook: unhooking person [%d]", pasFree->mcsID));
  1095. if (pasFree == m_pasLocal)
  1096. {
  1097. ASSERT(pasFree->pasNext == NULL);
  1098. }
  1099. else
  1100. {
  1101. //
  1102. // Clear syncs
  1103. //
  1104. // If this person was never synced, subtract them from the
  1105. // global "needing sync" count on each stream
  1106. //
  1107. for (streamID = SC_STREAM_LOW; streamID <= SC_STREAM_HIGH; streamID++ )
  1108. {
  1109. if (pasFree->scSyncSendStatus[streamID-1] == SC_NOT_SYNCED)
  1110. {
  1111. ASSERT(m_ascSynced[streamID-1] > 0);
  1112. m_ascSynced[streamID-1]--;
  1113. }
  1114. }
  1115. }
  1116. UT_Lock(UTLOCK_AS);
  1117. //
  1118. // Fix up linked list.
  1119. //
  1120. (*ppasPerson) = pasFree->pasNext;
  1121. #ifdef _DEBUG
  1122. ZeroMemory(pasFree, sizeof(ASPerson));
  1123. #endif // _DEBUG
  1124. delete pasFree;
  1125. UT_Unlock(UTLOCK_AS);
  1126. DC_QUIT;
  1127. }
  1128. }
  1129. //
  1130. // We didn't find this guy in the list--this is very bad.
  1131. //
  1132. ERROR_OUT(("SC_PersonFree: didn't find person %d", pasFree));
  1133. DC_EXIT_POINT:
  1134. DebugExitVOID(ASShare::SC_PersonFree);
  1135. }
  1136. //
  1137. // SC_AllocPkt()
  1138. // Allocates a SEND packet
  1139. //
  1140. PS20DATAPACKET ASShare::SC_AllocPkt
  1141. (
  1142. UINT streamID,
  1143. UINT nodeID,
  1144. UINT cbSizePkt
  1145. )
  1146. {
  1147. PS20DATAPACKET pPacket = NULL;
  1148. DebugEntry(ASShare::SC_AllocPkt);
  1149. if (g_asSession.scState != SCS_SHARING)
  1150. {
  1151. TRACE_OUT(("SC_AllocPkt failed; share is ending"));
  1152. DC_QUIT;
  1153. }
  1154. ASSERT((streamID >= SC_STREAM_LOW) && (streamID <= SC_STREAM_HIGH));
  1155. ASSERT(cbSizePkt >= sizeof(S20DATAPACKET));
  1156. //
  1157. // We'd better not be in the middle of a sync!
  1158. //
  1159. ASSERT(!m_scfInSync);
  1160. //
  1161. // Try and send any outstanding syncs
  1162. //
  1163. if (!SCSyncStream(streamID))
  1164. {
  1165. //
  1166. // If the stream is still not synced, don't allocate the packet
  1167. //
  1168. WARNING_OUT(("SC_AllocPkt failed; outstanding syncs are present"));
  1169. DC_QUIT;
  1170. }
  1171. pPacket = S20_AllocDataPkt(streamID, nodeID, cbSizePkt);
  1172. DC_EXIT_POINT:
  1173. DebugExitPVOID(ASShare::SC_AllocPkt, pPacket);
  1174. return(pPacket);
  1175. }
  1176. //
  1177. // SCSyncStream()
  1178. //
  1179. // This broadcasts a SNI sync packet intended for a new person who has just
  1180. // joined the share. That person ignores all received data from us until
  1181. // they get the sync. That's because data in transit before they are synced
  1182. // could refer to PKZIP data they don't have, second level order encoding
  1183. // info they can't decode, orders they can't process, etc.
  1184. //
  1185. // When we receive a SYNC from a remote, we then know that following
  1186. // data from that remote will make sense. The remote has settled us into
  1187. // the share, and the data encorporates our capabilities and will not refer
  1188. // to prior state info from before we joined the share.
  1189. //
  1190. // NOTE that in 2.x, this was O(N^2) where N is the number of people now in
  1191. // the share! Each person in the share would send SNI sync packets for each
  1192. // stream for each other person in the share, even for people who weren't new.
  1193. // But those people wouldn't reset received state, and would (could) continue
  1194. // processing data from us. When they finally got their sync packet, it
  1195. // would do nothing! Even more worst, 2 of the 5 streams are never used,
  1196. // and one stream is only used when a person is hosting. So 3 of these 5
  1197. // O(N^2) broadcasts were useless all or the majority of the time.
  1198. //
  1199. // So now we only send SNI sync packets for new joiners. This makes joining
  1200. // an O(N) broadcast algorithm.
  1201. //
  1202. // LAURABU BOGUS
  1203. // Post Beta1, we can make this even better. Each broadcast is itself O(N)
  1204. // packets. So for beta1, joining/syncing is O(N^2) packets instead of
  1205. // O(N^3) packets. With targeted sends (not broadcasts) whenever possible,
  1206. // we can drop this to O(N) total packets.
  1207. //
  1208. // NOTE also that no real app sharing packets are sent on a stream until
  1209. // we have fully synced everybody. That means we've reduced a lot the
  1210. // lag between somebody dialing into a conference and their seeing a result,
  1211. // and everybody else being able to work again.
  1212. //
  1213. BOOL ASShare::SCSyncStream(UINT streamID)
  1214. {
  1215. ASPerson * pasPerson;
  1216. PSNIPACKET pSNIPacket;
  1217. BOOL rc = TRUE;
  1218. DebugEntry(ASShare::SCSyncStream);
  1219. //
  1220. // Loop through each person in the call broadcasting sync packets as
  1221. // necessary.
  1222. //
  1223. // LAURABU BOGUS
  1224. // We can change this to a targeted send after Beta 1.
  1225. //
  1226. //
  1227. // Note that new people are added to the front of the this. So we will
  1228. // bail out of this loop very quickly when sending syncs to newcomers.
  1229. //
  1230. ValidatePerson(m_pasLocal);
  1231. pasPerson = m_pasLocal->pasNext;
  1232. while ((m_ascSynced[streamID-1] > 0) && (pasPerson != NULL))
  1233. {
  1234. ValidatePerson(pasPerson);
  1235. //
  1236. // If this person is new, we need to send them a SYNC packet so
  1237. // they know we are done processing their join and know they
  1238. // are in the share.
  1239. //
  1240. if (pasPerson->scSyncSendStatus[streamID-1] != SC_SYNCED)
  1241. {
  1242. TRACE_OUT(("Syncing stream %d for person [%d] in broadcast way",
  1243. streamID, pasPerson->mcsID));
  1244. //
  1245. // YES, syncs are broadcast even though they have the mcsID of
  1246. // just one person, the person they are intended for. Since we
  1247. // broadcast all state data, we also broadcast syncs. That's
  1248. // the only way to make sure the packets arrive in the same
  1249. // order, SYNC before data.
  1250. //
  1251. pSNIPacket = (PSNIPACKET)S20_AllocDataPkt(streamID,
  1252. g_s20BroadcastID, sizeof(SNIPACKET));
  1253. if (!pSNIPacket)
  1254. {
  1255. TRACE_OUT(("Failed to alloc SNI sync packet"));
  1256. rc = FALSE;
  1257. break;
  1258. }
  1259. //
  1260. // Set SNI packet fields
  1261. //
  1262. pSNIPacket->header.data.dataType = DT_SNI;
  1263. pSNIPacket->message = SNI_MSG_SYNC;
  1264. pSNIPacket->destination = (NET_UID)pasPerson->mcsID;
  1265. S20_SendDataPkt(streamID, g_s20BroadcastID, &(pSNIPacket->header));
  1266. pasPerson->scSyncSendStatus[streamID-1] = SC_SYNCED;
  1267. ASSERT(m_ascSynced[streamID-1] > 0);
  1268. m_ascSynced[streamID-1]--;
  1269. }
  1270. pasPerson = pasPerson->pasNext;
  1271. }
  1272. DebugExitBOOL(ASShare::SCSyncStream, rc);
  1273. return(rc);
  1274. }
  1275.