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.

1534 lines
41 KiB

  1. #include "precomp.h"
  2. #include <it120app.h>
  3. //
  4. // CMG.C
  5. // Call Management
  6. //
  7. // Copyright(c) Microsoft 1997-
  8. //
  9. #define MLZ_FILE_ZONE ZONE_NET
  10. //
  11. // CMP_Init()
  12. //
  13. BOOL CMP_Init(BOOL * pfCleanup)
  14. {
  15. BOOL rc = FALSE;
  16. GCCError gcc_rc;
  17. DebugEntry(CMP_Init);
  18. UT_Lock(UTLOCK_T120);
  19. if (g_putCMG || g_pcmPrimary)
  20. {
  21. *pfCleanup = FALSE;
  22. ERROR_OUT(("Can't start CMP primary task; already running"));
  23. DC_QUIT;
  24. }
  25. else
  26. {
  27. *pfCleanup = TRUE;
  28. }
  29. //
  30. // Register CMG task
  31. //
  32. if (!UT_InitTask(UTTASK_CMG, &g_putCMG))
  33. {
  34. ERROR_OUT(("Failed to start CMG task"));
  35. DC_QUIT;
  36. }
  37. //
  38. // Allocate a Call Manager handle, ref counted
  39. //
  40. g_pcmPrimary = (PCM_PRIMARY)UT_MallocRefCount(sizeof(CM_PRIMARY), TRUE);
  41. if (!g_pcmPrimary)
  42. {
  43. ERROR_OUT(("CMP_Init failed to allocate CM_PRIMARY data"));
  44. DC_QUIT;
  45. }
  46. SET_STAMP(g_pcmPrimary, CMPRIMARY);
  47. g_pcmPrimary->putTask = g_putCMG;
  48. //
  49. // Init the people list
  50. //
  51. COM_BasedListInit(&(g_pcmPrimary->people));
  52. //
  53. // Register event and exit procedures
  54. //
  55. UT_RegisterExit(g_putCMG, CMPExitProc, g_pcmPrimary);
  56. g_pcmPrimary->exitProcRegistered = TRUE;
  57. //
  58. // - GCCCreateSap, which is the interesting one.
  59. //
  60. gcc_rc = GCC_CreateAppSap((IGCCAppSap **) &(g_pcmPrimary->pIAppSap),
  61. g_pcmPrimary,
  62. CMPGCCCallback);
  63. if (GCC_NO_ERROR != gcc_rc || NULL == g_pcmPrimary->pIAppSap)
  64. {
  65. ERROR_OUT(( "Error from GCCCreateSap"));
  66. DC_QUIT;
  67. }
  68. rc = TRUE;
  69. DC_EXIT_POINT:
  70. UT_Unlock(UTLOCK_T120);
  71. DebugExitBOOL(CMP_Init, rc);
  72. return(rc);
  73. }
  74. //
  75. // CMP_Term()
  76. //
  77. void CMP_Term(void)
  78. {
  79. DebugEntry(CMP_Term);
  80. UT_Lock(UTLOCK_T120);
  81. if (g_pcmPrimary)
  82. {
  83. ValidateCMP(g_pcmPrimary);
  84. ValidateUTClient(g_putCMG);
  85. //
  86. // Unregister our GCC SAP.
  87. //
  88. if (NULL != g_pcmPrimary->pIAppSap)
  89. {
  90. g_pcmPrimary->pIAppSap->ReleaseInterface();
  91. g_pcmPrimary->pIAppSap = NULL;
  92. }
  93. //
  94. // Call the exit procedure to do all our termination
  95. //
  96. CMPExitProc(g_pcmPrimary);
  97. }
  98. UT_TermTask(&g_putCMG);
  99. UT_Unlock(UTLOCK_T120);
  100. DebugExitVOID(CMP_Term);
  101. }
  102. //
  103. // CMPExitProc()
  104. //
  105. void CALLBACK CMPExitProc(LPVOID data)
  106. {
  107. PCM_PRIMARY pcmPrimary = (PCM_PRIMARY)data;
  108. DebugEntry(CMPExitProc);
  109. UT_Lock(UTLOCK_T120);
  110. //
  111. // Check parameters
  112. //
  113. ValidateCMP(pcmPrimary);
  114. ASSERT(pcmPrimary == g_pcmPrimary);
  115. //
  116. // Deregister the exit procedure.
  117. //
  118. if (pcmPrimary->exitProcRegistered)
  119. {
  120. UT_DeregisterExit(pcmPrimary->putTask,
  121. CMPExitProc,
  122. pcmPrimary);
  123. pcmPrimary->exitProcRegistered = FALSE;
  124. }
  125. CMPCallEnded(pcmPrimary);
  126. //
  127. // Free the CMP data
  128. //
  129. UT_FreeRefCount((void**)&g_pcmPrimary, TRUE);
  130. UT_Unlock(UTLOCK_T120);
  131. DebugExitVOID(CMPExitProc);
  132. }
  133. //
  134. // CMPCallEnded()
  135. //
  136. void CMPCallEnded
  137. (
  138. PCM_PRIMARY pcmPrimary
  139. )
  140. {
  141. PCM_PERSON pPerson;
  142. PCM_PERSON pPersonT;
  143. int cmTask;
  144. DebugEntry(CMPCallEnded);
  145. ValidateCMP(pcmPrimary);
  146. if (!(pcmPrimary->currentCall))
  147. {
  148. TRACE_OUT(("CMCallEnded: not in call"));
  149. DC_QUIT;
  150. }
  151. //
  152. // Issue CMS_PERSON_LEFT events for all people still in the call.
  153. // Do this back to front.
  154. //
  155. pPerson = (PCM_PERSON)COM_BasedListLast(&(pcmPrimary->people), FIELD_OFFSET(CM_PERSON, chain));
  156. while (pPerson != NULL)
  157. {
  158. ASSERT(pcmPrimary->peopleCount > 0);
  159. TRACE_OUT(("Person [%d] LEAVING call", pPerson->netID));
  160. //
  161. // Get the previous person
  162. //
  163. pPersonT = (PCM_PERSON)COM_BasedListPrev(&(pcmPrimary->people), pPerson,
  164. FIELD_OFFSET(CM_PERSON, chain));
  165. //
  166. // Remove this guy from the list
  167. //
  168. COM_BasedListRemove(&(pPerson->chain));
  169. pcmPrimary->peopleCount--;
  170. //
  171. // Notify people of his leaving
  172. //
  173. CMPBroadcast(pcmPrimary,
  174. CMS_PERSON_LEFT,
  175. pcmPrimary->peopleCount,
  176. pPerson->netID);
  177. //
  178. // Free the memory for the item
  179. //
  180. delete pPerson;
  181. //
  182. // Move the previous person in the list
  183. pPerson = pPersonT;
  184. }
  185. //
  186. // Inform all registered secondary tasks of call ending (call
  187. // CMbroadcast() with CMS_END_CALL)
  188. //
  189. CMPBroadcast(pcmPrimary,
  190. CMS_END_CALL,
  191. 0,
  192. pcmPrimary->callID);
  193. //
  194. // Reset the current call vars
  195. //
  196. pcmPrimary->currentCall = FALSE;
  197. pcmPrimary->fTopProvider = FALSE;
  198. pcmPrimary->callID = 0;
  199. pcmPrimary->gccUserID = 0;
  200. pcmPrimary->gccTopProviderID = 0;
  201. //
  202. // Discard outstanding channel/token requests
  203. //
  204. for (cmTask = CMTASK_FIRST; cmTask < CMTASK_MAX; cmTask++)
  205. {
  206. if (pcmPrimary->tasks[cmTask])
  207. {
  208. pcmPrimary->tasks[cmTask]->channelKey = 0;
  209. pcmPrimary->tasks[cmTask]->tokenKey = 0;
  210. }
  211. }
  212. DC_EXIT_POINT:
  213. //
  214. // Nobody should be in the call anymore
  215. //
  216. ASSERT(pcmPrimary->peopleCount == 0);
  217. DebugExitVOID(CMCallEnded);
  218. }
  219. //
  220. // CMPGCCCallback
  221. //
  222. void CALLBACK CMPGCCCallback(GCCAppSapMsg * gccMessage)
  223. {
  224. PCM_PRIMARY pcmPrimary;
  225. GCCConferenceID confID;
  226. GCCApplicationRoster FAR * FAR * pRosterList;
  227. UINT roster;
  228. LPOSTR pOctetString;
  229. GCCObjectKey FAR * pObjectKey;
  230. UINT checkLen;
  231. DebugEntry(CMPGCCCallback);
  232. UT_Lock(UTLOCK_T120);
  233. //
  234. // The userDefined parameter is the Primary's PCM_CLIENT.
  235. //
  236. pcmPrimary = (PCM_PRIMARY)gccMessage->pAppData;
  237. if (pcmPrimary != g_pcmPrimary)
  238. {
  239. ASSERT(NULL == g_pcmPrimary);
  240. return;
  241. }
  242. ValidateCMP(pcmPrimary);
  243. switch (gccMessage->eMsgType)
  244. {
  245. case GCC_PERMIT_TO_ENROLL_INDICATION:
  246. {
  247. //
  248. // This indicates a conference has started:
  249. //
  250. CMPProcessPermitToEnroll(pcmPrimary,
  251. &gccMessage->AppPermissionToEnrollInd);
  252. }
  253. break;
  254. case GCC_ENROLL_CONFIRM:
  255. {
  256. //
  257. // This contains the result of a GCCApplicationEnrollRequest.
  258. //
  259. CMPProcessEnrollConfirm(pcmPrimary,
  260. &gccMessage->AppEnrollConfirm);
  261. }
  262. break;
  263. case GCC_REGISTER_CHANNEL_CONFIRM:
  264. {
  265. //
  266. // This contains the result of a GCCRegisterChannelRequest.
  267. //
  268. CMPProcessRegistryConfirm(
  269. pcmPrimary,
  270. gccMessage->eMsgType,
  271. &gccMessage->RegistryConfirm);
  272. }
  273. break;
  274. case GCC_ASSIGN_TOKEN_CONFIRM:
  275. {
  276. //
  277. // This contains the result of a GCCRegistryAssignTokenRequest.
  278. //
  279. CMPProcessRegistryConfirm(
  280. pcmPrimary,
  281. gccMessage->eMsgType,
  282. &gccMessage->RegistryConfirm);
  283. }
  284. break;
  285. case GCC_APP_ROSTER_REPORT_INDICATION:
  286. {
  287. //
  288. // This indicates that the application roster has changed.
  289. //
  290. confID = gccMessage->AppRosterReportInd.nConfID;
  291. pRosterList = gccMessage->AppRosterReportInd.apAppRosters;
  292. for (roster = 0;
  293. roster < gccMessage->AppRosterReportInd.cRosters;
  294. roster++)
  295. {
  296. //
  297. // Check this app roster to see if it relates to the
  298. // Groupware session (the first check is because we always
  299. // use a NON_STANDARD application key).
  300. //
  301. pObjectKey = &(pRosterList[roster]->
  302. session_key.application_protocol_key);
  303. //
  304. // We only ever use a non standard key.
  305. //
  306. if (pObjectKey->key_type != GCC_H221_NONSTANDARD_KEY)
  307. {
  308. TRACE_OUT(("Standard key, so not a roster we are interested in..."));
  309. continue;
  310. }
  311. pOctetString = &pObjectKey->h221_non_standard_id;
  312. //
  313. // Now check the octet string. It should be the same
  314. // length as our hardcoded GROUPWARE- string (including
  315. // NULL term) and should match byte for byte:
  316. //
  317. checkLen = sizeof(GROUPWARE_GCC_APPLICATION_KEY);
  318. if ((pOctetString->length != checkLen)
  319. ||
  320. (memcmp(pOctetString->value,
  321. GROUPWARE_GCC_APPLICATION_KEY,
  322. checkLen) != 0))
  323. {
  324. //
  325. // This roster is not for our session - go to the next
  326. // one.
  327. //
  328. TRACE_OUT(("Roster not for Groupware session - ignore"));
  329. continue;
  330. }
  331. //
  332. // Process the application roster.
  333. //
  334. CMPProcessAppRoster(pcmPrimary,
  335. confID,
  336. pRosterList[roster]);
  337. }
  338. }
  339. break;
  340. }
  341. UT_Unlock(UTLOCK_T120);
  342. DebugExitVOID(CMPGCCCallback);
  343. }
  344. //
  345. //
  346. // CMPBuildGCCRegistryKey(...)
  347. //
  348. //
  349. void CMPBuildGCCRegistryKey
  350. (
  351. UINT dcgKeyNum,
  352. GCCRegistryKey FAR * pGCCKey,
  353. LPSTR dcgKeyStr
  354. )
  355. {
  356. DebugEntry(CMPBuildGCCRegistryKey);
  357. //
  358. // Build up a string of the form "Groupware-XX" where XX is a string
  359. // representation (in decimal) of the <dcgKey> parameter passed in.
  360. //
  361. memcpy(dcgKeyStr, GROUPWARE_GCC_APPLICATION_KEY, sizeof(GROUPWARE_GCC_APPLICATION_KEY)-1);
  362. wsprintf(dcgKeyStr+sizeof(GROUPWARE_GCC_APPLICATION_KEY)-1, "%d",
  363. dcgKeyNum);
  364. //
  365. // Now build the GCCRegistryKey. This involves putting a pointer to
  366. // our static <dcgKeyStr> deep inside the GCC structure. We also store
  367. // the length, which is lstrlen+1, because we want to include the
  368. // NULLTERM explicitly (since GCC treats the octet_string as an
  369. // arbitrary array of bytes).
  370. //
  371. pGCCKey->session_key.application_protocol_key.
  372. key_type = GCC_H221_NONSTANDARD_KEY;
  373. pGCCKey->session_key.application_protocol_key.h221_non_standard_id.
  374. length = sizeof(GROUPWARE_GCC_APPLICATION_KEY);
  375. pGCCKey->session_key.application_protocol_key.h221_non_standard_id.
  376. value = (LPBYTE) GROUPWARE_GCC_APPLICATION_KEY;
  377. pGCCKey->session_key.session_id = 0;
  378. pGCCKey->resource_id.length =
  379. (sizeof(GROUPWARE_GCC_APPLICATION_KEY) +
  380. lstrlen(&dcgKeyStr[sizeof(GROUPWARE_GCC_APPLICATION_KEY)-1]));
  381. pGCCKey->resource_id.value = (LPBYTE) dcgKeyStr;
  382. DebugExitVOID(CMPBuildGCCRegistryKey);
  383. }
  384. //
  385. // CMPProcessPermitToEnroll(...)
  386. //
  387. void CMPProcessPermitToEnroll
  388. (
  389. PCM_PRIMARY pcmPrimary,
  390. GCCAppPermissionToEnrollInd * pMsg
  391. )
  392. {
  393. DebugEntry(CMPProcessPermitToEnroll);
  394. ValidateCMP(pcmPrimary);
  395. //
  396. // We will send CMS_PERSON_JOINED events when we receive a
  397. // GCC_APP_ROSTER_REPORT_INDICATION.
  398. //
  399. if (pMsg->fPermissionGranted)
  400. {
  401. // CALL STARTED
  402. //
  403. // If we haven't had a NCS yet then we store the conference ID.
  404. // Otherwise ignore it.
  405. //
  406. ASSERT(!pcmPrimary->currentCall);
  407. //
  408. // Initially, we do not consider ourselves to be in the call - we will
  409. // add an entry when we get the ENROLL_CONFIRM:
  410. //
  411. ASSERT(pcmPrimary->peopleCount == 0);
  412. pcmPrimary->currentCall = TRUE;
  413. pcmPrimary->callID = pMsg->nConfID;
  414. pcmPrimary->fTopProvider =
  415. pcmPrimary->pIAppSap->IsThisNodeTopProvider(pMsg->nConfID);
  416. //
  417. // Tell GCC whether we're interested:
  418. //
  419. if (!CMPGCCEnroll(pcmPrimary, pMsg->nConfID, TRUE))
  420. {
  421. //
  422. // We are only interested in an error if it is a Groupware conf.
  423. // All we can really do is pretend the conference has ended due
  424. // to a network error.
  425. //
  426. WARNING_OUT(("Error from CMPGCCEnroll"));
  427. CMPCallEnded(pcmPrimary);
  428. }
  429. //
  430. // The reply will arrive on a GCC_ENROLL_CONFIRM event.
  431. //
  432. }
  433. else
  434. {
  435. // CALL ENDED
  436. if (g_pcmPrimary->currentCall)
  437. {
  438. //
  439. // Inform Primary task and all secondary tasks that the call has ended
  440. //
  441. CMPCallEnded(g_pcmPrimary);
  442. //
  443. // Un-enroll from the GCC Application Roster.
  444. //
  445. if (g_pcmPrimary->bGCCEnrolled)
  446. {
  447. CMPGCCEnroll(g_pcmPrimary, g_pcmPrimary->callID, FALSE);
  448. g_pcmPrimary->bGCCEnrolled = FALSE;
  449. }
  450. }
  451. }
  452. DebugExitVOID(CMPProcessPermitToEnroll);
  453. }
  454. //
  455. //
  456. // CMPProcessEnrollConfirm(...)
  457. //
  458. //
  459. void CMPProcessEnrollConfirm
  460. (
  461. PCM_PRIMARY pcmPrimary,
  462. GCCAppEnrollConfirm * pMsg
  463. )
  464. {
  465. DebugEntry(CMPProcessEnrollConfirm);
  466. ValidateCMP(pcmPrimary);
  467. ASSERT(pcmPrimary->currentCall);
  468. ASSERT(pMsg->nConfID == pcmPrimary->callID);
  469. //
  470. // This event contains the GCC node ID (i.e. the MCS user ID of the
  471. // GCC node controller at this node). Store it for later reference
  472. // against the roster report:
  473. //
  474. TRACE_OUT(( "GCC user_id: %u", pMsg->nidMyself));
  475. pcmPrimary->gccUserID = pMsg->nidMyself;
  476. pcmPrimary->gccTopProviderID = pcmPrimary->pIAppSap->GetTopProvider(pcmPrimary->callID);
  477. ASSERT(pcmPrimary->gccTopProviderID);
  478. if (pMsg->nResult != GCC_RESULT_SUCCESSFUL)
  479. {
  480. WARNING_OUT(( "Attempt to enroll failed (reason: %u", pMsg->nResult));
  481. //
  482. // All we can really do is pretend the conference has ended due to
  483. // a network error.
  484. //
  485. CMPCallEnded(pcmPrimary);
  486. }
  487. DebugExitVOID(CMProcessEnrollConfirm);
  488. }
  489. //
  490. // CMPProcessRegistryConfirm(...)
  491. //
  492. void CMPProcessRegistryConfirm
  493. (
  494. PCM_PRIMARY pcmPrimary,
  495. GCCMessageType messageType,
  496. GCCRegistryConfirm *pConfirm
  497. )
  498. {
  499. UINT event = 0;
  500. BOOL succeeded;
  501. LPSTR pGCCKeyStr; // extracted from the GCC registry key
  502. UINT dcgKeyNum; // the value originally passed in as key
  503. UINT itemID; // can be channel or token ID
  504. int cmTask;
  505. PUT_CLIENT secondaryHandle = NULL;
  506. DebugEntry(CMPProcessRegistryConfirm);
  507. ValidateCMP(pcmPrimary);
  508. //
  509. // Check this is for the Groupware conference:
  510. //
  511. if (!pcmPrimary->currentCall ||
  512. (pConfirm->nConfID != pcmPrimary->callID))
  513. {
  514. WARNING_OUT(( "Got REGISTRY_XXX_CONFIRM for unknown conference %lu",
  515. pConfirm->nConfID));
  516. DC_QUIT;
  517. }
  518. //
  519. // Embedded deep down inside the message from GCC is a pointer to an
  520. // octet string which is of the form "Groupware-XX", where XX is a
  521. // string representation of the numeric key the original Call Manager
  522. // secondary used when registering the item. Extract it now:
  523. //
  524. pGCCKeyStr = (LPSTR)pConfirm->pRegKey->resource_id.value;
  525. dcgKeyNum = DecimalStringToUINT(&pGCCKeyStr[sizeof(GROUPWARE_GCC_APPLICATION_KEY)-1]);
  526. if (dcgKeyNum == 0)
  527. {
  528. WARNING_OUT(( "Received ASSIGN/REGISTER_CONFIRM with unknown key: %s",
  529. pGCCKeyStr));
  530. DC_QUIT;
  531. }
  532. TRACE_OUT(( "Conf ID %u, DCG Key %u, result %u",
  533. pConfirm->nConfID, dcgKeyNum, pConfirm->nResult));
  534. //
  535. // This is either a REGISTER_CHANNEL_CONFIRM or a ASSIGN_TOKEN_CONFIRM.
  536. // Check, and set up the relevant pointers:
  537. //
  538. switch (messageType)
  539. {
  540. case GCC_REGISTER_CHANNEL_CONFIRM:
  541. {
  542. event = CMS_CHANNEL_REGISTER_CONFIRM;
  543. itemID = pConfirm->pRegItem->channel_id;
  544. // Look for task that registered this channel
  545. for (cmTask = CMTASK_FIRST; cmTask < CMTASK_MAX; cmTask++)
  546. {
  547. if (pcmPrimary->tasks[cmTask] &&
  548. (pcmPrimary->tasks[cmTask]->channelKey == dcgKeyNum))
  549. {
  550. pcmPrimary->tasks[cmTask]->channelKey = 0;
  551. secondaryHandle = pcmPrimary->tasks[cmTask]->putTask;
  552. }
  553. }
  554. }
  555. break;
  556. case GCC_ASSIGN_TOKEN_CONFIRM:
  557. {
  558. event = CMS_TOKEN_ASSIGN_CONFIRM;
  559. itemID = pConfirm->pRegItem->token_id;
  560. // Look for task that assigned this token
  561. for (cmTask = CMTASK_FIRST; cmTask < CMTASK_MAX; cmTask++)
  562. {
  563. if (pcmPrimary->tasks[cmTask] &&
  564. (pcmPrimary->tasks[cmTask]->tokenKey == dcgKeyNum))
  565. {
  566. pcmPrimary->tasks[cmTask]->tokenKey = 0;
  567. secondaryHandle = pcmPrimary->tasks[cmTask]->putTask;
  568. }
  569. }
  570. }
  571. break;
  572. default:
  573. {
  574. ERROR_OUT(( "Unexpected registry event %u", messageType));
  575. DC_QUIT;
  576. }
  577. }
  578. switch (pConfirm->nResult)
  579. {
  580. case GCC_RESULT_SUCCESSFUL:
  581. {
  582. //
  583. // We were the first to register an item against this key.
  584. //
  585. TRACE_OUT(("We were first to register using key %u (itemID: %u)",
  586. dcgKeyNum, itemID));
  587. succeeded = TRUE;
  588. }
  589. break;
  590. case GCC_RESULT_ENTRY_ALREADY_EXISTS:
  591. {
  592. //
  593. // Someone beat us to it: they have registered a channel
  594. // against the key we specified. This value is in the GCC
  595. // message:
  596. //
  597. TRACE_OUT(("Another node registered using key %u (itemID: %u)",
  598. dcgKeyNum, itemID));
  599. succeeded = TRUE;
  600. }
  601. break;
  602. default:
  603. {
  604. ERROR_OUT(("Error %#hx registering/assigning item against key %u",
  605. pConfirm->nResult, dcgKeyNum));
  606. succeeded = FALSE;
  607. }
  608. break;
  609. }
  610. //
  611. // Tell the secondary about the result.
  612. //
  613. if (secondaryHandle)
  614. {
  615. UT_PostEvent(pcmPrimary->putTask,
  616. secondaryHandle,
  617. 0,
  618. event,
  619. succeeded,
  620. MAKELONG(itemID, dcgKeyNum));
  621. }
  622. DC_EXIT_POINT:
  623. DebugExitVOID(CMProcessRegistryConfirm);
  624. }
  625. //
  626. // CMPProcessAppRoster(...)
  627. //
  628. void CMPProcessAppRoster
  629. (
  630. PCM_PRIMARY pcmPrimary,
  631. GCCConferenceID confID,
  632. GCCApplicationRoster* pAppRoster
  633. )
  634. {
  635. UINT newList;
  636. UserID oldNode;
  637. UserID newNode;
  638. PCM_PERSON pPerson;
  639. PCM_PERSON pPersonT;
  640. BOOL found;
  641. int task;
  642. BOOL notInOldRoster = TRUE;
  643. BOOL inNewRoster = FALSE;
  644. DebugEntry(CMPProcessAppRoster);
  645. ValidateCMP(pcmPrimary);
  646. //
  647. // If we are not in a call ignore this.
  648. //
  649. if (!pcmPrimary->currentCall ||
  650. (confID != pcmPrimary->callID))
  651. {
  652. WARNING_OUT(("Report not for active Groupware conference - ignore"));
  653. DC_QUIT;
  654. }
  655. //
  656. // At this point, pAppRoster points to the bit of the roster which
  657. // relates to Groupware. Trace out some info:
  658. //
  659. TRACE_OUT(( "Number of records %u;", pAppRoster->number_of_records));
  660. TRACE_OUT(( "Nodes added: %s, removed: %s",
  661. (pAppRoster->nodes_were_added ? "YES" : "NO"),
  662. (pAppRoster->nodes_were_removed ? "YES" : "NO")));
  663. //
  664. // We store the GCC user IDs in shared memory as TSHR_PERSONIDs.
  665. // Compare this list of people we know to be in the call, and
  666. // * Remove people no longer around
  667. // * See if we are new to the roster
  668. // * Add people who are new
  669. //
  670. pPerson = (PCM_PERSON)COM_BasedListFirst(&(pcmPrimary->people), FIELD_OFFSET(CM_PERSON, chain));
  671. while (pPerson != NULL)
  672. {
  673. ASSERT(pcmPrimary->peopleCount > 0);
  674. oldNode = (UserID)pPerson->netID;
  675. //
  676. // Get the next guy in the list in case we remove this one.
  677. //
  678. pPersonT = (PCM_PERSON)COM_BasedListNext(&(pcmPrimary->people), pPerson,
  679. FIELD_OFFSET(CM_PERSON, chain));
  680. //
  681. // Check to see if our node is currently in the roster
  682. //
  683. if (oldNode == pcmPrimary->gccUserID)
  684. {
  685. TRACE_OUT(( "We are currently in the app roster"));
  686. notInOldRoster = FALSE;
  687. }
  688. //
  689. // ...check if they're in the new list...
  690. //
  691. found = FALSE;
  692. for (newList = 0; newList < pAppRoster->number_of_records; newList++)
  693. {
  694. if (oldNode == pAppRoster->application_record_list[newList]->node_id)
  695. {
  696. found = TRUE;
  697. break;
  698. }
  699. }
  700. if (!found)
  701. {
  702. //
  703. // This node is no longer present, so remove him.
  704. //
  705. TRACE_OUT(("Person %u left", oldNode));
  706. COM_BasedListRemove(&(pPerson->chain));
  707. pcmPrimary->peopleCount--;
  708. CMPBroadcast(pcmPrimary,
  709. CMS_PERSON_LEFT,
  710. pcmPrimary->peopleCount,
  711. oldNode);
  712. //
  713. // Free the memory for the person item
  714. //
  715. delete pPerson;
  716. }
  717. pPerson = pPersonT;
  718. }
  719. //
  720. // Now see if we are new to the roster
  721. //
  722. for (newList = 0; newList < pAppRoster->number_of_records; newList++)
  723. {
  724. if (pAppRoster->application_record_list[newList]->node_id ==
  725. pcmPrimary->gccUserID)
  726. {
  727. TRACE_OUT(( "We are in the new app roster"));
  728. inNewRoster = TRUE;
  729. break;
  730. }
  731. }
  732. if (notInOldRoster && inNewRoster)
  733. {
  734. //
  735. // We are new to the roster so we can now do all the processing we
  736. // were previously doing in the enroll confirm handler. GCC spec
  737. // requires that we do not do this until we get the roster
  738. // notification back.
  739. //
  740. // Flag we are enrolled and start registering channels etc.
  741. //
  742. pcmPrimary->bGCCEnrolled = TRUE;
  743. //
  744. // Post a CMS_NEW_CALL events to all secondary tasks
  745. //
  746. TRACE_OUT(( "Broadcasting CMS_NEW_CALL with call handle 0x%08lx",
  747. pcmPrimary->callID));
  748. //
  749. // If we are not the caller then delay the broadcast a little
  750. //
  751. CMPBroadcast(pcmPrimary, CMS_NEW_CALL,
  752. pcmPrimary->fTopProvider, pcmPrimary->callID);
  753. #ifdef _DEBUG
  754. //
  755. // Process any outstanding channel register and assign token
  756. // requests.
  757. //
  758. for (task = CMTASK_FIRST; task < CMTASK_MAX; task++)
  759. {
  760. if (pcmPrimary->tasks[task] != NULL)
  761. {
  762. ASSERT(pcmPrimary->tasks[task]->channelKey == 0);
  763. ASSERT(pcmPrimary->tasks[task]->tokenKey == 0);
  764. }
  765. }
  766. #endif // _DEBUG
  767. }
  768. //
  769. // If we are not yet enrolled in the conference then do not start
  770. // sending PERSON_JOINED notifications.
  771. //
  772. if (!pcmPrimary->bGCCEnrolled)
  773. {
  774. DC_QUIT;
  775. }
  776. //
  777. // Add the new people (this will include us). At this point, we know
  778. // that everyone in the people list is currently in the roster, since
  779. // we would have removed 'em above.
  780. //
  781. // We need to walk the existing list over and over.
  782. // But at least we can skip the people we add. So we save the current
  783. // front of the list.
  784. //
  785. pPersonT = (PCM_PERSON)COM_BasedListFirst(&(pcmPrimary->people), FIELD_OFFSET(CM_PERSON, chain));
  786. for (newList = 0; newList < pAppRoster->number_of_records; newList++)
  787. {
  788. newNode = pAppRoster->application_record_list[newList]->node_id;
  789. found = FALSE;
  790. pPerson = pPersonT;
  791. while (pPerson != NULL)
  792. {
  793. if (newNode == pPerson->netID)
  794. {
  795. //
  796. // This person already existed - don't need to do anything
  797. //
  798. found = TRUE;
  799. break; // out of inner for loop
  800. }
  801. pPerson = (PCM_PERSON)COM_BasedListNext(&(pcmPrimary->people), pPerson,
  802. FIELD_OFFSET(CM_PERSON, chain));
  803. }
  804. if (!found)
  805. {
  806. //
  807. // This dude is new; add him to our people list.
  808. //
  809. TRACE_OUT(("Person with GCC user_id %u joined", newNode));
  810. pPerson = new CM_PERSON;
  811. if (!pPerson)
  812. {
  813. //
  814. // Uh oh; can't add him.
  815. //
  816. ERROR_OUT(("Can't add person GCC user_id %u; out of memory",
  817. newNode));
  818. break;
  819. }
  820. ZeroMemory(pPerson, sizeof(*pPerson));
  821. pPerson->netID = newNode;
  822. //
  823. // LONCHANC: We should collapse all these events into a single one
  824. // that summarize all added and removed nodes,
  825. // instead of posting the events one by one.
  826. //
  827. //
  828. // Stick him in at the beginning. At least that way we don't
  829. // have to look at his record anymore.
  830. //
  831. COM_BasedListInsertAfter(&(pcmPrimary->people), &pPerson->chain);
  832. pcmPrimary->peopleCount++;
  833. CMPBroadcast(pcmPrimary,
  834. CMS_PERSON_JOINED,
  835. pcmPrimary->peopleCount,
  836. newNode);
  837. }
  838. }
  839. TRACE_OUT(( "Num people now in call %u", pcmPrimary->peopleCount));
  840. DC_EXIT_POINT:
  841. DebugExitVOID(CMPProcessAppRoster);
  842. }
  843. //
  844. // CMPBroadcast()
  845. //
  846. void CMPBroadcast
  847. (
  848. PCM_PRIMARY pcmPrimary,
  849. UINT event,
  850. UINT param1,
  851. UINT param2
  852. )
  853. {
  854. int task;
  855. DebugEntry(CMPBroadcast);
  856. ValidateCMP(pcmPrimary);
  857. //
  858. // for every secondary task
  859. //
  860. for (task = CMTASK_FIRST; task < CMTASK_MAX; task++)
  861. {
  862. if (pcmPrimary->tasks[task] != NULL)
  863. {
  864. UT_PostEvent(pcmPrimary->putTask,
  865. pcmPrimary->tasks[task]->putTask,
  866. NO_DELAY,
  867. event,
  868. param1,
  869. param2);
  870. }
  871. }
  872. DebugExitVOID(CMPBroadcast);
  873. }
  874. //
  875. // CMPGCCEnroll(...)
  876. //
  877. BOOL CMPGCCEnroll
  878. (
  879. PCM_PRIMARY pcmPrimary,
  880. GCCConferenceID conferenceID,
  881. BOOL fEnroll
  882. )
  883. {
  884. GCCError rcGCC = GCC_NO_ERROR;
  885. GCCSessionKey gccSessionKey;
  886. GCCObjectKey FAR * pGCCObjectKey;
  887. BOOL succeeded = TRUE;
  888. GCCEnrollRequest er;
  889. GCCRequestTag nReqTag;
  890. DebugEntry(CMPGCCEnroll);
  891. ValidateCMP(pcmPrimary);
  892. //
  893. // Do some error checking.
  894. //
  895. if (fEnroll && pcmPrimary->bGCCEnrolled)
  896. {
  897. WARNING_OUT(("Already enrolled"));
  898. DC_QUIT;
  899. }
  900. TRACE_OUT(("CMGCCEnroll for CM_hnd 0x%08x, confID 0x%08x, in/out %d",
  901. pcmPrimary, conferenceID, fEnroll));
  902. //
  903. // Set up the session key which identifies us uniquely in the GCC
  904. // AppRoster. We use a non-standard key (because we're not part of the
  905. // T.120 standards series)
  906. //
  907. // Octet strings aren't null terminated, but we want ours to include
  908. // the NULL at the end of the C string, so specify lstrlen+1 for the
  909. // length.
  910. //
  911. pGCCObjectKey = &(gccSessionKey.application_protocol_key);
  912. pGCCObjectKey->key_type = GCC_H221_NONSTANDARD_KEY;
  913. pGCCObjectKey->h221_non_standard_id.value =
  914. (LPBYTE) GROUPWARE_GCC_APPLICATION_KEY;
  915. pGCCObjectKey->h221_non_standard_id.length =
  916. sizeof(GROUPWARE_GCC_APPLICATION_KEY);
  917. gccSessionKey.session_id = 0;
  918. //
  919. // Try to enroll/unenroll with GCC. This may fail because we have not
  920. // yet received a GCC_PERMIT_TO_ENROLL_INDICATION.
  921. //
  922. // Fill in the enroll request structure
  923. //
  924. ZeroMemory(&er, sizeof(er));
  925. er.pSessionKey = &gccSessionKey;
  926. // er.fEnrollActively = FALSE;
  927. // er.nUserID = 0; // no user ID
  928. // er.fConductingCapable = FALSE;
  929. er.nStartupChannelType = MCS_STATIC_CHANNEL;
  930. // er.cNonCollapsedCaps = 0;
  931. // er.apNonCollapsedCaps = NULL;
  932. // er.cCollapsedCaps = 0;
  933. // er.apCollapsedCaps = NULL;
  934. er.fEnroll = fEnroll;
  935. rcGCC = pcmPrimary->pIAppSap->AppEnroll(
  936. conferenceID,
  937. &er,
  938. &nReqTag);
  939. if (GCC_NO_ERROR != rcGCC)
  940. {
  941. //
  942. // Leave the decision about any error processing to the caller.
  943. //
  944. TRACE_OUT(("Error 0x%08x from GCCApplicationEnrollRequest conf ID %lu enroll=%s",
  945. rcGCC, conferenceID, fEnroll ? "YES": "NO"));
  946. succeeded = FALSE;
  947. }
  948. else
  949. {
  950. //
  951. // Whether we have asked to enroll or un-enroll, we act as if we
  952. // are no longer enrolled at once. We are only really enrolled
  953. // when we receive an enroll confirm event.
  954. //
  955. pcmPrimary->bGCCEnrolled = FALSE;
  956. ASSERT(succeeded);
  957. TRACE_OUT(( "%s with conference %d", fEnroll ?
  958. "Enroll Outstanding" : "Unenrolled",
  959. conferenceID));
  960. }
  961. DC_EXIT_POINT:
  962. DebugExitBOOL(CMPGCCEnroll, succeeded);
  963. return(succeeded);
  964. }
  965. //
  966. // CMS_Register()
  967. //
  968. BOOL CMS_Register
  969. (
  970. PUT_CLIENT putTask,
  971. CMTASK taskType,
  972. PCM_CLIENT* ppcmClient
  973. )
  974. {
  975. BOOL fRegistered = FALSE;
  976. PCM_CLIENT pcmClient = NULL;
  977. DebugEntry(CMS_Register);
  978. UT_Lock(UTLOCK_T120);
  979. if (!g_pcmPrimary)
  980. {
  981. ERROR_OUT(("CMS_Register failed; primary doesn't exist"));
  982. DC_QUIT;
  983. }
  984. ValidateUTClient(putTask);
  985. ASSERT(taskType >= CMTASK_FIRST);
  986. ASSERT(taskType < CMTASK_MAX);
  987. *ppcmClient = NULL;
  988. //
  989. // Is this task already present? If so, share it
  990. //
  991. if (g_pcmPrimary->tasks[taskType] != NULL)
  992. {
  993. TRACE_OUT(("Sharing CMS task 0x%08x", g_pcmPrimary->tasks[taskType]));
  994. *ppcmClient = g_pcmPrimary->tasks[taskType];
  995. ValidateCMS(*ppcmClient);
  996. (*ppcmClient)->useCount++;
  997. // Return -- we exist.
  998. fRegistered = TRUE;
  999. DC_QUIT;
  1000. }
  1001. //
  1002. // If we got here the task is not a Call Manager Secondary yet, so go
  1003. // ahead with the registration.
  1004. //
  1005. //
  1006. // Allocate memory for the client
  1007. //
  1008. pcmClient = new CM_CLIENT;
  1009. if (! pcmClient)
  1010. {
  1011. ERROR_OUT(("Could not allocate CM handle"));
  1012. DC_QUIT;
  1013. }
  1014. ZeroMemory(pcmClient, sizeof(*pcmClient));
  1015. *ppcmClient = pcmClient;
  1016. //
  1017. // Fill in information
  1018. //
  1019. SET_STAMP(pcmClient, CMCLIENT);
  1020. pcmClient->putTask = putTask;
  1021. pcmClient->taskType = taskType;
  1022. pcmClient->useCount = 1;
  1023. UT_BumpUpRefCount(g_pcmPrimary);
  1024. g_pcmPrimary->tasks[taskType] = pcmClient;
  1025. //
  1026. // Register an exit procedure
  1027. //
  1028. UT_RegisterExit(putTask, CMSExitProc, pcmClient);
  1029. pcmClient->exitProcRegistered = TRUE;
  1030. fRegistered = TRUE;
  1031. DC_EXIT_POINT:
  1032. UT_Unlock(UTLOCK_T120);
  1033. DebugExitBOOL(CMS_Register, fRegistered);
  1034. return(fRegistered);
  1035. }
  1036. //
  1037. // CMS_Deregister()
  1038. //
  1039. void CMS_Deregister(PCM_CLIENT * ppcmClient)
  1040. {
  1041. PCM_CLIENT pcmClient = *ppcmClient;
  1042. DebugEntry(CMS_Deregister);
  1043. //
  1044. // Check the parameters are valid
  1045. //
  1046. UT_Lock(UTLOCK_T120);
  1047. ValidateCMS(pcmClient);
  1048. //
  1049. // Only actually deregister the client if the registration count has
  1050. // reached zero.
  1051. //
  1052. pcmClient->useCount--;
  1053. if (pcmClient->useCount != 0)
  1054. {
  1055. DC_QUIT;
  1056. }
  1057. //
  1058. // Call the exit procedure to do our local cleanup
  1059. //
  1060. CMSExitProc(pcmClient);
  1061. DC_EXIT_POINT:
  1062. *ppcmClient = NULL;
  1063. UT_Unlock(UTLOCK_T120);
  1064. DebugExitVOID(CMS_Deregister);
  1065. }
  1066. //
  1067. // CMS_ChannelRegister()
  1068. //
  1069. BOOL CMS_ChannelRegister
  1070. (
  1071. PCM_CLIENT pcmClient,
  1072. UINT channelKey,
  1073. UINT channelID
  1074. )
  1075. {
  1076. BOOL fRegistered = FALSE;
  1077. GCCRegistryKey gccRegistryKey;
  1078. GCCError rcGCC;
  1079. char dcgKeyStr[sizeof(GROUPWARE_GCC_APPLICATION_KEY)+MAX_ITOA_LENGTH];
  1080. DebugEntry(CMS_ChannelRegister);
  1081. UT_Lock(UTLOCK_T120);
  1082. //
  1083. // Check the CMG task
  1084. //
  1085. ValidateUTClient(g_putCMG);
  1086. //
  1087. // Check the parameters are valid
  1088. //
  1089. ValidateCMP(g_pcmPrimary);
  1090. ValidateCMS(pcmClient);
  1091. //
  1092. // If we are not in a call it is an error.
  1093. //
  1094. if (!g_pcmPrimary->currentCall)
  1095. {
  1096. WARNING_OUT(("CMS_ChannelRegister failed; not in call"));
  1097. DC_QUIT;
  1098. }
  1099. if (!g_pcmPrimary->bGCCEnrolled)
  1100. {
  1101. WARNING_OUT(("CMS_ChannelRegister failed; not enrolled in call"));
  1102. DC_QUIT;
  1103. }
  1104. // Make sure we don't have one pending already
  1105. ASSERT(pcmClient->channelKey == 0);
  1106. TRACE_OUT(("Channel ID %u Key %u", channelID, channelKey));
  1107. //
  1108. // Build a GCCRegistryKey based on our channelKey:
  1109. //
  1110. CMPBuildGCCRegistryKey(channelKey, &gccRegistryKey, dcgKeyStr);
  1111. //
  1112. // Now call through to GCC. GCC will invoke our callback when it
  1113. // has processed the request.
  1114. //
  1115. rcGCC = g_pcmPrimary->pIAppSap->RegisterChannel(
  1116. g_pcmPrimary->callID,
  1117. &gccRegistryKey,
  1118. (ChannelID)channelID);
  1119. if (rcGCC)
  1120. {
  1121. //
  1122. // Tell the secondary client that the request failed.
  1123. //
  1124. WARNING_OUT(( "Error %#lx from GCCRegisterChannel (key: %u)",
  1125. rcGCC, channelKey));
  1126. }
  1127. else
  1128. {
  1129. // Remember so we can post confirm event back to proper task
  1130. pcmClient->channelKey = channelKey;
  1131. fRegistered = TRUE;
  1132. }
  1133. DC_EXIT_POINT:
  1134. UT_Unlock(UTLOCK_T120);
  1135. DebugExitBOOL(CMS_ChannelRegister, fRegistered);
  1136. return(fRegistered);
  1137. }
  1138. //
  1139. // CMS_AssignTokenId()
  1140. //
  1141. BOOL CMS_AssignTokenId
  1142. (
  1143. PCM_CLIENT pcmClient,
  1144. UINT tokenKey
  1145. )
  1146. {
  1147. GCCRegistryKey gccRegistryKey;
  1148. GCCError rcGCC;
  1149. char dcgKeyStr[sizeof(GROUPWARE_GCC_APPLICATION_KEY)+MAX_ITOA_LENGTH];
  1150. BOOL fAssigned = FALSE;
  1151. DebugEntry(CMS_AssignTokenId);
  1152. UT_Lock(UTLOCK_T120);
  1153. //
  1154. // Check the parameters are valid
  1155. //
  1156. ValidateCMP(g_pcmPrimary);
  1157. ValidateCMS(pcmClient);
  1158. ValidateUTClient(g_putCMG);
  1159. if (!g_pcmPrimary->currentCall)
  1160. {
  1161. WARNING_OUT(("CMS_AssignTokenId failing; not in call"));
  1162. DC_QUIT;
  1163. }
  1164. if (!g_pcmPrimary->bGCCEnrolled)
  1165. {
  1166. WARNING_OUT(("CMS_AssignTokenId failing; not enrolled in call"));
  1167. DC_QUIT;
  1168. }
  1169. // Make sure we don't have one already
  1170. ASSERT(pcmClient->tokenKey == 0);
  1171. //
  1172. // Build a GCCRegistryKey based on our tokenKey:
  1173. //
  1174. CMPBuildGCCRegistryKey(tokenKey, &gccRegistryKey, dcgKeyStr);
  1175. //
  1176. // Now call through to GCC. GCC will invoke our callback when it
  1177. // has processed the request.
  1178. //
  1179. rcGCC = g_pcmPrimary->pIAppSap->RegistryAssignToken(
  1180. g_pcmPrimary->callID, &gccRegistryKey);
  1181. if (rcGCC)
  1182. {
  1183. //
  1184. // Tell the secondary client that the request failed.
  1185. //
  1186. WARNING_OUT(( "Error %x from GCCAssignToken (key: %u)",
  1187. rcGCC, tokenKey));
  1188. }
  1189. else
  1190. {
  1191. // Remember so we can post confirm to proper task
  1192. pcmClient->tokenKey = tokenKey;
  1193. fAssigned = TRUE;
  1194. }
  1195. DC_EXIT_POINT:
  1196. UT_Unlock(UTLOCK_T120);
  1197. DebugExitBOOL(CMS_AssignTokenId, fAssigned);
  1198. return(fAssigned);
  1199. }
  1200. //
  1201. // CMSExitProc()
  1202. //
  1203. void CALLBACK CMSExitProc(LPVOID data)
  1204. {
  1205. PCM_CLIENT pcmClient = (PCM_CLIENT)data;
  1206. DebugEntry(CMSExitProc);
  1207. UT_Lock(UTLOCK_T120);
  1208. //
  1209. // Check parameters
  1210. //
  1211. ValidateCMS(pcmClient);
  1212. //
  1213. // Deregister exit procedure
  1214. //
  1215. if (pcmClient->exitProcRegistered)
  1216. {
  1217. UT_DeregisterExit(pcmClient->putTask,
  1218. CMSExitProc,
  1219. pcmClient);
  1220. pcmClient->exitProcRegistered = FALSE;
  1221. }
  1222. //
  1223. // Remove the task entry from the primary's list
  1224. //
  1225. g_pcmPrimary->tasks[pcmClient->taskType] = NULL;
  1226. UT_FreeRefCount((void**)&g_pcmPrimary, TRUE);
  1227. //
  1228. // Free the client data
  1229. //
  1230. delete pcmClient;
  1231. UT_Unlock(UTLOCK_T120);
  1232. DebugExitVOID(CMSExitProc);
  1233. }
  1234. BOOL WINAPI CMS_GetStatus(PCM_STATUS pcmStatus)
  1235. {
  1236. BOOL inCall;
  1237. DebugEntry(CMS_GetStatus);
  1238. UT_Lock(UTLOCK_T120);
  1239. ASSERT(!IsBadWritePtr(pcmStatus, sizeof(CM_STATUS)));
  1240. ZeroMemory(pcmStatus, sizeof(CM_STATUS));
  1241. ValidateCMP(g_pcmPrimary);
  1242. T120_GetNodeName(pcmStatus->localName, CCHMAX(pcmStatus->localName));
  1243. pcmStatus->localHandle = g_pcmPrimary->gccUserID;
  1244. pcmStatus->peopleCount = g_pcmPrimary->peopleCount;
  1245. pcmStatus->fTopProvider = g_pcmPrimary->fTopProvider;
  1246. pcmStatus->topProviderID = g_pcmPrimary->gccTopProviderID;
  1247. //
  1248. // Fill in information about other primary
  1249. //
  1250. pcmStatus->callID = g_pcmPrimary->callID;
  1251. inCall = (g_pcmPrimary->currentCall != FALSE);
  1252. UT_Unlock(UTLOCK_T120);
  1253. DebugExitBOOL(CMS_GetStatus, inCall);
  1254. return(inCall);
  1255. }