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.

1161 lines
26 KiB

  1. // File: h323cc.cpp
  2. #include "precomp.h"
  3. #include "confreg.h"
  4. #include "version.h"
  5. EXTERN_C HINSTANCE g_hInst=NULL; // global module instance
  6. IRTP *g_pIRTP = NULL;
  7. UINT g_capFlags = CAPFLAGS_AV_ALL;
  8. #ifdef DEBUG
  9. HDBGZONE ghDbgZoneCC = NULL;
  10. static PTCHAR _rgZonesCC[] = {
  11. TEXT("H323"),
  12. TEXT("Init"),
  13. TEXT("Conn"),
  14. TEXT("Channels"),
  15. TEXT("Caps"),
  16. TEXT("Member"),
  17. TEXT("unused"),
  18. TEXT("unused"),
  19. TEXT("Ref count"),
  20. TEXT("unused"),
  21. TEXT("Profile spew")
  22. };
  23. int WINAPI CCDbgPrintf(LPTSTR lpszFormat, ... )
  24. {
  25. va_list v1;
  26. va_start(v1, lpszFormat);
  27. DbgPrintf("H323CC", lpszFormat, v1);
  28. va_end(v1);
  29. return TRUE;
  30. }
  31. #endif /* DEBUG */
  32. // The product ID fields are defined in the standard as an array of bytes. ASCII
  33. // characters are used regardless of local character set.
  34. // default Product ID and version ID strings
  35. static char DefaultProductID[] = H323_PRODUCTNAME_STR;
  36. static char DefaultProductVersion[] = H323_PRODUCTRELEASE_STR;
  37. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL,
  38. DWORD fdwReason,
  39. LPVOID lpvReserved);
  40. BOOL WINAPI DllEntryPoint(
  41. HINSTANCE hinstDLL, // handle to DLL module
  42. DWORD fdwReason, // reason for calling function
  43. LPVOID lpvReserved // reserved
  44. )
  45. {
  46. switch(fdwReason)
  47. {
  48. case DLL_PROCESS_ATTACH:
  49. DBGINIT(&ghDbgZoneCC, _rgZonesCC);
  50. DBG_INIT_MEMORY_TRACKING(hinstDLL);
  51. DisableThreadLibraryCalls(hinstDLL);
  52. g_hInst = hinstDLL;
  53. break;
  54. case DLL_PROCESS_DETACH:
  55. DBG_CHECK_MEMORY_TRACKING(hinstDLL);
  56. DBGDEINIT(&ghDbgZoneCC);
  57. break;
  58. default:
  59. break;
  60. }
  61. return TRUE;
  62. }
  63. HRESULT WINAPI CreateH323CC(IH323CallControl ** ppCC, BOOL fForCalling, UINT capFlags)
  64. {
  65. if(!ppCC)
  66. return H323CC_E_INVALID_PARAM;
  67. DBG_SAVE_FILE_LINE
  68. *ppCC = new CH323CallControl(fForCalling, capFlags);
  69. if(!(*ppCC))
  70. return H323CC_E_CREATE_FAILURE;
  71. return hrSuccess;
  72. }
  73. BOOL CH323CallControl::m_fGKProhibit = FALSE;
  74. RASNOTIFYPROC CH323CallControl::m_pRasNotifyProc = NULL;
  75. CH323CallControl::CH323CallControl(BOOL fForCalling, UINT capFlags) :
  76. m_uRef(1),
  77. m_fForCalling(fForCalling),
  78. m_numlines(0),
  79. m_pProcNotifyConnect(NULL),
  80. m_pCapabilityResolver(NULL),
  81. m_pListenLine(NULL),
  82. m_pLineList(NULL),
  83. m_pNextToAccept(NULL),
  84. m_pUserName(NULL),
  85. m_pLocalAliases(NULL),
  86. m_pRegistrationAliases(NULL),
  87. hrLast(hrSuccess),
  88. m_pSendAudioChannel(NULL),
  89. m_pSendVideoChannel(NULL),
  90. m_uMaximumBandwidth(0)
  91. {
  92. //
  93. // Set up caps.
  94. //
  95. if (fForCalling)
  96. {
  97. g_capFlags = capFlags;
  98. }
  99. m_VendorInfo.bCountryCode = USA_H221_COUNTRY_CODE;
  100. m_VendorInfo.bExtension = USA_H221_COUNTRY_EXTENSION;
  101. m_VendorInfo.wManufacturerCode = MICROSOFT_H_221_MFG_CODE;
  102. m_VendorInfo.pProductNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING)
  103. + sizeof(DefaultProductID));
  104. if(m_VendorInfo.pProductNumber)
  105. {
  106. m_VendorInfo.pProductNumber->wOctetStringLength = sizeof(DefaultProductID);
  107. m_VendorInfo.pProductNumber->pOctetString =
  108. ((BYTE *)m_VendorInfo.pProductNumber + sizeof(CC_OCTETSTRING));
  109. memcpy(m_VendorInfo.pProductNumber->pOctetString,
  110. DefaultProductID, sizeof(DefaultProductID));
  111. }
  112. m_VendorInfo.pVersionNumber = (PCC_OCTETSTRING)MemAlloc(sizeof(CC_OCTETSTRING)
  113. + sizeof(DefaultProductVersion));
  114. if(m_VendorInfo.pVersionNumber)
  115. {
  116. m_VendorInfo.pVersionNumber->wOctetStringLength = sizeof(DefaultProductVersion);
  117. m_VendorInfo.pVersionNumber->pOctetString =
  118. ((BYTE *)m_VendorInfo.pVersionNumber + sizeof(CC_OCTETSTRING));
  119. memcpy(m_VendorInfo.pVersionNumber->pOctetString,
  120. DefaultProductVersion, sizeof(DefaultProductVersion));
  121. }
  122. RegEntry reCC(szRegInternetPhone TEXT("\\") szRegInternetPhoneNac,
  123. HKEY_LOCAL_MACHINE,
  124. FALSE,
  125. KEY_READ);
  126. UINT uAPD = reCC.GetNumberIniStyle(TEXT ("AudioPacketDurationMs"), 0);
  127. if (uAPD)
  128. {
  129. g_AudioPacketDurationMs = uAPD;
  130. g_fRegAudioPacketDuration = TRUE;
  131. }
  132. DBG_SAVE_FILE_LINE
  133. m_pCapabilityResolver = new CapsCtl();
  134. if (!m_pCapabilityResolver)
  135. {
  136. ERRORMESSAGE(("CH323CallControl::CH323CallControl:cannot create capability resolver\r\n"));
  137. hrLast = H323CC_E_INIT_FAILURE;
  138. }
  139. if(!m_pCapabilityResolver->Init())
  140. {
  141. ERRORMESSAGE(("CH323CallControl::CH323CallControl cannot init capability resolver\r\n"));
  142. hrLast = H323CC_E_INIT_FAILURE;
  143. }
  144. }
  145. HRESULT CH323CallControl::Initialize(PORT *lpPort)
  146. {
  147. FX_ENTRY("CH323CallControl::Initialize");
  148. OBJ_CPT_RESET;
  149. ASSERT(m_fForCalling);
  150. if(!HR_SUCCEEDED(LastHR()))
  151. {
  152. goto EXIT;
  153. }
  154. if(!lpPort)
  155. {
  156. SetLastHR(H323CC_E_INVALID_PARAM);
  157. goto EXIT;
  158. }
  159. if(!Init())
  160. {
  161. goto EXIT;
  162. }
  163. else
  164. {
  165. ASSERT(m_pListenLine);
  166. hrLast = m_pListenLine->GetLocalPort(lpPort);
  167. }
  168. if (g_capFlags & CAPFLAGS_AV_STREAMS)
  169. {
  170. SetLastHR( ::CoCreateInstance(CLSID_RTP,
  171. NULL,
  172. CLSCTX_INPROC_SERVER,
  173. IID_IRTP,
  174. (void**)&g_pIRTP) );
  175. }
  176. SHOW_OBJ_ETIME("CH323CallControl::Initialize");
  177. EXIT:
  178. return LastHR();
  179. }
  180. HRESULT CH323CallControl::SetMaxPPBandwidth(UINT Bandwidth)
  181. {
  182. HRESULT hr = hrSuccess;
  183. LPAPPVIDCAPPIF lpIVidAppCap = NULL;
  184. DWORD dwcFormats = 0;
  185. DWORD dwcFormatsReturned = 0;
  186. DWORD x;
  187. BASIC_VIDCAP_INFO *pvidcaps = NULL;
  188. m_uMaximumBandwidth =Bandwidth;
  189. if (g_capFlags & CAPFLAGS_AV_STREAMS)
  190. {
  191. //Set the bandwidth on every video format
  192. hr = QueryInterface(IID_IAppVidCap, (void **)&lpIVidAppCap);
  193. if (! HR_SUCCEEDED (hr))
  194. goto EXIT;
  195. // Get the number of BASIC_VIDCAP_INFO structures available
  196. hr = lpIVidAppCap->GetNumFormats((UINT*)&dwcFormats);
  197. if (! HR_SUCCEEDED (hr))
  198. goto EXIT;
  199. if (dwcFormats > 0)
  200. {
  201. // Allocate some memory to hold the list in
  202. if (!(pvidcaps = (BASIC_VIDCAP_INFO*)MemAlloc(dwcFormats * sizeof (BASIC_VIDCAP_INFO))))
  203. {
  204. hr = H323CC_E_INSUFFICIENT_MEMORY;
  205. goto EXIT;
  206. }
  207. // Get the list
  208. hr=lpIVidAppCap->EnumFormats(pvidcaps, dwcFormats * sizeof (BASIC_VIDCAP_INFO),
  209. (UINT*)&dwcFormatsReturned);
  210. if (! HR_SUCCEEDED (hr))
  211. goto EXIT;
  212. //Set the bandwidth on each format
  213. for (x=0;x<dwcFormatsReturned;x++)
  214. {
  215. pvidcaps[x].uMaxBitrate=m_uMaximumBandwidth;
  216. }
  217. // Ok, now submit this list
  218. hr = lpIVidAppCap->ApplyAppFormatPrefs(pvidcaps, dwcFormats);
  219. if (! HR_SUCCEEDED (hr))
  220. goto EXIT;
  221. }
  222. }
  223. //Initialize the default H.323 simcaps.
  224. hr = m_pCapabilityResolver->ComputeCapabilitySets(m_uMaximumBandwidth);
  225. //if(!HR_SUCCEEDED(hr))
  226. // goto EXIT;
  227. EXIT:
  228. // let the interface go
  229. if (lpIVidAppCap)
  230. {
  231. lpIVidAppCap->Release();
  232. // (going out of scope) lpIVidAppCap = NULL;
  233. }
  234. if(pvidcaps)
  235. {
  236. // Free the memory, we're done
  237. MemFree(pvidcaps);
  238. }
  239. return hr;
  240. }
  241. BOOL CH323CallControl::Init()
  242. {
  243. HRESULT hResult;
  244. DEBUGMSG(ZONE_INIT,("Init: this:0x%08lX\r\n", this));
  245. SetLastHR(hrSuccess);
  246. if (m_fForCalling)
  247. {
  248. //
  249. // Only call control code should init CC_ stuff. Codec manipulation
  250. // via audiocpl should not.
  251. //
  252. hResult = CC_Initialize();
  253. if(!HR_SUCCEEDED(hResult))
  254. {
  255. goto CLEANUP;
  256. }
  257. }
  258. ASSERT(m_pCapabilityResolver);
  259. // Initialize capability data using default number, but clear the saved
  260. // bandwidth number afterwards. This detects attempts to place or
  261. // accept calls before the application initializes the real bandwidth
  262. hResult = SetMaxPPBandwidth(DEF_AP_BWMAX);
  263. m_uMaximumBandwidth = 0;
  264. if(!HR_SUCCEEDED(hResult))
  265. {
  266. goto CLEANUP;
  267. }
  268. // Create dual connection objects for listening for new connections
  269. if (m_fForCalling)
  270. {
  271. hResult = CreateConnection(&m_pListenLine,PID_H323);
  272. if(!HR_SUCCEEDED(hResult))
  273. {
  274. goto CLEANUP;
  275. }
  276. if(!m_pListenLine)
  277. {
  278. hResult = H323CC_E_INIT_FAILURE;
  279. goto CLEANUP;
  280. }
  281. if(!(m_pListenLine->ListenOn(H323_PORT)))
  282. {
  283. hResult = H323CC_E_NETWORK_ERROR;
  284. goto CLEANUP;
  285. }
  286. }
  287. return TRUE;
  288. CLEANUP:
  289. if (m_pListenLine)
  290. {
  291. m_pListenLine->Release();
  292. m_pListenLine = NULL;
  293. }
  294. SetLastHR(hResult);
  295. return FALSE;
  296. }
  297. CH323CallControl::~CH323CallControl()
  298. {
  299. if(m_VendorInfo.pProductNumber)
  300. MemFree(m_VendorInfo.pProductNumber);
  301. if(m_VendorInfo.pVersionNumber)
  302. MemFree(m_VendorInfo.pVersionNumber);
  303. if(m_pUserName)
  304. MemFree(m_pUserName);
  305. if(m_pLocalAliases)
  306. FreeTranslatedAliasList(m_pLocalAliases);
  307. if(m_pRegistrationAliases)
  308. FreeTranslatedAliasList(m_pRegistrationAliases);
  309. if (m_pCapabilityResolver)
  310. {
  311. m_pCapabilityResolver->Release();
  312. m_pCapabilityResolver = NULL;
  313. }
  314. if (m_pSendAudioChannel)
  315. {
  316. ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
  317. m_pSendAudioChannel->Release();
  318. m_pSendAudioChannel = NULL;
  319. }
  320. if (m_pSendVideoChannel)
  321. {
  322. ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
  323. m_pSendVideoChannel->Release();
  324. m_pSendVideoChannel = NULL;
  325. }
  326. if (m_fForCalling)
  327. {
  328. // toast backward references to this in all
  329. // connection objects
  330. CConnection *pLine = m_pLineList;
  331. CConnection *pNext;
  332. while(pLine)
  333. {
  334. pNext = pLine->next;
  335. pLine->DeInit();
  336. pLine = pNext;
  337. }
  338. // release the listening object if it exists
  339. if(m_pListenLine)
  340. m_pListenLine->Release();
  341. // shutdown CALLCONT.DLL
  342. CC_Shutdown();
  343. if (g_pIRTP)
  344. {
  345. ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
  346. g_pIRTP->Release();
  347. g_pIRTP = NULL;
  348. }
  349. // Put capflags back
  350. g_capFlags = CAPFLAGS_AV_ALL;
  351. }
  352. else
  353. {
  354. ASSERT(!m_pLineList);
  355. ASSERT(!m_pListenLine);
  356. }
  357. }
  358. ULONG CH323CallControl::AddRef()
  359. {
  360. m_uRef++;
  361. return m_uRef;
  362. }
  363. ULONG CH323CallControl::Release()
  364. {
  365. m_uRef--;
  366. if(m_uRef == 0)
  367. {
  368. delete this;
  369. return 0;
  370. }
  371. return m_uRef;
  372. }
  373. HRESULT CH323CallControl::SetUserDisplayName(LPWSTR lpwName)
  374. {
  375. LPWSTR lpwD;
  376. ULONG ulSize;
  377. if(!lpwName)
  378. {
  379. return (MakeResult(H323CC_E_INVALID_PARAM));
  380. }
  381. if(lpwName)
  382. {
  383. ulSize = ((lstrlenW(lpwName) +1)*sizeof(WCHAR));
  384. lpwD = (LPWSTR)MemAlloc(ulSize);
  385. if(!lpwD)
  386. return H323CC_E_INSUFFICIENT_MEMORY;
  387. if(m_pUserName)
  388. {
  389. MemFree(m_pUserName);
  390. }
  391. m_pUserName = lpwD;
  392. memcpy(m_pUserName, lpwName, ulSize);
  393. }
  394. return (MakeResult(hrSuccess));
  395. }
  396. // Find the most suitable alias for display. Return the first H323ID if it exists,
  397. // else return the first E.164 address
  398. PCC_ALIASITEM CH323CallControl::GetUserDisplayAlias()
  399. {
  400. WORD wC;
  401. PCC_ALIASITEM pItem, pFoundItem = NULL;
  402. if(m_pLocalAliases)
  403. {
  404. wC = m_pLocalAliases->wCount;
  405. pItem = m_pLocalAliases->pItems;
  406. while (wC--)
  407. {
  408. if(!pItem)
  409. {
  410. continue;
  411. }
  412. if(pItem->wType == CC_ALIAS_H323_ID)
  413. {
  414. if(!pItem->wDataLength || !pItem->pData)
  415. {
  416. continue;
  417. }
  418. else
  419. {
  420. pFoundItem = pItem; // done, done, done
  421. break; // I said done
  422. }
  423. }
  424. else if(pItem->wType == CC_ALIAS_H323_PHONE)
  425. {
  426. if(!pItem->wDataLength || !pItem->pData)
  427. {
  428. continue;
  429. }
  430. else
  431. {
  432. if(!pFoundItem) // if nothing at all was found so far
  433. pFoundItem = pItem; // remember this
  434. }
  435. }
  436. pItem++;
  437. }
  438. }
  439. return pFoundItem;
  440. }
  441. CREQ_RESPONSETYPE CH323CallControl::ConnectionRequest(CConnection *pConnection)
  442. {
  443. CREQ_RESPONSETYPE Response;
  444. // decide what to do internally
  445. // LOOKLOOK hardcoded acceptance
  446. Response = CRR_ACCEPT;
  447. return Response;
  448. }
  449. CREQ_RESPONSETYPE CH323CallControl::FilterConnectionRequest(CConnection *pConnection,
  450. P_APP_CALL_SETUP_DATA pAppData)
  451. {
  452. CREQ_RESPONSETYPE Response = CRR_ASYNC;
  453. ASSERT(m_uMaximumBandwidth);
  454. // run it past the notification callback (if there is one)
  455. if(m_pProcNotifyConnect)
  456. {
  457. // pass ptr to IConnection
  458. Response = (m_pProcNotifyConnect)((IH323Endpoint *)&pConnection->m_ImpConnection,
  459. pAppData);
  460. if(Response != CRR_ACCEPT)
  461. {
  462. return Response;
  463. }
  464. }
  465. return Response;
  466. }
  467. HRESULT CH323CallControl::RegisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler)
  468. {
  469. // reject if there's an existing registration
  470. if (m_pProcNotifyConnect || (!pConnectRequestHandler))
  471. {
  472. return H323CC_E_INVALID_PARAM;
  473. }
  474. m_pProcNotifyConnect = pConnectRequestHandler;
  475. return hrSuccess;
  476. }
  477. HRESULT CH323CallControl::DeregisterConnectionNotify(CNOTIFYPROC pConnectRequestHandler)
  478. {
  479. // reject if there's not an existing registration
  480. if (!m_pProcNotifyConnect)
  481. return H323CC_E_INVALID_PARAM;
  482. if (pConnectRequestHandler == m_pProcNotifyConnect)
  483. {
  484. m_pProcNotifyConnect = NULL;
  485. }
  486. else
  487. {
  488. return H323CC_E_INVALID_PARAM;
  489. }
  490. return hrSuccess;
  491. }
  492. HRESULT CH323CallControl::GetNumConnections(ULONG *lp)
  493. {
  494. ULONG ulRet = m_numlines;
  495. // hide the "listening" connection object from the client/ui/whatever
  496. if(ulRet && m_pListenLine)
  497. ulRet--;
  498. if(lp)
  499. {
  500. *lp = ulRet;
  501. }
  502. return hrSuccess;
  503. }
  504. HRESULT CH323CallControl::GetConnobjArray(CConnection **lplpArray, UINT uSize)
  505. {
  506. UINT uPublicConnections; // # of visible objects
  507. if(!lplpArray)
  508. return H323CC_E_INVALID_PARAM;
  509. uPublicConnections = m_numlines;
  510. if(m_pListenLine)
  511. uPublicConnections--;
  512. if(uSize < (sizeof(CConnection **) * uPublicConnections))
  513. {
  514. return H323CC_E_MORE_CONNECTIONS;
  515. }
  516. CConnection *pLine = m_pLineList;
  517. CConnection *pNext;
  518. int i=0;
  519. while(pLine)
  520. {
  521. DEBUGCHK(uSize--);
  522. pNext = pLine->next;
  523. // return everything but the objects used for listening
  524. if(pLine != m_pListenLine)
  525. {
  526. lplpArray[i++] = pLine;
  527. }
  528. pLine = pNext;
  529. }
  530. return hrSuccess;
  531. };
  532. HRESULT CH323CallControl::GetConnectionArray(IH323Endpoint * *lplpArray, UINT uSize)
  533. {
  534. UINT uPublicConnections; // # of visible objects
  535. if(!lplpArray)
  536. return H323CC_E_INVALID_PARAM;
  537. uPublicConnections = m_numlines;
  538. if(m_pListenLine)
  539. uPublicConnections--;
  540. if(uSize < (sizeof(IH323Endpoint * *) * uPublicConnections))
  541. {
  542. return H323CC_E_MORE_CONNECTIONS;
  543. }
  544. CConnection *pLine = m_pLineList;
  545. CConnection *pNext;
  546. int i=0;
  547. while(pLine)
  548. {
  549. DEBUGCHK(uSize--);
  550. pNext = pLine->next;
  551. // return everything but the objects used for listening
  552. if(pLine != m_pListenLine)
  553. {
  554. lplpArray[i++] = (IH323Endpoint *)&pLine->m_ImpConnection;
  555. }
  556. pLine = pNext;
  557. }
  558. return hrSuccess;
  559. };
  560. //
  561. // protocol specific CreateConnection
  562. //
  563. HRESULT CH323CallControl::CreateConnection(CConnection **lplpConnection, GUID PIDofProtocolType)
  564. {
  565. SetLastHR(hrSuccess);
  566. CConnection *lpConnection, *lpList;
  567. if(!lplpConnection)
  568. {
  569. SetLastHR(MakeResult(H323CC_E_INVALID_PARAM));
  570. goto EXIT;
  571. }
  572. *lplpConnection = NULL;
  573. DBG_SAVE_FILE_LINE
  574. if(!(lpConnection = new CConnection))
  575. {
  576. SetLastHR(MakeResult(H323CC_E_INSUFFICIENT_MEMORY));
  577. goto EXIT;
  578. }
  579. hrLast = lpConnection->Init(this, PIDofProtocolType);
  580. // LOOKLOOK need to insert this connection in the connection list
  581. if(!HR_SUCCEEDED(hrSuccess))
  582. {
  583. delete lpConnection;
  584. lpConnection = NULL;
  585. }
  586. else
  587. {
  588. *lplpConnection = lpConnection;
  589. // insert in connection list
  590. lpList = m_pLineList;
  591. m_pLineList = lpConnection;
  592. lpConnection->next =lpList;
  593. m_numlines++;
  594. }
  595. EXIT:
  596. return (LastHR());
  597. }
  598. //
  599. // IH323CallControl->CreateConnection(), EXTERNAL create connection interface.
  600. //
  601. HRESULT CH323CallControl::CreateConnection(IH323Endpoint * *lplpLine, GUID PIDofProtocolType)
  602. {
  603. SetLastHR(hrSuccess);
  604. CConnection *lpConnection;
  605. ASSERT(m_uMaximumBandwidth);
  606. if(!m_uMaximumBandwidth)
  607. {
  608. SetLastHR(MakeResult(H323CC_E_NOT_INITIALIZED));
  609. goto EXIT;
  610. }
  611. if(!lplpLine)
  612. {
  613. SetLastHR(MakeResult(H323CC_E_INVALID_PARAM));
  614. goto EXIT;
  615. }
  616. *lplpLine = NULL;
  617. hrLast = CreateConnection(&lpConnection, PIDofProtocolType);
  618. if(HR_SUCCEEDED(LastHR()) && lpConnection)
  619. {
  620. *lplpLine = (IH323Endpoint *)&lpConnection->m_ImpConnection;
  621. }
  622. EXIT:
  623. return (LastHR());
  624. }
  625. //
  626. // CreateLocalCommChannel creates the send side of a media channel outside the context
  627. // of any call.
  628. //
  629. HRESULT CH323CallControl::CreateLocalCommChannel(ICommChannel** ppCommChan, LPGUID lpMID,
  630. IMediaChannel* pMediaStream)
  631. {
  632. if(!ppCommChan || !lpMID || !pMediaStream)
  633. return H323CC_E_INVALID_PARAM;
  634. if (*lpMID == MEDIA_TYPE_H323AUDIO)
  635. {
  636. ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
  637. // allow only one of each media type to be created. This is an artificial
  638. // limitation.
  639. if(m_pSendAudioChannel)
  640. {
  641. hrLast = H323CC_E_CREATE_FAILURE;
  642. goto EXIT;
  643. }
  644. DBG_SAVE_FILE_LINE
  645. if(!(m_pSendAudioChannel = new ImpICommChan))
  646. {
  647. hrLast = H323CC_E_CREATE_FAILURE;
  648. goto EXIT;
  649. }
  650. hrLast = m_pSendAudioChannel->StandbyInit(lpMID, m_pCapabilityResolver,
  651. pMediaStream);
  652. if(!HR_SUCCEEDED(hrLast))
  653. {
  654. m_pSendAudioChannel->Release();
  655. m_pSendAudioChannel = NULL;
  656. goto EXIT;
  657. }
  658. hrLast = m_pSendAudioChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan);
  659. if(!HR_SUCCEEDED(hrLast))
  660. {
  661. m_pSendAudioChannel->Release();
  662. m_pSendAudioChannel = NULL;
  663. goto EXIT;
  664. }
  665. }
  666. else if (*lpMID == MEDIA_TYPE_H323VIDEO)
  667. {
  668. ASSERT(g_capFlags & CAPFLAGS_AV_STREAMS);
  669. // allow only one of each media type to be created. This is an artificial
  670. // limitation.
  671. if(m_pSendVideoChannel)
  672. {
  673. hrLast = H323CC_E_CREATE_FAILURE;
  674. goto EXIT;
  675. }
  676. DBG_SAVE_FILE_LINE
  677. if(!(m_pSendVideoChannel = new ImpICommChan))
  678. {
  679. hrLast = H323CC_E_CREATE_FAILURE;
  680. goto EXIT;
  681. }
  682. hrLast = m_pSendVideoChannel->StandbyInit(lpMID, m_pCapabilityResolver,
  683. pMediaStream);
  684. if(!HR_SUCCEEDED(hrLast))
  685. {
  686. m_pSendVideoChannel->Release();
  687. m_pSendVideoChannel = NULL;
  688. goto EXIT;
  689. }
  690. hrLast = m_pSendVideoChannel->QueryInterface(IID_ICommChannel, (void **)ppCommChan);
  691. if(!HR_SUCCEEDED(hrLast))
  692. {
  693. m_pSendVideoChannel->Release();
  694. m_pSendVideoChannel = NULL;
  695. goto EXIT;
  696. }
  697. }
  698. else
  699. hrLast = H323CC_E_INVALID_PARAM;
  700. EXIT:
  701. return hrLast;
  702. }
  703. ICtrlCommChan *CH323CallControl::QueryPreviewChannel(LPGUID lpMID)
  704. {
  705. HRESULT hr;
  706. ICtrlCommChan *pCommChan = NULL;
  707. if(*lpMID == MEDIA_TYPE_H323AUDIO)
  708. {
  709. if(m_pSendAudioChannel)
  710. {
  711. hr = m_pSendAudioChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan);
  712. if(HR_SUCCEEDED(hr))
  713. {
  714. return pCommChan;
  715. }
  716. }
  717. }
  718. else if (*lpMID == MEDIA_TYPE_H323VIDEO)
  719. {
  720. if(m_pSendVideoChannel)
  721. {
  722. hr = m_pSendVideoChannel->QueryInterface(IID_ICtrlCommChannel, (void **)&pCommChan);
  723. if(HR_SUCCEEDED(hr))
  724. {
  725. return pCommChan;
  726. }
  727. }
  728. }
  729. // fallout to error case
  730. return NULL;
  731. }
  732. HRESULT CH323CallControl::RemoveConnection(CConnection *lpConnection)
  733. {
  734. SetLastHR(hrSuccess);
  735. CConnection *lpList;
  736. UINT nLines;
  737. if((lpConnection == NULL) || lpConnection->m_pH323CallControl != this)
  738. {
  739. SetLastHR(MakeResult(H323CC_E_INVALID_PARAM));
  740. goto EXIT;
  741. }
  742. m_numlines--; // update count NOW
  743. // use # of lines for bug detection in list management code
  744. nLines = m_numlines;
  745. if(m_pListenLine == lpConnection)
  746. m_pListenLine = NULL;
  747. // zap the back pointer of the connection NOW - this is crucial for
  748. // implementing "asynchronous delete" of connection objects
  749. lpConnection->m_pH323CallControl = NULL;
  750. // find it in the connection list and remove it
  751. // sp. case head
  752. if(m_pLineList== lpConnection)
  753. {
  754. m_pLineList = lpConnection->next;
  755. }
  756. else
  757. {
  758. lpList = m_pLineList;
  759. while(lpList->next && nLines)
  760. {
  761. if(lpList->next == lpConnection)
  762. {
  763. lpList->next = lpConnection->next;
  764. break;
  765. }
  766. lpList = lpList->next;
  767. nLines--;
  768. }
  769. }
  770. EXIT:
  771. return (LastHR());
  772. }
  773. STDMETHODIMP CH323CallControl::QueryInterface( REFIID iid, void ** ppvObject)
  774. {
  775. // this breaks the rules for the official COM QueryInterface because
  776. // the interfaces that are queried for are not necessarily real COM
  777. // interfaces. The reflexive property of QueryInterface would be broken in
  778. // that case.
  779. HRESULT hr = E_NOINTERFACE;
  780. if(!ppvObject)
  781. return hr;
  782. *ppvObject = 0;
  783. if ((iid == IID_IH323CC) || (iid == IID_IUnknown))// satisfy symmetric property of QI
  784. {
  785. *ppvObject = this;
  786. hr = hrSuccess;
  787. AddRef();
  788. }
  789. else if (iid == IID_IAppAudioCap )
  790. {
  791. hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject);
  792. }
  793. else if(iid == IID_IAppVidCap )
  794. {
  795. hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject);
  796. }
  797. else if(iid == IID_IDualPubCap )
  798. {
  799. hr = m_pCapabilityResolver->QueryInterface(iid, ppvObject);
  800. }
  801. return (hr);
  802. }
  803. //
  804. // Create a copy of the alias names in the (somewhat bogus) format that
  805. // CALLCONT expects. The destination format has a two-part string for every
  806. // entry, but the lower layers concatenate the parts. Someday H323CC and CALLCONT
  807. // will be one, and all the extraneous layers, copies of data, and redundant
  808. // validations won't be needed.
  809. //
  810. HRESULT AllocTranslatedAliasList(PCC_ALIASNAMES *ppDest, P_H323ALIASLIST pSource)
  811. {
  812. HRESULT hr = H323CC_E_INVALID_PARAM;
  813. WORD w;
  814. PCC_ALIASNAMES pNewAliases = NULL;
  815. PCC_ALIASITEM pDestItem;
  816. P_H323ALIASNAME pSrcItem;
  817. if(!ppDest || !pSource || pSource->wCount == 0)
  818. {
  819. goto ERROR_OUT;
  820. }
  821. *ppDest = NULL;
  822. pNewAliases = (PCC_ALIASNAMES)MemAlloc(sizeof(CC_ALIASNAMES));
  823. if(!pNewAliases)
  824. {
  825. hr = H323CC_E_INSUFFICIENT_MEMORY;
  826. goto ERROR_OUT;
  827. }
  828. pNewAliases->wCount = 0;
  829. pNewAliases->pItems = (PCC_ALIASITEM)MemAlloc(pSource->wCount*sizeof(CC_ALIASITEM));
  830. if(!pNewAliases->pItems)
  831. {
  832. hr = H323CC_E_INSUFFICIENT_MEMORY;
  833. goto ERROR_OUT;
  834. }
  835. for(w=0;w<pSource->wCount;w++)
  836. {
  837. pDestItem = pNewAliases->pItems+w;
  838. pSrcItem = pSource->pItems+w;
  839. // don't tolerate empty entries - error out if any exist
  840. if(pSrcItem->wDataLength && pSrcItem->lpwData)
  841. {
  842. if(pSrcItem->aType ==AT_H323_ID)
  843. {
  844. pDestItem->wType = CC_ALIAS_H323_ID;
  845. }
  846. else if(pSrcItem->aType ==AT_H323_E164)
  847. {
  848. pDestItem->wType = CC_ALIAS_H323_PHONE;
  849. }
  850. else
  851. { // don't know how to translate this. I hope that the need for translation
  852. // goes away before new alias types are added. Adding an alias type
  853. // (H323_URL for example) requires many changes in lower layers anyway,
  854. // so that would be a good time to merge H323CC and CALLCONT.
  855. goto ERROR_OUT; // return invalid param
  856. }
  857. pDestItem->wPrefixLength = 0; // this prefix thing is bogus
  858. pDestItem->pPrefix = NULL;
  859. pDestItem->pData = (LPWSTR)MemAlloc(pSrcItem->wDataLength *sizeof(WCHAR));
  860. if(pDestItem->pData == NULL)
  861. {
  862. hr = H323CC_E_INSUFFICIENT_MEMORY;
  863. goto ERROR_OUT;
  864. }
  865. // got good data. Copy the data, set size/length, and count it
  866. memcpy(pDestItem->pData, pSrcItem->lpwData, pSrcItem->wDataLength * sizeof(WCHAR));
  867. pDestItem->wDataLength = pSrcItem->wDataLength;
  868. pNewAliases->wCount++;
  869. }
  870. else
  871. {
  872. goto ERROR_OUT;
  873. }
  874. }
  875. // got here, so output good data
  876. hr = hrSuccess;
  877. *ppDest = pNewAliases;
  878. //pNewAliases = NULL; // not needed if returning here instead of falling out
  879. return hr;
  880. ERROR_OUT:
  881. if(pNewAliases) // then it's an error condition needing cleanup
  882. {
  883. FreeTranslatedAliasList(pNewAliases);
  884. }
  885. return hr;
  886. }
  887. VOID FreeTranslatedAliasList(PCC_ALIASNAMES pDoomed)
  888. {
  889. WORD w;
  890. PCC_ALIASITEM pDoomedItem;
  891. if(!pDoomed)
  892. return;
  893. for(w=0;w<pDoomed->wCount;w++)
  894. {
  895. pDoomedItem = pDoomed->pItems+w;
  896. // don't tolerate empty entries - error out if any exist
  897. if(pDoomedItem->wDataLength && pDoomedItem->pData)
  898. {
  899. MemFree(pDoomedItem->pData);
  900. }
  901. else
  902. ASSERT(0);
  903. }
  904. MemFree(pDoomed->pItems);
  905. MemFree(pDoomed);
  906. }
  907. STDMETHODIMP CH323CallControl::SetUserAliasNames(P_H323ALIASLIST pAliases)
  908. {
  909. HRESULT hr = hrSuccess;
  910. PCC_ALIASNAMES pNewAliases = NULL;
  911. PCC_ALIASITEM pItem;
  912. hr = AllocTranslatedAliasList(&pNewAliases, pAliases);
  913. if(!HR_SUCCEEDED(hr))
  914. return hr;
  915. ASSERT(pNewAliases);
  916. if(m_pLocalAliases)
  917. FreeTranslatedAliasList(m_pLocalAliases);
  918. m_pLocalAliases = pNewAliases;
  919. return hr;
  920. }
  921. STDMETHODIMP CH323CallControl::EnableGatekeeper(BOOL bEnable,
  922. PSOCKADDR_IN pGKAddr, P_H323ALIASLIST pAliases,
  923. RASNOTIFYPROC pRasNotifyProc)
  924. {
  925. HRESULT hr = hrSuccess;
  926. PCC_ALIASNAMES pNewAliases = NULL;
  927. PCC_ALIASITEM pItem;
  928. m_pRasNotifyProc = pRasNotifyProc;
  929. if(bEnable)
  930. {
  931. if(!pRasNotifyProc || !pGKAddr || !pAliases)
  932. {
  933. return H323CC_E_INVALID_PARAM;
  934. }
  935. if((pGKAddr->sin_addr.s_addr == INADDR_NONE)
  936. || (pGKAddr->sin_addr.s_addr == INADDR_ANY))
  937. {
  938. return H323CC_E_INVALID_PARAM;
  939. }
  940. hr = AllocTranslatedAliasList(&pNewAliases, pAliases);
  941. if(!HR_SUCCEEDED(hr))
  942. return hr;
  943. ASSERT(pNewAliases);
  944. if(m_pRegistrationAliases)
  945. FreeTranslatedAliasList(m_pRegistrationAliases);
  946. m_pRegistrationAliases = pNewAliases;
  947. // reset "I can place calls" state
  948. m_fGKProhibit = FALSE;
  949. hr = CC_EnableGKRegistration(bEnable,
  950. pGKAddr, m_pRegistrationAliases,
  951. &m_VendorInfo,
  952. 0, // no multipoint/MC funtionality
  953. RasNotify);
  954. }
  955. else
  956. {
  957. // we are turning off knowledge of what a gatekeeper is,
  958. // so reset "I can place calls" state.
  959. m_fGKProhibit = FALSE;
  960. hr = CC_EnableGKRegistration(bEnable,
  961. NULL, NULL, NULL, 0, RasNotify);
  962. if(m_pRegistrationAliases)
  963. FreeTranslatedAliasList(m_pRegistrationAliases);
  964. m_pRegistrationAliases = NULL;
  965. }
  966. return hr;
  967. }
  968. STDMETHODIMP CH323CallControl::GetGKCallPermission()
  969. {
  970. if(m_fGKProhibit)
  971. return CONN_E_GK_NOT_REGISTERED;
  972. else
  973. return hrSuccess;
  974. }
  975. VOID CALLBACK CH323CallControl::RasNotify(DWORD dwRasEvent, HRESULT hReason)
  976. {
  977. switch(dwRasEvent)
  978. {
  979. case RAS_REG_CONFIRM: // received RCF (registration confirmed)
  980. // reset "I can place calls" state
  981. m_fGKProhibit = FALSE;
  982. break;
  983. case RAS_REG_TIMEOUT: // GK did not respond
  984. case RAS_UNREG_CONFIRM: // received UCF (unregistration confirmed)
  985. default:
  986. // do nothing. (except pass notification upward
  987. break;
  988. case RAS_REJECTED: // received RRJ (registration rejected)
  989. m_fGKProhibit = TRUE;
  990. break;
  991. case RAS_UNREG_REQ: // received URQ
  992. m_fGKProhibit = TRUE;
  993. break;
  994. }
  995. if(m_pRasNotifyProc)
  996. {
  997. (m_pRasNotifyProc)(dwRasEvent, hReason);
  998. }
  999. }