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

/****************************************************************************/
// acaapi.cpp
//
// RDP Control Arbitrator API functions
//
// Copyright (C) Microsoft, PictureTel 1993-1997
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <precomp.h>
#pragma hdrstop
#define TRC_FILE "acaapi"
#include <adcg.h>
#include <as_conf.hpp>
/****************************************************************************/
/* API FUNCTION: CA_Init */
/* */
/* Called to initialize the CA. */
/****************************************************************************/
void RDPCALL SHCLASS CA_Init(void)
{
DC_BEGIN_FN("CA_Init");
#define DC_INIT_DATA
#include <acadata.c>
#undef DC_INIT_DATA
// Set local node initial state to detached.
caStates[0] = CA_STATE_DETACHED;
DC_END_FN();
}
/****************************************************************************/
// CA_ReceivedPacket
//
// Handles control PDUs inbound from the client.
/****************************************************************************/
void RDPCALL SHCLASS CA_ReceivedPacket(
PTS_CONTROL_PDU pControlPDU,
unsigned DataLength,
LOCALPERSONID personID)
{
DC_BEGIN_FN("CA_ReceivedPacket");
// Ensure we can access the header.
if (DataLength >= sizeof(TS_CONTROL_PDU)) {
TRC_NRM((TB, "[%u] Packet:%d", personID, pControlPDU->action));
switch (pControlPDU->action) {
case TS_CTRLACTION_REQUEST_CONTROL:
CAEvent(CA_EVENTI_TRY_GIVE_CONTROL, (UINT32)personID);
break;
case TS_CTRLACTION_COOPERATE:
CAEvent(CA_EVENTI_REMOTE_COOPERATE, (UINT32)personID);
break;
default:
// An invalid action - log and disconnect the Client.
TRC_ERR((TB, "Invalid CA msg %d", pControlPDU->action));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_InvalidControlPDUAction,
(BYTE *)&(pControlPDU->action),
sizeof(pControlPDU->action));
break;
}
}
else {
TRC_ERR((TB,"Data length %u too short for control header",
DataLength));
WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_ShareDataTooShort,
(BYTE *)pControlPDU, DataLength);
}
DC_END_FN();
}
/****************************************************************************/
/* API FUNCTION: CA_PartyJoiningShare */
/* */
/* Called when a new party is joining the share */
/* */
/* PARAMETERS: */
/* personID - the ID of the new party. */
/* oldShareSize - the number of the parties which were in the share (ie */
/* excludes the joining party). */
/* */
/* RETURNS: */
/* TRUE - the CA can accept the new party */
/* FALSE - the CA cannot accept the new party */
/****************************************************************************/
BOOL RDPCALL SHCLASS CA_PartyJoiningShare(
LOCALPERSONID personID,
unsigned oldShareSize)
{
DC_BEGIN_FN("CA_PartyJoiningShare");
/************************************************************************/
// Check for share start, do some init if need be.
/************************************************************************/
if (oldShareSize == 0) {
// Enter cooperate mode then viewing. Note that we don't send
// a message now (we will send one when we process a CA_SyncNow call).
CAEvent(CA_EVENTI_ENTER_COOP_MODE, CA_DONT_SEND_MSG);
CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
caWhoHasControlToken = (LOCALPERSONID)-1;
}
// Set new node state to detached -- we should receive a CA packet
// to tell us what the remote state really is before we receive any IM
// packets. But just in case, choosing detached is the safest as it has
// least priveleges. Note that we will not enable the shadow cursors
// until (and if) we get a CA packet to tell us the remote system is
// detached.
caStates[personID] = CA_STATE_DETACHED;
DC_END_FN();
return TRUE;
}
/****************************************************************************/
/* API FUNCTION: CA_PartyLeftShare */
/* */
/* Called when a party has left the share. */
/* */
/* PARAMETERS: */
/* personID - the local ID of the new party. */
/* newShareSize - the number of the parties now in the share (ie excludes */
/* the leaving party). */
/****************************************************************************/
void RDPCALL SHCLASS CA_PartyLeftShare(
LOCALPERSONID personID,
unsigned newShareSize)
{
DC_BEGIN_FN("CA_PartyLeftShare");
// Just ensure their state is left as detached for safety.
caStates[personID] = CA_STATE_DETACHED;
DC_END_FN();
}
/****************************************************************************/
/* API FUNCTION: CA_SyncNow */
/* */
/* Called by the TT to signal the beginning of a sync. */
/****************************************************************************/
void RDPCALL SHCLASS CA_SyncNow(void)
{
DC_BEGIN_FN("CA_SyncNow");
/************************************************************************/
/* Tell the world we're cooperating. */
/************************************************************************/
TRC_NRM((TB, "Send cooperate"));
CAFlushAndSendMsg(TS_CTRLACTION_COOPERATE, 0, 0);
DC_END_FN();
}
/****************************************************************************/
/* FUNCTION: CASendMsg */
/* */
/* Sends a CA message to remote system */
/****************************************************************************/
__inline BOOL RDPCALL SHCLASS CASendMsg(
UINT16 msg,
UINT16 data1,
UINT32 data2)
{
NTSTATUS status;
PTS_CONTROL_PDU pControlPDU;
DC_BEGIN_FN("CASendMsg");
status = SC_AllocBuffer((PPVOID)&pControlPDU, sizeof(TS_CONTROL_PDU));
if ( STATUS_SUCCESS == status ) {
// Set up the packet header for a request message
pControlPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_CONTROL;
pControlPDU->action = msg;
pControlPDU->grantId = data1;
pControlPDU->controlId = data2;
SC_SendData((PTS_SHAREDATAHEADER)pControlPDU,
sizeof(TS_CONTROL_PDU),
sizeof(TS_CONTROL_PDU),
PROT_PRIO_MISC,
0);
}
else {
TRC_NRM((TB, "Failed to allocate packet %d", msg));
// Continue periodic scheduling.
SCH_ContinueScheduling(SCH_MODE_NORMAL);
}
DC_END_FN();
return STATUS_SUCCESS == status;
}
/****************************************************************************/
/* FUNCTION: CAFlushAndSendMsg */
/* */
/* This function will attempt to flush any outstanding CA messages and send */
/* the supplied message. This function relies on the CA messages being */
/* contiguous between TS_CTRLACTION_FIRST and TS_CTRLACTION_LAST. If it */
/* fails to send the message then it will set a flag to remember it is */
/* pending and continue to try to send the message every time it is called. */
/* */
/* PARAMETERS: */
/* msg - the message to be sent. If this is CA_NO_MESSAGE then the */
/* function only attempts to send outstanding messages. */
/* */
/* data1, data2 - the data for the extra fields in the message. */
/* */
/* RETURNS: TRUE or FALSE - whether the supplied message was sent */
/****************************************************************************/
BOOL RDPCALL SHCLASS CAFlushAndSendMsg(
UINT16 msg,
UINT16 GrantID,
UINT32 ControlID)
{
BOOL rc;
int i;
DC_BEGIN_FN("CAFlushAndSendMsg");
/************************************************************************/
/* The order messages get sent is not important - merely that they get */
/* sent as soon as possible whilst the conditions which triggered our */
/* intial attempt to send them are still valid (ie if we try to send a */
/* TS_CTRLACTION_COOPERATE we drop a pending TS_CTRLACTION_DETACH if */
/* there is one - see CAEvent). This means we can just ensure that the */
/* pending flag is set for our current event and then try to send all */
/* pending events. The other important point about CA messages is that */
/* the only one which can be sent out repeatedly is a */
/* TS_CTRLACTION_REQUEST_CONTROL. We effectively give that the lowest */
/* priority by looking through our array of pending flags backwards so */
/* that even if it is repeating and we can only ever get one packet */
/* here we will send the other messages (although it is unlikely that */
/* they'll be generated whilst we are requesting control). */
/************************************************************************/
/************************************************************************/
/* Set the pending flag for the current message */
/************************************************************************/
if (msg >= TS_CTRLACTION_FIRST && msg <= TS_CTRLACTION_LAST) {
caPendingMessages[msg - TS_CTRLACTION_FIRST].pending = TRUE;
caPendingMessages[msg - TS_CTRLACTION_FIRST].grantId = GrantID;
caPendingMessages[msg - TS_CTRLACTION_FIRST].controlId = ControlID;
}
else {
TRC_ASSERT((msg == CA_NO_MESSAGE),(TB,"Invalid msg"));
}
/************************************************************************/
/* Now flush out the pending messages. */
/************************************************************************/
for (i = (TS_CTRLACTION_LAST - TS_CTRLACTION_FIRST); i >= 0; i--) {
if (caPendingMessages[i].pending) {
// Try to send this message.
if (CASendMsg((UINT16)(i + TS_CTRLACTION_FIRST),
caPendingMessages[i].grantId,
caPendingMessages[i].controlId)) {
caPendingMessages[i].pending = FALSE;
if (i == (TS_CTRLACTION_GRANTED_CONTROL -
TS_CTRLACTION_FIRST)) {
// When we successfully send a granted message to another
// party then we relinquish control and must issue a
// 'given control' event.
if (caPendingMessages[i].grantId !=
SC_GetMyNetworkPersonID()) {
CAEvent(CA_EVENTI_GIVEN_CONTROL,
(UINT32)SC_NetworkIDToLocalID(
caPendingMessages[i].grantId));
}
}
}
else {
// It didn't work so break out and don't try to send any
// more messages.
break;
}
}
}
/************************************************************************/
/* Now return the status according to whether we sent the message that */
/* we were called with. */
/************************************************************************/
if (msg != CA_NO_MESSAGE)
rc = !caPendingMessages[msg - TS_CTRLACTION_FIRST].pending;
else
rc = TRUE;
DC_END_FN();
return rc;
}
/****************************************************************************/
/* FUNCTION: CAEvent */
/* */
/* Called from many CA functions to manage various inputs. */
/* */
/* PARAMETERS: */
/* caEvent - the event, the possible events are (the meaning of the */
/* additionalData parameter if any is given in brackets) */
/* */
/* The possible events for CA_Event plus */
/* */
/* CA_EVENTI_REQUEST_CONTROL */
/* CA_EVENTI_TRY_GIVE_CONTROL(person ID of party requesting control) */
/* CA_EVENTI_GIVEN_CONTROL(person ID who we gave control to) */
/* CA_EVENTI_GRANTED_CONTROL(person ID of the party granted control) */
/* CA_EVENTI_ENTER_DETACHED_MODE */
/* CA_EVENTI_ENTER_COOPERATING_MODE */
/* CA_EVENTI_ENTER_CONTROL_MODE */
/* CA_EVENTI_ENTER_VIEWING_MODE */
/* CA_EVENTI_REMOTE_DETACH(person ID of remote party) */
/* CA_EVENTI_REMOTE_COOPERATE(person ID of remote party) */
/* CA_EVENTI_GRAB_CONTROL */
/* */
/* additionalData - depends on the caEvent, see above. */
/****************************************************************************/
void RDPCALL SHCLASS CAEvent(
unsigned caEvent,
UINT32 additionalData)
{
LOCALPERSONID i;
DC_BEGIN_FN("CAEvent");
TRC_NRM((TB, "Processing event - %d(%04lX)", caEvent, additionalData));
switch (caEvent)
{
case CA_EVENT_OLD_UNATTENDED:
case CA_EVENT_CANT_CONTROL:
case CA_EVENT_BEGIN_UNATTENDED:
case CA_EVENT_TAKE_CONTROL:
case CA_EVENT_DETACH_CONTROL:
case CA_EVENTI_REQUEST_CONTROL:
case CA_EVENTI_REMOTE_DETACH:
case CA_EVENTI_GRAB_CONTROL:
case CA_EVENTI_GRANTED_CONTROL:
case CA_EVENTI_ENTER_DETACHED_MODE:
case CA_EVENTI_ENTER_CONTROL_MODE:
/****************************************************************/
/* we don't expect to get any of these */
/****************************************************************/
TRC_ALT((TB, "Nonsensical CA event %d", caEvent));
break;
case CA_EVENTI_TRY_GIVE_CONTROL:
{
NETPERSONID destPersonID;
/****************************************************************/
/* always try to give up control */
/****************************************************************/
destPersonID = SC_LocalIDToNetworkID(
(LOCALPERSONID)additionalData);
/****************************************************************/
/* Give control to the destPersonID. If this fails */
/* CAFlushAndSendMsg will remember for us and retry. */
/****************************************************************/
CAFlushAndSendMsg(TS_CTRLACTION_GRANTED_CONTROL,
(UINT16)destPersonID, SC_GetMyNetworkPersonID());
break;
}
case CA_EVENTI_GIVEN_CONTROL:
/****************************************************************/
/* Now update our globals. */
/****************************************************************/
caWhoHasControlToken = (LOCALPERSONID)additionalData;
/****************************************************************/
/* make sure we go to viewing */
/****************************************************************/
CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
/****************************************************************/
/* Update the state for the person we gave control to (as we */
/* will not see the GRANTED message). */
/****************************************************************/
i = (LOCALPERSONID)additionalData;
if (caStates[i] == CA_STATE_VIEWING)
caStates[i] = CA_STATE_IN_CONTROL;
break;
case CA_EVENTI_ENTER_COOP_MODE:
/****************************************************************/
/* Notify the remote system that we are cooperating - forget */
/* about any detach messages we've been unable to send. If */
/* we fail to send the message now then CAFlushAndSendMsg will */
/* remember and retry for us. We will enter cooperating state */
/* anyway. */
/****************************************************************/
caPendingMessages[TS_CTRLACTION_DETACH - TS_CTRLACTION_FIRST].
pending = FALSE;
if (additionalData != CA_DONT_SEND_MSG)
CAFlushAndSendMsg(TS_CTRLACTION_COOPERATE, 0, 0);
break;
case CA_EVENTI_ENTER_VIEWING_MODE:
// Change to viewing state.
caStates[0] = CA_STATE_VIEWING;
break;
case CA_EVENTI_REMOTE_COOPERATE:
TRC_NRM((TB, "Person %d (Local) is cooperating", additionalData));
/****************************************************************/
/* Make the state change */
/****************************************************************/
if (caWhoHasControlToken == (LOCALPERSONID)additionalData)
caStates[additionalData] = CA_STATE_IN_CONTROL;
else
caStates[additionalData] = CA_STATE_VIEWING;
break;
case CA_EVENT_COOPERATE_CONTROL:
TRC_ALT((TB, "Nonsensical CA event %d", caEvent));
#ifdef Unused
/****************************************************************/
/* need to change to viewing mode after leaving detached mode */
/****************************************************************/
CAEvent(CA_EVENTI_ENTER_COOP_MODE, 0);
/****************************************************************/
/* Enter viewing mode. */
/****************************************************************/
CAEvent(CA_EVENTI_ENTER_VIEWING_MODE, 0);
#endif
break;
default:
TRC_ERR((TB, "Unrecognised event - %d", caEvent));
break;
}
DC_END_FN();
}