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.

1084 lines
30 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. sdpblob.cpp
  5. Abstract:
  6. Implementation of CSdpConferenceBlob
  7. Author:
  8. */
  9. #include "stdafx.h"
  10. #include "blbgen.h"
  11. #include "sdpblb.h"
  12. #include "sdpblob.h"
  13. #include "blbreg.h"
  14. #include "addrgen.h"
  15. #include <time.h>
  16. #include <winsock2.h>
  17. #include "blbtico.h"
  18. #include "blbmeco.h"
  19. // ZoltanS: This is the multicast address we give by default. The app must then
  20. // go and get a real address via MDHCP and explicitly set it to a meaningful
  21. // value.
  22. const long DUMMY_ADDRESS = 0xe0000000; // A dummy address that qualifies as Class D.
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CSdpConferenceBlob
  25. /////////////////////////////////////////////////////////////////////////////
  26. //
  27. // definition for the critical section needed by
  28. // CObjectSafeImpl
  29. //
  30. CComAutoCriticalSection CObjectSafeImpl::s_CritSection;
  31. CCritSection g_DllLock;
  32. const USHORT MAX_IP_ADDRESS_STRLEN = 15;
  33. const USHORT NUM_CONF_BLOB_TEMPLATE_PARAMS = 9;
  34. // static SDP_REG_READER gs_SdpRegReader;
  35. // a 1-1 mapping from the index (BLOB_CHARACTER_SET) to the SDP_CHAR_SET
  36. // ASSUMPTION: BCS_UTF8 is the last value in the enumeration BLOB_CHARACTER_SET
  37. SDP_CHARACTER_SET const CSdpConferenceBlob::gs_SdpCharSetMapping[BCS_UTF8] =
  38. {
  39. CS_ASCII,
  40. CS_UTF7,
  41. CS_UTF8
  42. };
  43. CSdpConferenceBlob *
  44. CSdpConferenceBlob::GetConfBlob(
  45. )
  46. {
  47. return this;
  48. }
  49. HRESULT
  50. CSdpConferenceBlob::WriteStartTime(
  51. IN DWORD MinStartTime
  52. )
  53. {
  54. CLock Lock(g_DllLock);
  55. int NumEntries = (int)GetTimeList().GetSize();
  56. // set the first time entry to the MinStartTime
  57. if ( 0 < NumEntries )
  58. {
  59. // need to make sure that the stop time is after the start time or unbounded (0)
  60. HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(0))->SetStartTime(MinStartTime);
  61. BAIL_ON_FAILURE(HResult);
  62. }
  63. else // create an entry
  64. {
  65. // create a new entry, use vb 1 based indices
  66. HRESULT HResult = ((MY_TIME_COLL_IMPL *)m_TimeCollection)->Create(1, MinStartTime, 0);
  67. BAIL_ON_FAILURE(HResult);
  68. }
  69. // iterate through the time list and for each other time entry
  70. // modify the start time (if the start time is before MinStartTime, change it to MinStartTime)
  71. for(UINT i = 1; (int)i < NumEntries; i++ )
  72. {
  73. ULONG StartTime;
  74. HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->GetStartTime(StartTime);
  75. // ignore invalid values and continue
  76. if ( FAILED(HResult) )
  77. {
  78. continue;
  79. }
  80. if ( StartTime < MinStartTime )
  81. {
  82. HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->SetStartTime(MinStartTime);
  83. // ignore invalid values and continue
  84. if ( FAILED(HResult) )
  85. {
  86. continue;
  87. }
  88. }
  89. }
  90. return S_OK;
  91. }
  92. HRESULT
  93. CSdpConferenceBlob::WriteStopTime(
  94. IN DWORD MaxStopTime
  95. )
  96. {
  97. CLock Lock(g_DllLock);
  98. int NumEntries = (int)GetTimeList().GetSize();
  99. // set the first time entry to the MaxStopTime
  100. if ( 0 < NumEntries )
  101. {
  102. // need to make sure that the stop time is after the start time or unbounded (0)
  103. ((SDP_TIME *)GetTimeList().GetAt(0))->SetStopTime(MaxStopTime);
  104. }
  105. else // create an entry
  106. {
  107. // create a new entry, use vb 1 based indices
  108. HRESULT HResult = ((MY_TIME_COLL_IMPL *)m_TimeCollection)->Create(1, 0, MaxStopTime);
  109. BAIL_ON_FAILURE(HResult);
  110. }
  111. // iterate through the time list and for each other time entry
  112. // modify the stop time (if the stop time is after MaxStopTime, change it to MaxStopTime)
  113. for(UINT i = 1; (int)i < NumEntries; i++ )
  114. {
  115. ULONG StopTime;
  116. HRESULT HResult = ((SDP_TIME *)GetTimeList().GetAt(i))->GetStopTime(StopTime);
  117. // ignore invalid values and continue
  118. if ( FAILED(HResult) )
  119. {
  120. continue;
  121. }
  122. if ( StopTime > MaxStopTime )
  123. {
  124. ((SDP_TIME *)GetTimeList().GetAt(i))->SetStopTime(MaxStopTime);
  125. }
  126. }
  127. return S_OK;
  128. }
  129. /*
  130. enum RND_ADVERTISING_SCOPE // as per SDP recommendations
  131. {
  132. RAS_LOCAL, // ttl <=1 recommended ttl 1
  133. RAS_SITE, // <=15 15
  134. RAS_REGION, // <=63 63
  135. RAS_WORLD // <=255 127
  136. } RND_ADVERTISING_SCOPE;
  137. modification in target action
  138. ITConference SDP_BLOB for each connection line, the ttl is set to a max of the
  139. recommended ttl for the new advertising scope
  140. ITConnection CONFERENCE the SDP_BLOB component determines the max ttl and notifies the
  141. CONFERENCE of the new advertising scope
  142. this is similar to the way start/stop time modifications are handled.
  143. */
  144. HRESULT
  145. CSdpConferenceBlob::WriteAdvertisingScope(
  146. IN DWORD MaxAdvertisingScope
  147. )
  148. {
  149. CLock Lock(g_DllLock);
  150. // ZoltanS: bug # 191413: check for out of range advertising scopes
  151. if ( ( MaxAdvertisingScope > RAS_WORLD ) ||
  152. ( MaxAdvertisingScope < RAS_LOCAL ) )
  153. {
  154. return E_INVALIDARG;
  155. }
  156. BYTE MaxTtl = GetTtl((RND_ADVERTISING_SCOPE)MaxAdvertisingScope);
  157. // set the default connection ttl to the max ttl
  158. if ( GetConnection().GetTtl().IsValid() )
  159. {
  160. GetConnection().GetTtl().SetValue(MaxTtl);
  161. }
  162. else // hack** : using SetConnection method. instead, the ttl field should always be kept valid
  163. {
  164. // get the current address and the number of addresses value and use the SetConnection method
  165. // this puts the ttl field into the array of member fields
  166. BSTR StartAddress = NULL;
  167. BAIL_ON_FAILURE(GetConnection().GetStartAddress().GetBstr(&StartAddress));
  168. HRESULT HResult = GetConnection().SetConnection(
  169. StartAddress,
  170. GetConnection().GetNumAddresses().GetValue(),
  171. MaxTtl
  172. );
  173. BAIL_ON_FAILURE(HResult);
  174. }
  175. // iterate through the sdp media list and for each connection entry, set the ttl
  176. // to maxttl if its more than it
  177. int NumEntries = (int)GetMediaList().GetSize();
  178. for(UINT i = 1; (int)i < NumEntries; i++ )
  179. {
  180. SDP_CONNECTION &SdpConnection = ((SDP_MEDIA *)GetMediaList().GetAt(i))->GetConnection();
  181. if ( SdpConnection.GetTtl().IsValid() && (SdpConnection.GetTtl().GetValue() > MaxTtl) )
  182. {
  183. SdpConnection.GetTtl().SetValue(MaxTtl);
  184. }
  185. }
  186. return S_OK;
  187. }
  188. STDMETHODIMP CSdpConferenceBlob::Init(
  189. /*[in]*/ BSTR pName,
  190. /*[in]*/ BLOB_CHARACTER_SET CharacterSet,
  191. /*[in]*/ BSTR pBlob
  192. )
  193. {
  194. CLock Lock(g_DllLock);
  195. // validate the parameters
  196. // the name cannot be null, if no blob has been specified (if a blob is specified then the name
  197. // is implicit in it
  198. if ( (NULL == pName) && (NULL == pBlob) )
  199. {
  200. return E_INVALIDARG;
  201. }
  202. // initialize the sdp
  203. if ( !SDP_BLOB::Init() )
  204. {
  205. return HRESULT_FROM_ERROR_CODE(GetLastError());
  206. }
  207. // create media/time collection, query for I*Collection i/f
  208. CComObject<MEDIA_COLLECTION> *MediaCollection;
  209. try
  210. {
  211. MediaCollection = new CComObject<MEDIA_COLLECTION>;
  212. }
  213. catch(...)
  214. {
  215. MediaCollection = NULL;
  216. }
  217. BAIL_IF_NULL(MediaCollection, HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA));
  218. HRESULT HResult = MediaCollection->Init(*this, GetMediaList());
  219. if ( FAILED(HResult) )
  220. {
  221. delete MediaCollection;
  222. return HResult;
  223. }
  224. // inform the sdp instance that it needn't delete the media list on destruction
  225. ClearDestroyMediaListFlag();
  226. // query for the ITMediaCollection i/f
  227. HResult = MediaCollection->_InternalQueryInterface(IID_ITMediaCollection, (void **)&m_MediaCollection);
  228. if ( FAILED(HResult) )
  229. {
  230. delete MediaCollection;
  231. return HResult;
  232. }
  233. // on failure, just delete the time collection and return
  234. // no need to delete the media collection as well since that's taken care of by the destructor
  235. CComObject<TIME_COLLECTION> *TimeCollection;
  236. try
  237. {
  238. TimeCollection = new CComObject<TIME_COLLECTION>;
  239. }
  240. catch(...)
  241. {
  242. TimeCollection = NULL;
  243. }
  244. BAIL_IF_NULL(TimeCollection, HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA));
  245. HResult = TimeCollection->Init(*this, GetTimeList());
  246. if ( FAILED(HResult) )
  247. {
  248. delete TimeCollection;
  249. return HResult;
  250. }
  251. // inform the sdp instance that it needn't delete the time list on destruction
  252. ClearDestroyTimeListFlag();
  253. // query for the ITTimeCollection i/f
  254. HResult = TimeCollection->_InternalQueryInterface(IID_ITTimeCollection, (void **)&m_TimeCollection);
  255. if ( FAILED(HResult) )
  256. {
  257. delete TimeCollection;
  258. return HResult;
  259. }
  260. // check if a default sdp needs to be created, else use the sdp provided by the user
  261. if ( NULL == pBlob )
  262. {
  263. BAIL_ON_FAILURE(
  264. CreateDefault(
  265. pName,
  266. gs_SdpCharSetMapping[CharacterSet-1])
  267. );
  268. }
  269. else
  270. {
  271. // we change the Character set from the CS_UTF8
  272. // if the blob containts the "a=charset:" attribute
  273. CharacterSet = GetBlobCharacterSet( pBlob);
  274. // HACK ** we don't want notifications of blob contents when the sdp blob is being passed in
  275. // (conference directory - enumeration scenario), so the notification owner is set after the
  276. // conference blob is processed
  277. BAIL_ON_FAILURE(SetConferenceBlob(CharacterSet, pBlob));
  278. // at this point, the sdp is either passed in by the non-dir-user or is obtained by enumerating
  279. // the directory.
  280. // clear the modified state on the sdp (parsing in an sdp sets the state to modified) so that
  281. // only true modifications are tracked
  282. ClearModifiedState();
  283. }
  284. return S_OK;
  285. }
  286. STDMETHODIMP CSdpConferenceBlob::get_IsModified(VARIANT_BOOL * pVal)
  287. {
  288. BAIL_IF_NULL(pVal, E_INVALIDARG);
  289. CLock Lock(g_DllLock);
  290. *pVal = ( (GetWasModified() || SDP::IsModified()) ? VARIANT_TRUE : VARIANT_FALSE);
  291. return S_OK;
  292. }
  293. STDMETHODIMP CSdpConferenceBlob::get_TimeCollection(
  294. ITTimeCollection * *ppTimeCollection
  295. )
  296. {
  297. BAIL_IF_NULL(ppTimeCollection, E_INVALIDARG);
  298. CLock Lock(g_DllLock);
  299. ASSERT(NULL != m_TimeCollection);
  300. if ( NULL == m_TimeCollection )
  301. {
  302. return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
  303. }
  304. // increase the ref count
  305. m_TimeCollection->AddRef();
  306. *ppTimeCollection = m_TimeCollection;
  307. return S_OK;
  308. }
  309. STDMETHODIMP CSdpConferenceBlob::get_MediaCollection(
  310. ITMediaCollection * *ppMediaCollection
  311. )
  312. {
  313. BAIL_IF_NULL(ppMediaCollection, E_INVALIDARG);
  314. CLock Lock(g_DllLock);
  315. ASSERT(NULL != m_MediaCollection);
  316. if ( NULL == m_MediaCollection )
  317. {
  318. return HRESULT_FROM_ERROR_CODE(ERROR_INVALID_DATA);
  319. }
  320. // increase the ref count
  321. m_MediaCollection->AddRef();
  322. *ppMediaCollection = m_MediaCollection;
  323. return S_OK;
  324. }
  325. STDMETHODIMP CSdpConferenceBlob::get_IsValid(VARIANT_BOOL * pVal)
  326. {
  327. BAIL_IF_NULL(pVal, E_INVALIDARG);
  328. CLock Lock(g_DllLock);
  329. *pVal = (IsValid() ? VARIANT_TRUE : VARIANT_FALSE);
  330. return S_OK;
  331. }
  332. STDMETHODIMP CSdpConferenceBlob::get_CharacterSet(BLOB_CHARACTER_SET *pCharacterSet)
  333. {
  334. // map the sdp character set value for SDP_BLOB to the BLOB_CHARACTER_SET
  335. BAIL_IF_NULL(pCharacterSet, E_INVALIDARG);
  336. CLock Lock(g_DllLock);
  337. // check the sdp char set values corresponding to the blob character sets for a match
  338. // if a match is found, return the index as the blob character set
  339. // NOTE: the for loop is dependent upon the order of declaration of the BLOB_CHARACTER_SET
  340. // enum values
  341. for( UINT BlobCharSet = BCS_ASCII; BCS_UTF8 >= BlobCharSet; BlobCharSet++ )
  342. {
  343. // BCS_ASCII is 1, but the array starts with 0, so the index is BlobCharSet - 1.
  344. if ( gs_SdpCharSetMapping[BlobCharSet -1] == SDP::GetCharacterSet() )
  345. {
  346. *pCharacterSet = (BLOB_CHARACTER_SET)BlobCharSet;
  347. return S_OK;
  348. }
  349. }
  350. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  351. }
  352. STDMETHODIMP CSdpConferenceBlob::get_ConferenceBlob(BSTR * pVal)
  353. {
  354. CLock Lock(g_DllLock);
  355. return GetBstrCopy(pVal);
  356. }
  357. HRESULT
  358. CSdpConferenceBlob::WriteConferenceBlob(
  359. IN SDP_CHARACTER_SET SdpCharSet,
  360. IN BSTR newVal
  361. )
  362. {
  363. // set the character set of the SDP_BSTRING
  364. VERIFY(SetCharacterSet(SdpCharSet));
  365. // set the bstr to the passed in value, this is converted to the ascii representation and parsed
  366. HRESULT HResult = SetBstr(newVal);
  367. BAIL_ON_FAILURE(HResult);
  368. HResult = ((MEDIA_COLLECTION *)m_MediaCollection)->Init(*this, GetMediaList());
  369. BAIL_ON_FAILURE(HResult);
  370. HResult = ((TIME_COLLECTION *)m_TimeCollection)->Init(*this, GetTimeList());
  371. BAIL_ON_FAILURE(HResult);
  372. return S_OK;
  373. }
  374. STDMETHODIMP CSdpConferenceBlob::SetConferenceBlob(BLOB_CHARACTER_SET CharacterSet, BSTR newVal)
  375. {
  376. // validate the passed in character set value
  377. // although this is an enumeration, someone may try and pass in a different value
  378. // NOTE: Assumes BCS_ASCII is the first and BCS_UTF8 is the last enumerated value
  379. if ( !( (BCS_ASCII <= CharacterSet) && (BCS_UTF8 >= CharacterSet) ) )
  380. {
  381. return E_INVALIDARG;
  382. }
  383. CLock Lock(g_DllLock);
  384. // map the BLOB_CHARACTER_SET value to the sdp character set (since the BCS value start at 1,
  385. // subtract 1 from the blob character set to index into the array
  386. // write the conference blob, also send notifications for any modified dependent attributes
  387. HRESULT HResult = WriteConferenceBlob(gs_SdpCharSetMapping[CharacterSet-1], newVal);
  388. BAIL_ON_FAILURE(HResult);
  389. return S_OK;
  390. }
  391. STDMETHODIMP CSdpConferenceBlob::get_ProtocolVersion(BYTE * pVal)
  392. {
  393. BAIL_IF_NULL(pVal, E_INVALIDARG);
  394. CLock Lock(g_DllLock);
  395. // cast the ulong value to a byte because vb doesn't take a ulong, this shouldn't be
  396. // a problem until version 256
  397. *pVal = (BYTE)GetProtocolVersion().GetVersionValue();
  398. return S_OK;
  399. }
  400. STDMETHODIMP CSdpConferenceBlob::get_SessionId(DOUBLE * pVal)
  401. {
  402. BAIL_IF_NULL(pVal, E_INVALIDARG);
  403. CLock Lock(g_DllLock);
  404. // vb doesn't take ulong - cast the ulong value to a double, the next bigger type
  405. *pVal = (DOUBLE)GetOrigin().GetSessionId().GetValue();
  406. return S_OK;
  407. }
  408. STDMETHODIMP CSdpConferenceBlob::get_SessionVersion(DOUBLE * pVal)
  409. {
  410. BAIL_IF_NULL(pVal, E_INVALIDARG);
  411. CLock Lock(g_DllLock);
  412. // vb doesn't take ulong - cast the ulong value to a double, the next bigger type
  413. *pVal = (DOUBLE)GetOrigin().GetSessionVersion().GetValue();
  414. return S_OK;
  415. }
  416. STDMETHODIMP CSdpConferenceBlob::put_SessionVersion(DOUBLE newVal)
  417. {
  418. // the bandwidth value must be a valid ULONG value (vb restrictions)
  419. if ( !((0 <= newVal) && (ULONG(-1) > newVal)) )
  420. {
  421. return E_INVALIDARG;
  422. }
  423. // check if there is any fractional part, this check is valid as it is a valid ULONG value
  424. if ( newVal != (ULONG)newVal )
  425. {
  426. return E_INVALIDARG;
  427. }
  428. CLock Lock(g_DllLock);
  429. GetOrigin().GetSessionVersion().SetValue((ULONG)newVal);
  430. return S_OK;
  431. }
  432. STDMETHODIMP CSdpConferenceBlob::get_MachineAddress(BSTR * pVal)
  433. {
  434. CLock Lock(g_DllLock);
  435. return GetOrigin().GetAddress().GetBstrCopy(pVal);
  436. }
  437. STDMETHODIMP CSdpConferenceBlob::put_MachineAddress(BSTR newVal)
  438. {
  439. CLock Lock(g_DllLock);
  440. return GetOrigin().GetAddress().SetBstr(newVal);
  441. }
  442. STDMETHODIMP CSdpConferenceBlob::get_Name(BSTR * pVal)
  443. {
  444. CLock Lock(g_DllLock);
  445. return GetSessionName().GetBstrCopy(pVal);
  446. }
  447. STDMETHODIMP CSdpConferenceBlob::put_Name(BSTR newVal)
  448. {
  449. // write the new session name
  450. // acquire lock inside
  451. return WriteName(newVal);
  452. }
  453. STDMETHODIMP CSdpConferenceBlob::get_Description(BSTR * pVal)
  454. {
  455. CLock Lock(g_DllLock);
  456. return GetSessionTitle().GetBstrCopy(pVal);
  457. }
  458. STDMETHODIMP CSdpConferenceBlob::put_Description(BSTR newVal)
  459. {
  460. // write the new session title / description
  461. // acquire lock inside
  462. HRESULT HResult = WriteSessionTitle(newVal);
  463. BAIL_ON_FAILURE(HResult);
  464. return S_OK;
  465. }
  466. STDMETHODIMP CSdpConferenceBlob::get_Url(BSTR * pVal)
  467. {
  468. CLock Lock(g_DllLock);
  469. return GetUri().GetBstrCopy(pVal);
  470. }
  471. STDMETHODIMP CSdpConferenceBlob::put_Url(BSTR newVal)
  472. {
  473. // write the new Url
  474. // acquire lock inside
  475. HRESULT HResult = WriteUrl(newVal);
  476. BAIL_ON_FAILURE(HResult);
  477. return S_OK;
  478. }
  479. STDMETHODIMP CSdpConferenceBlob::GetEmailNames(
  480. VARIANT /*SAFEARRAY(BSTR)*/ *Addresses, VARIANT /*SAFEARRAY(BSTR)*/ *Names
  481. )
  482. {
  483. CLock Lock(g_DllLock);
  484. return GetEmailList().GetSafeArray(Addresses, Names);
  485. }
  486. STDMETHODIMP CSdpConferenceBlob::SetEmailNames(
  487. VARIANT /*SAFEARRAY(BSTR)*/ Addresses, VARIANT /*SAFEARRAY(BSTR)*/ Names
  488. )
  489. {
  490. CLock Lock(g_DllLock);
  491. return GetEmailList().SetSafeArray(Addresses, Names);
  492. }
  493. STDMETHODIMP CSdpConferenceBlob::GetPhoneNumbers(
  494. VARIANT /*SAFEARRAY(BSTR)*/ *Numbers, VARIANT /*SAFEARRAY(BSTR)*/ *Names
  495. )
  496. {
  497. CLock Lock(g_DllLock);
  498. return GetPhoneList().GetSafeArray(Numbers, Names);
  499. }
  500. STDMETHODIMP CSdpConferenceBlob::SetPhoneNumbers(
  501. VARIANT /*SAFEARRAY(BSTR)*/ Numbers, VARIANT /*SAFEARRAY(BSTR)*/ Names
  502. )
  503. {
  504. CLock Lock(g_DllLock);
  505. return GetPhoneList().SetSafeArray(Numbers, Names);
  506. }
  507. STDMETHODIMP CSdpConferenceBlob::get_Originator(BSTR * pVal)
  508. {
  509. CLock Lock(g_DllLock);
  510. return GetOrigin().GetUserName().GetBstrCopy(pVal);
  511. }
  512. STDMETHODIMP CSdpConferenceBlob::put_Originator(BSTR newVal)
  513. {
  514. // write the new user name
  515. // acquire lock inside
  516. HRESULT HResult = WriteOriginator(newVal);
  517. BAIL_ON_FAILURE(HResult);
  518. return S_OK;
  519. }
  520. inline WORD
  521. GetEvenValue(
  522. IN WORD Value
  523. )
  524. {
  525. return (0 == (Value % 2))? Value : (Value - 1);
  526. }
  527. TCHAR *
  528. CSdpConferenceBlob::GenerateSdpBlob(
  529. IN BSTR Name,
  530. IN SDP_CHARACTER_SET CharacterSet
  531. )
  532. {
  533. ASSERT(NULL != Name);
  534. //
  535. // Get multicast ports. We don't set addresses; that's the app's
  536. // responsibility via MDHCP.
  537. //
  538. MSA_PORT_GROUP PortGroup;
  539. PortGroup.PortType = VIDEO_PORT;
  540. WORD FirstVideoPort;
  541. // allocate video port
  542. if ( !MSAAllocatePorts(&PortGroup, FALSE, 2, &FirstVideoPort) )
  543. {
  544. return NULL;
  545. }
  546. PortGroup.PortType = AUDIO_PORT;
  547. WORD FirstAudioPort;
  548. // allocate audio port
  549. if ( !MSAAllocatePorts(&PortGroup, FALSE, 2, &FirstAudioPort) )
  550. {
  551. return NULL;
  552. }
  553. // convert the returned ports to even values for RTP compliance
  554. // ASSUMPTION : the sdp template read from the registry uses RTP as the transport
  555. FirstAudioPort = GetEvenValue(FirstAudioPort);
  556. FirstVideoPort = GetEvenValue(FirstVideoPort);
  557. IP_ADDRESS AudioIpAddress(DUMMY_ADDRESS);
  558. IP_ADDRESS VideoIpAddress(DUMMY_ADDRESS);
  559. const DWORD MAX_USER_NAME_LEN = 100;
  560. DWORD OriginatorBufLen = MAX_USER_NAME_LEN+1;
  561. TCHAR Originator[MAX_USER_NAME_LEN+1];
  562. if ( !GetUserName(Originator, &OriginatorBufLen) )
  563. {
  564. return NULL;
  565. }
  566. // altconv.h - requires this declaration for W2T to work
  567. USES_CONVERSION;
  568. // convert the provided name to a tchar; the returned tchar string is
  569. // allocated on the stack - no need to delete it
  570. TCHAR *TcharName = W2T(Name);
  571. BAIL_IF_NULL(TcharName, NULL);
  572. // allocate enough memory for the sdp blob
  573. TCHAR *SdpBlob;
  574. try
  575. {
  576. SdpBlob = new TCHAR[
  577. SDP_REG_READER::GetConfBlobTemplateLen() +
  578. lstrlen(Originator) +
  579. lstrlen(TcharName) +
  580. MAXHOSTNAME +
  581. 3*MAX_NTP_TIME_STRLEN +
  582. 2*MAX_IP_ADDRESS_STRLEN +
  583. 2*MAX_PORT_STRLEN -
  584. 2*NUM_CONF_BLOB_TEMPLATE_PARAMS
  585. ];
  586. }
  587. catch(...)
  588. {
  589. SdpBlob = NULL;
  590. }
  591. if ( NULL == SdpBlob )
  592. {
  593. SetLastError(ERROR_OUTOFMEMORY);
  594. return NULL;
  595. }
  596. //
  597. // ZoltanS: get the local host name (replaces all this IP address nonsense)
  598. //
  599. char szLocalHostName[MAXHOSTNAME + 1];
  600. char * pszHost;
  601. int WsockErrorCode;
  602. WsockErrorCode = gethostname(szLocalHostName, MAXHOSTNAME);
  603. if ( 0 == WsockErrorCode )
  604. {
  605. struct hostent *hostp = gethostbyname(szLocalHostName);
  606. if ( hostp )
  607. {
  608. pszHost = hostp->h_name;
  609. }
  610. else
  611. {
  612. // if we can't resolve our own hostname (yuck!) then we can
  613. // still do *something* (but it may be bad for l2tp scenarios).
  614. pszHost = SDP_REG_READER::GetHostIpAddress();
  615. }
  616. }
  617. else
  618. {
  619. // if we can't get a hostname (yuck!) then we can still do
  620. // *something* (but it may be bad for l2tp scenarios).
  621. pszHost = SDP_REG_READER::GetHostIpAddress();
  622. }
  623. // stprintf the string to create the conference blob
  624. // check if the stprintf operation succeeded
  625. CHAR* szCharacterSet = (CHAR*)UTF8_STRING;
  626. switch( CharacterSet )
  627. {
  628. case CS_ASCII:
  629. szCharacterSet = (CHAR*)ASCII_STRING;
  630. break;
  631. case CS_UTF7:
  632. szCharacterSet = (CHAR*)UTF7_STRING;
  633. break;
  634. }
  635. if ( 0 == _stprintf(SdpBlob,
  636. SDP_REG_READER::GetConfBlobTemplate(),
  637. Originator,
  638. GetCurrentNtpTime(),
  639. pszHost, // ZoltanS was: SDP_REG_READER::GetHostIpAddress(), // local machine ip address string,
  640. TcharName,
  641. AudioIpAddress.GetTstr(), // common c field
  642. GetCurrentNtpTime() + SDP_REG_READER::GetStartTimeOffset(), // start time - current time + start offset,
  643. GetCurrentNtpTime() + SDP_REG_READER::GetStopTimeOffset(), // stop time - current time + stop offset
  644. szCharacterSet,
  645. FirstAudioPort,
  646. FirstVideoPort,
  647. VideoIpAddress.GetTstr()
  648. ) )
  649. {
  650. delete SdpBlob;
  651. return NULL;
  652. }
  653. return SdpBlob;
  654. }
  655. HRESULT
  656. CSdpConferenceBlob::CreateDefault(
  657. IN BSTR Name,
  658. IN SDP_CHARACTER_SET CharacterSet
  659. )
  660. {
  661. BAIL_IF_NULL(Name, E_INVALIDARG);
  662. // check if the registry entries were read without errors
  663. if ( !SDP_REG_READER::IsValid() )
  664. {
  665. return HRESULT_FROM_ERROR_CODE(SDP_REG_READER::GetErrorCode());
  666. }
  667. // check if a valid conference blob already exists, return error
  668. if ( SDP_BLOB::IsValid() )
  669. {
  670. return E_FAIL;
  671. }
  672. // use the registry values to generate the default sdp
  673. CHAR *SdpBlob = GenerateSdpBlob(Name, CharacterSet);
  674. BAIL_IF_NULL(SdpBlob, HRESULT_FROM_ERROR_CODE(GetLastError()));
  675. ASSERT(NULL != SdpBlob);
  676. // parse in the sdp
  677. HRESULT HResult = SetTstr(SdpBlob);
  678. delete SdpBlob;
  679. BAIL_ON_FAILURE(HResult);
  680. HResult = ((MEDIA_COLLECTION *)m_MediaCollection)->Init(*this, GetMediaList());
  681. BAIL_ON_FAILURE(HResult);
  682. HResult = ((TIME_COLLECTION *)m_TimeCollection)->Init(*this, GetTimeList());
  683. BAIL_ON_FAILURE(HResult);
  684. return S_OK;
  685. }
  686. typedef IDispatchImpl<ITConferenceBlobVtbl<CSdpConferenceBlob>, &IID_ITConferenceBlob, &LIBID_SDPBLBLib> CTConferenceBlob;
  687. typedef IDispatchImpl<ITSdpVtbl<CSdpConferenceBlob>, &IID_ITSdp, &LIBID_SDPBLBLib> CTSdp;
  688. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  689. //
  690. // CSdpConferenceBlob::GetIDsOfNames
  691. //
  692. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  693. STDMETHODIMP CSdpConferenceBlob::GetIDsOfNames(REFIID riid,
  694. LPOLESTR* rgszNames,
  695. UINT cNames,
  696. LCID lcid,
  697. DISPID* rgdispid
  698. )
  699. {
  700. HRESULT hr = DISP_E_UNKNOWNNAME;
  701. //
  702. // See if the requsted method belongs to the default interface
  703. //
  704. hr = CTConferenceBlob::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  705. if (SUCCEEDED(hr))
  706. {
  707. rgdispid[0] |= IDISPCONFBLOB;
  708. return hr;
  709. }
  710. //
  711. // If not, then try the ITSdp base class
  712. //
  713. hr = CTSdp::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  714. if (SUCCEEDED(hr))
  715. {
  716. rgdispid[0] |= IDISPSDP;
  717. return hr;
  718. }
  719. //
  720. // If not, then try the ITConnection base class
  721. //
  722. hr = ITConnectionImpl::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  723. if (SUCCEEDED(hr))
  724. {
  725. rgdispid[0] |= IDISPCONNECTION;
  726. return hr;
  727. }
  728. //
  729. // If not, then try the ITAttributeList base class
  730. //
  731. hr = ITAttributeListImpl::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  732. if (SUCCEEDED(hr))
  733. {
  734. rgdispid[0] |= IDISPATTRLIST;
  735. return hr;
  736. }
  737. return hr;
  738. }
  739. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  740. //
  741. // CSdpConferenceBlob::Invoke
  742. //
  743. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  744. STDMETHODIMP CSdpConferenceBlob::Invoke(DISPID dispidMember,
  745. REFIID riid,
  746. LCID lcid,
  747. WORD wFlags,
  748. DISPPARAMS* pdispparams,
  749. VARIANT* pvarResult,
  750. EXCEPINFO* pexcepinfo,
  751. UINT* puArgErr
  752. )
  753. {
  754. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  755. DWORD dwInterface = (dispidMember & INTERFACEMASK);
  756. //
  757. // Call invoke for the required interface
  758. //
  759. switch (dwInterface)
  760. {
  761. case IDISPCONFBLOB:
  762. {
  763. hr = CTConferenceBlob::Invoke(dispidMember,
  764. riid,
  765. lcid,
  766. wFlags,
  767. pdispparams,
  768. pvarResult,
  769. pexcepinfo,
  770. puArgErr
  771. );
  772. break;
  773. }
  774. case IDISPSDP:
  775. {
  776. hr = CTSdp::Invoke(dispidMember,
  777. riid,
  778. lcid,
  779. wFlags,
  780. pdispparams,
  781. pvarResult,
  782. pexcepinfo,
  783. puArgErr
  784. );
  785. break;
  786. }
  787. case IDISPCONNECTION:
  788. {
  789. hr = ITConnectionImpl::Invoke(dispidMember,
  790. riid,
  791. lcid,
  792. wFlags,
  793. pdispparams,
  794. pvarResult,
  795. pexcepinfo,
  796. puArgErr
  797. );
  798. break;
  799. }
  800. case IDISPATTRLIST:
  801. {
  802. hr = ITAttributeListImpl::Invoke(dispidMember,
  803. riid,
  804. lcid,
  805. wFlags,
  806. pdispparams,
  807. pvarResult,
  808. pexcepinfo,
  809. puArgErr
  810. );
  811. break;
  812. }
  813. } // end switch (dwInterface)
  814. return hr;
  815. }
  816. BLOB_CHARACTER_SET CSdpConferenceBlob::GetBlobCharacterSet(
  817. IN BSTR bstrBlob
  818. )
  819. {
  820. BLOB_CHARACTER_SET CharSet = BCS_ASCII;
  821. const WCHAR szCharacterSet[] = L"a=charset:";
  822. WCHAR* szCharacterSetAttribute = wcsstr( bstrBlob, szCharacterSet);
  823. if( szCharacterSetAttribute == NULL)
  824. {
  825. //We don't have the attribute
  826. //We consider, for backward compability the default ASCII
  827. return CharSet;
  828. }
  829. // We have an attribute entry
  830. szCharacterSetAttribute += wcslen( szCharacterSet );
  831. if( wcsstr( szCharacterSetAttribute, L"unicode-1-1-utf8"))
  832. {
  833. CharSet = BCS_UTF8;
  834. }
  835. else if (wcsstr( szCharacterSetAttribute, L"unicode-1-1-utf7"))
  836. {
  837. CharSet = BCS_UTF7;
  838. }
  839. else if (wcsstr( szCharacterSetAttribute, L"ascii"))
  840. {
  841. CharSet = BCS_ASCII;
  842. }
  843. return CharSet;
  844. }