Leaked source code of windows server 2003
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.

1615 lines
50 KiB

  1. /****************************************************************************
  2. *
  3. * $Archive: S:/STURGEON/SRC/CALLCONT/VCS/confman.c_v $
  4. *
  5. * INTEL Corporation Prorietary Information
  6. *
  7. * This listing is supplied under the terms of a license agreement
  8. * with INTEL Corporation and may not be copied nor disclosed except
  9. * in accordance with the terms of that agreement.
  10. *
  11. * Copyright (c) 1993-1994 Intel Corporation.
  12. *
  13. * $Revision: 1.91 $
  14. * $Date: 04 Mar 1997 17:35:06 $
  15. * $Author: MANDREWS $
  16. *
  17. * Deliverable:
  18. *
  19. * Abstract:
  20. *
  21. *
  22. * Notes:
  23. *
  24. ***************************************************************************/
  25. #include "precomp.h"
  26. #include "apierror.h"
  27. #include "incommon.h"
  28. #include "callcont.h"
  29. #include "q931.h"
  30. #include "ccmain.h"
  31. #include "confman.h"
  32. #include "ccutils.h"
  33. #include "chanman.h"
  34. #include "callman.h"
  35. static BOOL bConferenceInited = FALSE;
  36. static struct {
  37. PCONFERENCE pHead;
  38. LOCK Lock;
  39. } ConferenceTable;
  40. static struct {
  41. CC_HCONFERENCE hConference;
  42. LOCK Lock;
  43. } ConferenceHandle;
  44. CC_CONFERENCEID InvalidConferenceID;
  45. HRESULT InitConferenceManager()
  46. {
  47. ASSERT(bConferenceInited == FALSE);
  48. ConferenceTable.pHead = NULL;
  49. InitializeLock(&ConferenceTable.Lock);
  50. ConferenceHandle.hConference = CC_INVALID_HANDLE + 1;
  51. InitializeLock(&ConferenceHandle.Lock);
  52. memset(&InvalidConferenceID, 0, sizeof(InvalidConferenceID));
  53. bConferenceInited = TRUE;
  54. return CC_OK;
  55. }
  56. HRESULT DeInitConferenceManager()
  57. {
  58. PCONFERENCE pConference;
  59. PCONFERENCE pNextConference;
  60. if (bConferenceInited == FALSE)
  61. return CC_OK;
  62. pConference = ConferenceTable.pHead;
  63. while (pConference != NULL) {
  64. AcquireLock(&pConference->Lock);
  65. pNextConference = pConference->pNextInTable;
  66. FreeConference(pConference);
  67. pConference = pNextConference;
  68. }
  69. DeleteLock(&ConferenceHandle.Lock);
  70. DeleteLock(&ConferenceTable.Lock);
  71. bConferenceInited = FALSE;
  72. return CC_OK;
  73. }
  74. HRESULT _CreateLocalH245H2250MuxCapability(
  75. PCONFERENCE pConference)
  76. {
  77. HRESULT status;
  78. CC_TERMCAP TermCap;
  79. struct MultipointCapability_mediaDistributionCapability RXMediaDistributionCapability;
  80. struct MultipointCapability_mediaDistributionCapability TXMediaDistributionCapability;
  81. struct MultipointCapability_mediaDistributionCapability RXTXMediaDistributionCapability;
  82. ASSERT(pConference != NULL);
  83. if (pConference->pLocalH245H2250MuxCapability != NULL)
  84. H245FreeCap(pConference->pLocalH245H2250MuxCapability);
  85. TermCap.Dir = H245_CAPDIR_LCLRXTX;
  86. TermCap.DataType = H245_DATA_MUX;
  87. TermCap.ClientType = H245_CLIENT_MUX_H2250;
  88. TermCap.CapId = 0; // CapId = 0 is a special case for mux capabilities
  89. TermCap.Cap.H245Mux_H2250.bit_mask = 0;
  90. TermCap.Cap.H245Mux_H2250.maximumAudioDelayJitter = 60;
  91. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
  92. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.multiUniCastConference = FALSE;
  93. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability = &RXMediaDistributionCapability;
  94. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->next = NULL;
  95. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
  96. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
  97. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  98. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
  99. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  100. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
  101. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  102. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
  103. TermCap.Cap.H245Mux_H2250.receiveMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
  104. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multicastCapability = (char)pConference->bMultipointCapable;
  105. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.multiUniCastConference = FALSE;
  106. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability = &TXMediaDistributionCapability;
  107. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->next = NULL;
  108. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.bit_mask = 0;
  109. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedControl = FALSE;
  110. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  111. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedAudio = FALSE;
  112. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  113. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedVideo = FALSE;
  114. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  115. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.centralizedData = NULL;
  116. TermCap.Cap.H245Mux_H2250.transmitMultipointCapability.mediaDistributionCapability->value.distributedData = NULL;
  117. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multicastCapability = (char)pConference->bMultipointCapable;
  118. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.multiUniCastConference = FALSE;
  119. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability = &RXTXMediaDistributionCapability;
  120. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->next = NULL;
  121. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.bit_mask = 0;
  122. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedControl = FALSE;
  123. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedControl = (char)pConference->bMultipointCapable;
  124. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedAudio = FALSE;
  125. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedAudio = (char)pConference->bMultipointCapable;
  126. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedVideo = FALSE;
  127. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedVideo = (char)pConference->bMultipointCapable;
  128. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.centralizedData = NULL;
  129. TermCap.Cap.H245Mux_H2250.rcvAndTrnsmtMltpntCpblty.mediaDistributionCapability->value.distributedData = NULL;
  130. TermCap.Cap.H245Mux_H2250.mcCapability.centralizedConferenceMC = FALSE;
  131. TermCap.Cap.H245Mux_H2250.mcCapability.decentralizedConferenceMC = (char)pConference->bMultipointCapable;
  132. TermCap.Cap.H245Mux_H2250.rtcpVideoControlCapability = FALSE;
  133. TermCap.Cap.H245Mux_H2250.mediaPacketizationCapability.bit_mask = 0;
  134. TermCap.Cap.H245Mux_H2250.mediaPacketizationCapability.h261aVideoPacketization = FALSE;
  135. status = H245CopyCap(&pConference->pLocalH245H2250MuxCapability,
  136. &TermCap);
  137. return status;
  138. }
  139. HRESULT _AddConferenceToTable( PCONFERENCE pConference)
  140. {
  141. PCONFERENCE pCurrent;
  142. ASSERT(pConference != NULL);
  143. ASSERT(pConference->hConference != CC_INVALID_HANDLE);
  144. ASSERT(pConference->bInTable == FALSE);
  145. AcquireLock(&ConferenceTable.Lock);
  146. // If a valid non-zero conference ID was specified, make sure
  147. // there's not a duplicate in the conference table
  148. if (!EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
  149. pCurrent = ConferenceTable.pHead;
  150. while (pCurrent != NULL) {
  151. if (EqualConferenceIDs(&pCurrent->ConferenceID,
  152. &pConference->ConferenceID)) {
  153. RelinquishLock(&ConferenceTable.Lock);
  154. return CC_DUPLICATE_CONFERENCE_ID;
  155. }
  156. pCurrent = pCurrent->pNextInTable;
  157. }
  158. }
  159. pConference->pNextInTable = ConferenceTable.pHead;
  160. pConference->pPrevInTable = NULL;
  161. if (ConferenceTable.pHead != NULL)
  162. ConferenceTable.pHead->pPrevInTable = pConference;
  163. ConferenceTable.pHead = pConference;
  164. pConference->bInTable = TRUE;
  165. RelinquishLock(&ConferenceTable.Lock);
  166. return CC_OK;
  167. }
  168. HRESULT _RemoveConferenceFromTable( PCONFERENCE pConference)
  169. {
  170. CC_HCONFERENCE hConference;
  171. BOOL bTimedOut;
  172. ASSERT(pConference != NULL);
  173. ASSERT(pConference->bInTable == TRUE);
  174. // Caller must have a lock on the conference object;
  175. // in order to avoid deadlock, we must:
  176. // 1. unlock the conference object,
  177. // 2. lock the ConferenceTable,
  178. // 3. locate the conference object in the ConferenceTable (note that
  179. // after step 2, the conference object may be deleted from the
  180. // ConferenceTable by another thread),
  181. // 4. lock the conference object (someone else may have the lock)
  182. // 5. remove the conference object from the ConferenceTable,
  183. // 6. unlock the ConferenceTable
  184. //
  185. // The caller can now safely unlock and destroy the conference object,
  186. // since no other thread will be able to find the object (its been
  187. // removed from the ConferenceTable), and therefore no other thread will
  188. // be able to lock it.
  189. // Save the conference handle; its the only way to look up
  190. // the conference object in the ConferenceTable. Note that we
  191. // can't use pConference to find the conference object, since
  192. // pConference may be free'd up, and another conference object
  193. // allocated at the same address
  194. hConference = pConference->hConference;
  195. // step 1
  196. RelinquishLock(&pConference->Lock);
  197. step2:
  198. // step 2
  199. AcquireLock(&ConferenceTable.Lock);
  200. // step 3
  201. pConference = ConferenceTable.pHead;
  202. while ((pConference != NULL) && (pConference->hConference != hConference))
  203. pConference = pConference->pNextInTable;
  204. if (pConference != NULL) {
  205. // step 4
  206. AcquireTimedLock(&pConference->Lock,10,&bTimedOut);
  207. if (bTimedOut) {
  208. RelinquishLock(&ConferenceTable.Lock);
  209. Sleep(0);
  210. goto step2;
  211. }
  212. // step 5
  213. if (pConference->pPrevInTable == NULL)
  214. ConferenceTable.pHead = pConference->pNextInTable;
  215. else
  216. pConference->pPrevInTable->pNextInTable = pConference->pNextInTable;
  217. if (pConference->pNextInTable != NULL)
  218. pConference->pNextInTable->pPrevInTable = pConference->pPrevInTable;
  219. pConference->pNextInTable = NULL;
  220. pConference->pPrevInTable = NULL;
  221. pConference->bInTable = FALSE;
  222. }
  223. // step 6
  224. RelinquishLock(&ConferenceTable.Lock);
  225. if (pConference == NULL)
  226. return CC_BAD_PARAM;
  227. else
  228. return CC_OK;
  229. }
  230. HRESULT _MakeConferenceHandle( PCC_HCONFERENCE phConference)
  231. {
  232. AcquireLock(&ConferenceHandle.Lock);
  233. *phConference = ConferenceHandle.hConference++;
  234. RelinquishLock(&ConferenceHandle.Lock);
  235. return CC_OK;
  236. }
  237. HRESULT AllocateTerminalNumber( PCONFERENCE pConference,
  238. H245_TERMINAL_LABEL_T *pH245TerminalLabel)
  239. {
  240. unsigned i, j;
  241. BYTE bMask;
  242. ASSERT(pConference != NULL);
  243. ASSERT(pH245TerminalLabel != NULL);
  244. ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  245. ASSERT(pConference->tsMultipointController == TS_TRUE);
  246. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  247. bMask = 0x01;
  248. if (pConference->TerminalNumberAllocation[i] != 0xFF) {
  249. for (j = 0; j < 8; j++) {
  250. if ((pConference->TerminalNumberAllocation[i] & bMask) == 0) {
  251. pConference->TerminalNumberAllocation[i] |= bMask;
  252. pH245TerminalLabel->mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  253. pH245TerminalLabel->terminalNumber = (TerminalNumber)((i * 8) + j + 1);
  254. return CC_OK;
  255. }
  256. bMask *= 2;
  257. }
  258. }
  259. }
  260. // No more terminal numbers are available for this conference
  261. return CC_BAD_PARAM;
  262. }
  263. HRESULT FreeTerminalNumber( PCONFERENCE pConference,
  264. BYTE bTerminalNumber)
  265. {
  266. unsigned i, j;
  267. BYTE bMask;
  268. ASSERT(pConference != NULL);
  269. if (bTerminalNumber > NUM_TERMINAL_ALLOCATION_SLOTS * 8)
  270. return CC_BAD_PARAM;
  271. --bTerminalNumber;
  272. i = bTerminalNumber / 8;
  273. j = bTerminalNumber % 8;
  274. bMask = (BYTE)(0x01 << j);
  275. if ((pConference->TerminalNumberAllocation[i] & bMask) == 0)
  276. return CC_BAD_PARAM;
  277. pConference->TerminalNumberAllocation[i] &= ~bMask;
  278. return CC_OK;
  279. }
  280. HRESULT AllocateChannelNumber( PCONFERENCE pConference,
  281. WORD *pwChannelNumber)
  282. {
  283. unsigned i, j;
  284. BYTE bMask;
  285. ASSERT(pConference != NULL);
  286. ASSERT(pwChannelNumber != NULL);
  287. for (i = 0; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++) {
  288. bMask = 0x01;
  289. if (pConference->ChannelNumberAllocation[i] != 0xFF) {
  290. for (j = 0; j < 8; j++) {
  291. if ((pConference->ChannelNumberAllocation[i] & bMask) == 0) {
  292. pConference->ChannelNumberAllocation[i] |= bMask;
  293. *pwChannelNumber = (WORD) (((i * 8) + j) +
  294. (pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber << 8));
  295. return CC_OK;
  296. }
  297. bMask *= 2;
  298. }
  299. }
  300. }
  301. // No more channel numbers are available for this conference
  302. *pwChannelNumber = 0;
  303. return CC_BAD_PARAM;
  304. }
  305. HRESULT FreeChannelNumber( PCONFERENCE pConference,
  306. WORD wChannelNumber)
  307. {
  308. unsigned i, j;
  309. BYTE bMask;
  310. ASSERT(pConference != NULL);
  311. wChannelNumber &= 0xFF;
  312. if ((wChannelNumber > NUM_CHANNEL_ALLOCATION_SLOTS * 8) ||
  313. (wChannelNumber == 0))
  314. return CC_BAD_PARAM;
  315. i = wChannelNumber / 8;
  316. j = wChannelNumber % 8;
  317. bMask = (BYTE)(0x01 << j);
  318. if ((pConference->ChannelNumberAllocation[i] & bMask) == 0)
  319. return CC_BAD_PARAM;
  320. pConference->ChannelNumberAllocation[i] &= ~bMask;
  321. return CC_OK;
  322. }
  323. HRESULT AllocAndLockConference( PCC_HCONFERENCE phConference,
  324. PCC_CONFERENCEID pConferenceID,
  325. BOOL bMultipointCapable,
  326. BOOL bForceMultipointController,
  327. PCC_TERMCAPLIST pLocalTermCapList,
  328. PCC_TERMCAPDESCRIPTORS pLocalTermCapDescriptors,
  329. PCC_VENDORINFO pVendorInfo,
  330. PCC_OCTETSTRING pTerminalID,
  331. DWORD_PTR dwConferenceToken,
  332. CC_SESSIONTABLE_CONSTRUCTOR SessionTableConstructor,
  333. CC_TERMCAP_CONSTRUCTOR TermCapConstructor,
  334. CC_CONFERENCE_CALLBACK ConferenceCallback,
  335. PPCONFERENCE ppConference)
  336. {
  337. WORD i;
  338. HRESULT status;
  339. TRISTATE tsMultipointController;
  340. ASSERT(bConferenceInited == TRUE);
  341. // all parameters should have been validated by the caller
  342. ASSERT(phConference != NULL);
  343. ASSERT(pLocalTermCapList != NULL);
  344. #ifdef _DEBUG
  345. if (pLocalTermCapList->wLength != 0)
  346. ASSERT(pLocalTermCapList->pTermCapArray != NULL);
  347. for (i = 0; i < pLocalTermCapList->wLength; i++)
  348. ASSERT(pLocalTermCapList->pTermCapArray[i] != NULL);
  349. if (pLocalTermCapDescriptors != NULL) {
  350. ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray != NULL);
  351. for (i = 0; i < pLocalTermCapDescriptors->wLength; i++)
  352. ASSERT(pLocalTermCapDescriptors->pTermCapDescriptorArray[i] != NULL);
  353. }
  354. #endif
  355. ASSERT(pVendorInfo != NULL);
  356. ASSERT(SessionTableConstructor != NULL);
  357. ASSERT(TermCapConstructor != NULL);
  358. ASSERT(ConferenceCallback != NULL);
  359. ASSERT(ppConference != NULL);
  360. // set phConference now, in case we encounter an error
  361. *phConference = CC_INVALID_HANDLE;
  362. *ppConference = (PCONFERENCE)MemAlloc(sizeof(CONFERENCE));
  363. if (*ppConference == NULL)
  364. return CC_NO_MEMORY;
  365. if (bForceMultipointController == TRUE)
  366. tsMultipointController = TS_TRUE;
  367. else if (bMultipointCapable == TRUE)
  368. tsMultipointController = TS_UNKNOWN;
  369. else
  370. tsMultipointController = TS_FALSE;
  371. (*ppConference)->bInTable = FALSE;
  372. (*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
  373. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
  374. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
  375. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  376. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  377. (*ppConference)->LocalParticipantInfo.pEnqueuedRequestsForTerminalID = NULL;
  378. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
  379. (*ppConference)->TerminalNumberAllocation[i] = 0;
  380. // Channel 0 is reserved for the H.245 control channel
  381. (*ppConference)->ChannelNumberAllocation[0] = 0x01;
  382. for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
  383. (*ppConference)->ChannelNumberAllocation[i] = 0;
  384. (*ppConference)->bMultipointCapable = bMultipointCapable;
  385. (*ppConference)->bForceMC = bForceMultipointController;
  386. (*ppConference)->SessionTableConstructor = SessionTableConstructor;
  387. (*ppConference)->TermCapConstructor = TermCapConstructor;
  388. (*ppConference)->dwConferenceToken = dwConferenceToken;
  389. (*ppConference)->bDeferredDelete = FALSE;
  390. (*ppConference)->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
  391. (*ppConference)->LocalEndpointAttached = NEVER_ATTACHED;
  392. (*ppConference)->ConferenceCallback = ConferenceCallback;
  393. (*ppConference)->SaveConferenceCallback = ConferenceCallback;
  394. (*ppConference)->bSessionTableInternallyConstructed = FALSE;
  395. (*ppConference)->pSessionTable = NULL;
  396. (*ppConference)->pConferenceH245H2250MuxCapability = NULL;
  397. (*ppConference)->pConferenceTermCapList = NULL;
  398. (*ppConference)->pConferenceTermCapDescriptors = NULL;
  399. (*ppConference)->pLocalH245H2250MuxCapability = NULL;
  400. (*ppConference)->pLocalH245TermCapList = NULL;
  401. (*ppConference)->pLocalH245TermCapDescriptors = NULL;
  402. (*ppConference)->pEnqueuedCalls = NULL;
  403. (*ppConference)->pPlacedCalls = NULL;
  404. (*ppConference)->pEstablishedCalls = NULL;
  405. (*ppConference)->pVirtualCalls = NULL;
  406. (*ppConference)->pChannels = NULL;
  407. (*ppConference)->tsMultipointController = tsMultipointController;
  408. (*ppConference)->tsMaster = TS_UNKNOWN;
  409. (*ppConference)->pMultipointControllerAddr = NULL;
  410. (*ppConference)->ConferenceMode = UNCONNECTED_MODE;
  411. (*ppConference)->pVendorInfo = NULL;
  412. (*ppConference)->pEnqueuedRequestModeCalls = NULL;
  413. (*ppConference)->pNextInTable = NULL;
  414. (*ppConference)->pPrevInTable = NULL;
  415. if (pConferenceID == NULL) {
  416. pConferenceID = &InvalidConferenceID;
  417. (*ppConference)->bDynamicConferenceID = TRUE;
  418. } else
  419. (*ppConference)->bDynamicConferenceID = FALSE;
  420. (*ppConference)->ConferenceID = *pConferenceID;
  421. InitializeLock(&(*ppConference)->Lock);
  422. AcquireLock(&(*ppConference)->Lock);
  423. status = _MakeConferenceHandle(&(*ppConference)->hConference);
  424. if (status != CC_OK) {
  425. FreeConference(*ppConference);
  426. return status;
  427. }
  428. if (pTerminalID != NULL) {
  429. (*ppConference)->bDynamicTerminalID = FALSE;
  430. (*ppConference)->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_VALID;
  431. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength =
  432. pTerminalID->wOctetStringLength;
  433. (*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString =
  434. (BYTE *)MemAlloc(pTerminalID->wOctetStringLength);
  435. if ((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString == NULL) {
  436. FreeConference(*ppConference);
  437. return CC_NO_MEMORY;
  438. }
  439. memcpy((*ppConference)->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString,
  440. pTerminalID->pOctetString,
  441. pTerminalID->wOctetStringLength);
  442. } else {
  443. (*ppConference)->bDynamicTerminalID = TRUE;
  444. }
  445. status = _CreateLocalH245H2250MuxCapability(*ppConference);
  446. if (status != CC_OK) {
  447. FreeConference(*ppConference);
  448. return status;
  449. }
  450. // make a local copy of pTermCapList
  451. status = CopyH245TermCapList(&(*ppConference)->pLocalH245TermCapList,
  452. pLocalTermCapList);
  453. if (status != CC_OK) {
  454. FreeConference(*ppConference);
  455. return CC_NO_MEMORY;
  456. }
  457. // create a new descriptor list if one was not supplied
  458. if (pLocalTermCapDescriptors == NULL)
  459. status = CreateH245DefaultTermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
  460. (*ppConference)->pLocalH245TermCapList);
  461. else
  462. // make a local copy of pTermCapDescriptors
  463. status = CopyH245TermCapDescriptors(&(*ppConference)->pLocalH245TermCapDescriptors,
  464. pLocalTermCapDescriptors);
  465. if (status != CC_OK) {
  466. FreeConference(*ppConference);
  467. return CC_NO_MEMORY;
  468. }
  469. status = CopyVendorInfo(&((*ppConference)->pVendorInfo), pVendorInfo);
  470. if (status != CC_OK) {
  471. FreeConference(*ppConference);
  472. return status;
  473. }
  474. *phConference = (*ppConference)->hConference;
  475. // add the conference to the conference table
  476. status = _AddConferenceToTable(*ppConference);
  477. if (status != CC_OK)
  478. FreeConference(*ppConference);
  479. // CreateConferenceTermCaps() must be called after _AddConferenceToTable(),
  480. // since it will re-lock the conference object
  481. if ((*ppConference)->tsMultipointController == TS_TRUE) {
  482. status = CreateConferenceTermCaps(*ppConference, NULL);
  483. if (status != CC_OK) {
  484. FreeConference(*ppConference);
  485. return status;
  486. }
  487. }
  488. return status;
  489. }
  490. HRESULT RemoveCallFromConference( PCALL pCall,
  491. PCONFERENCE pConference)
  492. {
  493. ASSERT(pCall != NULL);
  494. ASSERT(pConference != NULL);
  495. // The call object must have been removed from the call table
  496. // prior to removing it from the associated conference object.
  497. // This assures us that no other thread is waiting for a lock on it.
  498. ASSERT(pCall->bInTable == FALSE);
  499. if (pCall->pPrev == NULL) {
  500. // the call object is either at the head of the enqueued call list,
  501. // the head of the placed call list, the head of the established
  502. // call list, the head of the virtual call list, or is detached
  503. // from the conference
  504. if (pConference->pEnqueuedCalls == pCall)
  505. // The call is on the enqueued call list
  506. pConference->pEnqueuedCalls = pCall->pNext;
  507. else if (pConference->pPlacedCalls == pCall)
  508. // the call is on the placed call list
  509. pConference->pPlacedCalls = pCall->pNext;
  510. else if (pConference->pEstablishedCalls == pCall)
  511. // the call is on the established call list
  512. pConference->pEstablishedCalls = pCall->pNext;
  513. else if (pConference->pVirtualCalls == pCall)
  514. pConference->pVirtualCalls = pCall->pNext;
  515. } else
  516. pCall->pPrev->pNext = pCall->pNext;
  517. if (pCall->pNext != NULL)
  518. pCall->pNext->pPrev = pCall->pPrev;
  519. pCall->pNext = NULL;
  520. pCall->pPrev = NULL;
  521. return CC_OK;
  522. }
  523. HRESULT RemoveEnqueuedCallFromConference(
  524. PCONFERENCE pConference,
  525. PCC_HCALL phCall)
  526. {
  527. ASSERT(pConference != NULL);
  528. ASSERT(phCall != NULL);
  529. if (pConference->pEnqueuedCalls == NULL) {
  530. // No enqueued calls; this is not an error, since the caller can't tell
  531. // whether there are any enqueued calls in this conference
  532. *phCall = CC_INVALID_HANDLE;
  533. return CC_OK;
  534. }
  535. // Move the call object from the enqueued call list to the placed
  536. // call list.
  537. // Note that another thread may have a lock on the enqueued call
  538. // object, and may be trying to delete it; they will first need to
  539. // lock the conference object (which this thread has locked), remove
  540. // the call object from the enqueued call list, then free the call object.
  541. // We are therefore safe in creating a pointer to the call object, although
  542. // we may not examine or change any of its contents other than hCall (read-only),
  543. // pNext and pPrev.
  544. *phCall = pConference->pEnqueuedCalls->hCall;
  545. pConference->pEnqueuedCalls = pConference->pEnqueuedCalls->pNext;
  546. if (pConference->pEnqueuedCalls != NULL)
  547. pConference->pEnqueuedCalls->pPrev = NULL;
  548. return CC_OK;
  549. }
  550. HRESULT RemoveChannelFromConference(PCHANNEL pChannel,
  551. PCONFERENCE pConference)
  552. {
  553. ASSERT(pChannel != NULL);
  554. ASSERT(pConference != NULL);
  555. // The channel object must have been removed from the channel table
  556. // prior to removing it from the associated conference object.
  557. // This assures us that no other thread is waiting for a lock on it.
  558. ASSERT(pChannel->bInTable == FALSE);
  559. if (pChannel->pPrev == NULL) {
  560. // the channel object is at the head of the channel list,
  561. // or has been detached from the conference
  562. if (pConference->pChannels == pChannel)
  563. pConference->pChannels = pChannel->pNext;
  564. } else
  565. pChannel->pPrev->pNext = pChannel->pNext;
  566. if (pChannel->pNext != NULL)
  567. pChannel->pNext->pPrev = pChannel->pPrev;
  568. pChannel->pNext = NULL;
  569. pChannel->pPrev = NULL;
  570. return CC_OK;
  571. }
  572. HRESULT AddEnqueuedCallToConference(PCALL pCall,
  573. PCONFERENCE pConference)
  574. {
  575. ASSERT(pCall != NULL);
  576. ASSERT(pConference != NULL);
  577. ASSERT(EqualConferenceIDs(&pCall->ConferenceID, &InvalidConferenceID));
  578. ASSERT(EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID));
  579. ASSERT(pConference->pPlacedCalls != NULL);
  580. // Call cannot already be associated with the conference
  581. ASSERT(pCall->pNext == NULL);
  582. ASSERT(pCall->pPrev == NULL);
  583. pCall->hConference = pConference->hConference;
  584. pCall->pNext = pConference->pEnqueuedCalls;
  585. pCall->pPrev = NULL;
  586. if (pConference->pEnqueuedCalls != NULL) {
  587. ASSERT(pConference->pEnqueuedCalls->pPrev == NULL);
  588. pConference->pEnqueuedCalls->pPrev = pCall;
  589. }
  590. pConference->pEnqueuedCalls = pCall;
  591. return CC_OK;
  592. }
  593. HRESULT AddPlacedCallToConference( PCALL pCall,
  594. PCONFERENCE pConference)
  595. {
  596. ASSERT(pCall != NULL);
  597. ASSERT(pConference != NULL);
  598. if (EqualConferenceIDs(&pConference->ConferenceID,
  599. &InvalidConferenceID)) {
  600. // If a conference ID has not been assigned, but there are
  601. // placed or enqueued calls on the conference, the conference ID
  602. // will be assigned by a callee when the first of these calls completes.
  603. // Since pCall has an assigned conference ID (which will differ from
  604. // the ID to be assigned to this conference), we cannot assign pCall
  605. // to this conference.
  606. ASSERT(pConference->pEstablishedCalls == NULL);
  607. if (pConference->pPlacedCalls != NULL)
  608. return CC_BAD_PARAM;
  609. else
  610. pConference->ConferenceID = pCall->ConferenceID;
  611. } else
  612. if (!EqualConferenceIDs(&pConference->ConferenceID,
  613. &pCall->ConferenceID))
  614. return CC_BAD_PARAM;
  615. pCall->hConference = pConference->hConference;
  616. // Unlink pCall from pConference, if necessary
  617. if (pCall->pPrev == NULL) {
  618. // pCall is at the head of either the enqueued call list,
  619. // the placed call list, or the established call list, or
  620. // is not yet associated with the conference object
  621. if (pConference->pEnqueuedCalls == pCall)
  622. pConference->pEnqueuedCalls = pCall->pNext;
  623. else if (pConference->pPlacedCalls == pCall)
  624. pConference->pPlacedCalls = pCall->pNext;
  625. else if (pConference->pEstablishedCalls == pCall)
  626. pConference->pEstablishedCalls = pCall->pNext;
  627. } else
  628. pCall->pPrev->pNext = pCall->pNext;
  629. if (pCall->pNext != NULL)
  630. pCall->pNext->pPrev = pCall->pPrev;
  631. // Now link pCall into the placed call list
  632. pCall->pNext = pConference->pPlacedCalls;
  633. pCall->pPrev = NULL;
  634. if (pConference->pPlacedCalls != NULL) {
  635. ASSERT(pConference->pPlacedCalls->pPrev == NULL);
  636. pConference->pPlacedCalls->pPrev = pCall;
  637. }
  638. pConference->pPlacedCalls = pCall;
  639. return CC_OK;
  640. }
  641. HRESULT AddEstablishedCallToConference(
  642. PCALL pCall,
  643. PCONFERENCE pConference)
  644. {
  645. ASSERT(pCall != NULL);
  646. ASSERT(pConference != NULL);
  647. ASSERT((EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) ||
  648. (EqualConferenceIDs(&pCall->ConferenceID, &pConference->ConferenceID)));
  649. if (EqualConferenceIDs(&pConference->ConferenceID, &InvalidConferenceID)) {
  650. // If a conference ID has not been assigned, but there are
  651. // placed or enqueued calls on the conference, the conference ID
  652. // will be assigned by a callee when the first of these calls completes.
  653. // Since pCall has an assigned conference ID (which will differ from
  654. // the ID to be assigned to this conference), we cannot assign pCall
  655. // to this conference.
  656. ASSERT(pConference->pEstablishedCalls == NULL);
  657. pConference->ConferenceID = pCall->ConferenceID;
  658. } else if (!EqualConferenceIDs(&pConference->ConferenceID, &pCall->ConferenceID))
  659. return CC_BAD_PARAM;
  660. pCall->hConference = pConference->hConference;
  661. // Unlink pCall from pConference, if necessary
  662. if (pCall->pPrev == NULL) {
  663. // pCall is at the head of either the enqueued call list,
  664. // the placed call list, or the established call list, or
  665. // is not yet associated with the conference object
  666. if (pConference->pEnqueuedCalls == pCall)
  667. pConference->pEnqueuedCalls = pCall->pNext;
  668. else if (pConference->pPlacedCalls == pCall)
  669. pConference->pPlacedCalls = pCall->pNext;
  670. else if (pConference->pEstablishedCalls == pCall)
  671. pConference->pEstablishedCalls = pCall->pNext;
  672. } else
  673. pCall->pPrev->pNext = pCall->pNext;
  674. if (pCall->pNext != NULL)
  675. pCall->pNext->pPrev = pCall->pPrev;
  676. // Now link pCall into the established call list
  677. pCall->pNext = pConference->pEstablishedCalls;
  678. pCall->pPrev = NULL;
  679. if (pConference->pEstablishedCalls != NULL) {
  680. ASSERT(pConference->pEstablishedCalls->pPrev == NULL);
  681. pConference->pEstablishedCalls->pPrev = pCall;
  682. }
  683. pConference->pEstablishedCalls = pCall;
  684. return CC_OK;
  685. }
  686. HRESULT AddVirtualCallToConference( PCALL pCall,
  687. PCONFERENCE pConference)
  688. {
  689. ASSERT(pCall != NULL);
  690. ASSERT(pConference != NULL);
  691. // this is a bogus ASSERT --- ASSERT(pConference->ConferenceMode == MULTIPOINT_MODE);
  692. ASSERT(pConference->tsMultipointController == TS_FALSE);
  693. // Call cannot already be associated with the conference
  694. ASSERT(pCall->pNext == NULL);
  695. ASSERT(pCall->pPrev == NULL);
  696. pCall->hConference = pConference->hConference;
  697. pCall->pNext = pConference->pVirtualCalls;
  698. pCall->pPrev = NULL;
  699. if (pConference->pVirtualCalls != NULL) {
  700. ASSERT(pConference->pVirtualCalls->pPrev == NULL);
  701. pConference->pVirtualCalls->pPrev = pCall;
  702. }
  703. pConference->pVirtualCalls = pCall;
  704. return CC_OK;
  705. }
  706. HRESULT AddChannelToConference( PCHANNEL pChannel,
  707. PCONFERENCE pConference)
  708. {
  709. PPCHANNEL ppChannel;
  710. ASSERT(pChannel != NULL);
  711. ASSERT((pChannel->bChannelType == TX_CHANNEL) ||
  712. (pChannel->bChannelType == RX_CHANNEL) ||
  713. (pChannel->bChannelType == TXRX_CHANNEL) ||
  714. (pChannel->bChannelType == PROXY_CHANNEL));
  715. ASSERT(pConference != NULL);
  716. ASSERT(pChannel->hConference == pConference->hConference);
  717. ASSERT(pChannel->pNext == NULL);
  718. ASSERT(pChannel->pPrev == NULL);
  719. ASSERT(pConference->ConferenceMode != UNCONNECTED_MODE);
  720. if (pConference->pEstablishedCalls == NULL)
  721. // Can't open a channel unless we have at least one established call
  722. return CC_BAD_PARAM;
  723. ppChannel = &pConference->pChannels;
  724. pChannel->pNext = *ppChannel;
  725. pChannel->pPrev = NULL;
  726. if (*ppChannel != NULL) {
  727. ASSERT((*ppChannel)->pPrev == NULL);
  728. (*ppChannel)->pPrev = pChannel;
  729. }
  730. *ppChannel = pChannel;
  731. if (pConference->ConferenceMode == POINT_TO_POINT_MODE)
  732. pChannel->bMultipointChannel = FALSE;
  733. else
  734. pChannel->bMultipointChannel = TRUE;
  735. return CC_OK;
  736. }
  737. // Caller must have a lock on the conference object
  738. // There must be no calls on this conference object
  739. // (previous calls must have been cleared by calling Hangup())
  740. HRESULT FreeConference( PCONFERENCE pConference)
  741. {
  742. CC_HCONFERENCE hConference;
  743. PCALL pVirtualCall;
  744. WORD wNumCalls;
  745. WORD i;
  746. PCC_HCALL CallList;
  747. WORD wNumChannels;
  748. PCC_HCHANNEL ChannelList;
  749. PCHANNEL pChannel;
  750. ASSERT(pConference != NULL);
  751. ASSERT(pConference->pEnqueuedCalls == NULL);
  752. ASSERT(pConference->pPlacedCalls == NULL);
  753. ASSERT(pConference->pEstablishedCalls == NULL);
  754. // caller must have a lock on the conference object,
  755. // so there's no need to re-lock it
  756. hConference = pConference->hConference;
  757. if (pConference->bInTable == TRUE)
  758. if (_RemoveConferenceFromTable(pConference) == CC_BAD_PARAM)
  759. // the conference object was deleted by another thread,
  760. // so just return CC_OK
  761. return CC_OK;
  762. if (pConference->pLocalH245H2250MuxCapability != NULL)
  763. H245FreeCap(pConference->pLocalH245H2250MuxCapability);
  764. // free up the LocalTermCapList elements
  765. DestroyH245TermCapList(&pConference->pLocalH245TermCapList);
  766. // free up the local terminal capability descriptors
  767. DestroyH245TermCapDescriptors(&pConference->pLocalH245TermCapDescriptors);
  768. if (pConference->pMultipointControllerAddr != NULL)
  769. MemFree(pConference->pMultipointControllerAddr);
  770. if (pConference->pVendorInfo != NULL)
  771. FreeVendorInfo(pConference->pVendorInfo);
  772. if (pConference->pSessionTable != NULL)
  773. FreeConferenceSessionTable(pConference);
  774. if (pConference->pConferenceH245H2250MuxCapability != NULL)
  775. H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
  776. if ((pConference->pConferenceTermCapList != NULL) ||
  777. (pConference->pConferenceTermCapDescriptors != NULL))
  778. FreeConferenceTermCaps(pConference);
  779. if (pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL)
  780. {
  781. MemFree(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
  782. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  783. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  784. }
  785. while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
  786. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, VIRTUAL_CALL);
  787. for (i = 0; i < wNumCalls; i++)
  788. if (LockCall(CallList[i], &pVirtualCall) == CC_OK)
  789. FreeCall(pVirtualCall);
  790. if (CallList != NULL)
  791. MemFree(CallList);
  792. EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
  793. for (i = 0; i < wNumChannels; i++)
  794. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  795. FreeChannel(pChannel);
  796. if (ChannelList != NULL)
  797. MemFree(ChannelList);
  798. while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
  799. // since the conference object has been removed from the ConferenceTable,
  800. // no other thread will be able to find the conference object and obtain
  801. // a lock, so its safe to unlock the conference object and delete it here
  802. RelinquishLock(&pConference->Lock);
  803. DeleteLock(&pConference->Lock);
  804. MemFree(pConference);
  805. return CC_OK;
  806. }
  807. HRESULT LockConference( CC_HCONFERENCE hConference,
  808. PPCONFERENCE ppConference)
  809. {
  810. BOOL bTimedOut;
  811. ASSERT(hConference != CC_INVALID_HANDLE);
  812. ASSERT(ppConference != NULL);
  813. step1:
  814. AcquireLock(&ConferenceTable.Lock);
  815. *ppConference = ConferenceTable.pHead;
  816. while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
  817. *ppConference = (*ppConference)->pNextInTable;
  818. if (*ppConference != NULL) {
  819. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  820. if (bTimedOut) {
  821. RelinquishLock(&ConferenceTable.Lock);
  822. Sleep(0);
  823. goto step1;
  824. }
  825. }
  826. RelinquishLock(&ConferenceTable.Lock);
  827. if (*ppConference == NULL)
  828. return CC_BAD_PARAM;
  829. else
  830. return CC_OK;
  831. }
  832. HRESULT LockConferenceEx( CC_HCONFERENCE hConference,
  833. PPCONFERENCE ppConference,
  834. TRISTATE tsDeferredDelete)
  835. {
  836. BOOL bTimedOut;
  837. ASSERT(hConference != CC_INVALID_HANDLE);
  838. ASSERT(ppConference != NULL);
  839. step1:
  840. AcquireLock(&ConferenceTable.Lock);
  841. *ppConference = ConferenceTable.pHead;
  842. while ((*ppConference != NULL) && ((*ppConference)->hConference != hConference))
  843. *ppConference = (*ppConference)->pNextInTable;
  844. if (*ppConference != NULL) {
  845. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  846. if (bTimedOut) {
  847. RelinquishLock(&ConferenceTable.Lock);
  848. Sleep(0);
  849. goto step1;
  850. }
  851. if (tsDeferredDelete == TS_TRUE) {
  852. if ((*ppConference)->bDeferredDelete != TRUE) {
  853. RelinquishLock(&(*ppConference)->Lock);
  854. *ppConference = NULL;
  855. }
  856. } else if (tsDeferredDelete == TS_FALSE) {
  857. if ((*ppConference)->bDeferredDelete != FALSE) {
  858. RelinquishLock(&(*ppConference)->Lock);
  859. *ppConference = NULL;
  860. }
  861. }
  862. }
  863. RelinquishLock(&ConferenceTable.Lock);
  864. if (*ppConference == NULL)
  865. return CC_BAD_PARAM;
  866. else
  867. return CC_OK;
  868. }
  869. HRESULT ValidateConference( CC_HCONFERENCE hConference)
  870. {
  871. PCONFERENCE pConference;
  872. ASSERT(hConference != CC_INVALID_HANDLE);
  873. AcquireLock(&ConferenceTable.Lock);
  874. pConference = ConferenceTable.pHead;
  875. while ((pConference != NULL) && (pConference->hConference != hConference))
  876. pConference = pConference->pNextInTable;
  877. RelinquishLock(&ConferenceTable.Lock);
  878. if (pConference == NULL)
  879. return CC_BAD_PARAM;
  880. else
  881. return CC_OK;
  882. }
  883. HRESULT LockConferenceID( PCC_CONFERENCEID pConferenceID,
  884. PPCONFERENCE ppConference)
  885. {
  886. BOOL bTimedOut;
  887. ASSERT(!EqualConferenceIDs(pConferenceID, &InvalidConferenceID));
  888. ASSERT(ppConference != NULL);
  889. // There may be many conference objects in the table with unassigned
  890. // conference IDs (ConferenceID = InvalidConferenceID). The caller may
  891. // never ask us to search for an unassigned conference ID.
  892. step1:
  893. AcquireLock(&ConferenceTable.Lock);
  894. *ppConference = ConferenceTable.pHead;
  895. while ((*ppConference != NULL) &&
  896. (!EqualConferenceIDs(&(*ppConference)->ConferenceID, pConferenceID)))
  897. *ppConference = (*ppConference)->pNextInTable;
  898. if (*ppConference != NULL) {
  899. AcquireTimedLock(&(*ppConference)->Lock,10,&bTimedOut);
  900. if (bTimedOut) {
  901. RelinquishLock(&ConferenceTable.Lock);
  902. Sleep(0);
  903. goto step1;
  904. }
  905. }
  906. RelinquishLock(&ConferenceTable.Lock);
  907. if (*ppConference == NULL)
  908. return CC_BAD_PARAM;
  909. else
  910. return CC_OK;
  911. }
  912. HRESULT FindChannelInConference( WORD wChannel,
  913. BOOL bLocalChannel,
  914. BYTE bChannelType,
  915. CC_HCALL hCall,
  916. PCC_HCHANNEL phChannel,
  917. PCONFERENCE pConference)
  918. {
  919. PCHANNEL pChannel;
  920. WORD wChannelNumber;
  921. ASSERT(wChannel != 0);
  922. ASSERT(phChannel != NULL);
  923. ASSERT(pConference != NULL);
  924. *phChannel = CC_INVALID_HANDLE;
  925. pChannel = pConference->pChannels;
  926. while (pChannel != NULL) {
  927. if (bLocalChannel)
  928. wChannelNumber = pChannel->wLocalChannelNumber;
  929. else
  930. wChannelNumber = pChannel->wRemoteChannelNumber;
  931. if ((wChannelNumber == wChannel) &&
  932. ((pChannel->bChannelType & bChannelType) != 0) &&
  933. ((hCall == CC_INVALID_HANDLE) ||
  934. (pChannel->hCall == hCall)))
  935. break;
  936. pChannel = pChannel->pNext;
  937. }
  938. if (pChannel == NULL)
  939. return CC_BAD_PARAM;
  940. *phChannel = pChannel->hChannel;
  941. return CC_OK;
  942. }
  943. HRESULT EnumerateConferences( PWORD pwNumConferences,
  944. CC_HCONFERENCE ConferenceList[])
  945. {
  946. WORD wIndexLimit;
  947. PCONFERENCE pConference;
  948. if ((*pwNumConferences != 0) && (ConferenceList == NULL))
  949. return CC_BAD_PARAM;
  950. if ((*pwNumConferences == 0) && (ConferenceList != NULL))
  951. return CC_BAD_PARAM;
  952. wIndexLimit = *pwNumConferences;
  953. *pwNumConferences = 0;
  954. AcquireLock(&ConferenceTable.Lock);
  955. pConference = ConferenceTable.pHead;
  956. while (pConference != NULL) {
  957. if (*pwNumConferences < wIndexLimit)
  958. ConferenceList[*pwNumConferences] = pConference->hConference;
  959. (*pwNumConferences)++;
  960. pConference = pConference->pNextInTable;
  961. }
  962. RelinquishLock(&ConferenceTable.Lock);
  963. return CC_OK;
  964. }
  965. HRESULT EnumerateCallsInConference( WORD *pwNumCalls,
  966. PCC_HCALL pCallList[],
  967. PCONFERENCE pConference,
  968. BYTE bCallType)
  969. {
  970. WORD i;
  971. PCALL pCall;
  972. ASSERT(pwNumCalls != NULL);
  973. ASSERT(pConference != NULL);
  974. *pwNumCalls = 0;
  975. if (bCallType & ENQUEUED_CALL) {
  976. pCall = pConference->pEnqueuedCalls;
  977. while (pCall != NULL) {
  978. (*pwNumCalls)++;
  979. pCall = pCall->pNext;
  980. }
  981. }
  982. if (bCallType & PLACED_CALL) {
  983. pCall = pConference->pPlacedCalls;
  984. while (pCall != NULL) {
  985. (*pwNumCalls)++;
  986. pCall = pCall->pNext;
  987. }
  988. }
  989. if (bCallType & ESTABLISHED_CALL) {
  990. pCall = pConference->pEstablishedCalls;
  991. while (pCall != NULL) {
  992. (*pwNumCalls)++;
  993. pCall = pCall->pNext;
  994. }
  995. }
  996. if (bCallType & VIRTUAL_CALL) {
  997. pCall = pConference->pVirtualCalls;
  998. while (pCall != NULL) {
  999. (*pwNumCalls)++;
  1000. pCall = pCall->pNext;
  1001. }
  1002. }
  1003. if (pCallList == NULL)
  1004. return CC_OK;
  1005. if (*pwNumCalls == 0) {
  1006. *pCallList = NULL;
  1007. return CC_OK;
  1008. }
  1009. *pCallList = (PCC_HCALL)MemAlloc(sizeof(CC_HCALL) * (*pwNumCalls));
  1010. if (*pCallList == NULL)
  1011. return CC_NO_MEMORY;
  1012. i = 0;
  1013. if (bCallType & ENQUEUED_CALL) {
  1014. pCall = pConference->pEnqueuedCalls;
  1015. while (pCall != NULL) {
  1016. (*pCallList)[i] = pCall->hCall;
  1017. i++;
  1018. pCall = pCall->pNext;
  1019. }
  1020. }
  1021. if (bCallType & PLACED_CALL) {
  1022. pCall = pConference->pPlacedCalls;
  1023. while (pCall != NULL) {
  1024. (*pCallList)[i] = pCall->hCall;
  1025. i++;
  1026. pCall = pCall->pNext;
  1027. }
  1028. }
  1029. if (bCallType & ESTABLISHED_CALL) {
  1030. pCall = pConference->pEstablishedCalls;
  1031. while (pCall != NULL) {
  1032. (*pCallList)[i] = pCall->hCall;
  1033. i++;
  1034. pCall = pCall->pNext;
  1035. }
  1036. }
  1037. if (bCallType & VIRTUAL_CALL) {
  1038. pCall = pConference->pVirtualCalls;
  1039. while (pCall != NULL) {
  1040. (*pCallList)[i] = pCall->hCall;
  1041. i++;
  1042. pCall = pCall->pNext;
  1043. }
  1044. }
  1045. return CC_OK;
  1046. }
  1047. HRESULT EnumerateChannelsInConference(
  1048. WORD *pwNumChannels,
  1049. PCC_HCHANNEL pChannelList[],
  1050. PCONFERENCE pConference,
  1051. BYTE bChannelType)
  1052. {
  1053. WORD i;
  1054. PCHANNEL pChannel;
  1055. ASSERT(pwNumChannels != NULL);
  1056. ASSERT(pConference != NULL);
  1057. *pwNumChannels = 0;
  1058. pChannel = pConference->pChannels;
  1059. while (pChannel != NULL) {
  1060. if (pChannel->bChannelType & bChannelType)
  1061. (*pwNumChannels)++;
  1062. pChannel = pChannel->pNext;
  1063. }
  1064. if (pChannelList == NULL)
  1065. return CC_OK;
  1066. if (*pwNumChannels == 0) {
  1067. *pChannelList = NULL;
  1068. return CC_OK;
  1069. }
  1070. *pChannelList = (PCC_HCHANNEL)MemAlloc(sizeof(CC_HCHANNEL) * (*pwNumChannels));
  1071. if (*pChannelList == NULL)
  1072. return CC_NO_MEMORY;
  1073. i = 0;
  1074. pChannel = pConference->pChannels;
  1075. while (pChannel != NULL) {
  1076. if (pChannel->bChannelType & bChannelType) {
  1077. (*pChannelList)[i] = pChannel->hChannel;
  1078. i++;
  1079. }
  1080. pChannel = pChannel->pNext;
  1081. }
  1082. return CC_OK;
  1083. }
  1084. HRESULT EnumerateTerminalLabelsInConference(
  1085. WORD *pwNumTerminalLabels,
  1086. H245_TERMINAL_LABEL_T *pH245TerminalLabelList[],
  1087. PCONFERENCE pConference)
  1088. {
  1089. WORD i, j;
  1090. WORD wIndex;
  1091. BYTE bMask;
  1092. ASSERT(pwNumTerminalLabels != NULL);
  1093. ASSERT(pConference != NULL);
  1094. // First count the number of known terminals
  1095. *pwNumTerminalLabels = 0;
  1096. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  1097. if (pConference->TerminalNumberAllocation[i] != 0) {
  1098. bMask = 0x01;
  1099. for (j = 0; j < 8; j++) {
  1100. if ((pConference->TerminalNumberAllocation[i] & bMask) != 0)
  1101. (*pwNumTerminalLabels)++;
  1102. bMask *= 2;
  1103. }
  1104. }
  1105. }
  1106. if (pConference->LocalEndpointAttached == ATTACHED)
  1107. (*pwNumTerminalLabels)++;
  1108. if (pH245TerminalLabelList == NULL)
  1109. return CC_OK;
  1110. if (*pwNumTerminalLabels == 0)
  1111. *pH245TerminalLabelList = NULL;
  1112. *pH245TerminalLabelList = (H245_TERMINAL_LABEL_T *)MemAlloc(sizeof(H245_TERMINAL_LABEL_T) *
  1113. (*pwNumTerminalLabels));
  1114. if (*pH245TerminalLabelList == NULL)
  1115. return CC_NO_MEMORY;
  1116. wIndex = 0;
  1117. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++) {
  1118. if (pConference->TerminalNumberAllocation[i] != 0) {
  1119. bMask = 0x01;
  1120. for (j = 0; j < 8; j++) {
  1121. if ((pConference->TerminalNumberAllocation[i] & bMask) != 0) {
  1122. (*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  1123. (*pH245TerminalLabelList)[wIndex].terminalNumber = (TerminalNumber) ((i * 8) + j + 1);
  1124. wIndex++;
  1125. }
  1126. bMask *= 2;
  1127. }
  1128. }
  1129. }
  1130. if (pConference->LocalEndpointAttached == ATTACHED) {
  1131. (*pH245TerminalLabelList)[wIndex].mcuNumber = pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber;
  1132. (*pH245TerminalLabelList)[wIndex].terminalNumber = 0;
  1133. }
  1134. return CC_OK;
  1135. }
  1136. HRESULT UnlockConference( PCONFERENCE pConference)
  1137. {
  1138. ASSERT(pConference != NULL);
  1139. RelinquishLock(&pConference->Lock);
  1140. return CC_OK;
  1141. }
  1142. HRESULT AsynchronousDestroyConference(
  1143. CC_HCONFERENCE hConference,
  1144. BOOL bAutoAccept)
  1145. {
  1146. HRESULT status;
  1147. PCONFERENCE pConference;
  1148. WORD wNumCalls;
  1149. WORD wNumChannels;
  1150. WORD i;
  1151. PCHANNEL pChannel;
  1152. PCC_HCHANNEL ChannelList;
  1153. status = LockConference(hConference, &pConference);
  1154. if (status != CC_OK)
  1155. return status;
  1156. status = EnumerateCallsInConference(&wNumCalls, NULL, pConference, REAL_CALLS);
  1157. if (status != CC_OK) {
  1158. UnlockConference(pConference);
  1159. return status;
  1160. }
  1161. // This is an illegal call if:
  1162. // 1. The local endpoint is currently attached;
  1163. // 2. The local endpoint has never been attached, but is in the
  1164. // process of placing a call
  1165. if ((pConference->LocalEndpointAttached == ATTACHED) ||
  1166. ((pConference->LocalEndpointAttached == NEVER_ATTACHED) &&
  1167. (wNumCalls > 0))) {
  1168. UnlockConference(pConference);
  1169. return CC_BAD_PARAM;
  1170. }
  1171. pConference->ConferenceCallback = NULL;
  1172. // can't destroy a conference if there are active calls
  1173. if (wNumCalls != 0) {
  1174. pConference->bDeferredDelete = TRUE;
  1175. pConference->bAutoAccept = bAutoAccept;
  1176. UnlockConference(pConference);
  1177. return CC_OK;
  1178. }
  1179. status = EnumerateChannelsInConference(&wNumChannels,
  1180. &ChannelList,
  1181. pConference,
  1182. ALL_CHANNELS);
  1183. if (status != CC_OK) {
  1184. UnlockConference(pConference);
  1185. return status;
  1186. }
  1187. // free all the channels
  1188. for (i = 0; i < wNumChannels; i++) {
  1189. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  1190. // Notice that since we're going to hangup, we don't need to
  1191. // close any channels
  1192. FreeChannel(pChannel);
  1193. }
  1194. if (ChannelList != NULL)
  1195. MemFree(ChannelList);
  1196. FreeConference(pConference);
  1197. return CC_OK;
  1198. }
  1199. HRESULT FindPeerParticipantInfo( H245_TERMINAL_LABEL_T H245TerminalLabel,
  1200. PCONFERENCE pConference,
  1201. BYTE bCallType,
  1202. PCALL *ppCall)
  1203. {
  1204. WORD wNumCalls;
  1205. PCC_HCALL CallList;
  1206. WORD i;
  1207. HRESULT status;
  1208. ASSERT(pConference != NULL);
  1209. ASSERT(ppCall != NULL);
  1210. status = EnumerateCallsInConference(&wNumCalls,
  1211. &CallList,
  1212. pConference,
  1213. bCallType);
  1214. if (status != CC_OK)
  1215. return status;
  1216. for (i = 0; i < wNumCalls; i++) {
  1217. if (LockCall(CallList[i], ppCall) == CC_OK) {
  1218. if ((*ppCall)->pPeerParticipantInfo != NULL)
  1219. if (((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bMCUNumber ==
  1220. H245TerminalLabel.mcuNumber) &&
  1221. ((*ppCall)->pPeerParticipantInfo->ParticipantInfo.TerminalLabel.bTerminalNumber ==
  1222. H245TerminalLabel.terminalNumber)) {
  1223. MemFree(CallList);
  1224. return CC_OK;
  1225. }
  1226. UnlockCall(*ppCall);
  1227. }
  1228. }
  1229. if (CallList != NULL)
  1230. MemFree(CallList);
  1231. *ppCall = NULL;
  1232. return CC_BAD_PARAM;
  1233. }
  1234. HRESULT ReInitializeConference( PCONFERENCE pConference)
  1235. {
  1236. PCALL pCall;
  1237. WORD wNumCalls;
  1238. WORD i;
  1239. PCC_HCALL CallList;
  1240. PCHANNEL pChannel;
  1241. WORD wNumChannels;
  1242. PCC_HCHANNEL ChannelList;
  1243. HRESULT status;
  1244. ASSERT(pConference != NULL);
  1245. if (pConference->bDynamicConferenceID == TRUE)
  1246. pConference->ConferenceID = InvalidConferenceID;
  1247. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bMCUNumber = 1;
  1248. pConference->LocalParticipantInfo.ParticipantInfo.TerminalLabel.bTerminalNumber = 255;
  1249. if (pConference->bDynamicTerminalID == TRUE) {
  1250. pConference->LocalParticipantInfo.TerminalIDState = TERMINAL_ID_INVALID;
  1251. if(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString != NULL)
  1252. {
  1253. MemFree(pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString);
  1254. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.pOctetString = NULL;
  1255. pConference->LocalParticipantInfo.ParticipantInfo.TerminalID.wOctetStringLength = 0;
  1256. }
  1257. }
  1258. while (DequeueRequest(&pConference->LocalParticipantInfo.pEnqueuedRequestsForTerminalID, NULL) == CC_OK);
  1259. for (i = 0; i < NUM_TERMINAL_ALLOCATION_SLOTS; i++)
  1260. pConference->TerminalNumberAllocation[i] = 0;
  1261. // Channel 0 is reserved for the H.245 control channel
  1262. pConference->ChannelNumberAllocation[0] = 0x01;
  1263. for (i = 1; i < NUM_CHANNEL_ALLOCATION_SLOTS; i++)
  1264. pConference->ChannelNumberAllocation[i] = 0;
  1265. pConference->bDeferredDelete = FALSE;
  1266. pConference->bAutoAccept = FALSE; // ignored unless ConferenceCallback is NULL
  1267. pConference->LocalEndpointAttached = NEVER_ATTACHED;
  1268. if (pConference->pSessionTable != NULL)
  1269. FreeConferenceSessionTable(pConference);
  1270. _CreateLocalH245H2250MuxCapability(pConference);
  1271. if (pConference->pConferenceH245H2250MuxCapability != NULL) {
  1272. H245FreeCap(pConference->pConferenceH245H2250MuxCapability);
  1273. pConference->pConferenceH245H2250MuxCapability = NULL;
  1274. }
  1275. if ((pConference->pConferenceTermCapList != NULL) ||
  1276. (pConference->pConferenceTermCapDescriptors != NULL))
  1277. FreeConferenceTermCaps(pConference);
  1278. pConference->bSessionTableInternallyConstructed = FALSE;
  1279. pConference->ConferenceCallback = pConference->SaveConferenceCallback;
  1280. EnumerateCallsInConference(&wNumCalls, &CallList, pConference, ALL_CALLS);
  1281. for (i = 0; i < wNumCalls; i++)
  1282. if (LockCall(CallList[i], &pCall) == CC_OK)
  1283. FreeCall(pCall);
  1284. if (CallList != NULL)
  1285. MemFree(CallList);
  1286. EnumerateChannelsInConference(&wNumChannels, &ChannelList, pConference, ALL_CHANNELS);
  1287. for (i = 0; i < wNumChannels; i++)
  1288. if (LockChannel(ChannelList[i], &pChannel) == CC_OK)
  1289. FreeChannel(pChannel);
  1290. if (ChannelList != NULL)
  1291. MemFree(ChannelList);
  1292. if (pConference->bForceMC == TRUE)
  1293. pConference->tsMultipointController = TS_TRUE;
  1294. else if (pConference->bMultipointCapable == TRUE)
  1295. pConference->tsMultipointController = TS_UNKNOWN;
  1296. else
  1297. pConference->tsMultipointController = TS_FALSE;
  1298. pConference->tsMaster = TS_UNKNOWN;
  1299. pConference->ConferenceMode = UNCONNECTED_MODE;
  1300. if (pConference->pMultipointControllerAddr != NULL) {
  1301. MemFree(pConference->pMultipointControllerAddr);
  1302. pConference->pMultipointControllerAddr = NULL;
  1303. }
  1304. while (DequeueRequest(&pConference->pEnqueuedRequestModeCalls, NULL) == CC_OK);
  1305. if (pConference->tsMultipointController == TS_TRUE)
  1306. status = CreateConferenceTermCaps(pConference, NULL);
  1307. else
  1308. status = CC_OK;
  1309. return status;
  1310. }
  1311.