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.

2356 lines
64 KiB

  1. #include "precomp.h"
  2. DEBUG_FILEZONE(ZONE_T120_MCSNC);
  3. /*
  4. * user.cpp
  5. *
  6. * Copyright (c) 1993 - 1996 by DataBeam Corporation, Lexington, KY
  7. *
  8. * Abstract:
  9. * This is the implementation file for the User class. Objects of this
  10. * class represent the attachment between a user application and an MCS
  11. * domain. It "talks" to the application through an application interface
  12. * object, which is identified to it as a constructor parameter. Since
  13. * this class inherits from CommandTarget, it can talk to the domain
  14. * object using the MCS command language defined therein. The domain
  15. * object to which it must attach is another constructor parameter.
  16. *
  17. * When one of these objects is first created, it must register its
  18. * presence with both the application interface object above it, and the
  19. * domain object below it. To register with the application interface
  20. * object it sends it a registration message through the owner callback.
  21. * To register with the domain object, it issues an attach user request
  22. * on behalf of the application that created this attachment.
  23. *
  24. * This module contains code to perform three different tasks: accept
  25. * T.122 requests and responses from the user application and forward them
  26. * to the domain as MCS commands; accept MCS commands from the domain and
  27. * forward them to the application as T.122 primitives; and buffer those
  28. * indications and confirms until the controller allocates a time slice in
  29. * which to send them.
  30. *
  31. * T.122 requests and responses come from the application interface as
  32. * public member functions whose name is prefixed with "MCS" (for example,
  33. * "MCSChannelJoinRequest"). After validation, the equivalent MCS command
  34. * (whose name does NOT begin with "MCS") is sent to the domain object.
  35. *
  36. * MCS commands come from the domain object as public member functions that
  37. * are inherited from CommandTarget and overridden by this class. The
  38. * names of these functions are NOT prefixed with "MCS". Any MCS commands
  39. * that do not map to (or can be converted to) T.122 primitives are simply
  40. * not overridden. The default behavior of these functions ,as defined in
  41. * the CommandTarget class, is to return an error.
  42. *
  43. * Indication and confirm primitives are buffered by objects of this class
  44. * before being sent to the application. This allows the controller more
  45. * flexibility in the timing of events in the system. This is done by
  46. * allocating a structure to hold the information associated with the
  47. * primitive, and then putting a pointer to that structure into a linked
  48. * list. When the command comes to flush this message queue, the
  49. * primitives are sent to the application interface object through the
  50. * owner callback, and the structures are released.
  51. *
  52. * Private Instance Variables:
  53. * m_pDomain
  54. * This is a pointer to the domain, to which this user is (or wishes
  55. * to be) attached.
  56. * User_ID
  57. * This is the user ID assigned to this user attachment. This is
  58. * guaranteed to be unique ONLY within this domain. Note that a value
  59. * of 0 (zero) indicates that this user is not yet attached to the
  60. * domain. This is set by a successful attach user confirm, and the
  61. * user application should wait until that confirm is received before
  62. * trying to invoke any other MCS services.
  63. * Merge_In_Progress
  64. * This is a boolean flag that indicates whether or not the attached
  65. * Domain object is in the merge state. When in the merge state it
  66. * is invalid to send it any MCS commands.
  67. * Deletion_Pending
  68. * This is a boolean flag that indicates whether or not an internally
  69. * requested deletion is pending. This is used by the destructor to
  70. * determine if a deletion was requested by the object itself, or is
  71. * simply an asynchronous event.
  72. * Maximum_User_Data_Length
  73. * This is the maximum amount of user data that can be placed into
  74. * a single MCS PDU. This number is derived from the arbitrated
  75. * maximum MCS PDU size (minus enough space for overhead bytes).
  76. *
  77. * Private Member Functions:
  78. * ValidateUserRequest
  79. * This member function is called each time the user application makes
  80. * a request. It checks the current state of the system to see if
  81. * conditions are such that the request can be processed at the
  82. * current time.
  83. * PurgeMessageQueue
  84. * This member function walks through the current message queue,
  85. * freeing all resources held therein.
  86. *
  87. * Caveats:
  88. * None.
  89. *
  90. * Author:
  91. * James P. Galvin, Jr.
  92. */
  93. #include "omcscode.h"
  94. #define USER_MSG_BASE WM_APP
  95. /*
  96. * bugbug:
  97. * The following constant is only used to cover a bug in NM 2.0 for backward
  98. * compatibility purposes. NM 2.0 can not accept MCS data PDUs with more than
  99. * 4096 bytes of user data. Because of the Max MCS PDU size we negotiate (4128),
  100. * even in NM 2.0, we should have been able to send 4120 bytes. But NM 2.0 chokes
  101. * in this case.
  102. * The constant should eliminated after NM 3.0.
  103. */
  104. #define BER_PROTOCOL_EXTRA_OVERHEAD 24
  105. /*
  106. * This is a global variable that has a pointer to the one MCS coder that
  107. * is instantiated by the MCS Controller. Most objects know in advance
  108. * whether they need to use the MCS or the GCC coder, so, they do not need
  109. * this pointer in their constructors.
  110. */
  111. extern CMCSCoder *g_MCSCoder;
  112. // The external MCS Controller object
  113. extern PController g_pMCSController;
  114. // The global MCS Critical Section
  115. extern CRITICAL_SECTION g_MCS_Critical_Section;
  116. // The DLL's HINSTANCE
  117. extern HINSTANCE g_hDllInst;
  118. // Class name for windows used by MCS attachments.
  119. static char s_WindowClassName[CLASS_NAME_LENGTH];
  120. // Initialization of the class's static variables.
  121. CTimerUserList2* User::s_pTimerUserList2 = NULL;
  122. HINSTANCE User::s_hInstance = NULL;
  123. /*
  124. * BOOL InitializeClass ()
  125. *
  126. * Public, static
  127. *
  128. * Functional Description
  129. *
  130. * This function initializes the class's static variables. It is
  131. * called during the MCS Controller's construction.
  132. */
  133. BOOL User::InitializeClass (void)
  134. {
  135. BOOL bReturnValue;
  136. WNDCLASS window_class;
  137. DBG_SAVE_FILE_LINE
  138. s_pTimerUserList2 = new CTimerUserList2();
  139. bReturnValue = (s_pTimerUserList2 != NULL);
  140. if (bReturnValue) {
  141. // Construct the window class name
  142. wsprintf (s_WindowClassName, "MCS Window %x %x", GetCurrentProcessId(), GetTickCount());
  143. /*
  144. * Fill out a window class structure in preparation for registering
  145. * the window with Windows. Note that since this is a hidden
  146. * window, most of the fields can be set to NULL or 0.
  147. */
  148. ZeroMemory (&window_class, sizeof(WNDCLASS));
  149. window_class.lpfnWndProc = (WNDPROC) UserWindowProc;
  150. window_class.hInstance = s_hInstance = g_hDllInst;
  151. window_class.lpszClassName = s_WindowClassName;
  152. /*
  153. * Register the class with Windows so that we can create a window
  154. * for use by this portal.
  155. */
  156. if (RegisterClass (&window_class) == 0)
  157. {
  158. ERROR_OUT (("InitWindowPortals: window class registration failed. Error: %d", GetLastError()));
  159. bReturnValue = FALSE;
  160. }
  161. }
  162. else {
  163. ERROR_OUT(("User::InitializeClass: Failed to allocate timer dictionary."));
  164. }
  165. return bReturnValue;
  166. }
  167. /*
  168. * void CleanupClass ()
  169. *
  170. * Public, static
  171. *
  172. * Functional Description
  173. *
  174. * This function cleans up the class's static variables. It is
  175. * called when the MCS Controller is deleted.
  176. */
  177. void User::CleanupClass (void)
  178. {
  179. delete s_pTimerUserList2;
  180. UnregisterClass (s_WindowClassName, s_hInstance);
  181. }
  182. /*
  183. * MCSError MCS_AttachRequest ()
  184. *
  185. * Public
  186. *
  187. * Functional Description:
  188. * This API entry point is used to attach to an existing domain. Once
  189. * attached, a user application can utilize the services of MCS. When
  190. * a user application is through with MCS, it should detach from the domain
  191. * by calling MCSDetachUserRequest (see below).
  192. */
  193. MCSError WINAPI MCS_AttachRequest (IMCSSap ** ppIMCSSap,
  194. DomainSelector domain_selector,
  195. UINT, // domain_selector_length
  196. MCSCallBack user_callback,
  197. PVoid user_defined,
  198. UINT flags)
  199. {
  200. MCSError return_value = MCS_NO_ERROR;
  201. AttachRequestInfo attach_request_info;
  202. PUser pUser;
  203. TRACE_OUT(("AttachUserRequest: beginning attachment process"));
  204. ASSERT (user_callback);
  205. // Initialize the interface ptr.
  206. *ppIMCSSap = NULL;
  207. /*
  208. * Pack the attach parameters into a structure since they will not fit
  209. * into the one parameter we have available in the owner callback.
  210. */
  211. attach_request_info.domain_selector = (GCCConfID *) domain_selector;
  212. attach_request_info.ppuser = &pUser;
  213. /*
  214. * Enter the critical section which protects global data.
  215. */
  216. EnterCriticalSection (& g_MCS_Critical_Section);
  217. if (g_pMCSController != NULL) {
  218. /*
  219. * Send an attach user request message to the controller through its
  220. * owner callback function.
  221. */
  222. return_value = g_pMCSController->HandleAppletAttachUserRequest(&attach_request_info);
  223. if (return_value == (ULong) MCS_NO_ERROR)
  224. {
  225. // Set the returned interface ptr
  226. *ppIMCSSap = (IMCSSap *) pUser;
  227. /*
  228. * If the request was accepted, then register
  229. * the new user attachment. Note that there
  230. * is still no user ID associated with this
  231. * attachment, since the attach user confirm
  232. * has not yet been received.
  233. */
  234. pUser->RegisterUserAttachment (user_callback, user_defined,
  235. flags);
  236. }
  237. }
  238. else {
  239. ERROR_OUT(("MCS_AttachRequest: MCS Provider is not initialized."));
  240. return_value = MCS_NOT_INITIALIZED;
  241. }
  242. /*
  243. * Leave the critical section before returning.
  244. */
  245. LeaveCriticalSection (& g_MCS_Critical_Section);
  246. return (return_value);
  247. }
  248. /*
  249. * User ()
  250. *
  251. * Public
  252. *
  253. * Functional Description:
  254. * This is the constructor for the user class. It initializes all instance
  255. * variables (mostly with passed in information). It then registers its
  256. * presence with the application interface object, so that user requests
  257. * and responses will get here okay. Finally, it issues an attach user
  258. * request to the domain to start the attachment process.
  259. */
  260. User::User (PDomain pDomain,
  261. PMCSError pError)
  262. :
  263. CAttachment(USER_ATTACHMENT),
  264. m_pDomain(pDomain),
  265. Deletion_Pending (FALSE),
  266. User_ID (0),
  267. Merge_In_Progress (FALSE),
  268. m_DataPktQueue(),
  269. m_PostMsgPendingQueue(),
  270. m_DataIndMemoryBuf2(),
  271. CRefCount(MAKE_STAMP_ID('U','s','e','r'))
  272. {
  273. DomainParameters domain_parameters;
  274. g_pMCSController->AddRef();
  275. /*
  276. * We now need to create the window that the MCS Provider
  277. * will use to deliver MCS messages to the attachment.
  278. * These messages are indications and confirms.
  279. */
  280. m_hWnd = CreateWindow (s_WindowClassName,
  281. NULL,
  282. WS_POPUP,
  283. CW_USEDEFAULT,
  284. CW_USEDEFAULT,
  285. CW_USEDEFAULT,
  286. CW_USEDEFAULT,
  287. NULL,
  288. NULL,
  289. g_hDllInst,
  290. NULL);
  291. if (m_hWnd != NULL) {
  292. /*
  293. * Call the domain object to find out the current domain parameters.
  294. * From this, set the maximum user data length appropriately.
  295. */
  296. m_pDomain->GetDomainParameters (&domain_parameters, NULL, NULL);
  297. Maximum_User_Data_Length = domain_parameters.max_mcspdu_size -
  298. (MAXIMUM_PROTOCOL_OVERHEAD_MCS +
  299. BER_PROTOCOL_EXTRA_OVERHEAD);
  300. TRACE_OUT (("User::User: "
  301. "maximum user data length = %ld", Maximum_User_Data_Length));
  302. /*
  303. * Use the specified domain parameters to set the type of encoding rules
  304. * to be used.
  305. */
  306. ASSERT (domain_parameters.protocol_version == PROTOCOL_VERSION_PACKED);
  307. /*
  308. * Send an attach user request to the specified domain.
  309. */
  310. m_pDomain->AttachUserRequest (this);
  311. *pError = MCS_NO_ERROR;
  312. }
  313. else {
  314. *pError = MCS_ALLOCATION_FAILURE;
  315. }
  316. }
  317. /*
  318. * ~User ()
  319. *
  320. * Public
  321. *
  322. * Functional Description:
  323. *
  324. */
  325. User::~User ()
  326. {
  327. PDataPacket packet;
  328. while (NULL != (packet = m_PostMsgPendingQueue.Get()))
  329. {
  330. packet->Unlock();
  331. }
  332. if (m_hWnd) {
  333. // Destroy the window; we do not need it anymore
  334. DestroyWindow (m_hWnd);
  335. }
  336. g_pMCSController->Release();
  337. }
  338. /*
  339. * MCSError GetBuffer ()
  340. *
  341. * Public
  342. *
  343. * Functional Description:
  344. * This function allocates an MCS buffer for a user attachment.
  345. * Because this function allocates a buffer for the user and a Memory
  346. * object that immediately precedes the buffer, after the user fills in
  347. * the buffer with data and gives it to MCS to send, it needs to specify the
  348. * right flags in the SendData request API.
  349. */
  350. MCSError User::GetBuffer (UINT size, PVoid *pbuffer)
  351. {
  352. MCSError return_value;
  353. PMemory memory;
  354. EnterCriticalSection (& g_MCS_Critical_Section);
  355. /*
  356. * This request may be a retry from a previous request which
  357. * returned MCS_TRANSMIT_BUFFER_FULL. If so, delete the associated
  358. * buffer retry info structure since resource levels will be
  359. * checked in this function anyway.
  360. */
  361. if (m_BufferRetryInfo != NULL) {
  362. KillTimer (NULL, m_BufferRetryInfo->timer_id);
  363. s_pTimerUserList2->Remove(m_BufferRetryInfo->timer_id);
  364. delete m_BufferRetryInfo;
  365. m_BufferRetryInfo = NULL;
  366. }
  367. // Allocate the memory
  368. DBG_SAVE_FILE_LINE
  369. memory = AllocateMemory (NULL, size + MAXIMUM_PROTOCOL_OVERHEAD,
  370. SEND_PRIORITY);
  371. LeaveCriticalSection (& g_MCS_Critical_Section);
  372. if (NULL != memory) {
  373. // the allocation succeeded.
  374. ASSERT ((PUChar) memory + sizeof(Memory) == memory->GetPointer());
  375. *pbuffer = (PVoid) (memory->GetPointer() + MAXIMUM_PROTOCOL_OVERHEAD);
  376. return_value = MCS_NO_ERROR;
  377. }
  378. else {
  379. // the allocation failed.
  380. TRACE_OUT (("User::GetBuffer: Failed to allocate data buffer."));
  381. CreateRetryTimer (size + MAXIMUM_PROTOCOL_OVERHEAD);
  382. return_value = MCS_TRANSMIT_BUFFER_FULL;
  383. }
  384. return (return_value);
  385. }
  386. /*
  387. * MCSError FreeBuffer ()
  388. *
  389. * Public
  390. *
  391. * Functional Description:
  392. */
  393. void User::FreeBuffer (PVoid buffer_ptr)
  394. {
  395. PMemory memory;
  396. ASSERT (m_fFreeDataIndBuffer == FALSE);
  397. /*
  398. * Attempt to find the buffer in the m_DataIndDictionary dictionary.
  399. * This is where irregular data indications go.
  400. */
  401. if (NULL == (memory = m_DataIndMemoryBuf2.Remove(buffer_ptr)))
  402. {
  403. memory = GetMemoryObject(buffer_ptr);
  404. }
  405. // Free the memory.
  406. EnterCriticalSection (& g_MCS_Critical_Section);
  407. FreeMemory (memory);
  408. LeaveCriticalSection (& g_MCS_Critical_Section);
  409. }
  410. /*
  411. * Void CreateRetryTimer
  412. *
  413. * Private
  414. *
  415. * Functional Description
  416. * This functions creates a timer in response to a failure to
  417. * allocate memory for the send data that the user is trying to
  418. * send. The timer will fire off periodically so that this code
  419. * will remember to check the memory levels and provide an
  420. * MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION to the user.
  421. *
  422. * Return Value:
  423. * None.
  424. *
  425. * Side effects:
  426. * The timer is created.
  427. */
  428. Void User::CreateRetryTimer (ULong size)
  429. {
  430. UINT_PTR timer_id;
  431. timer_id = SetTimer (NULL, 0, TIMER_PROCEDURE_TIMEOUT, (TIMERPROC) TimerProc);
  432. if (timer_id != 0) {
  433. DBG_SAVE_FILE_LINE
  434. m_BufferRetryInfo = new BufferRetryInfo;
  435. if (m_BufferRetryInfo != NULL) {
  436. m_BufferRetryInfo->user_data_length = size;
  437. m_BufferRetryInfo->timer_id = timer_id;
  438. s_pTimerUserList2->Append(timer_id, this);
  439. }
  440. else {
  441. ERROR_OUT (("User::CreateRetryTimer: Failed to allocate BufferRetryInfo struct."));
  442. KillTimer (NULL, timer_id);
  443. }
  444. }
  445. else {
  446. /*
  447. * This is a bad error, The notification to the user when buffers
  448. * are available will be lost. Hopefully, the user will try again
  449. * later.
  450. */
  451. WARNING_OUT(("User::CreateRetryTimer: Could not SetTimer."));
  452. }
  453. }
  454. /*
  455. * MCSError ReleaseInterface ()
  456. *
  457. * Public
  458. *
  459. * Functional Description:
  460. * This function is called when a user wishes to detach from the domain.
  461. * It kicks off the process of detaching, and seeing that this object
  462. * is properly deleted.
  463. */
  464. MCSError User::ReleaseInterface ()
  465. {
  466. CUidList deletion_list;
  467. MCSError return_value;
  468. EnterCriticalSection (& g_MCS_Critical_Section);
  469. /*
  470. * Check to see if there is a merge operation in progress before proceeding
  471. * with the request.
  472. */
  473. if (Merge_In_Progress == FALSE)
  474. {
  475. /*
  476. * If deletion is not already pending, then it is necessary for us
  477. * to tell the domain that we are leaving.
  478. */
  479. if (Deletion_Pending == FALSE)
  480. {
  481. /*
  482. * If we are already attached, user ID will not be 0, and we
  483. * should send a detach user request. If user ID IS 0, then we
  484. * are not yet attached to the domain, so a disconnect provider
  485. * ultimatum is used instead.
  486. */
  487. if (User_ID != 0)
  488. {
  489. deletion_list.Append(User_ID);
  490. m_pDomain->DetachUserRequest (this,
  491. REASON_USER_REQUESTED, &deletion_list);
  492. User_ID = 0;
  493. }
  494. else
  495. m_pDomain->DisconnectProviderUltimatum (this,
  496. REASON_USER_REQUESTED);
  497. /*
  498. * Set the flag that will cause the object to be deleted during
  499. * the next call to FlushMessageQueue.
  500. */
  501. Deletion_Pending = TRUE;
  502. }
  503. /*
  504. * Empty out the message queue (the application should receive no
  505. * messages once the attachment has been deleted).
  506. */
  507. PurgeMessageQueue ();
  508. // Cleanup timers and retry structures;
  509. if (m_BufferRetryInfo != NULL) {
  510. s_pTimerUserList2->Remove(m_BufferRetryInfo->timer_id);
  511. KillTimer (NULL, m_BufferRetryInfo->timer_id);
  512. delete m_BufferRetryInfo;
  513. m_BufferRetryInfo = NULL;
  514. }
  515. return_value = MCS_NO_ERROR;
  516. // Release can release the MCS Controller, so, we have to exit the CS now.
  517. LeaveCriticalSection (& g_MCS_Critical_Section);
  518. /*
  519. * Release this object. Note that the object may be deleted
  520. * here, so, we should not access any member variables after this
  521. * call.
  522. */
  523. Release();
  524. }
  525. else
  526. {
  527. LeaveCriticalSection (& g_MCS_Critical_Section);
  528. /*
  529. * This operation could not be processed at this time due to a merge
  530. * operation in progress at the local provider.
  531. */
  532. WARNING_OUT (("User::ReleaseInterface: "
  533. "merge in progress"));
  534. return_value = MCS_DOMAIN_MERGING;
  535. }
  536. return (return_value);
  537. }
  538. #define CHANNEL_JOIN 0
  539. #define CHANNEL_LEAVE 1
  540. #define CHANNEL_CONVENE 2
  541. #define CHANNEL_DISBAND 3
  542. /*
  543. * MCSError ChannelJLCD ()
  544. *
  545. * Public
  546. *
  547. * Functional Description:
  548. * This function is called when the user application wishes to join/leave/convene/disband
  549. * a channel. If the user is attached to the domain, the request will be
  550. * repackaged as an MCS command and sent to the domain object.
  551. */
  552. MCSError User::ChannelJLCD (int type, ChannelID channel_id)
  553. {
  554. MCSError return_value;
  555. EnterCriticalSection (& g_MCS_Critical_Section);
  556. /*
  557. * Verify that current conditions are appropriate for a request to be
  558. * accepted from a user attachment.
  559. */
  560. return_value = ValidateUserRequest ();
  561. if (return_value == MCS_NO_ERROR) {
  562. switch (type) {
  563. case CHANNEL_JOIN:
  564. m_pDomain->ChannelJoinRequest (this, User_ID, channel_id);
  565. break;
  566. case CHANNEL_LEAVE:
  567. {
  568. CChannelIDList deletion_list;
  569. deletion_list.Append(channel_id);
  570. m_pDomain->ChannelLeaveRequest (this, &deletion_list);
  571. }
  572. break;
  573. case CHANNEL_CONVENE:
  574. m_pDomain->ChannelConveneRequest (this, User_ID);
  575. break;
  576. case CHANNEL_DISBAND:
  577. m_pDomain->ChannelDisbandRequest (this, User_ID, channel_id);
  578. break;
  579. }
  580. }
  581. LeaveCriticalSection (& g_MCS_Critical_Section);
  582. return (return_value);
  583. }
  584. /*
  585. * MCSError ChannelJoin ()
  586. *
  587. * Public
  588. *
  589. * Functional Description:
  590. * This function is called when the user application wishes to join a
  591. * channel. If the user is attached to the domain, the request will be
  592. * repackaged as an MCS command and sent to the domain object.
  593. */
  594. MCSError User::ChannelJoin (ChannelID channel_id)
  595. {
  596. return (ChannelJLCD (CHANNEL_JOIN, channel_id));
  597. }
  598. /*
  599. * MCSError ChannelLeave ()
  600. *
  601. * Public
  602. *
  603. * Functional Description:
  604. * This function is called when the user application wishes to leave a
  605. * channel. If the user is attached to the domain, the request will be
  606. * repackaged as an MCS command and sent to the domain object.
  607. */
  608. MCSError User::ChannelLeave (ChannelID channel_id)
  609. {
  610. return (ChannelJLCD (CHANNEL_LEAVE, channel_id));
  611. }
  612. /*
  613. * MCSError ChannelConvene ()
  614. *
  615. * Public
  616. *
  617. * Functional Description:
  618. * This function is called when the user application wishes to convene a
  619. * private channel. If the user is attached to the domain, the request
  620. * will be repackaged as an MCS command and sent to the domain object.
  621. */
  622. MCSError User::ChannelConvene ()
  623. {
  624. return (ChannelJLCD (CHANNEL_CONVENE, 0));
  625. }
  626. /*
  627. * MCSError ChannelDisband ()
  628. *
  629. * Public
  630. *
  631. * Functional Description:
  632. * This function is called when the user application wishes to disband a
  633. * private channel. If the user is attached to the domain, the request
  634. * will be repackaged as an MCS command and sent to the domain object.
  635. */
  636. MCSError User::ChannelDisband (
  637. ChannelID channel_id)
  638. {
  639. return (ChannelJLCD (CHANNEL_DISBAND, channel_id));
  640. }
  641. /*
  642. * MCSError ChannelAdmit ()
  643. *
  644. * Public
  645. *
  646. * Functional Description:
  647. * This function is called when the user application wishes to admit more
  648. * users to a private channel for which it is manager. If the user is
  649. * attached to the domain, the request will be repackaged as an MCS command
  650. * and sent to the domain object.
  651. */
  652. MCSError User::ChannelAdmit (
  653. ChannelID channel_id,
  654. PUserID user_id_list,
  655. UINT user_id_count)
  656. {
  657. UINT count;
  658. CUidList local_user_id_list;
  659. MCSError return_value = MCS_NO_ERROR;
  660. /*
  661. * Verify that the value of each user ID included in the user ID list is
  662. * a valid value. Otherwise, fail the call.
  663. */
  664. for (count = 0; count < user_id_count; count++)
  665. {
  666. if (user_id_list[count] > 1000) {
  667. // add the UserID into the singly-linked list.
  668. local_user_id_list.Append(user_id_list[count]);
  669. }
  670. else {
  671. return_value = MCS_INVALID_PARAMETER;
  672. break;
  673. }
  674. }
  675. if (return_value == MCS_NO_ERROR) {
  676. EnterCriticalSection (& g_MCS_Critical_Section);
  677. /*
  678. * Verify that current conditions are appropriate for a request to be
  679. * accepted from a user attachment.
  680. */
  681. return_value = ValidateUserRequest ();
  682. if (return_value == MCS_NO_ERROR)
  683. {
  684. m_pDomain->ChannelAdmitRequest (this, User_ID, channel_id,
  685. &local_user_id_list);
  686. }
  687. LeaveCriticalSection (& g_MCS_Critical_Section);
  688. }
  689. return (return_value);
  690. }
  691. #ifdef USE_CHANNEL_EXPEL_REQUEST
  692. /*
  693. * MCSError MCSChannelExpelRequest ()
  694. *
  695. * Public
  696. *
  697. * Functional Description:
  698. * This function is called when the user application wishes to expel
  699. * users from a private channel for which it is manager. If the user is
  700. * attached to the domain, the request will be repackaged as an MCS command
  701. * and sent to the domain object.
  702. */
  703. MCSError User::ChannelExpel (
  704. ChannelID channel_id,
  705. PMemory memory,
  706. UINT user_id_count)
  707. {
  708. UINT count;
  709. CUidList local_user_id_list;
  710. MCSError return_value;
  711. PUserID user_id_list = (PUserID) memory->GetPointer();
  712. /*
  713. * Verify that current conditions are appropriate for a request to be
  714. * accepted from a user attachment.
  715. */
  716. return_value = ValidateUserRequest ();
  717. if (return_value == MCS_NO_ERROR)
  718. {
  719. /*
  720. * Repack the user ID list into an S-list before sending it on.
  721. */
  722. for (count=0; count < user_id_count; count++)
  723. local_user_id_list.append ((DWORD) user_id_list[count]);
  724. m_pDomain->ChannelExpelRequest (this, User_ID, channel_id,
  725. &local_user_id_list);
  726. }
  727. if (return_value != MCS_DOMAIN_MERGING)
  728. FreeMemory (memory);
  729. return (return_value);
  730. }
  731. #endif // USE_CHANNEL_EXPEL_REQUEST
  732. /*
  733. * MCSError SendData ()
  734. *
  735. * Public
  736. *
  737. * Functional Description:
  738. * This function is called when the user application wishes to send data
  739. * on a channel. If the user is attached to the domain, the request will
  740. * be repackaged as an MCS command and sent to the domain object.
  741. *
  742. * Note that this version of the send data request assumes that the user
  743. * data has not already been segmented. This is the function that
  744. * performs the segmentation.
  745. */
  746. MCSError User::SendData (DataRequestType request_type,
  747. ChannelID channel_id,
  748. Priority priority,
  749. unsigned char * user_data,
  750. ULong user_data_length,
  751. SendDataFlags flags)
  752. {
  753. MCSError return_value = MCS_NO_ERROR;
  754. ULong i, request_count, user_packet_length;
  755. PDataPacket packet;
  756. ASN1choice_t choice;
  757. UINT type;
  758. PUChar data_ptr = user_data;
  759. PacketError packet_error;
  760. Segmentation segmentation;
  761. PMemory memory;
  762. PDataPacket *packets;
  763. /*
  764. * Calculate how many different MCS packets are going to be generated.
  765. * Remember that if the size of the request exceeds the maximum allowed
  766. * value, we will segment the data into multiple smaller pieces.
  767. */
  768. request_count = ((user_data_length + (Maximum_User_Data_Length - 1)) /
  769. Maximum_User_Data_Length);
  770. /*
  771. * Allocate the array of PDataPackets, before we get the critical section.
  772. */
  773. if (request_count == 1) {
  774. packets = &packet;
  775. packet = NULL;
  776. }
  777. else {
  778. DBG_SAVE_FILE_LINE
  779. packets = new PDataPacket[request_count];
  780. if (packets == NULL) {
  781. ERROR_OUT (("User::SendData: Failed to allocate packet array."));
  782. return_value = MCS_TRANSMIT_BUFFER_FULL;
  783. }
  784. else {
  785. ZeroMemory ((PVoid) packets, request_count * sizeof(PDataPacket));
  786. }
  787. }
  788. if (MCS_NO_ERROR == return_value) {
  789. // Set the choice and type variables for all the DataPackets.
  790. if (NORMAL_SEND_DATA == request_type) {
  791. choice = SEND_DATA_REQUEST_CHOSEN;
  792. type = MCS_SEND_DATA_INDICATION;
  793. }
  794. else {
  795. choice = UNIFORM_SEND_DATA_REQUEST_CHOSEN;
  796. type = MCS_UNIFORM_SEND_DATA_INDICATION;
  797. }
  798. EnterCriticalSection (& g_MCS_Critical_Section);
  799. /*
  800. * Verify that current conditions are appropriate for a request to be
  801. * accepted from a user attachment.
  802. */
  803. return_value = ValidateUserRequest ();
  804. /*
  805. * Check to see if there is a merge operation in progress before proceeding
  806. * with the request.
  807. */
  808. if (MCS_NO_ERROR == return_value) {
  809. /*
  810. * This request may be a retry from a previous request which
  811. * returned MCS_TRANSMIT_BUFFER_FULL. If so, delete the associated
  812. * buffer retry info structure since resource levels will be
  813. * checked in this function anyway.
  814. */
  815. if (m_BufferRetryInfo != NULL) {
  816. s_pTimerUserList2->Remove(m_BufferRetryInfo->timer_id);
  817. KillTimer (NULL, m_BufferRetryInfo->timer_id);
  818. delete m_BufferRetryInfo;
  819. m_BufferRetryInfo = NULL;
  820. }
  821. /*
  822. * Depending on the "flags" argument, we either have
  823. * to allocate the buffer space and copy the data into
  824. * it, or just create a Memory object for the supplied
  825. * buffer.
  826. */
  827. if (flags != APP_ALLOCATION) {
  828. ASSERT (flags == MCS_ALLOCATION);
  829. /*
  830. * The buffer was allocated by MCS, thru an
  831. * MCSGetBufferRequest call. So, the Memory object
  832. * must preceed the buffer.
  833. */
  834. memory = GetMemoryObject (user_data);
  835. ASSERT (SIGNATURE_MATCH(memory, MemorySignature));
  836. }
  837. else
  838. memory = NULL;
  839. /*
  840. * We now attempt to allocate all data packets at once.
  841. * We need to do that before starting to send them, because
  842. * the request has to be totally successful or totally fail.
  843. * We can not succeed in sending a part of the request.
  844. */
  845. for (i = 0; (ULong) i < request_count; i++) {
  846. // take care of segmentation flags
  847. if (i == 0)
  848. // first segment
  849. segmentation = SEGMENTATION_BEGIN;
  850. else
  851. segmentation = 0;
  852. if (i == request_count - 1) {
  853. // last segment
  854. segmentation |= SEGMENTATION_END;
  855. user_packet_length = user_data_length - (ULong)(data_ptr - user_data);
  856. }
  857. else {
  858. user_packet_length = Maximum_User_Data_Length;
  859. }
  860. // Now, create the new DataPacket.
  861. DBG_SAVE_FILE_LINE
  862. packets[i] = new DataPacket (choice, data_ptr, user_packet_length,
  863. (UINT) channel_id, priority,
  864. segmentation, (UINT) User_ID,
  865. flags, memory, &packet_error);
  866. // Make sure the allocation succeeded
  867. if ((packets[i] == NULL) || (packet_error != PACKET_NO_ERROR)) {
  868. /*
  869. * The allocation of the packet failed. We must therefore
  870. * return a failure to the user application.
  871. */
  872. WARNING_OUT (("User::SendData: data packet allocation failed"));
  873. return_value = MCS_TRANSMIT_BUFFER_FULL;
  874. break;
  875. }
  876. // Adjust the user data ptr
  877. data_ptr += Maximum_User_Data_Length;
  878. }
  879. if (return_value == MCS_NO_ERROR) {
  880. // We now can send the data.
  881. // Forward all the data packets to the appropriate places.
  882. for (i = 0; i < request_count; i++) {
  883. /*
  884. * Send the successfully created packet to the domain
  885. * for processing.
  886. */
  887. m_pDomain->SendDataRequest (this, (UINT) type, packets[i]);
  888. /*
  889. * Enable the packet to free itself. Note that it will not
  890. * actually do so until everyone that is using it is through
  891. * with it. Also, if nobody has locked it so far,
  892. * it will be deleted.
  893. */
  894. packets[i]->Unlock ();
  895. }
  896. }
  897. else {
  898. // some packet allocation failed
  899. for (i = 0; i < request_count; i++)
  900. delete packets[i];
  901. }
  902. }
  903. if (request_count > 1)
  904. delete [] packets;
  905. }
  906. if (MCS_TRANSMIT_BUFFER_FULL == return_value) {
  907. CreateRetryTimer(user_data_length + request_count * MAXIMUM_PROTOCOL_OVERHEAD);
  908. }
  909. else if (MCS_NO_ERROR == return_value) {
  910. FreeMemory (memory);
  911. }
  912. LeaveCriticalSection (& g_MCS_Critical_Section);
  913. return (return_value);
  914. }
  915. #define GRAB 0
  916. #define INHIBIT 1
  917. #define PLEASE 2
  918. #define RELEASE 3
  919. #define TEST 4
  920. /*
  921. * MCSError TokenGIRPT ()
  922. *
  923. * Public
  924. *
  925. * Functional Description:
  926. * This function is called when the user application wishes to grab/inhibit/request/release/test
  927. * a token. If the user is attached to the domain, the request will
  928. * be repackaged as an MCS command and sent to the domain object.
  929. */
  930. MCSError User::TokenGIRPT (int type, TokenID token_id)
  931. {
  932. MCSError return_value;
  933. EnterCriticalSection (& g_MCS_Critical_Section);
  934. /*
  935. * Verify that current conditions are appropriate for a request to be
  936. * accepted from a user attachment.
  937. */
  938. return_value = ValidateUserRequest ();
  939. if (return_value == MCS_NO_ERROR)
  940. {
  941. switch (type) {
  942. case GRAB:
  943. m_pDomain->TokenGrabRequest (this, User_ID, token_id);
  944. break;
  945. case INHIBIT:
  946. m_pDomain->TokenInhibitRequest (this, User_ID, token_id);
  947. break;
  948. case PLEASE:
  949. m_pDomain->TokenPleaseRequest (this, User_ID, token_id);
  950. break;
  951. case RELEASE:
  952. m_pDomain->TokenReleaseRequest (this, User_ID, token_id);
  953. break;
  954. case TEST:
  955. m_pDomain->TokenTestRequest (this, User_ID, token_id);
  956. break;
  957. }
  958. }
  959. LeaveCriticalSection (& g_MCS_Critical_Section);
  960. return (return_value);
  961. }
  962. /*
  963. * MCSError TokenGrab ()
  964. *
  965. * Public
  966. *
  967. * Functional Description:
  968. * This function is called when the user application wishes to grab
  969. * a token. If the user is attached to the domain, the request will
  970. * be repackaged as an MCS command and sent to the domain object.
  971. */
  972. MCSError User::TokenGrab (TokenID token_id)
  973. {
  974. return (TokenGIRPT (GRAB, token_id));
  975. }
  976. /*
  977. * MCSError TokenInhibit ()
  978. *
  979. * Public
  980. *
  981. * Functional Description:
  982. * This function is called when the user application wishes to inhibit
  983. * a token. If the user is attached to the domain, the request will
  984. * be repackaged as an MCS command and sent to the domain object.
  985. */
  986. MCSError User::TokenInhibit (TokenID token_id)
  987. {
  988. return (TokenGIRPT (INHIBIT, token_id));
  989. }
  990. /*
  991. * MCSError TokenGive ()
  992. *
  993. * Public
  994. *
  995. * Functional Description:
  996. * This function is called when the user application wishes to give away
  997. * a token. If the user is attached to the domain, the request will
  998. * be repackaged as an MCS command and sent to the domain object.
  999. */
  1000. MCSError User::TokenGive (TokenID token_id, UserID receiver_id)
  1001. {
  1002. MCSError return_value;
  1003. TokenGiveRecord TokenGiveRec;
  1004. if (receiver_id > 1000) {
  1005. // Fill in the TokenGive command structure.
  1006. TokenGiveRec.uidInitiator = User_ID;
  1007. TokenGiveRec.token_id = token_id;
  1008. TokenGiveRec.receiver_id = receiver_id;
  1009. EnterCriticalSection (& g_MCS_Critical_Section);
  1010. /*
  1011. * Verify that current conditions are appropriate for a request to be
  1012. * accepted from a user attachment.
  1013. */
  1014. return_value = ValidateUserRequest ();
  1015. if (return_value == MCS_NO_ERROR) {
  1016. m_pDomain->TokenGiveRequest (this, &TokenGiveRec);
  1017. }
  1018. LeaveCriticalSection (& g_MCS_Critical_Section);
  1019. }
  1020. else {
  1021. ERROR_OUT(("User::TokenGive: Invalid UserID for receiver."));
  1022. return_value = MCS_INVALID_PARAMETER;
  1023. }
  1024. return (return_value);
  1025. }
  1026. /*
  1027. * MCSError TokenGiveResponse ()
  1028. *
  1029. * Public
  1030. *
  1031. * Functional Description:
  1032. * This function is called when the user application wishes to respond to
  1033. * a previously received token give indication. If the user is attached to
  1034. * the domain, the request will be repackaged as an MCS command and sent to
  1035. * the domain object.
  1036. */
  1037. MCSError User::TokenGiveResponse (TokenID token_id, Result result)
  1038. {
  1039. MCSError return_value;
  1040. EnterCriticalSection (& g_MCS_Critical_Section);
  1041. /*
  1042. * Verify that current conditions are appropriate for a request to be
  1043. * accepted from a user attachment.
  1044. */
  1045. return_value = ValidateUserRequest ();
  1046. if (return_value == MCS_NO_ERROR)
  1047. {
  1048. m_pDomain->TokenGiveResponse (this, result, User_ID, token_id);
  1049. }
  1050. LeaveCriticalSection (& g_MCS_Critical_Section);
  1051. return (return_value);
  1052. }
  1053. /*
  1054. * MCSError TokenPlease ()
  1055. *
  1056. * Public
  1057. *
  1058. * Functional Description:
  1059. * This function is called when the user application wishes to be given
  1060. * a token. If the user is attached to the domain, the request will
  1061. * be repackaged as an MCS command and sent to the domain object.
  1062. */
  1063. MCSError User::TokenPlease (TokenID token_id)
  1064. {
  1065. return (TokenGIRPT (PLEASE, token_id));
  1066. }
  1067. /*
  1068. * MCSError TokenRelease ()
  1069. *
  1070. * Public
  1071. *
  1072. * Functional Description:
  1073. * This function is called when the user application wishes to release
  1074. * a token. If the user is attached to the domain, the request will
  1075. * be repackaged as an MCS command and sent to the domain object.
  1076. */
  1077. MCSError User::TokenRelease (TokenID token_id)
  1078. {
  1079. return (TokenGIRPT (RELEASE, token_id));
  1080. }
  1081. /*
  1082. * MCSError TokenTest ()
  1083. *
  1084. * Public
  1085. *
  1086. * Functional Description:
  1087. * This function is called when the user application wishes to test
  1088. * a token. If the user is attached to the domain, the request will
  1089. * be repackaged as an MCS command and sent to the domain object.
  1090. */
  1091. MCSError User::TokenTest (TokenID token_id)
  1092. {
  1093. return (TokenGIRPT (TEST, token_id));
  1094. }
  1095. /*
  1096. * MCSError ValidateUserRequest ()
  1097. *
  1098. * Private
  1099. *
  1100. * Functional Description:
  1101. * This function is used to determine if it is valid to process an incoming
  1102. * request at the current time. It checks several different conditions
  1103. * to determine this, as follows:
  1104. *
  1105. * - If there is a merge in progress, then the request is not valid.
  1106. * - If this user is not yet attached to a domain, then the request
  1107. * is not valid.
  1108. * - If there are not enough objects of the Memory, Packet, or UserMessage
  1109. * class to handle a reasonable request, then the request is not valid.
  1110. *
  1111. * Note that the check on number of objects is not an absolute guarantee
  1112. * that there will be enough to handle a given request, because a request
  1113. * can result in MANY PDUs and user messages being generated. For example,
  1114. * a single channel admit request can result in lots of channel admit
  1115. * indications being sent. However, checking against a minimum number
  1116. * of objects can reduce the possibility of failure to be astronomically
  1117. * low. And remember, even if MCS runs out of something while processing
  1118. * such a request, it WILL handle it properly (by cleanly destroying the
  1119. * user attachment or MCS connection upon which the failure occurred). So
  1120. * there is no chance of MCS crashing as a result of this.
  1121. *
  1122. * Caveats:
  1123. * None.
  1124. */
  1125. MCSError User::ValidateUserRequest ()
  1126. {
  1127. MCSError return_value = MCS_NO_ERROR;
  1128. /*
  1129. * Check to see if there is a merge operation in progress.
  1130. */
  1131. if (Merge_In_Progress == FALSE)
  1132. {
  1133. /*
  1134. * Make sure the user is attached to the domain.
  1135. */
  1136. if (User_ID == 0)
  1137. {
  1138. /*
  1139. * The user is not yet attached to the domain. So fail the request
  1140. * without passing it on to the domain object.
  1141. */
  1142. TRACE_OUT (("User::ValidateUserRequest: user not attached"));
  1143. return_value = MCS_USER_NOT_ATTACHED;
  1144. }
  1145. }
  1146. else
  1147. {
  1148. /*
  1149. * This operation could not be processed at this time due to a merge
  1150. * operation in progress at the local provider.
  1151. *
  1152. * NOTE for JASPER:
  1153. * Jasper probably will need to wait on an event handle here, which will be
  1154. * set when the main MCS thread receives all the merging PDUs that get us out
  1155. * of the merging state. Since the only MCS client for Jasper is the GCC,
  1156. * it should be ok to block the client (GCC) while the merging goes on.
  1157. */
  1158. WARNING_OUT (("User::ValidateUserRequest: merge in progress"));
  1159. return_value = MCS_DOMAIN_MERGING;
  1160. }
  1161. return (return_value);
  1162. }
  1163. /*
  1164. * Void RegisterUserAttachment ()
  1165. *
  1166. * Public
  1167. *
  1168. * Functional Description:
  1169. * This method registers a user attachment with the User object.
  1170. */
  1171. void User::RegisterUserAttachment (MCSCallBack mcs_callback,
  1172. PVoid user_defined,
  1173. UINT flags)
  1174. {
  1175. TRACE_OUT (("User::RegisterUserAttachment: user handle = %p", this));
  1176. /*
  1177. * Fill in all of the members of the User object.
  1178. */
  1179. m_MCSCallback = mcs_callback;
  1180. m_UserDefined = user_defined;
  1181. m_BufferRetryInfo = NULL;
  1182. m_fDisconnectInDataLoss = (flags & ATTACHMENT_DISCONNECT_IN_DATA_LOSS);
  1183. m_fFreeDataIndBuffer = (flags & ATTACHMENT_MCS_FREES_DATA_IND_BUFFER);
  1184. // Increase the ref count to indicate that the client is now using the object.
  1185. AddRef();
  1186. }
  1187. /*
  1188. * Void SetDomainParameters ()
  1189. *
  1190. * Public
  1191. *
  1192. * Functional Description:
  1193. * This command is used to set the current value of the instance variable
  1194. * that holds the maximum user data field length.
  1195. */
  1196. void User::SetDomainParameters (
  1197. PDomainParameters domain_parameters)
  1198. {
  1199. /*
  1200. * Set the maximum user data length instance variable to conform to the
  1201. * maximum PDU size within the attached domain (minus some overhead to
  1202. * allow for protocol bytes).
  1203. */
  1204. Maximum_User_Data_Length = domain_parameters->max_mcspdu_size -
  1205. (MAXIMUM_PROTOCOL_OVERHEAD_MCS +
  1206. BER_PROTOCOL_EXTRA_OVERHEAD);
  1207. TRACE_OUT (("User::SetDomainParameters: "
  1208. "maximum user data length = %ld", Maximum_User_Data_Length));
  1209. /*
  1210. * Use the specified domain parameters to set the type of encoding rules
  1211. * to be used.
  1212. */
  1213. ASSERT (domain_parameters->protocol_version == PROTOCOL_VERSION_PACKED);
  1214. }
  1215. /*
  1216. * Void PurgeChannelsIndication ()
  1217. *
  1218. * Public
  1219. *
  1220. * Functional Description:
  1221. * This function is called during a domain merge operation when there is
  1222. * a conflict in the use of channels. The former Top Provider responds
  1223. * by issuing this command, which causes all users of the channel to be
  1224. * expelled from it. Additionally, if the channel corresponds to a user
  1225. * ID channel, that user is purged from the network.
  1226. */
  1227. void User::PurgeChannelsIndication (
  1228. CUidList *purge_user_list,
  1229. CChannelIDList *)
  1230. {
  1231. /*
  1232. * Issue a DetachUserIndication to each user contained in the purge user
  1233. * list.
  1234. */
  1235. DetachUserIndication(REASON_PROVIDER_INITIATED, purge_user_list);
  1236. }
  1237. /*
  1238. * Void DisconnectProviderUltimatum ()
  1239. *
  1240. * Public
  1241. *
  1242. * Functional Description:
  1243. * This function will be called when the domain determines the need to
  1244. * tear down quickly. This call simulates the reception of a detach user
  1245. * indication (if the user is already attached), or an unsuccessful
  1246. * attach user confirm (if the user is not yet attached). In either
  1247. * case, the user attachment will be eliminated by this call.
  1248. */
  1249. void User::DisconnectProviderUltimatum (
  1250. Reason reason)
  1251. {
  1252. CUidList deletion_list;
  1253. if (User_ID != 0)
  1254. {
  1255. /*
  1256. * If the user is already attached, simulate a detach user indication
  1257. * on the local user ID.
  1258. */
  1259. deletion_list.Append(User_ID);
  1260. DetachUserIndication(reason, &deletion_list);
  1261. }
  1262. else
  1263. {
  1264. /*
  1265. * If the user is not yet attached, simulate an unsuccessful attach
  1266. * user confirm.
  1267. */
  1268. AttachUserConfirm(RESULT_UNSPECIFIED_FAILURE, 0);
  1269. }
  1270. }
  1271. /*
  1272. * Void AttachUserConfirm ()
  1273. *
  1274. * Public
  1275. *
  1276. * Functional Description:
  1277. * This function is called by the domain in response to the attach user
  1278. * request that was sent by this object when it was first created. This
  1279. * call will contain the result of that attachment operation. If the
  1280. * result is successful, this call will also contain the user ID for this
  1281. * attachment.
  1282. */
  1283. void User::AttachUserConfirm (
  1284. Result result,
  1285. UserID uidInitiator)
  1286. {
  1287. LPARAM parameter;
  1288. if (Deletion_Pending == FALSE)
  1289. {
  1290. ASSERT (User_ID == 0);
  1291. /*
  1292. * If the result is successful, set the user ID of this user
  1293. * object to indicate its new status.
  1294. */
  1295. if (result == RESULT_SUCCESSFUL)
  1296. User_ID = uidInitiator;
  1297. else
  1298. Deletion_Pending = TRUE;
  1299. parameter = PACK_PARAMETER (uidInitiator, result);
  1300. /*
  1301. * Post the user message to the application.
  1302. */
  1303. if (! PostMessage (m_hWnd, USER_MSG_BASE + MCS_ATTACH_USER_CONFIRM,
  1304. (WPARAM) this, parameter)) {
  1305. WARNING_OUT (("User::AttachUserConfirm: Failed to post msg to application. Error: %d",
  1306. GetLastError()));
  1307. if (result != RESULT_SUCCESSFUL)
  1308. Release();
  1309. }
  1310. }
  1311. else {
  1312. Release();
  1313. }
  1314. }
  1315. /*
  1316. * Void DetachUserIndication ()
  1317. *
  1318. * Public
  1319. *
  1320. * Functional Description:
  1321. * This function is called by the domain whenever a user leaves the domain
  1322. * (voluntarily or otherwise). Furthermore, if a user ID in the indication
  1323. * is the same as the local user ID, then this user is being involuntarily
  1324. * detached.
  1325. */
  1326. Void User::DetachUserIndication (
  1327. Reason reason,
  1328. CUidList *user_id_list)
  1329. {
  1330. UserID uid;
  1331. LPARAM parameter;
  1332. BOOL bPostMsgResult;
  1333. if (Deletion_Pending == FALSE)
  1334. {
  1335. /*
  1336. * Iterate through the list of users to be deleted.
  1337. */
  1338. user_id_list->Reset();
  1339. while (NULL != (uid = user_id_list->Iterate()))
  1340. {
  1341. parameter = PACK_PARAMETER(uid, reason);
  1342. /*
  1343. * Post the user message to the application.
  1344. */
  1345. bPostMsgResult = PostMessage (m_hWnd, USER_MSG_BASE + MCS_DETACH_USER_INDICATION,
  1346. (WPARAM) this, parameter);
  1347. if (! bPostMsgResult) {
  1348. WARNING_OUT (("User::DetachUserIndication: Failed to post msg to application. Error: %d",
  1349. GetLastError()));
  1350. }
  1351. /*
  1352. * If this indication is deleting this user attachment, then
  1353. * set the deletion pending flag, and break out of the loop.
  1354. */
  1355. if (User_ID == uid)
  1356. {
  1357. m_originalUser_ID = User_ID;
  1358. User_ID = 0;
  1359. Deletion_Pending = TRUE;
  1360. if (! bPostMsgResult)
  1361. Release();
  1362. break;
  1363. }
  1364. }
  1365. }
  1366. else {
  1367. /*
  1368. * The user has already called ReleaseInterface(). If the
  1369. * Indication is for this attachment, we have to release and
  1370. * probably, delete the object.
  1371. */
  1372. if (user_id_list->Find(User_ID)) {
  1373. Release();
  1374. }
  1375. }
  1376. }
  1377. /*
  1378. * Void ChannelJLCDAEConfInd ()
  1379. *
  1380. * Public
  1381. *
  1382. * Functional Description:
  1383. * This function is called to post a channel confirm/indication message
  1384. * to the user application. It handles ChannelJoinConfirms,
  1385. * ChannelLeaveIndications, ChannelConveneConfirms, ChannelDisbandIndications
  1386. * and ChannelExpelIndications.
  1387. */
  1388. Void User::ChannelConfInd ( UINT type,
  1389. ChannelID channel_id,
  1390. UINT arg16)
  1391. {
  1392. LPARAM parameter;
  1393. ASSERT (HIWORD(arg16) == 0);
  1394. if (Deletion_Pending == FALSE)
  1395. {
  1396. parameter = PACK_PARAMETER (channel_id, arg16);
  1397. /*
  1398. * Post the user message to the application.
  1399. */
  1400. if (! PostMessage (m_hWnd, USER_MSG_BASE + type,
  1401. (WPARAM) this, parameter)) {
  1402. WARNING_OUT (("User::ChannelConfInd: Failed to post msg to application. Type: %d. Error: %d",
  1403. type, GetLastError()));
  1404. }
  1405. }
  1406. }
  1407. /*
  1408. * Void ChannelJoinConfirm ()
  1409. *
  1410. * Public
  1411. *
  1412. * Functional Description:
  1413. * This function is called by the domain in response to a previous channel
  1414. * join request. This call contains the result of the join request, as
  1415. * well as the channel that has just been joined.
  1416. */
  1417. Void User::ChannelJoinConfirm (
  1418. Result result,
  1419. UserID,
  1420. ChannelID requested_id,
  1421. ChannelID channel_id)
  1422. {
  1423. ChannelConfInd (MCS_CHANNEL_JOIN_CONFIRM, channel_id, (UINT) result);
  1424. }
  1425. /*
  1426. * Void ChannelLeaveIndication ()
  1427. *
  1428. * Public
  1429. *
  1430. * Functional Description:
  1431. */
  1432. Void User::ChannelLeaveIndication (
  1433. Reason reason,
  1434. ChannelID channel_id)
  1435. {
  1436. ChannelConfInd (MCS_CHANNEL_LEAVE_INDICATION, channel_id, (UINT) reason);
  1437. }
  1438. /*
  1439. * Void ChannelConveneConfirm ()
  1440. *
  1441. * Public
  1442. *
  1443. * Functional Description:
  1444. * This function is called by the domain in response to a previous channel
  1445. * convene request. This call contains the result of the request, as
  1446. * well as the channel that has just been convened.
  1447. */
  1448. Void User::ChannelConveneConfirm (
  1449. Result result,
  1450. UserID,
  1451. ChannelID channel_id)
  1452. {
  1453. ChannelConfInd (MCS_CHANNEL_CONVENE_CONFIRM, channel_id, (UINT) result);
  1454. }
  1455. /*
  1456. * Void ChannelDisbandIndication ()
  1457. *
  1458. * Public
  1459. *
  1460. * Functional Description:
  1461. * This function is called by the domain when MCS disbands an existing
  1462. * private channel.
  1463. */
  1464. Void User::ChannelDisbandIndication (
  1465. ChannelID channel_id)
  1466. {
  1467. ChannelConfInd (MCS_CHANNEL_DISBAND_INDICATION, channel_id, REASON_CHANNEL_PURGED);
  1468. }
  1469. /*
  1470. * Void ChannelAdmitIndication ()
  1471. *
  1472. * Public
  1473. *
  1474. * Functional Description:
  1475. * This function is called by the domain when a user is admitted to a
  1476. * private channel.
  1477. */
  1478. Void User::ChannelAdmitIndication (
  1479. UserID uidInitiator,
  1480. ChannelID channel_id,
  1481. CUidList *)
  1482. {
  1483. ChannelConfInd (MCS_CHANNEL_ADMIT_INDICATION, channel_id, (UINT) uidInitiator);
  1484. }
  1485. /*
  1486. * Void ChannelExpelIndication ()
  1487. *
  1488. * Public
  1489. *
  1490. * Functional Description:
  1491. * This function is called by the domain when a user is expelled from a
  1492. * private channel.
  1493. */
  1494. Void User::ChannelExpelIndication (
  1495. ChannelID channel_id,
  1496. CUidList *)
  1497. {
  1498. ChannelConfInd (MCS_CHANNEL_EXPEL_INDICATION, channel_id, REASON_USER_REQUESTED);
  1499. }
  1500. /*
  1501. * Void SendDataIndication ()
  1502. *
  1503. * Public
  1504. *
  1505. * Functional Description:
  1506. * This function is called by the domain when data needs to sent to the
  1507. * user on a channel that the user has joined.
  1508. */
  1509. Void User::SendDataIndication (
  1510. UINT message_type,
  1511. PDataPacket packet)
  1512. {
  1513. if (Deletion_Pending == FALSE)
  1514. {
  1515. /*
  1516. * Lock the packet object to indicate that we wish to have future
  1517. * access to the decoded data that it contains. Then get the
  1518. * address of the decoded data structure.
  1519. */
  1520. packet->Lock ();
  1521. packet->SetMessageType(message_type);
  1522. // flush packets in the pending queue
  1523. PDataPacket pkt;
  1524. while (NULL != (pkt = m_PostMsgPendingQueue.PeekHead()))
  1525. {
  1526. if (::PostMessage(m_hWnd, USER_MSG_BASE + pkt->GetMessageType(),
  1527. (WPARAM) this, (LPARAM) pkt))
  1528. {
  1529. // remove the item just posted
  1530. m_PostMsgPendingQueue.Get();
  1531. }
  1532. else
  1533. {
  1534. // fail to post pending ones, just append the new one and bail out.
  1535. m_PostMsgPendingQueue.Append(packet);
  1536. return;
  1537. }
  1538. }
  1539. /*
  1540. * Post the user message to the application.
  1541. */
  1542. if (! ::PostMessage(m_hWnd, USER_MSG_BASE + message_type,
  1543. (WPARAM) this, (LPARAM) packet))
  1544. {
  1545. // fail to post pending ones, just append the new one and bail out.
  1546. m_PostMsgPendingQueue.Append(packet);
  1547. return;
  1548. }
  1549. }
  1550. }
  1551. /*
  1552. * Void TokenConfInd ()
  1553. *
  1554. * Public
  1555. *
  1556. * Functional Description:
  1557. * This function is called to post a token confirm/indication message
  1558. * to the user application.
  1559. */
  1560. Void User::TokenConfInd (UINT type,
  1561. TokenID token_id,
  1562. UINT arg16)
  1563. {
  1564. LPARAM parameter;
  1565. ASSERT (HIWORD(arg16) == 0);
  1566. if (Deletion_Pending == FALSE)
  1567. {
  1568. parameter = PACK_PARAMETER (token_id, arg16);
  1569. /*
  1570. * Post the user message to the application.
  1571. */
  1572. if (! PostMessage (m_hWnd, USER_MSG_BASE + type,
  1573. (WPARAM) this, parameter)) {
  1574. WARNING_OUT (("User::TokenConfInd: Failed to post msg to application. Type: %d. Error: %d",
  1575. type, GetLastError()));
  1576. }
  1577. }
  1578. }
  1579. /*
  1580. * Void TokenGrabConfirm ()
  1581. *
  1582. * Public
  1583. *
  1584. * Functional Description:
  1585. * This function is called by the domain in response to a previous token
  1586. * grab request. This call contains the result of the grab request, as
  1587. * well as the token that has just been grabbed.
  1588. */
  1589. Void User::TokenGrabConfirm (
  1590. Result result,
  1591. UserID,
  1592. TokenID token_id,
  1593. TokenStatus)
  1594. {
  1595. TokenConfInd (MCS_TOKEN_GRAB_CONFIRM, token_id, (UINT) result);
  1596. }
  1597. /*
  1598. * Void TokenInhibitConfirm ()
  1599. *
  1600. * Public
  1601. *
  1602. * Functional Description:
  1603. * This function is called by the domain in response to a previous token
  1604. * inhibit request. This call contains the result of the inhibit request,
  1605. * as well as the token that has just been inhibited.
  1606. */
  1607. Void User::TokenInhibitConfirm (
  1608. Result result,
  1609. UserID,
  1610. TokenID token_id,
  1611. TokenStatus)
  1612. {
  1613. TokenConfInd (MCS_TOKEN_INHIBIT_CONFIRM, token_id, (UINT) result);
  1614. }
  1615. /*
  1616. * Void TokenGiveIndication ()
  1617. *
  1618. * Public
  1619. *
  1620. * Functional Description:
  1621. * This function is called by the domain when another user attempts to
  1622. * give this user a token.
  1623. */
  1624. Void User::TokenGiveIndication (
  1625. PTokenGiveRecord pTokenGiveRec)
  1626. {
  1627. TokenConfInd (MCS_TOKEN_GIVE_INDICATION, pTokenGiveRec->token_id,
  1628. (UINT) pTokenGiveRec->uidInitiator);
  1629. }
  1630. /*
  1631. * Void TokenGiveConfirm ()
  1632. *
  1633. * Public
  1634. *
  1635. * Functional Description:
  1636. * This function is called by the domain in response to a previous token
  1637. * give request. This call contains the result of the give request.
  1638. */
  1639. Void User::TokenGiveConfirm (
  1640. Result result,
  1641. UserID,
  1642. TokenID token_id,
  1643. TokenStatus)
  1644. {
  1645. TokenConfInd (MCS_TOKEN_GIVE_CONFIRM, token_id, (UINT) result);
  1646. }
  1647. /*
  1648. * Void TokenPleaseIndication ()
  1649. *
  1650. * Public
  1651. *
  1652. * Functional Description:
  1653. * This function is called by the domain when a user somewhere in the
  1654. * domain issues a token please request for a token that is currently
  1655. * owned by this user.
  1656. */
  1657. Void User::TokenPleaseIndication (
  1658. UserID uidInitiator,
  1659. TokenID token_id)
  1660. {
  1661. TokenConfInd (MCS_TOKEN_PLEASE_INDICATION, token_id, (UINT) uidInitiator);
  1662. }
  1663. /*
  1664. * Void TokenReleaseIndication ()
  1665. *
  1666. * Public
  1667. *
  1668. * Functional Description:
  1669. * This command is called when a token is being purged from the lower
  1670. * domain after a new connection is established. It causes the indication
  1671. * to be forwarded to the user application, letting it know that it no
  1672. * longer owns the token.
  1673. */
  1674. Void User::TokenReleaseIndication (
  1675. Reason reason,
  1676. TokenID token_id)
  1677. {
  1678. TokenConfInd (MCS_TOKEN_RELEASE_INDICATION, token_id, (UINT) reason);
  1679. }
  1680. /*
  1681. * Void TokenReleaseConfirm ()
  1682. *
  1683. * Public
  1684. *
  1685. * Functional Description:
  1686. * This function is called by the domain in response to a previous token
  1687. * release request. This call contains the result of the release request,
  1688. * as well as the token that has just been released.
  1689. */
  1690. Void User::TokenReleaseConfirm (
  1691. Result result,
  1692. UserID,
  1693. TokenID token_id,
  1694. TokenStatus)
  1695. {
  1696. TokenConfInd (MCS_TOKEN_RELEASE_CONFIRM, token_id, (UINT) result);
  1697. }
  1698. /*
  1699. * Void TokenTestConfirm ()
  1700. *
  1701. * Public
  1702. *
  1703. * Functional Description:
  1704. * This function is called by the domain in response to a previous token
  1705. * test request. This call contains the result of the test request,
  1706. * as well as the token that has just been tested.
  1707. */
  1708. Void User::TokenTestConfirm (
  1709. UserID,
  1710. TokenID token_id,
  1711. TokenStatus token_status)
  1712. {
  1713. TokenConfInd (MCS_TOKEN_TEST_CONFIRM, token_id, (UINT) token_status);
  1714. }
  1715. /*
  1716. * Void MergeDomainIndication ()
  1717. *
  1718. * Public
  1719. *
  1720. * Functional Description:
  1721. * This function is called by domain upon entering or leaving a domain
  1722. * merger state.
  1723. */
  1724. Void User::MergeDomainIndication (
  1725. MergeStatus merge_status)
  1726. {
  1727. if (Deletion_Pending == FALSE)
  1728. {
  1729. /*
  1730. * If the merge operation is starting, set a boolean flag
  1731. * indicating that this object should reject all user activity.
  1732. * Otherwise, reset the flag.
  1733. */
  1734. if (merge_status == MERGE_DOMAIN_IN_PROGRESS)
  1735. {
  1736. TRACE_OUT (("User::MergeDomainIndication: entering merge state"));
  1737. Merge_In_Progress = TRUE;
  1738. }
  1739. else
  1740. {
  1741. TRACE_OUT (("User::MergeDomainIndication: leaving merge state"));
  1742. Merge_In_Progress = FALSE;
  1743. }
  1744. }
  1745. }
  1746. /*
  1747. * Void PurgeMessageQueue ()
  1748. *
  1749. * Private
  1750. *
  1751. * Functional Description:
  1752. * This function is called to purge all current entries from the message
  1753. * queue, freeing up resources correctly (to prevent leaks).
  1754. *
  1755. * Formal Parameters:
  1756. * None.
  1757. *
  1758. * Return Value:
  1759. * None.
  1760. *
  1761. * Side Effects:
  1762. * None.
  1763. *
  1764. * Caveats:
  1765. * This function should only be called in the client's thread's context.
  1766. */
  1767. Void User::PurgeMessageQueue ()
  1768. {
  1769. MSG msg;
  1770. PDataPacket packet;
  1771. HWND hWnd;
  1772. // First, unlock the packets in the list of pending data indications
  1773. while (NULL != (packet = m_DataPktQueue.Get()))
  1774. packet->Unlock();
  1775. // Keep a copy of the attachment's HWND to destroy it later.
  1776. hWnd = m_hWnd;
  1777. m_hWnd = NULL;
  1778. /*
  1779. * This loop calls PeekMessage to go through all the messages in the thread's
  1780. * queue that were posted by the main MCS thread. It removes these
  1781. * messages and frees the resources that they consume.
  1782. */
  1783. while (PeekMessage (&msg, hWnd, USER_MSG_BASE, USER_MSG_BASE + MCS_LAST_USER_MESSAGE,
  1784. PM_REMOVE)) {
  1785. if (msg.message == WM_QUIT) {
  1786. // Repost the quit
  1787. PostQuitMessage (0);
  1788. break;
  1789. }
  1790. /*
  1791. * If this is a data indication message, we need to unlock
  1792. * the packet associated with this message.
  1793. */
  1794. else if ((msg.message == USER_MSG_BASE + MCS_SEND_DATA_INDICATION) ||
  1795. (msg.message == USER_MSG_BASE + MCS_UNIFORM_SEND_DATA_INDICATION)) {
  1796. ((PDataPacket) msg.lParam)->Unlock ();
  1797. }
  1798. else if (((msg.message == USER_MSG_BASE + MCS_ATTACH_USER_CONFIRM) &&
  1799. ((Result) HIWORD(msg.lParam) != RESULT_SUCCESSFUL)) ||
  1800. ((msg.message == USER_MSG_BASE + MCS_DETACH_USER_INDICATION) &&
  1801. (m_originalUser_ID == (UserID) LOWORD(msg.lParam)))) {
  1802. ASSERT (this == (PUser) msg.wParam);
  1803. Release();
  1804. break;
  1805. }
  1806. }
  1807. // Destroy the window; we do not need it anymore
  1808. DestroyWindow (hWnd);
  1809. }
  1810. void User::IssueDataIndication (
  1811. UINT message_type,
  1812. PDataPacket packet)
  1813. {
  1814. LPARAM parameter;
  1815. PMemory memory;
  1816. BOOL bIssueCallback = TRUE;
  1817. BOOL bBufferInPacket = TRUE;
  1818. PUChar data_ptr;
  1819. SendDataIndicationPDU send_data_ind_pdu;
  1820. switch (packet->GetSegmentation()) {
  1821. case SEGMENTATION_BEGIN | SEGMENTATION_END:
  1822. parameter = (LPARAM) &(((PDomainMCSPDU) (packet->GetDecodedData()))->
  1823. u.send_data_indication);
  1824. data_ptr = packet->GetUserData();
  1825. memory = packet->GetMemory();
  1826. break;
  1827. case SEGMENTATION_END:
  1828. {
  1829. /*
  1830. * We now have to collect all the individual packets from m_DataPktQueue
  1831. * that go with this MCS Data PDU and sent them as a single data indication
  1832. * using a buffer large enough for all the data.
  1833. */
  1834. /*
  1835. * First, find out the size of the large buffer we need to allocate.
  1836. * Note that we make a copy of the original m_DataPktList and operate
  1837. * on the copy, since we need to remove items from the original list.
  1838. */
  1839. CDataPktQueue PktQ(&m_DataPktQueue);
  1840. UINT size;
  1841. PDataPacket data_pkt;
  1842. PUChar ptr;
  1843. #ifdef DEBUG
  1844. UINT uiCount = 0;
  1845. #endif // DEBUG
  1846. size = packet->GetUserDataLength();
  1847. PktQ.Reset();
  1848. while (NULL != (data_pkt = PktQ.Iterate()))
  1849. {
  1850. if (packet->Equivalent (data_pkt)) {
  1851. #ifdef DEBUG
  1852. if (uiCount == 0) {
  1853. ASSERT (data_pkt->GetSegmentation() == SEGMENTATION_BEGIN);
  1854. }
  1855. else {
  1856. ASSERT (data_pkt->GetSegmentation() == 0);
  1857. }
  1858. uiCount++;
  1859. #endif // DEBUG
  1860. size += data_pkt->GetUserDataLength();
  1861. // Remove from the original list, since we are processing the callback.
  1862. m_DataPktQueue.Remove(data_pkt);
  1863. }
  1864. }
  1865. // Allocate the memory we need.
  1866. DBG_SAVE_FILE_LINE
  1867. memory = AllocateMemory (NULL, size);
  1868. if (memory != NULL) {
  1869. bBufferInPacket = FALSE;
  1870. // Copy the individual indications into the large buffer.
  1871. data_ptr = ptr = memory->GetPointer();
  1872. PktQ.Reset();
  1873. /*
  1874. * We need to enter the MCS critical section, because
  1875. * we are unlocking packets.
  1876. */
  1877. EnterCriticalSection (& g_MCS_Critical_Section);
  1878. while (NULL != (data_pkt = PktQ.Iterate()))
  1879. {
  1880. if (packet->Equivalent (data_pkt)) {
  1881. size = data_pkt->GetUserDataLength();
  1882. memcpy ((void *) ptr,
  1883. (void *) data_pkt->GetUserData(),
  1884. size);
  1885. ptr += size;
  1886. data_pkt->Unlock();
  1887. }
  1888. }
  1889. // Leave the MCS critical section
  1890. LeaveCriticalSection (& g_MCS_Critical_Section);
  1891. // Copy the last indication into the large buffer.
  1892. memcpy ((void *) ptr,
  1893. (void *) packet->GetUserData(),
  1894. packet->GetUserDataLength());
  1895. /*
  1896. * Prepare the SendDataIndicationPDU structure for the client.
  1897. * Notice that we can use the first 8 bytes from the decoded
  1898. * structure of the current "packet" to fill in the first bytes from
  1899. * it.
  1900. */
  1901. memcpy ((void *) &send_data_ind_pdu,
  1902. (void *) &(((PDomainMCSPDU) (packet->GetDecodedData()))->
  1903. u.send_data_indication), 8);
  1904. send_data_ind_pdu.segmentation = SEGMENTATION_BEGIN | SEGMENTATION_END;
  1905. send_data_ind_pdu.user_data.length = memory->GetLength();
  1906. send_data_ind_pdu.user_data.value = data_ptr;
  1907. parameter = (ULONG_PTR) &send_data_ind_pdu;
  1908. }
  1909. else {
  1910. /*
  1911. * We have failed to issue the data indication callback to the client.
  1912. * The user attachment has been compromised. If the attachment can not
  1913. * live with this loss, we have to detach them from the conference.
  1914. */
  1915. ERROR_OUT (("User::IssueDataIndication: Memory allocation failed for segmented buffer of size %d.",
  1916. size));
  1917. bIssueCallback = FALSE;
  1918. // Clean up after the failure
  1919. EnterCriticalSection (& g_MCS_Critical_Section);
  1920. PktQ.Reset();
  1921. while (NULL != (data_pkt = PktQ.Iterate()))
  1922. {
  1923. if (m_fDisconnectInDataLoss ||
  1924. (packet->Equivalent (data_pkt))) {
  1925. data_pkt->Unlock();
  1926. }
  1927. }
  1928. packet->Unlock();
  1929. LeaveCriticalSection (& g_MCS_Critical_Section);
  1930. // Disconnect if the client wants us to.
  1931. if (m_fDisconnectInDataLoss) {
  1932. // Clear the list of the already-cleared pending packets. We will soon get a ReleaseInterface().
  1933. m_DataPktQueue.Clear();
  1934. ERROR_OUT(("User::IssueDataIndication: Disconnecting user because of data loss..."));
  1935. /*
  1936. * Send a detach user indication directly to the user application.
  1937. * Note that this cannot go through the queue, due to the memory
  1938. * failure.
  1939. */
  1940. (*m_MCSCallback) (MCS_DETACH_USER_INDICATION,
  1941. PACK_PARAMETER (User_ID, REASON_PROVIDER_INITIATED),
  1942. m_UserDefined);
  1943. }
  1944. }
  1945. break;
  1946. }
  1947. case SEGMENTATION_BEGIN:
  1948. case 0:
  1949. // Append the packet to the list of packets for send.
  1950. m_DataPktQueue.Append(packet);
  1951. bIssueCallback = FALSE;
  1952. break;
  1953. default:
  1954. ASSERT (FALSE);
  1955. ERROR_OUT(("User::IssueDataIndication: Processed packet with invalid segmentation field."));
  1956. break;
  1957. }
  1958. if (bIssueCallback) {
  1959. /*
  1960. * If the client has advised the server not to free the data, we have to
  1961. * lock the buffer.
  1962. */
  1963. if (m_fFreeDataIndBuffer == FALSE) {
  1964. if (bBufferInPacket)
  1965. LockMemory (memory);
  1966. // Enter the data indication info in a dictionary, for the Free request.
  1967. if (GetMemoryObject(data_ptr) != memory)
  1968. {
  1969. m_DataIndMemoryBuf2.Append((LPVOID) data_ptr, memory);
  1970. }
  1971. }
  1972. /*
  1973. * Issue the callback. The callee can not refuse to process this.
  1974. */
  1975. (*m_MCSCallback) (message_type, parameter, m_UserDefined);
  1976. /*
  1977. * If the client has advised the server to free the data indication buffer
  1978. * after delivering the callback, we must do so.
  1979. */
  1980. if (m_fFreeDataIndBuffer) {
  1981. if (bBufferInPacket == FALSE)
  1982. FreeMemory (memory);
  1983. }
  1984. // To unlock a packet, we need to enter the MCS CS.
  1985. EnterCriticalSection (& g_MCS_Critical_Section);
  1986. packet->Unlock();
  1987. LeaveCriticalSection (& g_MCS_Critical_Section);
  1988. }
  1989. }
  1990. /*
  1991. * LRESULT UserWindowProc ()
  1992. *
  1993. * Public
  1994. *
  1995. * Functional Description:
  1996. * This is the window procedure that will be used by all internally
  1997. * created windows. A hidden window is created internally when the
  1998. * application attaches to an MCS domain. This technique insures
  1999. * that callbacks are delivered to the owner in the same thread that
  2000. * initially created the attachment.
  2001. */
  2002. LRESULT CALLBACK UserWindowProc (
  2003. HWND window_handle,
  2004. UINT message,
  2005. WPARAM word_parameter,
  2006. LPARAM long_parameter)
  2007. {
  2008. UINT mcs_message;
  2009. //PDataPacket packet;
  2010. PUser puser;
  2011. if ((message >= USER_MSG_BASE) && (message < USER_MSG_BASE + MCS_LAST_USER_MESSAGE)) {
  2012. // This is an MCS msg going to the user application.
  2013. // Compute the MCS msg type
  2014. mcs_message = message - USER_MSG_BASE;
  2015. // Retrieve the pointer to the User (interface) object.
  2016. puser = (PUser) word_parameter;
  2017. if (NULL != puser)
  2018. {
  2019. /*
  2020. * Find out whether this is a data indication. If it is, set the
  2021. * packet variable.
  2022. */
  2023. if ((mcs_message == MCS_SEND_DATA_INDICATION) ||
  2024. (mcs_message == MCS_UNIFORM_SEND_DATA_INDICATION)) {
  2025. puser->IssueDataIndication (mcs_message, (PDataPacket) long_parameter);
  2026. }
  2027. else {
  2028. /*
  2029. * Issue the callback. Notice that the callee can not refuse
  2030. * to process this.
  2031. */
  2032. (*(puser->m_MCSCallback)) (mcs_message, long_parameter, puser->m_UserDefined);
  2033. }
  2034. /*
  2035. * We may need to release the User object. This is the Server
  2036. * side release.
  2037. */
  2038. if (((mcs_message == MCS_ATTACH_USER_CONFIRM) &&
  2039. ((Result) HIWORD(long_parameter) != RESULT_SUCCESSFUL)) ||
  2040. ((mcs_message == MCS_DETACH_USER_INDICATION) &&
  2041. (puser->m_originalUser_ID == (UserID) LOWORD(long_parameter)))) {
  2042. puser->Release();
  2043. }
  2044. }
  2045. else
  2046. {
  2047. ERROR_OUT(("UserWindowProc: null puser"));
  2048. }
  2049. return (0);
  2050. }
  2051. else {
  2052. /*
  2053. * Invoke the default window message handler to handle this
  2054. * message.
  2055. */
  2056. return (DefWindowProc (window_handle, message, word_parameter,
  2057. long_parameter));
  2058. }
  2059. }
  2060. /*
  2061. * Void CALLBACK TimerProc (HWND, UINT, UINT, DWORD
  2062. *
  2063. * Public
  2064. *
  2065. * Functional Description:
  2066. * This is the timer procedure. Timer messages will be routed to this
  2067. * function as a result of timer events which have been set up to recheck
  2068. * resource levels. This would happen following a call to either
  2069. * MCSSendDataRequest or MCSUniformSendDataRequest which resulted in a
  2070. * return value of MCS_TRANSMIT_BUFFER_FULL.
  2071. */
  2072. Void CALLBACK TimerProc (HWND, UINT, UINT timer_id, DWORD)
  2073. {
  2074. PUser puser;
  2075. /*
  2076. * Enter the critical section which protects global data.
  2077. */
  2078. EnterCriticalSection (& g_MCS_Critical_Section);
  2079. /*
  2080. * First, we must find which user owns this timer. We will do this by
  2081. * searching through the Static_User_List.
  2082. */
  2083. if (NULL == (puser = User::s_pTimerUserList2->Find(timer_id)))
  2084. {
  2085. WARNING_OUT (("TimerProc: no user owns this timer - deleting timer"));
  2086. KillTimer (NULL, timer_id);
  2087. goto Bail;
  2088. }
  2089. /*
  2090. * Make sure that this user is actively attached. If not, then kill the
  2091. * timer and delete the user's buffer retry info structure.
  2092. */
  2093. if ((puser->User_ID == 0) || puser->Deletion_Pending)
  2094. {
  2095. WARNING_OUT (("TimerProc: user is not attached - deleting timer"));
  2096. goto CleanupBail;
  2097. }
  2098. /*
  2099. * If we don't have retryinfo just get out of here.
  2100. */
  2101. if(puser->m_BufferRetryInfo == NULL)
  2102. {
  2103. WARNING_OUT (("TimerProc: user does not have buffer retry info - deleting timer"));
  2104. goto CleanupBail;
  2105. }
  2106. /*
  2107. * We have identified a valid owner of this timer.
  2108. * Verify that there is enough memory for the
  2109. * required size before proceeding. Note that since there
  2110. * can be multiple processes allocating from the same memory
  2111. * at the same time, this call does not guarantee
  2112. * that that the allocations will succeed.
  2113. */
  2114. if (GetFreeMemory (SEND_PRIORITY) < puser->m_BufferRetryInfo->user_data_length)
  2115. {
  2116. TRACE_OUT (("TimerProc: not enough memory buffers of required size"));
  2117. goto Bail;
  2118. }
  2119. /*
  2120. * If the routine gets this far, then an adequate level of resources
  2121. * now exists.
  2122. */
  2123. /*
  2124. * Issue an MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION to the user.
  2125. */
  2126. TRACE_OUT(("TimerProc: Delivering MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION callback."));
  2127. // (*(puser->m_MCSCallback)) (MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION,
  2128. // 0, puser->m_UserDefined);
  2129. if(!PostMessage (puser->m_hWnd, USER_MSG_BASE + MCS_TRANSMIT_BUFFER_AVAILABLE_INDICATION,(WPARAM) puser, 0))
  2130. {
  2131. ERROR_OUT (("TimerProc: Failed to post msg to application. Error: %d", GetLastError()));
  2132. }
  2133. CleanupBail:
  2134. KillTimer (NULL, timer_id);
  2135. delete puser->m_BufferRetryInfo;
  2136. puser->m_BufferRetryInfo = NULL;
  2137. User::s_pTimerUserList2->Remove(timer_id);
  2138. Bail:
  2139. // Leave the attachment's critical section
  2140. LeaveCriticalSection (& g_MCS_Critical_Section);
  2141. }
  2142.