Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

466 lines
21 KiB

  1. /****************************************************************************/
  2. // acaapi.cpp
  3. //
  4. // RDP Control Arbitrator API functions
  5. //
  6. // Copyright (C) Microsoft, PictureTel 1993-1997
  7. // Copyright (C) 1997-2000 Microsoft Corporation
  8. /****************************************************************************/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. #define TRC_FILE "acaapi"
  12. #include <adcg.h>
  13. #include <as_conf.hpp>
  14. /****************************************************************************/
  15. /* API FUNCTION: CA_Init */
  16. /* */
  17. /* Called to initialize the CA. */
  18. /****************************************************************************/
  19. void RDPCALL SHCLASS CA_Init(void)
  20. {
  21. DC_BEGIN_FN("CA_Init");
  22. #define DC_INIT_DATA
  23. #include <acadata.c>
  24. #undef DC_INIT_DATA
  25. // Set local node initial state to detached.
  26. caStates[0] = CA_STATE_DETACHED;
  27. DC_END_FN();
  28. }
  29. /****************************************************************************/
  30. // CA_ReceivedPacket
  31. //
  32. // Handles control PDUs inbound from the client.
  33. /****************************************************************************/
  34. void RDPCALL SHCLASS CA_ReceivedPacket(
  35. PTS_CONTROL_PDU pControlPDU,
  36. unsigned DataLength,
  37. LOCALPERSONID personID)
  38. {
  39. DC_BEGIN_FN("CA_ReceivedPacket");
  40. // Ensure we can access the header.
  41. if (DataLength >= sizeof(TS_CONTROL_PDU)) {
  42. TRC_NRM((TB, "[%u] Packet:%d", personID, pControlPDU->action));
  43. switch (pControlPDU->action) {
  44. case TS_CTRLACTION_REQUEST_CONTROL:
  45. CAEvent(CA_EVENTI_TRY_GIVE_CONTROL, (UINT32)personID);
  46. break;
  47. case TS_CTRLACTION_COOPERATE:
  48. CAEvent(CA_EVENTI_REMOTE_COOPERATE, (UINT32)personID);
  49. break;
  50. default:
  51. // An invalid action - log and disconnect the Client.
  52. TRC_ERR((TB, "Invalid CA msg %d", pControlPDU->action));
  53. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_InvalidControlPDUAction,
  54. (BYTE *)&(pControlPDU->action),
  55. sizeof(pControlPDU->action));
  56. break;
  57. }
  58. }
  59. else {
  60. TRC_ERR((TB,"Data length %u too short for control header",
  61. DataLength));
  62. WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShareDataTooShort,
  63. (BYTE *)pControlPDU, DataLength);
  64. }
  65. DC_END_FN();
  66. }
  67. /****************************************************************************/
  68. /* API FUNCTION: CA_PartyJoiningShare */
  69. /* */
  70. /* Called when a new party is joining the share */
  71. /* */
  72. /* PARAMETERS: */
  73. /* personID - the ID of the new party. */
  74. /* oldShareSize - the number of the parties which were in the share (ie */
  75. /* excludes the joining party). */
  76. /* */
  77. /* RETURNS: */
  78. /* TRUE - the CA can accept the new party */
  79. /* FALSE - the CA cannot accept the new party */
  80. /****************************************************************************/
  81. BOOL RDPCALL SHCLASS CA_PartyJoiningShare(
  82. LOCALPERSONID personID,
  83. unsigned oldShareSize)
  84. {
  85. DC_BEGIN_FN("CA_PartyJoiningShare");
  86. /************************************************************************/
  87. // Check for share start, do some init if need be.
  88. /************************************************************************/
  89. if (oldShareSize == 0) {
  90. // Enter cooperate mode then viewing. Note that we don't send
  91. // a message now (we will send one when we process a CA_SyncNow call).
  92. CAEvent(CA_EVENTI_ENTER_COOP_MODE, CA_DONT_SEND_MSG);
  93. CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
  94. caWhoHasControlToken = (LOCALPERSONID)-1;
  95. }
  96. // Set new node state to detached -- we should receive a CA packet
  97. // to tell us what the remote state really is before we receive any IM
  98. // packets. But just in case, choosing detached is the safest as it has
  99. // least priveleges. Note that we will not enable the shadow cursors
  100. // until (and if) we get a CA packet to tell us the remote system is
  101. // detached.
  102. caStates[personID] = CA_STATE_DETACHED;
  103. DC_END_FN();
  104. return TRUE;
  105. }
  106. /****************************************************************************/
  107. /* API FUNCTION: CA_PartyLeftShare */
  108. /* */
  109. /* Called when a party has left the share. */
  110. /* */
  111. /* PARAMETERS: */
  112. /* personID - the local ID of the new party. */
  113. /* newShareSize - the number of the parties now in the share (ie excludes */
  114. /* the leaving party). */
  115. /****************************************************************************/
  116. void RDPCALL SHCLASS CA_PartyLeftShare(
  117. LOCALPERSONID personID,
  118. unsigned newShareSize)
  119. {
  120. DC_BEGIN_FN("CA_PartyLeftShare");
  121. // Just ensure their state is left as detached for safety.
  122. caStates[personID] = CA_STATE_DETACHED;
  123. DC_END_FN();
  124. }
  125. /****************************************************************************/
  126. /* API FUNCTION: CA_SyncNow */
  127. /* */
  128. /* Called by the TT to signal the beginning of a sync. */
  129. /****************************************************************************/
  130. void RDPCALL SHCLASS CA_SyncNow(void)
  131. {
  132. DC_BEGIN_FN("CA_SyncNow");
  133. /************************************************************************/
  134. /* Tell the world we're cooperating. */
  135. /************************************************************************/
  136. TRC_NRM((TB, "Send cooperate"));
  137. CAFlushAndSendMsg(TS_CTRLACTION_COOPERATE, 0, 0);
  138. DC_END_FN();
  139. }
  140. /****************************************************************************/
  141. /* FUNCTION: CASendMsg */
  142. /* */
  143. /* Sends a CA message to remote system */
  144. /****************************************************************************/
  145. __inline BOOL RDPCALL SHCLASS CASendMsg(
  146. UINT16 msg,
  147. UINT16 data1,
  148. UINT32 data2)
  149. {
  150. NTSTATUS status;
  151. PTS_CONTROL_PDU pControlPDU;
  152. DC_BEGIN_FN("CASendMsg");
  153. status = SC_AllocBuffer((PPVOID)&pControlPDU, sizeof(TS_CONTROL_PDU));
  154. if ( STATUS_SUCCESS == status ) {
  155. // Set up the packet header for a request message
  156. pControlPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_CONTROL;
  157. pControlPDU->action = msg;
  158. pControlPDU->grantId = data1;
  159. pControlPDU->controlId = data2;
  160. SC_SendData((PTS_SHAREDATAHEADER)pControlPDU,
  161. sizeof(TS_CONTROL_PDU),
  162. sizeof(TS_CONTROL_PDU),
  163. PROT_PRIO_MISC,
  164. 0);
  165. }
  166. else {
  167. TRC_NRM((TB, "Failed to allocate packet %d", msg));
  168. // Continue periodic scheduling.
  169. SCH_ContinueScheduling(SCH_MODE_NORMAL);
  170. }
  171. DC_END_FN();
  172. return STATUS_SUCCESS == status;
  173. }
  174. /****************************************************************************/
  175. /* FUNCTION: CAFlushAndSendMsg */
  176. /* */
  177. /* This function will attempt to flush any outstanding CA messages and send */
  178. /* the supplied message. This function relies on the CA messages being */
  179. /* contiguous between TS_CTRLACTION_FIRST and TS_CTRLACTION_LAST. If it */
  180. /* fails to send the message then it will set a flag to remember it is */
  181. /* pending and continue to try to send the message every time it is called. */
  182. /* */
  183. /* PARAMETERS: */
  184. /* msg - the message to be sent. If this is CA_NO_MESSAGE then the */
  185. /* function only attempts to send outstanding messages. */
  186. /* */
  187. /* data1, data2 - the data for the extra fields in the message. */
  188. /* */
  189. /* RETURNS: TRUE or FALSE - whether the supplied message was sent */
  190. /****************************************************************************/
  191. BOOL RDPCALL SHCLASS CAFlushAndSendMsg(
  192. UINT16 msg,
  193. UINT16 GrantID,
  194. UINT32 ControlID)
  195. {
  196. BOOL rc;
  197. int i;
  198. DC_BEGIN_FN("CAFlushAndSendMsg");
  199. /************************************************************************/
  200. /* The order messages get sent is not important - merely that they get */
  201. /* sent as soon as possible whilst the conditions which triggered our */
  202. /* intial attempt to send them are still valid (ie if we try to send a */
  203. /* TS_CTRLACTION_COOPERATE we drop a pending TS_CTRLACTION_DETACH if */
  204. /* there is one - see CAEvent). This means we can just ensure that the */
  205. /* pending flag is set for our current event and then try to send all */
  206. /* pending events. The other important point about CA messages is that */
  207. /* the only one which can be sent out repeatedly is a */
  208. /* TS_CTRLACTION_REQUEST_CONTROL. We effectively give that the lowest */
  209. /* priority by looking through our array of pending flags backwards so */
  210. /* that even if it is repeating and we can only ever get one packet */
  211. /* here we will send the other messages (although it is unlikely that */
  212. /* they'll be generated whilst we are requesting control). */
  213. /************************************************************************/
  214. /************************************************************************/
  215. /* Set the pending flag for the current message */
  216. /************************************************************************/
  217. if (msg >= TS_CTRLACTION_FIRST && msg <= TS_CTRLACTION_LAST) {
  218. caPendingMessages[msg - TS_CTRLACTION_FIRST].pending = TRUE;
  219. caPendingMessages[msg - TS_CTRLACTION_FIRST].grantId = GrantID;
  220. caPendingMessages[msg - TS_CTRLACTION_FIRST].controlId = ControlID;
  221. }
  222. else {
  223. TRC_ASSERT((msg == CA_NO_MESSAGE),(TB,"Invalid msg"));
  224. }
  225. /************************************************************************/
  226. /* Now flush out the pending messages. */
  227. /************************************************************************/
  228. for (i = (TS_CTRLACTION_LAST - TS_CTRLACTION_FIRST); i >= 0; i--) {
  229. if (caPendingMessages[i].pending) {
  230. // Try to send this message.
  231. if (CASendMsg((UINT16)(i + TS_CTRLACTION_FIRST),
  232. caPendingMessages[i].grantId,
  233. caPendingMessages[i].controlId)) {
  234. caPendingMessages[i].pending = FALSE;
  235. if (i == (TS_CTRLACTION_GRANTED_CONTROL -
  236. TS_CTRLACTION_FIRST)) {
  237. // When we successfully send a granted message to another
  238. // party then we relinquish control and must issue a
  239. // 'given control' event.
  240. if (caPendingMessages[i].grantId !=
  241. SC_GetMyNetworkPersonID()) {
  242. CAEvent(CA_EVENTI_GIVEN_CONTROL,
  243. (UINT32)SC_NetworkIDToLocalID(
  244. caPendingMessages[i].grantId));
  245. }
  246. }
  247. }
  248. else {
  249. // It didn't work so break out and don't try to send any
  250. // more messages.
  251. break;
  252. }
  253. }
  254. }
  255. /************************************************************************/
  256. /* Now return the status according to whether we sent the message that */
  257. /* we were called with. */
  258. /************************************************************************/
  259. if (msg != CA_NO_MESSAGE)
  260. rc = !caPendingMessages[msg - TS_CTRLACTION_FIRST].pending;
  261. else
  262. rc = TRUE;
  263. DC_END_FN();
  264. return rc;
  265. }
  266. /****************************************************************************/
  267. /* FUNCTION: CAEvent */
  268. /* */
  269. /* Called from many CA functions to manage various inputs. */
  270. /* */
  271. /* PARAMETERS: */
  272. /* caEvent - the event, the possible events are (the meaning of the */
  273. /* additionalData parameter if any is given in brackets) */
  274. /* */
  275. /* The possible events for CA_Event plus */
  276. /* */
  277. /* CA_EVENTI_REQUEST_CONTROL */
  278. /* CA_EVENTI_TRY_GIVE_CONTROL(person ID of party requesting control) */
  279. /* CA_EVENTI_GIVEN_CONTROL(person ID who we gave control to) */
  280. /* CA_EVENTI_GRANTED_CONTROL(person ID of the party granted control) */
  281. /* CA_EVENTI_ENTER_DETACHED_MODE */
  282. /* CA_EVENTI_ENTER_COOPERATING_MODE */
  283. /* CA_EVENTI_ENTER_CONTROL_MODE */
  284. /* CA_EVENTI_ENTER_VIEWING_MODE */
  285. /* CA_EVENTI_REMOTE_DETACH(person ID of remote party) */
  286. /* CA_EVENTI_REMOTE_COOPERATE(person ID of remote party) */
  287. /* CA_EVENTI_GRAB_CONTROL */
  288. /* */
  289. /* additionalData - depends on the caEvent, see above. */
  290. /****************************************************************************/
  291. void RDPCALL SHCLASS CAEvent(
  292. unsigned caEvent,
  293. UINT32 additionalData)
  294. {
  295. LOCALPERSONID i;
  296. DC_BEGIN_FN("CAEvent");
  297. TRC_NRM((TB, "Processing event - %d(%04lX)", caEvent, additionalData));
  298. switch (caEvent)
  299. {
  300. case CA_EVENT_OLD_UNATTENDED:
  301. case CA_EVENT_CANT_CONTROL:
  302. case CA_EVENT_BEGIN_UNATTENDED:
  303. case CA_EVENT_TAKE_CONTROL:
  304. case CA_EVENT_DETACH_CONTROL:
  305. case CA_EVENTI_REQUEST_CONTROL:
  306. case CA_EVENTI_REMOTE_DETACH:
  307. case CA_EVENTI_GRAB_CONTROL:
  308. case CA_EVENTI_GRANTED_CONTROL:
  309. case CA_EVENTI_ENTER_DETACHED_MODE:
  310. case CA_EVENTI_ENTER_CONTROL_MODE:
  311. /****************************************************************/
  312. /* we don't expect to get any of these */
  313. /****************************************************************/
  314. TRC_ALT((TB, "Nonsensical CA event %d", caEvent));
  315. break;
  316. case CA_EVENTI_TRY_GIVE_CONTROL:
  317. {
  318. NETPERSONID destPersonID;
  319. /****************************************************************/
  320. /* always try to give up control */
  321. /****************************************************************/
  322. destPersonID = SC_LocalIDToNetworkID(
  323. (LOCALPERSONID)additionalData);
  324. /****************************************************************/
  325. /* Give control to the destPersonID. If this fails */
  326. /* CAFlushAndSendMsg will remember for us and retry. */
  327. /****************************************************************/
  328. CAFlushAndSendMsg(TS_CTRLACTION_GRANTED_CONTROL,
  329. (UINT16)destPersonID, SC_GetMyNetworkPersonID());
  330. break;
  331. }
  332. case CA_EVENTI_GIVEN_CONTROL:
  333. /****************************************************************/
  334. /* Now update our globals. */
  335. /****************************************************************/
  336. caWhoHasControlToken = (LOCALPERSONID)additionalData;
  337. /****************************************************************/
  338. /* make sure we go to viewing */
  339. /****************************************************************/
  340. CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
  341. /****************************************************************/
  342. /* Update the state for the person we gave control to (as we */
  343. /* will not see the GRANTED message). */
  344. /****************************************************************/
  345. i = (LOCALPERSONID)additionalData;
  346. if (caStates[i] == CA_STATE_VIEWING)
  347. caStates[i] = CA_STATE_IN_CONTROL;
  348. break;
  349. case CA_EVENTI_ENTER_COOP_MODE:
  350. /****************************************************************/
  351. /* Notify the remote system that we are cooperating - forget */
  352. /* about any detach messages we've been unable to send. If */
  353. /* we fail to send the message now then CAFlushAndSendMsg will */
  354. /* remember and retry for us. We will enter cooperating state */
  355. /* anyway. */
  356. /****************************************************************/
  357. caPendingMessages[TS_CTRLACTION_DETACH - TS_CTRLACTION_FIRST].
  358. pending = FALSE;
  359. if (additionalData != CA_DONT_SEND_MSG)
  360. CAFlushAndSendMsg(TS_CTRLACTION_COOPERATE, 0, 0);
  361. break;
  362. case CA_EVENTI_ENTER_VIEWING_MODE:
  363. // Change to viewing state.
  364. caStates[0] = CA_STATE_VIEWING;
  365. break;
  366. case CA_EVENTI_REMOTE_COOPERATE:
  367. TRC_NRM((TB, "Person %d (Local) is cooperating", additionalData));
  368. /****************************************************************/
  369. /* Make the state change */
  370. /****************************************************************/
  371. if (caWhoHasControlToken == (LOCALPERSONID)additionalData)
  372. caStates[additionalData] = CA_STATE_IN_CONTROL;
  373. else
  374. caStates[additionalData] = CA_STATE_VIEWING;
  375. break;
  376. case CA_EVENT_COOPERATE_CONTROL:
  377. TRC_ALT((TB, "Nonsensical CA event %d", caEvent));
  378. #ifdef Unused
  379. /****************************************************************/
  380. /* need to change to viewing mode after leaving detached mode */
  381. /****************************************************************/
  382. CAEvent(CA_EVENTI_ENTER_COOP_MODE, 0);
  383. /****************************************************************/
  384. /* Enter viewing mode. */
  385. /****************************************************************/
  386. CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
  387. #endif
  388. break;
  389. default:
  390. TRC_ERR((TB, "Unrecognised event - %d", caEvent));
  391. break;
  392. }
  393. DC_END_FN();
  394. }