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.

2760 lines
84 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. socket.cpp
  5. Abstract:
  6. Implementation of CSocketManager class.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Jan-1997 DonRyan
  11. Created.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #define SOCKET_ISRX 0x01
  20. #define SOCKET_ISTX 0x02
  21. #define SOCKET_ISRXTX (SOCKET_ISRX | SOCKET_ISTX)
  22. #define DBG_DWKIND 1
  23. const char g_sPolicyLocator[] = "APP=MICROSOFT TAPI,VER=3.0";
  24. const char g_sAppName[] = "MICROSOFT TAPI";
  25. #define MAX_PROVIDERSPECIFIC_BUFFER \
  26. (sizeof(RSVP_RESERVE_INFO) + \
  27. sizeof(FLOWDESCRIPTOR) + \
  28. (sizeof(RSVP_FILTERSPEC)*MAX_FILTERS) + \
  29. sizeof(RSVP_POLICY_INFO) + \
  30. RSVP_POLICY_HDR_LEN + \
  31. (IDPE_ATTR_HDR_LEN * 2) + \
  32. MAX_QOS_NAME + \
  33. sizeof(g_sPolicyLocator) + 4 + \
  34. sizeof(g_sAppName) + 4 + \
  35. sizeof(",SAPP=UNKNOWN,SAPP="))
  36. DWORD AddQosAppID(
  37. IN OUT char *pAppIdBuf,
  38. IN WORD wBufLen,
  39. IN const char *szPolicyLocator,
  40. IN const char *szAppName,
  41. IN const char *szAppClass,
  42. IN char *szQosName
  43. );
  44. ///////////////////////////////////////////////////////////////////////////////
  45. // //
  46. // CSocketManager implementation //
  47. // //
  48. ///////////////////////////////////////////////////////////////////////////////
  49. CSocketManager::CSocketManager(
  50. )
  51. /*++
  52. Routine Description:
  53. Constructor for CSocketManager class.
  54. Arguments:
  55. None.
  56. Return Values:
  57. Returns an HRESULT value.
  58. --*/
  59. {
  60. TraceDebug((
  61. TRACE_TRACE,
  62. TRACE_DEVELOP2,
  63. TEXT("CSocketManager::CSocketManager")
  64. ));
  65. // initialize linked list of sockets
  66. InitializeListHead(&m_SharedSockets);
  67. }
  68. CSocketManager::~CSocketManager(
  69. )
  70. /*++
  71. Routine Description:
  72. Destructor for CSocketManager class.
  73. Arguments:
  74. None.
  75. Return Values:
  76. Returns an HRESULT value.
  77. --*/
  78. {
  79. TraceDebug((
  80. TRACE_TRACE,
  81. TRACE_DEVELOP2,
  82. TEXT("CSocketManager::~CSocketManager")
  83. ));
  84. // check for unaccounted for sockets
  85. if (!IsListEmpty(&m_SharedSockets)) {
  86. TraceDebug((
  87. TRACE_ERROR,
  88. TRACE_DEVELOP,
  89. TEXT("CSocketManager::~CSocketManager: Shared sockets still open")
  90. ));
  91. }
  92. }
  93. DWORD
  94. CSocketManager::GetSocket(
  95. SOCKET *pSocket,
  96. struct sockaddr_in *pAddr,
  97. struct sockaddr_in *pLocalAddr,
  98. DWORD dwScope,
  99. DWORD dwKind,
  100. WSAPROTOCOL_INFO *pProtocolInfo
  101. )
  102. /*++
  103. Routine Description:
  104. Create a socket from an address structure.
  105. Arguments:
  106. pSocket - pointer to socket which will be filled in.
  107. pAddr - pointer to destination address structure.
  108. pLocalAddr - pointer to local address structure
  109. dwScope - multicast scope used for sending.
  110. dwKind - if true, socket is just for sending.
  111. pProtocolInfo - specify the protocol to be used
  112. Return Values:
  113. Returns error code from WSAGetLastError.
  114. --*/
  115. {
  116. TraceDebug((
  117. TRACE_TRACE,
  118. TRACE_DEVELOP2,
  119. TEXT("CSocketManager::GetSocket")
  120. ));
  121. // object lock to this object
  122. CAutoLock LockThis(pStateLock());
  123. // initialize
  124. DWORD dwErr = NOERROR;
  125. BOOL fReuse;
  126. /////////////////////////////////////////////////////
  127. // If a protocol has been specified, use WSASocket(),
  128. // otherwise use socket()
  129. /////////////////////////////////////////////////////
  130. SOCKET NewSocket;
  131. int Flags = WSA_FLAG_OVERLAPPED;
  132. if (pProtocolInfo) {
  133. if (IS_MULTICAST(pAddr->sin_addr.s_addr))
  134. Flags |= WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
  135. }
  136. NewSocket = WSASocket(AF_INET, SOCK_DGRAM, 0, pProtocolInfo, 0, Flags);
  137. // validate socket handle returned
  138. if (NewSocket == INVALID_SOCKET) {
  139. // obtain last error
  140. dwErr = WSAGetLastError();
  141. TraceDebug((
  142. TRACE_ERROR,
  143. TRACE_DEVELOP,
  144. TEXT("CSocketManager::GetSocket: failed %d"),
  145. dwErr
  146. ));
  147. goto cleanup; // bail...
  148. }
  149. struct sockaddr_in LocalAddr;
  150. // initialize
  151. LocalAddr.sin_family = AF_INET;
  152. LocalAddr.sin_addr = pLocalAddr->sin_addr;
  153. //INADDR_ANY;
  154. // determine whether we need to specify particular port
  155. LocalAddr.sin_port =
  156. (dwKind & SOCKET_MASK_RECV)? pAddr->sin_port : htons(0);
  157. // set socket options required before binding
  158. //if (IS_MULTICAST(pAddr->sin_addr.s_addr)) {
  159. fReuse = TRUE;
  160. if (setsockopt(
  161. NewSocket,
  162. SOL_SOCKET,
  163. SO_REUSEADDR,
  164. (PCHAR)&fReuse,
  165. sizeof(fReuse)
  166. ) == SOCKET_ERROR) {
  167. // obtain last error
  168. dwErr = WSAGetLastError();
  169. TraceDebug((
  170. TRACE_ERROR,
  171. TRACE_DEVELOP,
  172. TEXT("Could not modify REUSEADDR: %d"),
  173. dwErr
  174. ));
  175. goto cleanup; // bail...
  176. }
  177. // bind rtp socket to the local address specified
  178. if (bind(NewSocket, (sockaddr *)&LocalAddr, sizeof(LocalAddr))) {
  179. // obtain last error
  180. dwErr = WSAGetLastError();
  181. TraceDebug((
  182. TRACE_ERROR,
  183. TRACE_DEVELOP,
  184. TEXT("bind returned %d"),
  185. dwErr
  186. ));
  187. goto cleanup; // bail...
  188. }
  189. // set socket options required after binding
  190. // receiving?
  191. if ( (dwKind & SOCKET_MASK_RECV) ) {
  192. if (IS_MULTICAST(pAddr->sin_addr.s_addr)) {
  193. struct ip_mreq mreq;
  194. // initialize multicast group address
  195. mreq.imr_multiaddr.s_addr = pAddr->sin_addr.s_addr;
  196. mreq.imr_interface.s_addr = INADDR_ANY;
  197. // join multicast group
  198. if(setsockopt(NewSocket,
  199. IPPROTO_IP,
  200. IP_ADD_MEMBERSHIP,
  201. (char*)&mreq,
  202. sizeof(mreq)
  203. ) == SOCKET_ERROR) {
  204. // obtain last error
  205. dwErr = WSAGetLastError();
  206. TraceDebug((
  207. TRACE_ERROR,
  208. TRACE_DEVELOP,
  209. TEXT("Could not join multicast group %d"),
  210. dwErr
  211. ));
  212. goto cleanup; // bail...
  213. }
  214. }
  215. }
  216. // transmitting?
  217. if ( (dwKind & SOCKET_MASK_SEND) ) {
  218. // set ttl
  219. if (setsockopt(
  220. NewSocket,
  221. IPPROTO_IP,
  222. IP_MULTICAST_TTL,
  223. (PCHAR)&dwScope,
  224. sizeof(dwScope)
  225. ) == SOCKET_ERROR) {
  226. // obtain last error
  227. dwErr = WSAGetLastError();
  228. TraceDebug((
  229. TRACE_ERROR,
  230. TRACE_DEVELOP,
  231. TEXT("Could not modify time-to-live %d"),
  232. dwErr
  233. ));
  234. goto cleanup; // bail...
  235. }
  236. }
  237. // copy new socket
  238. *pSocket = NewSocket;
  239. return NOERROR;
  240. cleanup:
  241. // see if we created socket
  242. if (NewSocket != INVALID_SOCKET) {
  243. // make sure socket is closed
  244. if (closesocket(NewSocket)) {
  245. TraceDebug((
  246. TRACE_ERROR,
  247. TRACE_DEVELOP,
  248. TEXT("closesocket returned %d"),
  249. WSAGetLastError()
  250. ));
  251. }
  252. }
  253. return dwErr;
  254. }
  255. DWORD
  256. CSocketManager::ReleaseSocket(
  257. SOCKET Socket
  258. )
  259. /*++
  260. Routine Description:
  261. Releases a socket.
  262. Arguments:
  263. Socket - socket to release.
  264. Return Values:
  265. Returns error code from WSAGetLastError.
  266. --*/
  267. {
  268. TraceDebug((
  269. TRACE_TRACE,
  270. TRACE_DEVELOP2,
  271. TEXT("CSocketManager::ReleaseSocket")
  272. ));
  273. // object lock to this object
  274. CAutoLock LockThis(pStateLock());
  275. DWORD dwErr = NOERROR;
  276. // see if we created socket
  277. if (Socket != INVALID_SOCKET) {
  278. // make sure socket closed
  279. if (closesocket(Socket)) {
  280. // retrieve error code
  281. dwErr = WSAGetLastError();
  282. TraceDebug((
  283. TRACE_ERROR,
  284. TRACE_DEVELOP2,
  285. TEXT("closesocket returned %d"),
  286. dwErr
  287. ));
  288. }
  289. }
  290. return dwErr;
  291. }
  292. /* Sockets are shared IF the source and destination address/port
  293. * match, AND the cookie matches AND the QOS state matches.
  294. *
  295. * They are matched provided the max number of receiver(s) and/or
  296. * sender(s) hasn't been reached.
  297. *
  298. * local remote cookie local Addr remote Addr QOS enabled
  299. * ======= ======= ======= =========== =========== =========
  300. * Receiver: RlocRTP 0 RCookie RlocAddr RremAddr RQOSstate
  301. * Sender: 0 SremRTP SCookie SlocAddr SremAddr SQOSstate
  302. *
  303. * The RTP sockets for sender and receiver will be matched provided
  304. * ALL the colums match, the wildcard value (0) matches anything.
  305. *
  306. * The RTCP sockets will be matched following the same rules, except
  307. * that in local and remote port, I will have the RTCP ports:
  308. *
  309. * local remote cookie local Addr remote Addr QOS enabled
  310. * ======= ======= ======= =========== =========== =========
  311. * Receiver: RlocRTCP RremRTCP RCookie RlocAddr RremAddr RQOSstate
  312. * Sender: SlocRTCP SremRTCP SCookie SlocAddr SremAddr SQOSstate
  313. *
  314. * The cookie is constructed using the local and remote RTCP ports
  315. *
  316. * For a sender and a receiver that should belong to the same RTP/RTCP
  317. * session, the session may end having 2 or 3 sockets depending on the
  318. * order on which the receiver and sender are started, and depending
  319. * on the use of wildcard ports (port 0 is the wildcard value).
  320. *
  321. * The different scenarios are as follow:
  322. *
  323. * 1. If wildcard is not used, and since the beggining both, receiver
  324. * and sender, receive the right local and remote ports (which will be
  325. * the same for the receiver and sender), then the sockets will be
  326. * shared no matter the order on which the receiver and sender
  327. * starts. The RTP/RTCP session will have 2 sockets.
  328. *
  329. * 2. Wildcard ports are used, i.e. the sender specify a local port 0,
  330. * and the receiver specifies a remote port 0, and the sender starts
  331. * first. In this case, as the socket needs to be bound (QOS), the
  332. * local port is system assigned, when the receiver is started,
  333. * everything will match except the local ports, so a new socket will
  334. * be created. The RTP/RTCP session will have 3 sockets.
  335. *
  336. * 3. Wildcard ports are used, i.e. the sender specify a local port 0,
  337. * and the receiver specifies a remote port 0, and the receiver starts
  338. * first. In this case, when the sender starts with a wildcard local
  339. * port, everything will match and the socket will be shared for the
  340. * receiver and sender. The RTP/RTCP session will have 2 sockets.
  341. *
  342. * The RTP/RTCP session is shared based on the 3 sockets (RTPRecv,
  343. * RTPSend, RTCP), in some cases of course RTPRecv == RTPSend. */
  344. DWORD
  345. CSocketManager::GetSharedSocket(
  346. CShSocket **ppCShSocket,
  347. long *pMaxShare,
  348. DWORD cookie,
  349. DWORD *pAddr,
  350. WORD *pPort,
  351. DWORD dwScope,
  352. DWORD dwKind,
  353. WSAPROTOCOL_INFO *pProtocolInfo,
  354. DWORD dwMaxFilters,
  355. CRtpSession *pCRtpSession
  356. )
  357. /*++
  358. Routine Description:
  359. Create a shared socket from an address structure.
  360. Arguments:
  361. pAddr - pointer to local/remote address.
  362. pPort - pointer to local/remote port.
  363. pSocket - pointer to socket which will be filled in.
  364. dwScope - multicast scope used for sending.
  365. Return Values:
  366. Returns error code from WSAGetLastError.
  367. --*/
  368. {
  369. HRESULT hr;
  370. if (!ppCShSocket || !pAddr[LOCAL] || !pAddr[REMOTE]) {
  371. TraceDebug((
  372. TRACE_TRACE,
  373. TRACE_DEVELOP,
  374. TEXT("CSocketManager::GetSharedSocket: "
  375. "failed: NULL pointer")
  376. ));
  377. return(E_POINTER);
  378. }
  379. char remaddr[RTPNTOASIZE];
  380. char locaddr[RTPNTOASIZE];
  381. RtpNtoA(pAddr[LOCAL], locaddr);
  382. RtpNtoA(pAddr[REMOTE], remaddr);
  383. TraceRetail((
  384. TRACE_TRACE,
  385. TRACE_DEVELOP,
  386. TEXT("CSocketManager::GetSharedSocket: TTL:%d "
  387. "Local:%s/%d Remote:%s/%d Get(%d,%d), "
  388. "Max(%d,%d), Cook(%d,%d), Ini(%s,%s), QOS(%d,%d)"),
  389. dwScope,
  390. locaddr, ntohs(pPort[LOCAL]),
  391. remaddr, ntohs(pPort[REMOTE]),
  392. (dwKind & SOCKET_MASK_RECV)? 1:0,
  393. (dwKind & SOCKET_MASK_SEND)? 1:0,
  394. pMaxShare[0], pMaxShare[1],
  395. ntohs((WORD)(cookie & 0xffff)), ntohs((WORD)(cookie >> 16)),
  396. (dwKind & SOCKET_MASK_INIT_RECV)? "R":"-",
  397. (dwKind & SOCKET_MASK_INIT_SEND)? "S":"-",
  398. ((dwKind & SOCKET_MASK_QOS_SES) != 0),
  399. ((dwKind & SOCKET_MASK_QOS_RQ) != 0)
  400. ));
  401. if ( ((struct in_addr *)&pAddr[REMOTE])->s_addr == INADDR_ANY ) {
  402. // I may add a check against the local IP address(es)
  403. TraceRetail((
  404. TRACE_TRACE,
  405. TRACE_DEVELOP,
  406. TEXT("CSocketManager::GetSharedSocket: "
  407. "failed: remote address == INADDR_ANY")
  408. ));
  409. return(E_INVALIDARG);
  410. }
  411. *ppCShSocket = NULL;
  412. if (!(dwKind & SOCKET_MASK_RS)) {
  413. TraceDebug((
  414. TRACE_TRACE,
  415. TRACE_DEVELOP,
  416. TEXT("CSocketManager::GetSharedSocket: "
  417. "failed: no kind specified")
  418. ));
  419. return(E_INVALIDARG);
  420. }
  421. // object lock to this object
  422. CAutoLock LockThis(pStateLock());
  423. PLIST_ENTRY pLE;
  424. CShSocket *pCShSocket;
  425. BOOL found = FALSE;
  426. int count;
  427. // loop through shared sockets
  428. for(pLE = m_SharedSockets.Flink, count = 0;
  429. !found && (pLE != &m_SharedSockets);
  430. pLE = pLE->Flink, count++) {
  431. // obtain shared socket entry from list entry
  432. pCShSocket = CONTAINING_RECORD(pLE, CShSocket, Link);
  433. // check cookie
  434. if (cookie != pCShSocket->GetCookie())
  435. continue; // do not match
  436. // find out if local and remote address/port match with
  437. // current, take into account wildcard values
  438. // (in this case that is 0)
  439. DWORD match = 0;
  440. DWORD match_bit = 0x1;
  441. for(DWORD p = LOCAL; p <= REMOTE; p++) {
  442. // port
  443. if ( (p == REMOTE) && (dwKind & SOCKET_MASK_RTCPMATCH) ) {
  444. match |= match_bit; /* force remote port to match
  445. * (used for RTCP) */
  446. } else {
  447. if (!pCShSocket->GetPort(p) || !pPort[p])
  448. match |= match_bit; // wildcard port match
  449. else if (pCShSocket->GetPort(p) == pPort[p])
  450. match |= match_bit; // same port match
  451. else
  452. break; // doesn't match, no need to continue
  453. }
  454. match_bit <<= 1;
  455. // address
  456. if (!pCShSocket->GetAddress(p) || !pAddr[p])
  457. match |= match_bit; // wildcard address match
  458. else if (pCShSocket->GetAddress(p) == pAddr[p])
  459. match |= match_bit; // same address match
  460. else
  461. break; // doesn't match, no need to continue
  462. match_bit <<= 1;
  463. }
  464. if (match == 0xf) {
  465. // local and remote address/port DO match
  466. found = TRUE;
  467. for(DWORD k = SOCKET_FIRST; k < SOCKET_LAST; k++) {
  468. if ( ( (dwKind & SOCKET_MASK(k)) &&
  469. ( (pCShSocket->GetRefCount(k) >= pMaxShare[k]) ||
  470. (pCShSocket->GetRefCount(k) >=
  471. pCShSocket->GetMaxCount(k)) ) )
  472. ||
  473. ((dwKind & SOCKET_MASK_QOS_SES) !=
  474. (pCShSocket->GetKind() & SOCKET_MASK_QOS_SES)) ) {
  475. // This kind (recv/send) already exists
  476. #if defined(DEBUG)
  477. DWORD addr;
  478. addr = pCShSocket->GetAddress(LOCAL);
  479. RtpNtoA(addr, locaddr);
  480. addr = pCShSocket->GetAddress(REMOTE);
  481. RtpNtoA(addr, remaddr);
  482. TraceDebug((
  483. TRACE_TRACE,
  484. TRACE_DEVELOP,
  485. TEXT("CSocketManager::GetSharedSocket: "
  486. "Full socket %d:%s/%d-%s/%d "
  487. "Cook(%d, %d), "
  488. "Cur(%d,%d), Lim(%d,%d), "
  489. "Ini(%s,%s), "
  490. "QOS(%d,%d), Ctx(0x%X,0x%X)"
  491. ),
  492. pCShSocket->GetShSocket(),
  493. locaddr,
  494. ntohs(pCShSocket->GetPort(LOCAL)),
  495. remaddr,
  496. ntohs(pCShSocket->GetPort(REMOTE)),
  497. ntohs((WORD)(cookie & 0xffff)),
  498. ntohs((WORD)(cookie >> 16)),
  499. pCShSocket->GetRefCount(SOCKET_RECV),
  500. pCShSocket->GetRefCount(SOCKET_SEND),
  501. pCShSocket->GetMaxCount(SOCKET_RECV),
  502. pCShSocket->GetMaxCount(SOCKET_SEND),
  503. (pCShSocket->GetKind() & SOCKET_MASK_INIT_RECV) ?
  504. "R":"-",
  505. (pCShSocket->GetKind() & SOCKET_MASK_INIT_SEND) ?
  506. "S":"-",
  507. pCShSocket->IsQOSSession(),
  508. pCShSocket->IsQOSEnabled(),
  509. pCShSocket->m_pCRtpSession[SOCKET_RECV],
  510. pCShSocket->m_pCRtpSession[SOCKET_SEND]
  511. ));
  512. #endif
  513. // If multicast, create a new socket,
  514. // if unicast, fail!
  515. // Actually do not fail in unicast either
  516. // In both cases create a new socket
  517. found = FALSE;
  518. }
  519. }
  520. if (found) {
  521. // initialize wildcards to right value
  522. for(DWORD p = LOCAL; p <= REMOTE; p++) {
  523. // wildcard port
  524. if (!pCShSocket->GetPort(p)) {
  525. pCShSocket->SetPort(p, pPort[p]);
  526. }
  527. // wildcard address
  528. if (!pCShSocket->GetAddress(p)) {
  529. pCShSocket->SetAddress(p, pAddr[p]);
  530. }
  531. }
  532. TraceDebug((
  533. TRACE_TRACE,
  534. TRACE_DEVELOP,
  535. TEXT("CSocketManager::GetSharedSocket: "
  536. "requested socket %d already created."),
  537. pCShSocket->GetShSocket()
  538. ));
  539. }
  540. }
  541. }
  542. if (!found) {
  543. // Allocate new shared socket structure
  544. pCShSocket = new CShSocket(pAddr[REMOTE],
  545. pMaxShare,
  546. pProtocolInfo,
  547. dwMaxFilters,
  548. &hr);
  549. if (!pCShSocket) {
  550. TraceRetail((
  551. TRACE_ERROR,
  552. TRACE_DEVELOP,
  553. TEXT("CSocketManager::GetSharedSocket: "
  554. "out of memory: %d"),
  555. GetLastError()
  556. ));
  557. return(E_FAIL);
  558. } else if (FAILED(hr)) {
  559. TraceRetail((
  560. TRACE_ERROR,
  561. TRACE_DEVELOP,
  562. TEXT("CSocketManager::GetSharedSocket: "
  563. "failed: 0x%X"),
  564. hr
  565. ));
  566. pCShSocket->CloseSocket();
  567. delete pCShSocket;
  568. return(E_FAIL);
  569. } else {
  570. TraceRetail((
  571. TRACE_TRACE,
  572. TRACE_DEVELOP,
  573. TEXT("CSocketManager::GetSharedSocket: "
  574. "New socket created: %d"),
  575. pCShSocket->GetShSocket()
  576. ));
  577. }
  578. // Save local and remote address/port (including wildcards)
  579. for(DWORD p = LOCAL; p <= REMOTE; p++) {
  580. // port
  581. pCShSocket->SetPort(p, pPort[p]);
  582. // address
  583. pCShSocket->SetAddress(p, pAddr[p]);
  584. }
  585. pCShSocket->SetCookie(cookie);
  586. // Insert to list of shared sockets
  587. InsertHeadList(&m_SharedSockets, &pCShSocket->Link);
  588. pCShSocket->SetKind(dwKind & SOCKET_MASK_QOS_SES);
  589. pCShSocket->SetKind(dwKind & SOCKET_MASK_QOS_RQ);
  590. }
  591. // Now some final socket options may be requiered
  592. int errorR = 0;
  593. // Set socket kind and add ref count for that kind
  594. if (dwKind & SOCKET_MASK_RECV) {
  595. pCShSocket->AddRefCount(SOCKET_RECV);
  596. pCShSocket->SetKind(SOCKET_MASK_RECV);
  597. }
  598. // Do this just once per socket per receiver
  599. if ( (dwKind & SOCKET_MASK_INIT_RECV) &&
  600. !pCShSocket->GetInit(SOCKET_MASK_INIT_RECV) ) {
  601. // Mark socket as initialized for RECV
  602. pCShSocket->SetInit(SOCKET_MASK_INIT_RECV);
  603. if (!errorR && !pCShSocket->GetInit(SOCKET_MASK_INIT_BIND)) {
  604. pCShSocket->SetInit(SOCKET_MASK_INIT_BIND);
  605. SOCKADDR_IN localaddr;
  606. ZeroMemory(&localaddr, sizeof(localaddr));
  607. SOCKET sock = pCShSocket->GetShSocket();
  608. DWORD addr;
  609. addr = pCShSocket->GetAddress(LOCAL);
  610. localaddr.sin_family = AF_INET;
  611. localaddr.sin_addr = *(struct in_addr *) &addr;
  612. localaddr.sin_port = pCShSocket->GetPort(LOCAL);
  613. // bind rtp socket to the local address specified
  614. if (bind(sock, (SOCKADDR *)&localaddr, sizeof(localaddr))) {
  615. // obtain last error
  616. TraceRetail((
  617. TRACE_ERROR,
  618. TRACE_DEVELOP,
  619. TEXT("CSocketManager::GetSharedSocket: "
  620. "RECV bind(%d) port: %d failed: %d"),
  621. sock, ntohs(localaddr.sin_port), WSAGetLastError()
  622. ));
  623. errorR++;
  624. } else if (!pCShSocket->GetPort(LOCAL)) {
  625. /* if local port was assigned by the system, we need
  626. * to update its value, we don't want the wildcard (0)
  627. * to remain, because if it does, the socket may be
  628. * erroneously shared with another socket requesting
  629. * an specific local port */
  630. int localaddrlen = sizeof(localaddr);
  631. if (!getsockname(sock,
  632. (struct sockaddr *)&localaddr,
  633. &localaddrlen)) {
  634. pCShSocket->SetPort(LOCAL, localaddr.sin_port);
  635. }
  636. }
  637. }
  638. if (!errorR) {
  639. if (IS_MULTICAST(pAddr[REMOTE])) {
  640. // Join the group for receivers
  641. SOCKADDR_IN joinaddr;
  642. ZeroMemory(&joinaddr, sizeof(joinaddr));
  643. DWORD addr;
  644. addr = pCShSocket->GetAddress(REMOTE);
  645. joinaddr.sin_family = AF_INET;
  646. joinaddr.sin_addr = *(struct in_addr *) &addr;
  647. joinaddr.sin_port = pCShSocket->GetPort(REMOTE);
  648. if (WSAJoinLeaf(pCShSocket->GetShSocket(),
  649. (const struct sockaddr *)&joinaddr,
  650. sizeof(joinaddr),
  651. NULL, NULL, NULL, NULL,
  652. JL_RECEIVER_ONLY) == INVALID_SOCKET) {
  653. errorR++;
  654. TraceRetail((
  655. TRACE_ERROR,
  656. TRACE_DEVELOP,
  657. TEXT("CSocketManager::GetSharedSocket: "
  658. "WSAJoinLeaf(RECEIVER) failed: %d"),
  659. WSAGetLastError()
  660. ));
  661. } else {
  662. TraceRetail((
  663. TRACE_TRACE,
  664. TRACE_DEVELOP,
  665. TEXT("CSocketManager::GetSharedSocket: "
  666. "WSAJoinLeaf(RECEIVER) succeded")
  667. ));
  668. }
  669. }
  670. }
  671. }
  672. int errorS = 0;
  673. // Set socket kind and add ref count for that kind
  674. if (dwKind & SOCKET_MASK_SEND) {
  675. pCShSocket->AddRefCount(SOCKET_SEND);
  676. pCShSocket->SetKind(SOCKET_MASK_SEND);
  677. }
  678. // Do this just once per socket per sender
  679. if ( (dwKind & SOCKET_MASK_INIT_SEND) &&
  680. !pCShSocket->GetInit(SOCKET_MASK_INIT_SEND) ) {
  681. // Mark socket as initialized for SEND
  682. pCShSocket->SetInit(SOCKET_MASK_INIT_SEND);
  683. if (!errorS && !pCShSocket->GetInit(SOCKET_MASK_INIT_BIND)) {
  684. pCShSocket->SetInit(SOCKET_MASK_INIT_BIND);
  685. SOCKADDR_IN localaddr;
  686. ZeroMemory(&localaddr, sizeof(localaddr));
  687. SOCKET sock = pCShSocket->GetShSocket();
  688. DWORD addr;
  689. addr = pCShSocket->GetAddress(LOCAL);
  690. localaddr.sin_family = AF_INET;
  691. localaddr.sin_addr = *(struct in_addr *) &addr;
  692. localaddr.sin_port = pCShSocket->GetPort(LOCAL);
  693. // bind rtp socket to the local address specified
  694. if (bind(sock, (SOCKADDR *)&localaddr, sizeof(localaddr))) {
  695. // obtain last error
  696. TraceRetail((
  697. TRACE_ERROR,
  698. TRACE_DEVELOP,
  699. TEXT("CSocketManager::GetSharedSocket: "
  700. "SEND bind(%d) port:%d failed:%d"),
  701. sock, ntohs(localaddr.sin_port), WSAGetLastError()
  702. ));
  703. errorS++;
  704. } else if (!pCShSocket->GetPort(LOCAL)) {
  705. /* if local port was assigned by the system, we need
  706. * to update its value, we don't want the wildcard (0)
  707. * to remain, because if it does, the socket may be
  708. * erroneously shared with another socket requesting
  709. * an specific local port */
  710. int localaddrlen = sizeof(localaddr);
  711. if (!getsockname(sock,
  712. (struct sockaddr *)&localaddr,
  713. &localaddrlen)) {
  714. pCShSocket->SetPort(LOCAL, localaddr.sin_port);
  715. }
  716. }
  717. }
  718. // TTL for senders
  719. if (!errorS) {
  720. if (setsockopt(
  721. pCShSocket->GetShSocket(),
  722. IPPROTO_IP,
  723. IS_MULTICAST(pAddr[REMOTE])?
  724. IP_MULTICAST_TTL : IP_TTL,
  725. (PCHAR)&dwScope,
  726. sizeof(dwScope)
  727. ) == SOCKET_ERROR) {
  728. DWORD dwError = WSAGetLastError();
  729. // Only Administrators can change TTL,
  730. // that is not a reason to fail altogether
  731. if (dwError != WSAEACCES)
  732. errorS++;
  733. TraceRetail((
  734. TRACE_ERROR,
  735. TRACE_DEVELOP,
  736. TEXT("CSocketManager::GetSharedSocket: "
  737. "setsockopt(%s)=%d failed: %d"),
  738. IS_MULTICAST(pAddr[REMOTE])?
  739. "IP_MULTICAST_TTL" : "IP_TTL",
  740. dwScope,
  741. dwError
  742. ));
  743. }
  744. }
  745. if (!errorS) {
  746. if (IS_MULTICAST(pAddr[REMOTE])) {
  747. // Set multicast address
  748. SOCKADDR_IN joinaddr;
  749. ZeroMemory(&joinaddr, sizeof(joinaddr));
  750. DWORD addr;
  751. addr = pCShSocket->GetAddress(REMOTE);
  752. joinaddr.sin_family = AF_INET;
  753. joinaddr.sin_addr = *(struct in_addr *) &addr;
  754. joinaddr.sin_port = pCShSocket->GetPort(REMOTE);
  755. if (WSAJoinLeaf(pCShSocket->GetShSocket(),
  756. (const struct sockaddr *)&joinaddr,
  757. sizeof(joinaddr),
  758. NULL, NULL, NULL, NULL,
  759. JL_SENDER_ONLY) == INVALID_SOCKET) {
  760. errorS++;
  761. TraceRetail((
  762. TRACE_ERROR,
  763. TRACE_DEVELOP,
  764. TEXT("CSocketManager::GetSharedSocket: "
  765. "WSAJoinLeaf(SENDER) failed: %d"),
  766. WSAGetLastError()
  767. ));
  768. } else {
  769. TraceRetail((
  770. TRACE_TRACE,
  771. TRACE_DEVELOP,
  772. TEXT("CSocketManager::GetSharedSocket: "
  773. "WSAJoinLeaf(SENDER) succeded")
  774. ));
  775. }
  776. }
  777. }
  778. }
  779. if (pCRtpSession) {
  780. if (pCRtpSession->IsSender()) {
  781. pCShSocket->m_pCRtpSession[SOCKET_SEND] = pCRtpSession;
  782. pCShSocket->m_pCRtpSession2[SOCKET_SEND] = pCRtpSession;
  783. } else {
  784. pCShSocket->m_pCRtpSession[SOCKET_RECV] = pCRtpSession;
  785. pCShSocket->m_pCRtpSession2[SOCKET_RECV] = pCRtpSession;
  786. }
  787. }
  788. ///////////////////////////////////////////////
  789. #if defined(DEBUG)
  790. {
  791. TraceDebug((
  792. TRACE_TRACE,
  793. TRACE_DEVELOP2,
  794. TEXT("CSocketManager::GetSharedSocket: "
  795. "Searched on %d elements =================="),
  796. count
  797. ));
  798. char Str[512];
  799. CShSocket *pCShSocket;
  800. for(pLE = m_SharedSockets.Flink;
  801. pLE != &m_SharedSockets;
  802. pLE = pLE->Flink) {
  803. DWORD addr;
  804. // obtain shared socket entry from list entry
  805. pCShSocket = CONTAINING_RECORD(pLE, CShSocket, Link);
  806. addr = pCShSocket->GetAddress(LOCAL);
  807. RtpNtoA(addr, locaddr);
  808. addr = pCShSocket->GetAddress(REMOTE);
  809. RtpNtoA(addr, remaddr);
  810. wsprintf(Str,
  811. " {%d:%s/%05d-%s/%05d Cur(%d,%d), Max(%d,%d), "
  812. "Cook(%05d,%05d), "
  813. "Ini(%s,%s), QOS(%d,%d), Ctx(0x%X,0x%X)}",
  814. pCShSocket->GetShSocket(),
  815. locaddr, ntohs(pCShSocket->GetPort(LOCAL)),
  816. remaddr, ntohs(pCShSocket->GetPort(REMOTE)),
  817. pCShSocket->GetRefCount(0),
  818. pCShSocket->GetRefCount(1),
  819. pCShSocket->GetMaxCount(0),
  820. pCShSocket->GetMaxCount(1),
  821. ntohs((WORD)(pCShSocket->GetCookie() & 0xffff)),
  822. ntohs((WORD)(pCShSocket->GetCookie() >> 16)),
  823. (pCShSocket->GetKind() & SOCKET_MASK_INIT_RECV)? "R":"-",
  824. (pCShSocket->GetKind() & SOCKET_MASK_INIT_SEND)? "S":"-",
  825. pCShSocket->IsQOSSession(),
  826. pCShSocket->IsQOSEnabled(),
  827. pCShSocket->m_pCRtpSession[SOCKET_RECV],
  828. pCShSocket->m_pCRtpSession[SOCKET_SEND]
  829. );
  830. TraceDebug((
  831. TRACE_TRACE,
  832. TRACE_DEVELOP,
  833. TEXT("%s"), Str
  834. ));
  835. }
  836. }
  837. #endif
  838. ///////////////////////////////////////////////
  839. if (errorR)
  840. ReleaseSharedSocket(pCShSocket, SOCKET_MASK_RECV, pCRtpSession);
  841. if (errorS)
  842. ReleaseSharedSocket(pCShSocket, SOCKET_MASK_SEND, pCRtpSession);
  843. if (errorR + errorS)
  844. return(E_FAIL);
  845. *ppCShSocket = pCShSocket;
  846. return(NOERROR);
  847. }
  848. DWORD
  849. CSocketManager::ReleaseSharedSocket(CShSocket *pCShSocket, DWORD dwKind,
  850. CRtpSession *pCRtpSession)
  851. /*++
  852. Routine Description:
  853. Releases a shared socket (RTCP).
  854. Arguments:
  855. Socket - shared socket to release.
  856. Return Values:
  857. Returns error code from WSAGetLastError.
  858. --*/
  859. {
  860. CShSocket *pCShSocket2;
  861. PLIST_ENTRY pLE;
  862. CheckPointer(pCShSocket, E_POINTER);
  863. TraceRetail((
  864. TRACE_TRACE,
  865. TRACE_DEVELOP,
  866. TEXT("CSocketManager::ReleaseSharedSocket: %d"),
  867. pCShSocket->GetShSocket()
  868. ));
  869. // object lock to this object
  870. CAutoLock LockThis(pStateLock());
  871. PRTP_SESSION pRTPSession = (PRTP_SESSION)NULL;
  872. if (pCRtpSession->GetpRTPSession()) {
  873. // This code to debug the hang in RTCP
  874. pRTPSession = pCRtpSession->GetpRTPSession();
  875. }
  876. // obtain pointer to first
  877. pLE = m_SharedSockets.Flink;
  878. // loop through shared sockets to make shure this exist
  879. while (pLE != &m_SharedSockets) {
  880. // obtain shared socket entry from list entry
  881. pCShSocket2 = CONTAINING_RECORD(pLE, CShSocket, Link);
  882. // check for matching socket
  883. if (pCShSocket == pCShSocket2) {
  884. SOCKET sock = pCShSocket->GetShSocket();
  885. DWORD mask = 0x1;
  886. if (pRTPSession) {
  887. for(DWORD s = SOCK_RECV; s <= SOCK_RTCP; s++) {
  888. if (sock == pRTPSession->pSocket[s])
  889. break;
  890. else
  891. mask <<= 1;
  892. }
  893. #if defined(DEBUG)
  894. if (mask > (1<<SOCK_RTCP)) {
  895. char str[256];
  896. wsprintf(str,
  897. "CShSocket[0x%X] socket=%d "
  898. "m_pCRtpSession[0x%X - 0x%X, 0x%X - 0x%X]\n"
  899. "CRtpSession[0x%X] RTPSession[0x%X]\n",
  900. pCShSocket, sock,
  901. pCShSocket->m_pCRtpSession[0],
  902. pCShSocket->m_pCRtpSession2[0],
  903. pCShSocket->m_pCRtpSession[1],
  904. pCShSocket->m_pCRtpSession2[1],
  905. pCRtpSession, pRTPSession);
  906. OutputDebugString(str);
  907. //DebugBreak();
  908. }
  909. #endif
  910. }
  911. for(DWORD k = SOCKET_FIRST; k < SOCKET_LAST; k++) {
  912. if (dwKind & SOCKET_MASK(k) & pCShSocket->GetKind()) {
  913. // This kind (recv/send) exists
  914. if (pCShSocket->GetRefCount(k) > 1)
  915. if (pRTPSession)
  916. pRTPSession->dwStatus |= (mask << 24);
  917. if (!pCShSocket->DelRefCount(k)) {
  918. // if no more refs, reset kind and
  919. // null the RtpSession pointer
  920. pCShSocket->RstKind(SOCKET_MASK(k));
  921. pCShSocket->m_pCRtpSession[k] = NULL;
  922. }
  923. }
  924. }
  925. if (!pCShSocket->GetRefCountAll()) {
  926. RemoveEntryList(&pCShSocket->Link);
  927. HRESULT hr = pCShSocket->CloseSocket();
  928. delete pCShSocket;
  929. if (pRTPSession) {
  930. if (!pRTPSession->dwCloseTime)
  931. pRTPSession->dwCloseTime = GetTickCount();
  932. if (FAILED(hr)) {
  933. // Close socket failed
  934. pRTPSession->dwLastError = WSAGetLastError();
  935. pRTPSession->dwStatus |= (mask << 4);
  936. } else {
  937. pRTPSession->dwStatus |= mask;
  938. }
  939. }
  940. return(hr);
  941. } else {
  942. if (pRTPSession)
  943. pRTPSession->dwStatus |= (mask << 8);
  944. }
  945. return(NOERROR);
  946. }
  947. // goto next pointer
  948. pLE = pLE->Flink;
  949. }
  950. if (pRTPSession) {
  951. if (pRTPSession->dwStatus & (1<<12))
  952. pRTPSession->dwStatus |= (1<<13);
  953. else
  954. pRTPSession->dwStatus |= (1<<12);
  955. }
  956. TraceRetail((
  957. TRACE_ERROR,
  958. TRACE_DEVELOP,
  959. TEXT("CSocketManager::ReleaseSharedSocket: "
  960. "failed: structure not found: %d"),
  961. pCShSocket->GetShSocket()
  962. ));
  963. // Structure not found
  964. return(E_INVALIDARG);
  965. }
  966. //////////////////////////////////////////////////////////////////////
  967. //
  968. // CShSocket
  969. //
  970. //////////////////////////////////////////////////////////////////////
  971. CShSocket::CShSocket(DWORD dwRemAddr,
  972. long *plMaxShare,
  973. WSAPROTOCOL_INFO *pProtocolInfo,
  974. DWORD dwMaxFilters,
  975. HRESULT *phr)
  976. {
  977. TraceDebug((
  978. TRACE_TRACE,
  979. TRACE_DEVELOP,
  980. TEXT("CShSocket::CShSocket(%d,%d)"),
  981. plMaxShare[0], plMaxShare[1]
  982. ));
  983. // Create a new socket
  984. int Flags = WSA_FLAG_OVERLAPPED;
  985. BOOL fReuse;
  986. DWORD dwLoopBack = 0;
  987. ZeroMemory(this, sizeof(CShSocket));
  988. // Record the limits
  989. m_MaxCount[0] = plMaxShare[0];
  990. m_MaxCount[1] = plMaxShare[1];
  991. if (pProtocolInfo) {
  992. // Asking for QOS, reserve the requiered structure
  993. // for the QOS reservation
  994. m_pCRtpQOSReserve = new CRtpQOSReserve(this, dwMaxFilters);
  995. if (!m_pCRtpQOSReserve) {
  996. // Log info about success/failure,
  997. // may also notify or fail.
  998. // TODO
  999. goto cleanup;
  1000. }
  1001. }
  1002. if (IS_MULTICAST(dwRemAddr))
  1003. Flags |= WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;
  1004. m_Socket = WSASocket(AF_INET, SOCK_DGRAM, 0,
  1005. pProtocolInfo, 0, Flags);
  1006. // validate socket handle returned
  1007. if (m_Socket == INVALID_SOCKET) {
  1008. // obtain last error
  1009. TraceDebug((
  1010. TRACE_ERROR,
  1011. TRACE_DEVELOP,
  1012. TEXT("CShSocket::CShSocket: failed %d"),
  1013. WSAGetLastError()
  1014. ));
  1015. goto cleanup;
  1016. }
  1017. #if 0
  1018. // XXX: Don't close the handle so a second close will break
  1019. SetHandleInformation((HANDLE)m_Socket,
  1020. HANDLE_FLAG_PROTECT_FROM_CLOSE,
  1021. HANDLE_FLAG_PROTECT_FROM_CLOSE);
  1022. #endif
  1023. fReuse = TRUE;
  1024. // BUG!!! (build 1735): WSARecv fails for QoS enabled sockets
  1025. // in unicast with error WSAEINVAL=10022 when
  1026. // I use REUSEADDR.
  1027. //
  1028. // Anyway, allowing REUSEADDR unicast is not a good thing,
  1029. // in fact we want to prevent that -- suppose another application
  1030. // is using the same address/port pair, we would get a weird
  1031. // behavior withouth knowing the reason, so we better fail in such
  1032. // a case.
  1033. // In multicast that's a different matter, we want to be able to
  1034. // REUSEADDR, WS2 delivers a copy of each packet ro every listener
  1035. if (IS_MULTICAST(dwRemAddr)) {
  1036. if (setsockopt(
  1037. m_Socket,
  1038. SOL_SOCKET,
  1039. SO_REUSEADDR,
  1040. (PCHAR)&fReuse,
  1041. sizeof(fReuse)
  1042. ) == SOCKET_ERROR) {
  1043. // obtain last error
  1044. TraceDebug((
  1045. TRACE_ERROR,
  1046. TRACE_DEVELOP,
  1047. TEXT("CShSocket::CShSocket: "
  1048. "setsockopt(SO_REUSEADDR) failed: %d"),
  1049. WSAGetLastError()
  1050. ));
  1051. goto cleanup;
  1052. }
  1053. // BUGBUG, this should be done only for receivers,
  1054. // but if the socket is created first for a sender
  1055. // this option would have already been set.
  1056. // This is not a problem right now because this flag
  1057. // is set first when the socket is created, and then
  1058. // can be updated only by a receiver.
  1059. if (setsockopt(
  1060. m_Socket,
  1061. IPPROTO_IP,
  1062. IP_MULTICAST_LOOP,
  1063. (PCHAR)&dwLoopBack,
  1064. sizeof(dwLoopBack)
  1065. ) == SOCKET_ERROR) {
  1066. // obtain last error
  1067. TraceDebug((
  1068. TRACE_ERROR,
  1069. TRACE_DEVELOP,
  1070. TEXT("CShSocket::CShSocket: "
  1071. "setsockopt(IP_MULTICAST_LOOP) failed: %d"),
  1072. WSAGetLastError()
  1073. ));
  1074. goto cleanup;
  1075. }
  1076. }
  1077. // bind lives now in GetSharedSocket in the socket initialization,
  1078. // done differently for a sender, a receiver, and a sender/reciever
  1079. TraceDebug((
  1080. TRACE_TRACE,
  1081. TRACE_DEVELOP2,
  1082. TEXT("CShSocket::CShSocket: succeded: %d"),
  1083. m_Socket
  1084. ));
  1085. *phr = NOERROR;
  1086. return;
  1087. cleanup:
  1088. if (m_pCRtpQOSReserve) {
  1089. delete m_pCRtpQOSReserve;
  1090. m_pCRtpQOSReserve = NULL;
  1091. }
  1092. if (m_Socket != INVALID_SOCKET) {
  1093. closesocket(m_Socket);
  1094. m_Socket = INVALID_SOCKET;
  1095. }
  1096. *phr = E_FAIL;
  1097. return;
  1098. }
  1099. CShSocket::~CShSocket()
  1100. {
  1101. TraceDebug((
  1102. TRACE_TRACE,
  1103. TRACE_DEVELOP,
  1104. TEXT("CShSocket::~CShSocket"),
  1105. m_Socket
  1106. ));
  1107. }
  1108. HRESULT
  1109. CShSocket::CloseSocket()
  1110. {
  1111. HRESULT dwError = E_FAIL;
  1112. TraceDebug((
  1113. TRACE_TRACE,
  1114. TRACE_DEVELOP,
  1115. TEXT("CShSocket::CloseSocket: Socket:%d"),
  1116. m_Socket
  1117. ));
  1118. #if defined(DEBUG)
  1119. if (m_RefCount[0] + m_RefCount[1])
  1120. TraceDebug((
  1121. TRACE_ERROR,
  1122. TRACE_DEVELOP,
  1123. TEXT("CShSocket::CloseSocket: Inconsistency detected "
  1124. "in socket:%d: m_RefCount[0,1]=%d,%d"),
  1125. m_Socket, m_RefCount[0], m_RefCount[1]
  1126. ));
  1127. #endif
  1128. ASSERT( !(m_RefCount[0] + m_RefCount[1]) );
  1129. if (m_Socket != INVALID_SOCKET) {
  1130. #if 0
  1131. // XXX: Now allow to close the handle
  1132. SetHandleInformation((HANDLE)m_Socket,
  1133. HANDLE_FLAG_PROTECT_FROM_CLOSE,
  1134. 0);
  1135. #endif
  1136. if (closesocket(m_Socket)) {
  1137. // On error, do not wait for any overlapped IO to complete
  1138. TraceRetail((
  1139. TRACE_ERROR,
  1140. TRACE_DEVELOP,
  1141. TEXT("CShSocket::CloseSocket: closesocket(%d) failed: %d"),
  1142. m_Socket, WSAGetLastError()
  1143. ));
  1144. } else {
  1145. dwError = NOERROR;
  1146. TraceRetail((
  1147. TRACE_TRACE,
  1148. TRACE_DEVELOP,
  1149. TEXT("CShSocket::CloseSocket: closesocket(%d)"),
  1150. m_Socket
  1151. ));
  1152. }
  1153. }
  1154. if (m_pCRtpQOSReserve) {
  1155. delete m_pCRtpQOSReserve;
  1156. m_pCRtpQOSReserve = NULL;
  1157. }
  1158. return(dwError);
  1159. }
  1160. HRESULT
  1161. CShSocket::ShSocketStopQOS(DWORD dwIsSender)
  1162. {
  1163. TraceDebug((
  1164. TRACE_TRACE,
  1165. TRACE_DEVELOP,
  1166. TEXT("CShSocket::ShSocketStopQOS")
  1167. ));
  1168. if (m_pCRtpQOSReserve)
  1169. return(m_pCRtpQOSReserve->Unreserve(dwIsSender));
  1170. return(NOERROR);
  1171. }
  1172. //////////////////////////////////////////////////////////////////////
  1173. //
  1174. // InitializeFlowSpec
  1175. //
  1176. //////////////////////////////////////////////////////////////////////
  1177. VOID
  1178. InitializeFlowSpec(
  1179. IN OUT PFLOWSPEC FlowSpec,
  1180. IN SERVICETYPE ServiceType
  1181. )
  1182. {
  1183. FlowSpec->TokenRate = QOS_NOT_SPECIFIED;
  1184. FlowSpec->TokenBucketSize = QOS_NOT_SPECIFIED;
  1185. FlowSpec->PeakBandwidth = QOS_NOT_SPECIFIED;
  1186. FlowSpec->Latency = QOS_NOT_SPECIFIED;
  1187. FlowSpec->DelayVariation = QOS_NOT_SPECIFIED;
  1188. FlowSpec->ServiceType = ServiceType;
  1189. FlowSpec->MaxSduSize = QOS_NOT_SPECIFIED;
  1190. FlowSpec->MinimumPolicedSize = QOS_NOT_SPECIFIED;
  1191. }
  1192. //////////////////////////////////////////////////////////////////////
  1193. //
  1194. // CRtpQOSReserve
  1195. //
  1196. //////////////////////////////////////////////////////////////////////
  1197. CRtpQOSReserve::CRtpQOSReserve(CShSocket *pCShSocket, DWORD dwMaxFilters)
  1198. : m_pCShSocket(pCShSocket),
  1199. m_pRsvpSSRC(NULL),
  1200. m_pRsvpFilterSpec(NULL),
  1201. m_Style(RSVP_DEFAULT_STYLE),
  1202. m_dwFlags(flags_par(FG_RES_CONFIRMATION_REQUEST)),
  1203. m_dwLastReserveTime(0),
  1204. m_dwReserveIntervalTime(INITIAL_RESERVE_INTERVAL_TIME) // ms
  1205. {
  1206. TraceDebug((
  1207. TRACE_TRACE,
  1208. TRACE_DEVELOP,
  1209. TEXT("CRtpQOSReserve::CRtpQOSReserve")
  1210. ));
  1211. InitializeFlowSpec( &m_qos.ReceivingFlowspec, SERVICETYPE_NOCHANGE );
  1212. InitializeFlowSpec( &m_qos.SendingFlowspec, SERVICETYPE_NOCHANGE );
  1213. m_qos.ProviderSpecific.len = 0;
  1214. m_qos.ProviderSpecific.buf = NULL;
  1215. // Initial values for destination address
  1216. ZeroMemory(&m_destaddr, sizeof(m_destaddr));
  1217. m_destaddr.ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR;
  1218. m_destaddr.ObjectHdr.ObjectLength =
  1219. sizeof(m_destaddr) +
  1220. sizeof(m_sockin_destaddr);
  1221. m_destaddr.SocketAddress = (SOCKADDR *)&m_sockin_destaddr;
  1222. m_destaddr.SocketAddressLength = sizeof(m_sockin_destaddr);
  1223. SetMaxFilters(dwMaxFilters);
  1224. }
  1225. CRtpQOSReserve::~CRtpQOSReserve()
  1226. {
  1227. TraceDebug((
  1228. TRACE_TRACE,
  1229. TRACE_DEVELOP,
  1230. TEXT("CRtpQOSReserve::~CRtpQOSReserve")
  1231. ));
  1232. if (m_pRsvpSSRC)
  1233. delete m_pRsvpSSRC;
  1234. if (m_pRsvpFilterSpec)
  1235. delete m_pRsvpFilterSpec;
  1236. m_MaxFilters = m_NumFilters = 0;
  1237. m_pRsvpSSRC = NULL;
  1238. m_pRsvpFilterSpec = NULL;
  1239. }
  1240. // change the max number of filters,
  1241. // and flush the current list
  1242. HRESULT
  1243. CRtpQOSReserve::SetMaxFilters(DWORD dwMaxFilters)
  1244. {
  1245. HRESULT hr = NOERROR;
  1246. TraceDebug((
  1247. TRACE_TRACE,
  1248. TRACE_DEVELOP,
  1249. TEXT("CRtpQOSReserve::SetMaxFilters(%d)"), dwMaxFilters
  1250. ));
  1251. if (dwMaxFilters > MAX_FILTERS)
  1252. return(E_INVALIDARG);
  1253. if (m_MaxFilters != dwMaxFilters) {
  1254. // release old memory
  1255. if (m_pRsvpSSRC)
  1256. delete m_pRsvpSSRC;
  1257. if (m_pRsvpFilterSpec)
  1258. delete m_pRsvpFilterSpec;
  1259. m_MaxFilters = dwMaxFilters;
  1260. if (dwMaxFilters > 0) {
  1261. // get new memory
  1262. m_pRsvpSSRC = new DWORD[dwMaxFilters];
  1263. m_pRsvpFilterSpec = new RSVP_FILTERSPEC[dwMaxFilters];
  1264. if (!(m_pRsvpSSRC && m_pRsvpFilterSpec)) {
  1265. TraceDebug((
  1266. TRACE_ERROR,
  1267. TRACE_DEVELOP,
  1268. TEXT("CRtpQOSReserve::SetMaxFilters(%d) failed"),
  1269. dwMaxFilters
  1270. ));
  1271. if (m_pRsvpSSRC) {
  1272. delete m_pRsvpSSRC;
  1273. m_pRsvpSSRC = (DWORD *)NULL;
  1274. }
  1275. if (m_pRsvpFilterSpec) {
  1276. delete m_pRsvpFilterSpec;
  1277. m_pRsvpFilterSpec = (RSVP_FILTERSPEC *)NULL;
  1278. }
  1279. m_MaxFilters = 0;
  1280. hr = E_FAIL;
  1281. }
  1282. }
  1283. }
  1284. m_NumFilters = 0;
  1285. return(hr);
  1286. }
  1287. // Ask for the template's names (e.g. G711, G723, H261CIF, etc.)
  1288. HRESULT
  1289. CRtpQOSReserve::QueryTemplates(char *templates, int size)
  1290. {
  1291. WSABUF wsabuf;
  1292. QOS qos; // For query this parameter should be passed as NULL
  1293. HRESULT hr = E_FAIL;
  1294. TraceDebug((
  1295. TRACE_TRACE,
  1296. TRACE_DEVELOP,
  1297. TEXT("CRtpQOSReserve::QueryTemplates")
  1298. ));
  1299. if ( !templates || size < 1 || !m_pCShSocket )
  1300. return(hr);
  1301. templates[0] = '\0';
  1302. wsabuf.buf = templates;
  1303. wsabuf.len = size;
  1304. qos.ProviderSpecific.len = 0;
  1305. qos.ProviderSpecific.buf = NULL;
  1306. if (WSAGetQOSByName(m_pCShSocket->GetShSocket(), &wsabuf, &qos)) {
  1307. char *str, *str0;
  1308. // change NULLs by SPACE
  1309. for(str0 = str = templates;
  1310. (*str || *(str+1)) && ((str-str0) < size);
  1311. str++) {
  1312. if (!*str)
  1313. *str = ' ';
  1314. }
  1315. hr = NOERROR;
  1316. }
  1317. return(hr);
  1318. }
  1319. // Get just one template
  1320. HRESULT
  1321. CRtpQOSReserve::GetTemplate(char *template_name, char *qosClass, QOS *pqos)
  1322. {
  1323. WSABUF wsabuf;
  1324. DWORD dwNewTokenRate;
  1325. DWORD dwTokenBucketSize;
  1326. DWORD dwMaxSduSize;
  1327. DWORD dwMinimumPolicedSize;
  1328. HRESULT hr = E_FAIL;
  1329. TraceDebug((
  1330. TRACE_TRACE,
  1331. TRACE_DEVELOP,
  1332. TEXT("CRtpQOSReserve::GetTemplate")
  1333. ));
  1334. if (!template_name || !pqos)
  1335. return(hr);
  1336. wsabuf.buf = template_name;
  1337. wsabuf.len = strlen(template_name);
  1338. if (wsabuf.len > 0)
  1339. wsabuf.len++; // Include NULL character
  1340. pqos->ProviderSpecific.len = 0;
  1341. pqos->ProviderSpecific.buf = NULL;
  1342. /*
  1343. * RTP = 12 bytes.
  1344. *
  1345. * Add at least 3% to the nominal token rate
  1346. *
  1347. * For G711. It is (240 + 40) * (1000 / 30) = 9333.33 bytes => 9613
  1348. * (currently 8500), Min size 252 (current 340)
  1349. *
  1350. * For G723. It is (24 + 40) * (1000 / 30) = 2133.33 bytes => 2200
  1351. * (currently 1138), Min size 32 (current 68)
  1352. *
  1353. * For GSM. It is (65 + 40) * (1000 / 40) = 2625 bytes => 2704
  1354. * (currently 2150), Min size 77 (current 86)
  1355. * */
  1356. if (WSAGetQOSByName(m_pCShSocket->GetShSocket(), &wsabuf, pqos)) {
  1357. dwNewTokenRate = (DWORD)-1;
  1358. dwTokenBucketSize = (DWORD)-1;
  1359. dwMaxSduSize = (DWORD)-1;
  1360. dwMinimumPolicedSize = (DWORD)-1;
  1361. if (!strcmp("G711", template_name)) {
  1362. dwNewTokenRate = 9613;
  1363. dwMaxSduSize = (240 * 3) + 12; /* 732 */
  1364. dwTokenBucketSize = dwMaxSduSize * 2;
  1365. dwMinimumPolicedSize = 92; /* Actually we support 10ms,
  1366. * so change from 30ms to 10ms */
  1367. } else if (!strcmp("G723", template_name)) {
  1368. /*
  1369. * WARNING: MSP passes G723, but template name is G723.1
  1370. */
  1371. dwNewTokenRate = 2198;
  1372. dwMaxSduSize = (24 * 3) + 12; /* 84 */
  1373. dwTokenBucketSize = dwMaxSduSize * 4;
  1374. dwMinimumPolicedSize = 32;
  1375. } else if (!strcmp("GSM6.10", template_name)) {
  1376. dwNewTokenRate = 2704;
  1377. dwMinimumPolicedSize = 77;
  1378. }
  1379. /* TokenRate & PeakBandwidth */
  1380. if (dwNewTokenRate != (DWORD)-1) {
  1381. if (dwNewTokenRate > pqos->SendingFlowspec.TokenRate) {
  1382. /* take the maximum */
  1383. pqos->SendingFlowspec.TokenRate = dwNewTokenRate;
  1384. pqos->ReceivingFlowspec.TokenRate = dwNewTokenRate;
  1385. }
  1386. pqos->SendingFlowspec.PeakBandwidth =
  1387. (dwNewTokenRate * 17) / 10; /* + 70 % */
  1388. pqos->ReceivingFlowspec.PeakBandwidth =
  1389. (dwNewTokenRate * 17) / 10; /* + 70 % */
  1390. }
  1391. /* TokenBucketSize */
  1392. if (dwTokenBucketSize != (DWORD)-1) {
  1393. if (dwTokenBucketSize > pqos->SendingFlowspec.TokenBucketSize) {
  1394. /* take the maximum */
  1395. pqos->SendingFlowspec.TokenBucketSize = dwTokenBucketSize;
  1396. pqos->ReceivingFlowspec.TokenBucketSize = dwTokenBucketSize;
  1397. }
  1398. }
  1399. /* MaxSduSize */
  1400. if (dwMaxSduSize != (DWORD)-1) {
  1401. if (dwMaxSduSize > pqos->SendingFlowspec.MaxSduSize) {
  1402. /* take the maximum */
  1403. pqos->SendingFlowspec.MaxSduSize = dwMaxSduSize;
  1404. pqos->ReceivingFlowspec.MaxSduSize = dwMaxSduSize;
  1405. }
  1406. }
  1407. /* MinimumPolicedSize */
  1408. if (dwMinimumPolicedSize != (DWORD)-1) {
  1409. if (dwMinimumPolicedSize <
  1410. pqos->SendingFlowspec.MinimumPolicedSize) {
  1411. /* take the minimum */
  1412. pqos->SendingFlowspec.MinimumPolicedSize =
  1413. dwMinimumPolicedSize;
  1414. pqos->ReceivingFlowspec.MinimumPolicedSize =
  1415. dwMinimumPolicedSize;
  1416. }
  1417. }
  1418. hr = NOERROR;
  1419. // Save class and name
  1420. strncpy(m_QOSclass, qosClass, sizeof(m_QOSclass));
  1421. strncpy(m_QOSname, template_name, sizeof(m_QOSname));
  1422. }
  1423. return(hr);
  1424. }
  1425. // Set the Sender/Receiver FlowSpec
  1426. HRESULT
  1427. CRtpQOSReserve::SetFlowSpec(FLOWSPEC *pFlowSpec, DWORD dwIsSender)
  1428. {
  1429. TraceDebug((
  1430. TRACE_TRACE,
  1431. TRACE_DEVELOP,
  1432. TEXT("CRtpQOSReserve::SetFlowSpec")
  1433. ));
  1434. if (!pFlowSpec)
  1435. return(E_FAIL);
  1436. CopyMemory(dwIsSender? &m_qos.SendingFlowspec : &m_qos.ReceivingFlowspec,
  1437. pFlowSpec,
  1438. sizeof(m_qos.SendingFlowspec));
  1439. return(NOERROR);
  1440. }
  1441. // Scale a flow spec
  1442. // Only scale the following parameters:
  1443. //
  1444. // TokenRate; /* In Bytes/sec */
  1445. // TokenBucketSize; /* In Bytes */
  1446. // PeakBandwidth; /* In Bytes/sec */
  1447. //
  1448. // TokenBucketSize and PeakBandwidth are scaled up, but not down
  1449. HRESULT
  1450. CRtpQOSReserve::ScaleFlowSpec(FLOWSPEC *pFlowSpec,
  1451. DWORD dwNumParticipants,
  1452. DWORD dwMaxParticipants,
  1453. DWORD dwBandwidth)
  1454. {
  1455. DWORD dwOverallBW = pFlowSpec->TokenRate * dwMaxParticipants;
  1456. dwBandwidth /= 8; // flowspec is in bytes/sec
  1457. TraceRetail((
  1458. TRACE_TRACE,
  1459. TRACE_DEVELOP,
  1460. TEXT("CRtpQOSReserve::ScaleFlowSpec(%u, %u, %u b/s) "
  1461. "flowspec(Tr:%u, Tbs:%u, PBw:%u, ST:%u, "
  1462. "MaxSDU:%u MinSize:%u)"),
  1463. dwNumParticipants, dwMaxParticipants, dwBandwidth*8,
  1464. pFlowSpec->TokenRate,
  1465. pFlowSpec->TokenBucketSize,
  1466. (pFlowSpec->PeakBandwidth != QOS_NOT_SPECIFIED) ?
  1467. pFlowSpec->PeakBandwidth : QOS_NOT_SPECIFIED,
  1468. pFlowSpec->ServiceType,
  1469. pFlowSpec->MaxSduSize, pFlowSpec->MinimumPolicedSize
  1470. ));
  1471. if (dwOverallBW <= dwBandwidth) {
  1472. // use as it is, scale up to dwNumParticipants
  1473. pFlowSpec->TokenRate *= dwNumParticipants;
  1474. pFlowSpec->TokenBucketSize *= dwNumParticipants;
  1475. if (pFlowSpec->PeakBandwidth != QOS_NOT_SPECIFIED)
  1476. pFlowSpec->PeakBandwidth *= dwNumParticipants;
  1477. } else {
  1478. // don't have all we need, scale according
  1479. // to number of participants
  1480. DWORD fac1;
  1481. DWORD fac2;
  1482. if (dwNumParticipants == dwMaxParticipants) {
  1483. // use all the bandwidth available
  1484. // Scale = 1 + [ (Bw - TokenRate) / TokenRate ]
  1485. // Scale = Bw / TokenRate = fac1 / fac2
  1486. fac1 = dwBandwidth;
  1487. fac2 = pFlowSpec->TokenRate;
  1488. } else {
  1489. // use the bandwidth according to num of participants
  1490. // Scale = [ ((Bw / Max) * Num ] / TokenRate
  1491. // Scale = (Bw * Num) / (TokenRate * Max) = fac1 / fac2
  1492. fac1 = dwBandwidth * dwNumParticipants;
  1493. fac2 = pFlowSpec->TokenRate * dwMaxParticipants;
  1494. }
  1495. // scale TokenRate up or down
  1496. pFlowSpec->TokenRate =
  1497. (pFlowSpec->TokenRate * fac1) / fac2;
  1498. if (fac1 > fac2) {
  1499. // can still scale up the other parameters
  1500. pFlowSpec->TokenBucketSize =
  1501. ((pFlowSpec->TokenBucketSize * fac1) / fac2);
  1502. if (pFlowSpec->PeakBandwidth != QOS_NOT_SPECIFIED)
  1503. pFlowSpec->PeakBandwidth =
  1504. ((pFlowSpec->PeakBandwidth * fac1) / fac2);
  1505. }
  1506. }
  1507. // The bandwidth we request include RTP/UDP/IP headers overhead,
  1508. // but RSVP also scales up to consider headers overhead, to ovoid
  1509. // requesting more bandwidth than we intend, pass to RSVP a
  1510. // smaller value such that the final one RSVP comes up with would
  1511. // be the original value we request.
  1512. DWORD RSVPTokenRate;
  1513. if (pFlowSpec->MinimumPolicedSize > 0) {
  1514. RSVPTokenRate =
  1515. (pFlowSpec->TokenRate * 1000) /
  1516. (1000 + 28000/pFlowSpec->MinimumPolicedSize);
  1517. }
  1518. DWORD RSVPPeakBandwidth;
  1519. RSVPPeakBandwidth = pFlowSpec->PeakBandwidth;
  1520. if (RSVPPeakBandwidth != QOS_NOT_SPECIFIED) {
  1521. RSVPPeakBandwidth =
  1522. (pFlowSpec->PeakBandwidth * 1000) /
  1523. (1000 + 28000/pFlowSpec->MinimumPolicedSize);
  1524. }
  1525. TraceRetail((
  1526. TRACE_TRACE,
  1527. TRACE_DEVELOP,
  1528. TEXT("CRtpQOSReserve::ScaleFlowSpec: "
  1529. "flowspec(Tr:%u/%u, Tbs:%u, PBw:%u/%u ST:%u, "
  1530. "MaxSDU:%u MinSize:%u) scaled"),
  1531. pFlowSpec->TokenRate, RSVPTokenRate,
  1532. pFlowSpec->TokenBucketSize,
  1533. (pFlowSpec->PeakBandwidth != QOS_NOT_SPECIFIED) ?
  1534. pFlowSpec->PeakBandwidth : QOS_NOT_SPECIFIED,
  1535. (RSVPPeakBandwidth != QOS_NOT_SPECIFIED) ?
  1536. RSVPPeakBandwidth : QOS_NOT_SPECIFIED,
  1537. pFlowSpec->ServiceType,
  1538. pFlowSpec->MaxSduSize, pFlowSpec->MinimumPolicedSize
  1539. ));
  1540. pFlowSpec->TokenRate = RSVPTokenRate;
  1541. pFlowSpec->PeakBandwidth = RSVPPeakBandwidth;
  1542. return(NOERROR);
  1543. }
  1544. // Set the destination address (required for unicast)
  1545. HRESULT
  1546. CRtpQOSReserve::SetDestAddr(LPBYTE pbDestAddr, DWORD dwAddrLen)
  1547. {
  1548. CheckPointer(pbDestAddr, E_POINTER);
  1549. if (dwAddrLen != sizeof(m_sockin_destaddr))
  1550. return(E_INVALIDARG);
  1551. char addrstr[RTPNTOASIZE];
  1552. SOCKADDR_IN *pSinAddr = (SOCKADDR_IN *)pbDestAddr;
  1553. TraceRetail((
  1554. TRACE_TRACE,
  1555. TRACE_DEVELOP,
  1556. TEXT("CRtpQOSReserve::SetDestAddr(%s/%d)"),
  1557. RtpNtoA(pSinAddr->sin_addr.s_addr, addrstr),
  1558. ntohs(((SOCKADDR_IN *)pbDestAddr)->sin_port)
  1559. ));
  1560. // Update only the address as the other elements do not change
  1561. // since they are first initialized
  1562. CopyMemory(&m_sockin_destaddr, pbDestAddr, dwAddrLen);
  1563. return(NOERROR);
  1564. }
  1565. // Find out if an SSRC is in the reservation list or not
  1566. DWORD
  1567. CRtpQOSReserve::FindSSRC(DWORD ssrc)
  1568. {
  1569. if (m_pRsvpSSRC && m_NumFilters) {
  1570. DWORD i;
  1571. for(i = 0; i < m_NumFilters; i++)
  1572. if (ssrc == m_pRsvpSSRC[i])
  1573. break;
  1574. if (i < m_NumFilters)
  1575. return(i);
  1576. else
  1577. return(-1);
  1578. }
  1579. return(-1);
  1580. }
  1581. // Add/Delete one SSRC (participant) to the
  1582. // Shared Explicit Filter (SEF) list
  1583. // 0==delete; other==add
  1584. HRESULT
  1585. CRtpQOSReserve::AddDeleteSSRC(DWORD ssrc, DWORD dwAddDel)
  1586. {
  1587. HRESULT hr = E_FAIL;
  1588. TraceDebug((
  1589. TRACE_TRACE,
  1590. TRACE_DEVELOP,
  1591. TEXT("CRtpQOSReserve::AddDeleteSSRC(0x%X, %s)"),
  1592. ssrc, dwAddDel? "ADD":"DEL"
  1593. ));
  1594. CAutoLock LockThis(pStateLock());
  1595. if (m_pRsvpFilterSpec) {
  1596. unsigned int i;
  1597. // Lookup the SSRC and find out if it is already in
  1598. // the priority list
  1599. for(i = 0; i < m_NumFilters; i++)
  1600. if (ssrc == m_pRsvpSSRC[i])
  1601. break;
  1602. if (i < m_NumFilters) { // if (in list)
  1603. /////////////////////////
  1604. // Found at the ith place
  1605. /////////////////////////
  1606. if (dwAddDel) {
  1607. //////////////////////
  1608. // ******* ADD *******
  1609. //////////////////////
  1610. hr = NOERROR;// Add -- do nothing, already in list
  1611. } else {
  1612. /////////////////////////
  1613. // ******* DELETE *******
  1614. /////////////////////////
  1615. // remove from list
  1616. RSVP_FILTERSPEC *rsvp1 = &m_pRsvpFilterSpec[i];
  1617. RSVP_FILTERSPEC *rsvp2 = rsvp1 + 1;
  1618. DWORD *ssrc1 = &m_pRsvpSSRC[i];
  1619. DWORD *ssrc2 = ssrc1 + 1;
  1620. for(m_NumFilters--;
  1621. i < m_NumFilters;
  1622. rsvp1++, rsvp2++, ssrc1++, ssrc2++, i++) {
  1623. MoveMemory(rsvp1, rsvp2, sizeof(*rsvp1));
  1624. *ssrc1 = *ssrc2;
  1625. }
  1626. }
  1627. hr = NOERROR;
  1628. } else { // else if (not in list)
  1629. /////////////////////
  1630. // Not found in list!
  1631. /////////////////////
  1632. if (dwAddDel) {
  1633. //////////////////////
  1634. // ******* ADD *******
  1635. //////////////////////
  1636. // add to the list
  1637. // Validate the number of SRRCs in the list
  1638. if (m_NumFilters < m_MaxFilters) {
  1639. CRtpSession *pCRtpSession =
  1640. m_pCShSocket->GetpCRtpSession(-1);
  1641. if (pCRtpSession) {
  1642. DWORD addrlen;
  1643. SOCKADDR_IN saddr;
  1644. // Get SSRC's IP address/port (from RTP packets)
  1645. addrlen = sizeof(saddr);
  1646. hr = pCRtpSession->
  1647. GetParticipantAddress(ssrc,
  1648. (LPBYTE)&saddr,
  1649. (int *)&addrlen);
  1650. if (SUCCEEDED(hr)) {
  1651. RSVP_FILTERSPEC *rsvp =
  1652. &m_pRsvpFilterSpec[m_NumFilters];
  1653. rsvp->Type = FILTERSPECV4;
  1654. rsvp->FilterSpecV4.Address.Addr =
  1655. saddr.sin_addr.s_addr;
  1656. // Take the port from the RTP Session's address
  1657. // as the learned address may be from an
  1658. // RTCP packet and hence be the wrong port
  1659. // number.
  1660. //
  1661. // !!!!! Note
  1662. // The address from RTP packets may not be
  1663. // available yet, it will be once we receive
  1664. // a valid RTP packet.
  1665. // If that address is not available, then
  1666. // all 0's address will be returned
  1667. // but the function will not fail.
  1668. // The sending port can be anything, as
  1669. // in NetMeeting, In this case,
  1670. // the MSP needs to lookup participants
  1671. // using the SSRC/CNAME, being CNAME
  1672. // the unique ID.
  1673. rsvp->FilterSpecV4.Port = saddr.sin_port;
  1674. if (saddr.sin_port) {
  1675. // Record the filter only if a valid
  1676. // address/port is available
  1677. m_pRsvpSSRC[m_NumFilters] = ssrc;
  1678. m_NumFilters++;
  1679. // Succeeds only if really added
  1680. // to the list
  1681. char addrstr[RTPNTOASIZE];
  1682. TraceDebug((
  1683. TRACE_TRACE,
  1684. TRACE_DEVELOP,
  1685. TEXT("CRtpQOSReserve::AddDeleteSSRC"
  1686. "(%s: 0x%X/%s/%d)"),
  1687. dwAddDel? "ADD":"DEL",
  1688. ssrc,
  1689. RtpNtoA(saddr.sin_addr.s_addr,addrstr),
  1690. ntohs(saddr.sin_port)
  1691. ));
  1692. hr = NOERROR;
  1693. }
  1694. } else {
  1695. TraceDebug((
  1696. TRACE_ERROR,
  1697. TRACE_DEVELOP,
  1698. TEXT("CRtpQOSReserve::AddDeleteSSRC"
  1699. ": could not get IP addr for 0x%X"),
  1700. ssrc
  1701. ));
  1702. }
  1703. }
  1704. }
  1705. } else {
  1706. /////////////////////////
  1707. // ******* DELETE *******
  1708. /////////////////////////
  1709. hr = NOERROR;// do nothing, not in list
  1710. }
  1711. } // if (not in list)
  1712. } // if (filters list exist)
  1713. return(hr);
  1714. }
  1715. void dumpQOS(char *msg, QOS *pQOS);
  1716. void dumpObjectType(char *msg, char *ptr, unsigned int len);
  1717. HRESULT
  1718. CRtpQOSReserve::Reserve(DWORD dwIsSender)
  1719. {
  1720. TraceDebug((
  1721. TRACE_TRACE,
  1722. TRACE_DEVELOP,
  1723. TEXT("CRtpQOSReserve::Reserve(%s) @ %d"),
  1724. dwIsSender? "SEND":"RECV",
  1725. GetTickCount() - m_dwLastReserveTime
  1726. ));
  1727. DWORD len;
  1728. char *ptr;
  1729. QOS qos;
  1730. char buf[MAX_PROVIDERSPECIFIC_BUFFER];
  1731. QOS_DESTADDR *dest_addr;
  1732. RSVP_RESERVE_INFO *reserve_info;
  1733. FLOWDESCRIPTOR *flow_desc;
  1734. RSVP_FILTERSPEC *filterspec;
  1735. HRESULT hr = NOERROR;
  1736. CopyMemory(&qos, &m_qos, sizeof(qos));
  1737. // Always enable notifications,
  1738. // except if the WSAIctl(SIO_SET_QOS) fails or
  1739. // we are receiver and are requesting BEST_EFFORT
  1740. m_pCShSocket->ModifyFlags(
  1741. dwIsSender? FG_SOCK_ENABLE_NOTIFY_SEND:FG_SOCK_ENABLE_NOTIFY_RECV,
  1742. 1);
  1743. if (m_pCShSocket->TestFlags(
  1744. dwIsSender? FG_SOCK_ENABLE_NOTIFY_SEND:FG_SOCK_ENABLE_NOTIFY_RECV)) {
  1745. TraceDebug((
  1746. TRACE_TRACE,
  1747. TRACE_DEVELOP,
  1748. TEXT("CRtpQOSReserve::Reserve(%s) Enable Notifications"),
  1749. dwIsSender? "SEND":"RECV"
  1750. ));
  1751. } else {
  1752. TraceDebug((
  1753. TRACE_TRACE,
  1754. TRACE_DEVELOP,
  1755. TEXT("CRtpQOSReserve::Reserve(%s) Disable Notifications"),
  1756. dwIsSender? "SEND":"RECV"
  1757. ));
  1758. }
  1759. qos.ProviderSpecific.len = 0;
  1760. qos.ProviderSpecific.buf = NULL;
  1761. ptr = buf;
  1762. if (dwIsSender) {
  1763. // Do not change the receiver
  1764. qos.ReceivingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  1765. // Init the destination object if unicast
  1766. if (!IS_MULTICAST(m_sockin_destaddr.sin_addr.s_addr) &&
  1767. (m_sockin_destaddr.sin_addr.s_addr != INADDR_ANY)) {
  1768. if (!fg_tst(m_dwFlags, FG_RES_DEST_ADDR_OBJECT_USED)) {
  1769. // Specify the dest addr object only once,
  1770. // to do so remember it was used
  1771. fg_set(m_dwFlags, FG_RES_DEST_ADDR_OBJECT_USED);;
  1772. dest_addr = (QOS_DESTADDR *)ptr;
  1773. ZeroMemory((char *)dest_addr,
  1774. sizeof(m_destaddr) +
  1775. sizeof(m_sockin_destaddr));
  1776. dest_addr->ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR;
  1777. dest_addr->ObjectHdr.ObjectLength =
  1778. sizeof(m_destaddr);
  1779. //sizeof(m_sockin_destaddr);
  1780. // Copy QOS_DESTADDR and SocketAddress, update pointer
  1781. // to SocketAddress
  1782. CopyMemory((char *)dest_addr,
  1783. (char *)&m_destaddr,
  1784. sizeof(m_destaddr));
  1785. CopyMemory((char *)(dest_addr + 1),
  1786. (char *)&m_sockin_destaddr,
  1787. sizeof(m_sockin_destaddr));
  1788. dest_addr->SocketAddress = (const struct sockaddr *)
  1789. (dest_addr + 1);
  1790. dest_addr->SocketAddressLength = sizeof(m_sockin_destaddr);
  1791. ptr += sizeof(m_destaddr) + sizeof(m_sockin_destaddr);
  1792. }
  1793. }
  1794. reserve_info = (RSVP_RESERVE_INFO *)ptr;
  1795. // Partially Init RSVP_RESERVE_INFO
  1796. ZeroMemory(reserve_info, sizeof(RSVP_RESERVE_INFO));
  1797. reserve_info->ObjectHdr.ObjectType = RSVP_OBJECT_RESERVE_INFO;
  1798. reserve_info->ConfirmRequest =
  1799. flags_tst(FG_RES_CONFIRMATION_REQUEST);
  1800. reserve_info->Style = m_Style;
  1801. // Add QOS app ID later at ptr
  1802. ptr += sizeof(RSVP_RESERVE_INFO);
  1803. // Scale the flow spec for the sender (if needed)
  1804. ScaleFlowSpec(&qos.SendingFlowspec, 1, 1, m_MaxBandwidth);
  1805. // Remember when was the last time a reserve was done for the sender
  1806. // (not really reserve but specify the flowspec)
  1807. SetLastReserveTime(GetTickCount());
  1808. } else {
  1809. // Do not change the sender
  1810. qos.SendingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  1811. reserve_info = (RSVP_RESERVE_INFO *)ptr;
  1812. // Partially Init RSVP_RESERVE_INFO
  1813. ZeroMemory(reserve_info, sizeof(RSVP_RESERVE_INFO));
  1814. reserve_info->ObjectHdr.ObjectType = RSVP_OBJECT_RESERVE_INFO;
  1815. reserve_info->ConfirmRequest =
  1816. flags_tst(FG_RES_CONFIRMATION_REQUEST);
  1817. reserve_info->Style = m_Style;
  1818. if (m_Style == RSVP_SHARED_EXPLICIT_STYLE) {
  1819. // Shared Explicit filter -- SEF
  1820. if (m_pRsvpFilterSpec && m_NumFilters > 0) {
  1821. // We have some filters
  1822. TraceDebug((
  1823. TRACE_TRACE,
  1824. TRACE_DEVELOP,
  1825. TEXT("CRtpQOSReserve::Reserve(RECV) "
  1826. "Multicast(SE, %d)"),
  1827. m_NumFilters
  1828. ));
  1829. // Scale the flow descriptor to m_NumFilters
  1830. ScaleFlowSpec(&qos.ReceivingFlowspec,
  1831. m_NumFilters,
  1832. m_MaxFilters,
  1833. m_MaxBandwidth);
  1834. // Build the ProviderSpecific buffer
  1835. flow_desc = (FLOWDESCRIPTOR *)(reserve_info + 1);
  1836. filterspec = (RSVP_FILTERSPEC *)(flow_desc + 1);
  1837. // Init RSVP_RESERVE_INFO
  1838. reserve_info->ObjectHdr.ObjectLength =
  1839. sizeof(RSVP_RESERVE_INFO) +
  1840. sizeof(FLOWDESCRIPTOR) +
  1841. (sizeof(RSVP_FILTERSPEC) * m_NumFilters);
  1842. reserve_info->NumFlowDesc = 1;
  1843. reserve_info->FlowDescList = flow_desc;
  1844. // Init FLOWDESCRIPTOR
  1845. CopyMemory(&flow_desc->FlowSpec,
  1846. &qos.ReceivingFlowspec,
  1847. sizeof(qos.ReceivingFlowspec));
  1848. flow_desc->NumFilters = m_NumFilters;
  1849. flow_desc->FilterList = filterspec;;
  1850. // Init RSVP_FILTERSPEC
  1851. CopyMemory(filterspec,
  1852. m_pRsvpFilterSpec,
  1853. m_NumFilters * sizeof(RSVP_FILTERSPEC));
  1854. // Add QOS app ID later at ptr
  1855. ptr = (char *)filterspec +
  1856. m_NumFilters * sizeof(RSVP_FILTERSPEC);
  1857. } else {
  1858. // Nothing selected yet, select BEST_EFFORT
  1859. TraceDebug((
  1860. TRACE_TRACE,
  1861. TRACE_DEVELOP,
  1862. TEXT("CRtpQOSReserve::Reserve(RECV) "
  1863. "Multicast(SE, %d) pass to BEST EFFORT"),
  1864. m_NumFilters
  1865. ));
  1866. qos.ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT;
  1867. // no reserve_info needed
  1868. // Don't add QOS app ID
  1869. reserve_info = (RSVP_RESERVE_INFO *)NULL;
  1870. // Not allowed to start notifications yet as
  1871. // we are going to request BEST EFFORT
  1872. m_pCShSocket->ModifyFlags(
  1873. dwIsSender? FG_SOCK_ENABLE_NOTIFY_SEND:
  1874. FG_SOCK_ENABLE_NOTIFY_RECV,
  1875. 0);
  1876. }
  1877. } else if (m_Style == RSVP_WILDCARD_STYLE) {
  1878. // Share N*FlowSpec -- WF
  1879. TraceDebug((
  1880. TRACE_TRACE,
  1881. TRACE_DEVELOP,
  1882. TEXT("CRtpQOSReserve::Reserve(RECV) Multicast(WF)")
  1883. ));
  1884. // Scale the flow spec to m_MaxFilters
  1885. ScaleFlowSpec(&qos.ReceivingFlowspec,
  1886. m_MaxFilters,
  1887. m_MaxFilters,
  1888. m_MaxBandwidth);
  1889. // Add QOS app ID later at ptr
  1890. ptr = (char *)(reserve_info + 1);
  1891. } else {
  1892. // RSVP_DEFAULT_STYLE || RSVP_FIXED_FILTER_STYLE
  1893. // Unicast -- FF
  1894. TraceDebug((
  1895. TRACE_TRACE,
  1896. TRACE_DEVELOP,
  1897. TEXT("CRtpQOSReserve::Reserve(RECV) Unicast(DEF STYLE)")
  1898. ));
  1899. // Scale the flow spec to m_MaxFilters
  1900. ScaleFlowSpec(&qos.ReceivingFlowspec,
  1901. m_MaxFilters,
  1902. m_MaxFilters,
  1903. m_MaxBandwidth);
  1904. // Add QOS app ID later at ptr
  1905. ptr = (char *)(reserve_info + 1);
  1906. }
  1907. }
  1908. if (reserve_info) {
  1909. // Add QOS APP ID if reserve info is defined
  1910. len = AddQosAppID(ptr,
  1911. sizeof(buf) - (ptr - buf),
  1912. g_sPolicyLocator,
  1913. g_sAppName,
  1914. m_QOSclass,
  1915. m_QOSname);
  1916. if (len > 0) {
  1917. reserve_info->PolicyElementList = (RSVP_POLICY_INFO *)ptr;
  1918. ptr += len;
  1919. }
  1920. reserve_info->ObjectHdr.ObjectLength = (DWORD)
  1921. (ptr - (char *)reserve_info);
  1922. // Init ProviderSpecific
  1923. qos.ProviderSpecific.len = ptr - buf;
  1924. qos.ProviderSpecific.buf = buf;
  1925. }
  1926. DWORD outBufSize = 0;
  1927. // Set QOS using WSAIoctl
  1928. #if defined(DEBUG)
  1929. DWORD t0 = GetTickCount();
  1930. dumpQOS("CRtpQOSReserve::Reserve(before)", &qos);
  1931. if (qos.ProviderSpecific.buf &&
  1932. qos.ProviderSpecific.len >= sizeof(QOS_OBJECT_HDR)) {
  1933. dumpObjectType("CRtpQOSReserve::Reserve",
  1934. qos.ProviderSpecific.buf,
  1935. qos.ProviderSpecific.len);
  1936. }
  1937. #endif
  1938. if ( WSAIoctl(m_pCShSocket->GetShSocket(),
  1939. SIO_SET_QOS,
  1940. (LPVOID)&qos,
  1941. sizeof(qos),
  1942. NULL,
  1943. 0,
  1944. &outBufSize,
  1945. NULL,
  1946. NULL) ) {
  1947. // WSAIoctl failed, disable notifications
  1948. m_pCShSocket->ModifyFlags(
  1949. dwIsSender? FG_SOCK_ENABLE_NOTIFY_SEND:
  1950. FG_SOCK_ENABLE_NOTIFY_RECV,
  1951. 0);
  1952. hr = E_FAIL;
  1953. TraceDebug((
  1954. TRACE_ERROR,
  1955. TRACE_DEVELOP,
  1956. TEXT("CRtpQOSReserve::Reserve(%s) WSAIoctl failed: %d"),
  1957. dwIsSender? "SEND":"RECV", WSAGetLastError()
  1958. ));
  1959. } else {
  1960. #if defined(DEBUG)
  1961. DWORD t1 = GetTickCount();
  1962. TraceDebug((
  1963. TRACE_TRACE,
  1964. TRACE_DEVELOP,
  1965. TEXT("CRtpQOSReserve::Reserve(%s) WSAIoctl succeeded, "
  1966. "DELAY: %d ms"),
  1967. dwIsSender? "SEND":"RECV", t1-t0
  1968. ));
  1969. dumpQOS("CRtpQOSReserve::Reserve(after )", &qos);
  1970. if (qos.ProviderSpecific.buf &&
  1971. qos.ProviderSpecific.len >= sizeof(QOS_OBJECT_HDR)) {
  1972. dumpObjectType("CRtpQOSReserve::Reserve",
  1973. qos.ProviderSpecific.buf,
  1974. qos.ProviderSpecific.len);
  1975. }
  1976. #endif
  1977. }
  1978. return(hr);
  1979. }
  1980. HRESULT
  1981. CRtpQOSReserve::Unreserve(DWORD dwIsSender)
  1982. {
  1983. TraceDebug((
  1984. TRACE_TRACE,
  1985. TRACE_DEVELOP,
  1986. TEXT("CRtpQOSReserve::Unreserve(%s)"),
  1987. dwIsSender? "SEND":"RECV"
  1988. ));
  1989. QOS qos;
  1990. CopyMemory(&qos, &m_qos, sizeof(qos));
  1991. qos.ProviderSpecific.len = 0;
  1992. qos.ProviderSpecific.buf = NULL;
  1993. if (dwIsSender) {
  1994. qos.SendingFlowspec.ServiceType = SERVICETYPE_NOTRAFFIC;
  1995. qos.ReceivingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  1996. } else {
  1997. qos.SendingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  1998. qos.ReceivingFlowspec.ServiceType = SERVICETYPE_NOTRAFFIC;
  1999. }
  2000. // Disable notifications
  2001. m_pCShSocket->ModifyFlags(
  2002. dwIsSender? FG_SOCK_ENABLE_NOTIFY_SEND:FG_SOCK_ENABLE_NOTIFY_RECV,
  2003. 0);
  2004. DWORD outBufSize = 0;
  2005. // Set QOS using WSAIoctl
  2006. if ( WSAIoctl(m_pCShSocket->GetShSocket(),
  2007. SIO_SET_QOS,
  2008. (LPVOID)&qos,
  2009. sizeof(qos),
  2010. NULL,
  2011. 0,
  2012. &outBufSize,
  2013. NULL,
  2014. NULL) )
  2015. return(E_FAIL);
  2016. return(NOERROR);
  2017. }
  2018. // Ask for permission to send
  2019. HRESULT
  2020. CRtpQOSReserve::AllowedToSend()
  2021. {
  2022. TraceDebug((
  2023. TRACE_TRACE,
  2024. TRACE_DEVELOP,
  2025. TEXT("CRtpQOSReserve::AllowedToSend")
  2026. ));
  2027. #if defined(SIO_CHK_QOS)
  2028. DWORD request = ALLOWED_TO_SEND_DATA;
  2029. DWORD result;
  2030. DWORD bytes_returned = 0;
  2031. if ( WSAIoctl(m_pCShSocket->GetShSocket(),
  2032. SIO_CHK_QOS,
  2033. (LPVOID)&request,
  2034. sizeof(request),
  2035. (LPVOID)&result,
  2036. sizeof(result),
  2037. &bytes_returned,
  2038. NULL,
  2039. NULL) ) {
  2040. TraceDebug((
  2041. TRACE_ERROR,
  2042. TRACE_DEVELOP,
  2043. TEXT("CRtpQOSReserve::AllowedToSend: "
  2044. "WSAIoctl(SIO_CHK_QOS) failed: %d"),
  2045. WSAGetLastError()
  2046. ));
  2047. return(NO_ERROR); // For safety, return NOEROR
  2048. }
  2049. result = result? NOERROR : E_FAIL;
  2050. #else
  2051. result = NOERROR;
  2052. #endif
  2053. TraceDebug((
  2054. TRACE_TRACE,
  2055. TRACE_DEVELOP,
  2056. TEXT("CRtpQOSReserve::AllowedToSend: %s"),
  2057. (SUCCEEDED(result))? "YES":"NO"
  2058. ));
  2059. return(result);
  2060. }
  2061. // Inquire about the link's speed
  2062. HRESULT
  2063. CRtpQOSReserve::LinkSpeed(DWORD *pdwLinkSpeed)
  2064. {
  2065. TraceDebug((
  2066. TRACE_TRACE,
  2067. TRACE_DEVELOP,
  2068. TEXT("CRtpQOSReserve::LinkSpeed")
  2069. ));
  2070. CheckPointer(pdwLinkSpeed, E_POINTER);
  2071. *pdwLinkSpeed = 0;
  2072. #if defined(SIO_CHK_QOS)
  2073. DWORD request = LINE_RATE;
  2074. if ( WSAIoctl(m_pCShSocket->GetShSocket(),
  2075. SIO_CHK_QOS,
  2076. (LPVOID)&request,
  2077. sizeof(request),
  2078. NULL,
  2079. 0,
  2080. pdwLinkSpeed,
  2081. NULL,
  2082. NULL) ) {
  2083. return(E_FAIL);
  2084. }
  2085. #endif
  2086. return(NOERROR);
  2087. }
  2088. // Inquire about the estimated available bandwidth
  2089. HRESULT
  2090. CRtpQOSReserve::EstimatedAvailableBandwidth(DWORD *pdwBandwidth)
  2091. {
  2092. TraceDebug((
  2093. TRACE_TRACE,
  2094. TRACE_DEVELOP,
  2095. TEXT("CRtpQOSReserve::EstimatedAvailableBandwidth")
  2096. ));
  2097. return(E_NOTIMPL);
  2098. }
  2099. /*+++
  2100. Description:
  2101. This routine generates the application identity PE given the
  2102. name and policy locator strings for the application.
  2103. szAppName is used to construct the CREDENTIAL attribute of the
  2104. Identity PE. Its subtype is set to ASCII_ID.
  2105. szPolicyLocator is used to construct the POLICY_LOCATOR
  2106. attribute of the Identity PE. Its subtype is set to ASCII_DN.
  2107. Refer to draft-ietf-rap-rsvp-identity-03.txt and
  2108. draft-bernet-appid-00.txt for details on the Identity Policy
  2109. Elements. Also draft-bernet-appid-00.txt conatins some
  2110. examples for arguments szPolicyLocator and szAppName.
  2111. The PE is generated in the supplied buffer. If the length of
  2112. the buffer is not enough, zero is returned.
  2113. Parameters: szAppName app name, string, caller supply
  2114. szPolicyLocator Policy Locator string, caller supply
  2115. wBufLen length of caller allocated buffer
  2116. pAppIdBuf pointer to caller allocated buffer
  2117. Return Values:
  2118. Number of bytes used from buffer
  2119. ---*/
  2120. DWORD AddQosAppID(
  2121. IN OUT char *pAppIdBuf,
  2122. IN WORD wBufLen,
  2123. IN const char *szPolicyLocator,
  2124. IN const char *szAppName,
  2125. IN const char *szAppClass,
  2126. IN char *szQosName
  2127. )
  2128. {
  2129. RSVP_POLICY_INFO *pPolicyInfo = ( RSVP_POLICY_INFO* )pAppIdBuf;
  2130. RSVP_POLICY* pAppIdPE;
  2131. IDPE_ATTR *pAttr;
  2132. USHORT nAppIdAttrLen;
  2133. USHORT nPolicyLocatorAttrLen;
  2134. USHORT nTotalPaddedLen;
  2135. char str[128];
  2136. // Calculate the length of the buffer required
  2137. strcpy(str,",SAPP=");
  2138. strcat(str, szAppClass);
  2139. strcat(str, ",SAPP=");
  2140. strcat(str, szQosName);
  2141. nPolicyLocatorAttrLen =
  2142. IDPE_ATTR_HDR_LEN + strlen( szPolicyLocator ) + strlen( str ) + 1;
  2143. nAppIdAttrLen = IDPE_ATTR_HDR_LEN + strlen( szAppName ) + 1;
  2144. nTotalPaddedLen = sizeof( RSVP_POLICY_INFO ) - ( sizeof( UCHAR ) * 4 ) +
  2145. RSVP_BYTE_MULTIPLE( nAppIdAttrLen ) +
  2146. RSVP_BYTE_MULTIPLE( nPolicyLocatorAttrLen );
  2147. // If the supplied buffer is not long enough, return 0
  2148. if( wBufLen < nTotalPaddedLen )
  2149. {
  2150. return 0;
  2151. }
  2152. ZeroMemory( pAppIdBuf, nTotalPaddedLen );
  2153. // Set the RSVP_POLICY_INFO header
  2154. pPolicyInfo->ObjectHdr.ObjectType = RSVP_OBJECT_POLICY_INFO;
  2155. pPolicyInfo->ObjectHdr.ObjectLength = nTotalPaddedLen;
  2156. pPolicyInfo->NumPolicyElement = 1;
  2157. // Now set up RSVP_POLICY object header
  2158. pAppIdPE = pPolicyInfo->PolicyElement;
  2159. pAppIdPE->Len = RSVP_POLICY_HDR_LEN +
  2160. RSVP_BYTE_MULTIPLE( nAppIdAttrLen ) +
  2161. RSVP_BYTE_MULTIPLE( nPolicyLocatorAttrLen );
  2162. pAppIdPE->Type = PE_TYPE_APPID;
  2163. // The first application id attribute is the policy locator string
  2164. pAttr = ( IDPE_ATTR * )( (char *)pAppIdPE + RSVP_POLICY_HDR_LEN );
  2165. // Set the attribute length in network order.
  2166. pAttr->PeAttribLength = htons( nPolicyLocatorAttrLen );
  2167. pAttr->PeAttribType = PE_ATTRIB_TYPE_POLICY_LOCATOR;
  2168. pAttr->PeAttribSubType = POLICY_LOCATOR_SUB_TYPE_ASCII_DN;
  2169. strcpy( (char *)pAttr->PeAttribValue, szPolicyLocator );
  2170. strcat( (char *)pAttr->PeAttribValue, str );
  2171. // The application name attribute comes next
  2172. pAttr = ( IDPE_ATTR * )( (char*)pAttr +
  2173. RSVP_BYTE_MULTIPLE( nPolicyLocatorAttrLen ) );
  2174. pAttr->PeAttribLength = htons( nAppIdAttrLen );
  2175. pAttr->PeAttribType = PE_ATTRIB_TYPE_CREDENTIAL;
  2176. pAttr->PeAttribSubType = CREDENTIAL_SUB_TYPE_ASCII_ID;
  2177. strcpy( ( char * )pAttr->PeAttribValue, szAppName );
  2178. return( nTotalPaddedLen );
  2179. }