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.
 
 
 
 
 
 

1685 lines
59 KiB

/****************************************************************************/
// jetrpcfn.cpp
//
// TS Directory Integrity Service Jet RPC server-side implementations.
//
// Copyright (C) 2000, Microsoft Corporation
/****************************************************************************/
#include "dis.h"
#include "tssdshrd.h"
#include "jetrpc.h"
#include "jetsdis.h"
#pragma warning (push, 4)
/****************************************************************************/
// MIDL_user_allocate
// MIDL_user_free
//
// RPC-required allocation functions.
/****************************************************************************/
void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t Size)
{
return LocalAlloc(LMEM_FIXED, Size);
}
void __RPC_USER MIDL_user_free(void __RPC_FAR *p)
{
LocalFree(p);
}
/****************************************************************************/
// OutputAllTables (debug only)
//
// Output all tables to debug output.
/****************************************************************************/
#ifdef DBG
void OutputAllTables()
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
JET_TABLEID clusdirtableid;
JET_RETRIEVECOLUMN rcSessDir[NUM_SESSDIRCOLUMNS];
WCHAR UserNameBuf[256];
WCHAR DomainBuf[127];
WCHAR ApplicationBuf[256];
WCHAR ServerNameBuf[128];
WCHAR ClusterNameBuf[128];
unsigned count;
long num_vals[NUM_SESSDIRCOLUMNS];
char state;
char SingleSessMode;
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetBeginTransaction(sesid));
TSDISErrorOut(L"SESSION DIRECTORY\n");
err = JetMove(sesid, sessdirtableid, JET_MoveFirst, 0);
if (JET_errNoCurrentRecord == err) {
TSDISErrorOut(L" (empty database)\n");
}
while (JET_errNoCurrentRecord != err) {
// Retrieve all the columns
memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
NUM_SESSDIRCOLUMNS);
for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
rcSessDir[count].columnid = sesdircolumnid[count];
rcSessDir[count].pvData = &num_vals[count];
rcSessDir[count].cbData = sizeof(long);
rcSessDir[count].itagSequence = 1;
}
// fix up pvData, cbData for non-int fields
rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserNameBuf;
rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData = sizeof(UserNameBuf);
rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = DomainBuf;
rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData = sizeof(DomainBuf);
rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = ApplicationBuf;
rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
sizeof(ApplicationBuf);
rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(state);
CALL(JetRetrieveColumns(sesid, sessdirtableid, &rcSessDir[0],
NUM_SESSDIRCOLUMNS));
TSDISErrorOut(L"%8s, %s, %d, %d, %d\n",
UserNameBuf,
DomainBuf,
num_vals[SESSDIR_SERVERID_INTERNAL_INDEX],
num_vals[SESSDIR_SESSIONID_INTERNAL_INDEX],
num_vals[SESSDIR_TSPROTOCOL_INTERNAL_INDEX]);
TSDISErrorTimeOut(L" %s, ",
num_vals[SESSDIR_CTLOW_INTERNAL_INDEX],
num_vals[SESSDIR_CTHIGH_INTERNAL_INDEX]);
TSDISErrorTimeOut(L"%s\n",
num_vals[SESSDIR_DTLOW_INTERNAL_INDEX],
num_vals[SESSDIR_DTHIGH_INTERNAL_INDEX]);
TSDISErrorOut(L" %s, %d, %d, %d, %s\n",
ApplicationBuf ? L"(no application)" : ApplicationBuf,
num_vals[SESSDIR_RESWIDTH_INTERNAL_INDEX],
num_vals[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
num_vals[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
state ? L"disconnected" : L"connected");
err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
}
// Output Server Directory (we are reusing the rcSessDir structure).
TSDISErrorOut(L"SERVER DIRECTORY\n");
err = JetMove(sesid, servdirtableid, JET_MoveFirst, 0);
if (JET_errNoCurrentRecord == err) {
TSDISErrorOut(L" (empty database)\n");
}
while (JET_errNoCurrentRecord != err) {
// Retrieve all the columns.
memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
NUM_SERVDIRCOLUMNS);
for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
rcSessDir[count].columnid = servdircolumnid[count];
rcSessDir[count].pvData = &num_vals[count];
rcSessDir[count].cbData = sizeof(long);
rcSessDir[count].itagSequence = 1;
}
rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerNameBuf;
rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
sizeof(ServerNameBuf);
rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSessMode);
CALL(JetRetrieveColumns(sesid, servdirtableid, &rcSessDir[0],
NUM_SERVDIRCOLUMNS));
TSDISErrorOut(L"%d, %s, %d, %d, %d, %d, %s\n", num_vals[
SERVDIR_SERVID_INTERNAL_INDEX], ServerNameBuf, num_vals[
SERVDIR_CLUSID_INTERNAL_INDEX], num_vals[
SERVDIR_AITLOW_INTERNAL_INDEX], num_vals[
SERVDIR_AITHIGH_INTERNAL_INDEX], num_vals[
SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], SingleSessMode ?
L"single session mode" : L"multi-session mode");
err = JetMove(sesid, servdirtableid, JET_MoveNext, 0);
}
// Output Cluster Directory
TSDISErrorOut(L"CLUSTER DIRECTORY\n");
err = JetMove(sesid, clusdirtableid, JET_MoveFirst, 0);
if (JET_errNoCurrentRecord == err) {
TSDISErrorOut(L" (empty database)\n");
}
while (JET_errNoCurrentRecord != err) {
memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
NUM_CLUSDIRCOLUMNS);
for (count = 0; count < NUM_CLUSDIRCOLUMNS; count++) {
rcSessDir[count].columnid = clusdircolumnid[count];
rcSessDir[count].pvData = &num_vals[count];
rcSessDir[count].cbData = sizeof(long);
rcSessDir[count].itagSequence = 1;
}
rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].pvData = ClusterNameBuf;
rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].cbData =
sizeof(ClusterNameBuf);
rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].cbData =
sizeof(SingleSessMode);
CALL(JetRetrieveColumns(sesid, clusdirtableid, &rcSessDir[0],
NUM_CLUSDIRCOLUMNS));
TSDISErrorOut(L"%d, %s, %s\n", num_vals[CLUSDIR_CLUSID_INTERNAL_INDEX],
ClusterNameBuf, SingleSessMode ? L"single session mode" :
L"multi-session mode");
err = JetMove(sesid, clusdirtableid, JET_MoveNext, 0);
}
TSDISErrorOut(L"\n");
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
}
#endif //DBG
typedef DWORD CLIENTINFO;
/****************************************************************************/
// TSSDRpcServerOnline
//
// Called for server-active indications on each cluster TS machine.
/****************************************************************************/
DWORD TSSDRpcServerOnline(
handle_t Binding,
WCHAR __RPC_FAR *ClusterName,
/* out */ HCLIENTINFO *hCI,
DWORD SrvOnlineFlags)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID clusdirtableid;
JET_TABLEID servdirtableid;
JET_SETCOLUMN scServDir[NUM_SERVDIRCOLUMNS];
WCHAR *StringBinding = NULL;
WCHAR *ServerAddress = NULL;
RPC_BINDING_HANDLE ServerBinding = 0;
unsigned long cbActual;
long ClusterID;
long ServerID = 0;
long zero = 0;
char czero = 0;
// The single session mode of this server.
char SingleSession = (char) SrvOnlineFlags & SINGLE_SESSION_FLAG;
char ClusSingleSessionMode;
unsigned count;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In ServOnline, ClusterName=%s, SrvOnlineFlags=%u\n",
ClusterName, SrvOnlineFlags);
// Determine client address.
if (RpcBindingServerFromClient(Binding, &ServerBinding) != RPC_S_OK) {
TSDISErrorOut(L"ServOn: BindingServerFromClient failed!\n");
goto HandleError;
}
if (RpcBindingToStringBinding(ServerBinding, &StringBinding) != RPC_S_OK) {
TSDISErrorOut(L"ServOn: BindingToStringBinding failed!\n");
goto HandleError;
}
if (RpcStringBindingParse(StringBinding, NULL, NULL, &ServerAddress, NULL,
NULL) != RPC_S_OK) {
TSDISErrorOut(L"ServOn: StringBindingParse failed!\n");
goto HandleError;
}
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
// First, delete all entries for this server from the session/server
//directories
CALL(JetBeginTransaction(sesid));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
(wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
if (JET_errSuccess == err) {
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
&cbActual, 0, NULL));
if (TSSDPurgeServer(ServerID) != 0)
TSDISErrorOut(L"ServOn: PurgeServer %d failed.\n", ServerID);
} else if (JET_errRecordNotFound != err) {
CALL(err);
}
CALL(JetCommitTransaction(sesid, 0));
// We have to do the add in a loop, because we have to:
// 1) Check if the record is there.
// 2) If it's not, add it. (The next time through the loop, therefore,
// we'll go step 1->3, and we're done.)
// 3) If it is, retrieve the value of clusterID and break out.
//
// There is an additional complication in that someone else may be in the
// thread simultaneously, doing the same thing. Therefore, someone might
// be in step 2 and try to add a new cluster, but fail because someone
// else added it. So they have to keep trying, because though the other
// thread has added it, it may not have committed the change. To try to
// keep that to a minimum, we sleep a short time before trying again.
for ( ; ; ) {
// Now do the actual add.
CALL(JetBeginTransaction(sesid));
// Search for the cluster in the cluster directory.
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusNameIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, ClusterName, (unsigned)
(wcslen(ClusterName) + 1) * sizeof(WCHAR), JET_bitNewKey));
err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
// If the cluster does not exist, create it.
if (JET_errRecordNotFound == err) {
CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepInsert));
// ClusterName
CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSNAME_INTERNAL_INDEX], ClusterName,
(unsigned) (wcslen(ClusterName) + 1) * sizeof(WCHAR), 0,
NULL));
// SingleSessionMode
// Since this is the only server in the cluster, the single session
// mode is simply the mode of this server.
CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
sizeof(SingleSession), 0, NULL));
err = JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual);
// If it's a duplicate key, someone else made the key so we should
// be ok. Yield the processor and try the query again, next time
// through the loop.
if (JET_errKeyDuplicate == err) {
CALL(JetCommitTransaction(sesid, 0));
Sleep(100);
}
else {
CALL(err);
// Now we've succeeded. Just continue through the loop.
// The next time through, we will retrieve the autoincrement
// column we just added and break out.
CALL(JetCommitTransaction(sesid, 0));
}
}
else {
CALL(err);
// If the above check makes it here, we have found the row.
// Now retrieve the clusid, commit, and break out of the loop.
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
sizeof(ClusterID), &cbActual, 0, NULL));
CALL(JetCommitTransaction(sesid, 0));
break;
}
}
CALL(JetBeginTransaction(sesid));
// Insert the servername, clusterid, 0, 0 into the server directory table
err = JetMove(sesid, servdirtableid, JET_MoveLast, 0);
CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepInsert));
memset(&scServDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SERVDIRCOLUMNS);
for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
scServDir[count].columnid = servdircolumnid[count];
scServDir[count].cbData = 4; // most of them, set the rest individually
scServDir[count].itagSequence = 1;
}
scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerAddress;
scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(ServerAddress) + 1) * sizeof(WCHAR);
scServDir[SERVDIR_CLUSID_INTERNAL_INDEX].pvData = &ClusterID;
scServDir[SERVDIR_AITLOW_INTERNAL_INDEX].pvData = &zero;
scServDir[SERVDIR_AITHIGH_INTERNAL_INDEX].pvData = &zero;
scServDir[SERVDIR_NUMFAILPINGS_INTERNAL_INDEX].pvData = &zero;
scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSession;
scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSession);
// Don't set the first column (index 0)--it is autoincrement.
CALL(JetSetColumns(sesid, servdirtableid, &scServDir[
SERVDIR_SERVADDR_INTERNAL_INDEX], NUM_SERVDIRCOLUMNS - 1));
CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
(wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
&cbActual, 0, NULL));
*hCI = ULongToPtr(ServerID);
// Now that the server is all set up, we have to set the cluster to the
// correct mode. If any server in the cluster is in multisession mode, then
// we stick with multisession. If they are all single session, though, we
// turn on single session in this cluster. We do some database magic
// to make this work. We have an index on the ClusterID and the Single
// Session mode. We query for this cluster with single session mode 0
// (i.e., multi-session mode). If we get any results back, we are multi-
// session, otherwise we're single session.
// Set up the key.
CALL(JetSetCurrentIndex(sesid, servdirtableid, "SingleSessionIndex"));
CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID),
JET_bitNewKey));
CALL(JetMakeKey(sesid, servdirtableid, &czero, sizeof(czero), 0));
err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
// NOTE REUSE OF SingleSession VARIABLE! Up there it meant what the flag
// passed in meant. Here it means what we determine the cluster's state to
// be based on our logic.
if (err == JET_errRecordNotFound) {
SingleSession = 1;
}
else {
// CALL the error value to make sure it's success
CALL(err);
// If we got here then everything is ok.
SingleSession = 0;
}
// Check the cluster to see if it is already in that mode.
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&ClusterID,
sizeof(ClusterID), JET_bitNewKey));
CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &ClusSingleSessionMode, sizeof(
ClusSingleSessionMode), &cbActual, 0, NULL));
// If not, change the mode.
if (SingleSession != ClusSingleSessionMode) {
CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepReplace));
CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
sizeof(SingleSession), 0, NULL));
CALL(JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual));
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
if (ServerBinding != NULL)
RpcBindingFree(&ServerBinding);
if (StringBinding != NULL)
RpcStringFree(&StringBinding);
if (ServerAddress != NULL)
RpcStringFree(&ServerAddress);
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
if (ServerBinding != NULL)
RpcBindingFree(&ServerBinding);
if (StringBinding != NULL)
RpcStringFree(&StringBinding);
if (ServerAddress != NULL)
RpcStringFree(&ServerAddress);
// Just in case we got to commit.
TSSDPurgeServer(ServerID);
// Close the context handle.
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcServerOffline
//
// Called for server-shutdown indications on each cluster TS machine.
/****************************************************************************/
DWORD TSSDRpcServerOffline(
handle_t Binding,
HCLIENTINFO *hCI)
{
DWORD retval = 0;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In ServOff, hCI = 0x%x\n", *hCI);
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
if (pCI != NULL)
retval = TSSDPurgeServer(*pCI);
*hCI = NULL;
return retval;
}
/****************************************************************************/
// TSSDPurgeServer
//
// Delete a server and all its sessions from the session directory.
/****************************************************************************/
DWORD TSSDPurgeServer(
DWORD ServerID)
{
JET_SESID sesid = JET_sesidNil;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
JET_DBID dbid;
JET_ERR err;
TSDISErrorOut(L"In PurgeServer, ServerID=%d\n", ServerID);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Delete all sessions in session directory that have this serverid
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
while (0 == err) {
CALL(JetDelete(sesid, sessdirtableid));
CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
}
// Should be err -1601 -- JET_errRecordNotFound
// Delete the server in the server directory with this serverid
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
JET_bitNewKey));
err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
if (JET_errSuccess == err)
CALL(JetDelete(sesid, servdirtableid));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcGetUserDisconnectedSessions
//
// Queries disconnected sessions from the session database.
/****************************************************************************/
DWORD TSSDRpcGetUserDisconnectedSessions(
handle_t Binding,
HCLIENTINFO *hCI,
WCHAR __RPC_FAR *UserName,
WCHAR __RPC_FAR *Domain,
/* out */ DWORD __RPC_FAR *pNumSessions,
/* out */ TSSD_DiscSessInfo __RPC_FAR __RPC_FAR **padsi)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
JET_TABLEID clusdirtableid;
*pNumSessions = 0;
unsigned i = 0;
unsigned j = 0;
unsigned long cbActual;
DWORD tempClusterID;
DWORD CallingServersClusID;
long ServerID;
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
TSSD_DiscSessInfo *adsi = NULL;
char one = 1;
char bSingleSession = 0;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In GetUserDiscSess: ServID = %d, User: %s, "
L"Domain: %s\n", *pCI, UserName, Domain);
*padsi = (TSSD_DiscSessInfo *) MIDL_user_allocate(sizeof(TSSD_DiscSessInfo) *
TSSD_MaxDisconnectedSessions);
adsi = *padsi;
if (adsi == NULL) {
TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
goto HandleError;
}
// Set the pointers to 0 to be safe, and so that we can free uninitialized
// ones later without AVing.
for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
adsi[j].ServerAddress = NULL;
adsi[j].AppType = NULL;
}
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
&clusdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
// First, get the cluster ID for the server making the query.
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *)pCI, sizeof(DWORD),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_CLUSID_INTERNAL_INDEX], &CallingServersClusID, sizeof(
CallingServersClusID), &cbActual, 0, NULL));
// Now that we have the cluster id, check to see whether this cluster
// is in single session mode.
CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&CallingServersClusID,
sizeof(CallingServersClusID), JET_bitNewKey));
CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
CLUSDIR_SINGLESESS_INTERNAL_INDEX], &bSingleSession, sizeof(
bSingleSession), &cbActual, 0, NULL));
// Now, get all the disconnected or all sessions for this cluster, depending
// on the single session mode retrieved above.
if (bSingleSession == FALSE) {
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "DiscSessionIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
(wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
(wcslen(Domain) + 1) * sizeof(WCHAR), 0));
CALL(JetMakeKey(sesid, sessdirtableid, &one, sizeof(one), 0));
}
else {
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "AllSessionIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
(wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
(wcslen(Domain) + 1) * sizeof(WCHAR), 0));
}
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
while ((i < TSSD_MaxDisconnectedSessions) && (JET_errSuccess == err)) {
// Remember the initial retrieval does not have cluster id in the
// index, so filter by cluster id for each one.
// Get the ServerID for this record.
CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_SERVERID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
&cbActual, 0, NULL));
// Get the clusterID
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_CLUSID_INTERNAL_INDEX], &tempClusterID,
sizeof(tempClusterID), &cbActual, 0, NULL));
// Compare to the passed-in cluster id.
if (tempClusterID == CallingServersClusID) {
// Allocate space.
adsi[i].ServerAddress = (WCHAR *) MIDL_user_allocate(64 *
sizeof(WCHAR));
adsi[i].AppType = (WCHAR *) MIDL_user_allocate(256 * sizeof(WCHAR));
if ((adsi[i].ServerAddress == NULL) || (adsi[i].AppType == NULL)) {
TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
goto HandleError;
}
// ServerAddress comes out of the server table
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], adsi[i].ServerAddress,
128, &cbActual, 0, NULL));
// The rest come out of the session directory
// Session ID
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_SESSIONID_INTERNAL_INDEX],
&(adsi[i].SessionID), sizeof(DWORD), &cbActual, 0, NULL));
// TSProtocol
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_TSPROTOCOL_INTERNAL_INDEX],
&(adsi[i].TSProtocol), sizeof(DWORD), &cbActual, 0, NULL));
// Application Type
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_APPTYPE_INTERNAL_INDEX],
adsi[i].AppType, 512, &cbActual, 0, NULL));
// ResolutionWidth
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_RESWIDTH_INTERNAL_INDEX],
&(adsi[i].ResolutionWidth), sizeof(DWORD), &cbActual, 0,
NULL));
// ResolutionHeight
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
&(adsi[i].ResolutionHeight), sizeof(DWORD), &cbActual, 0,
NULL));
// Color Depth
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
&(adsi[i].ColorDepth), sizeof(DWORD), &cbActual, 0, NULL));
// CreateTimeLow
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_CTLOW_INTERNAL_INDEX],
&(adsi[i].CreateTimeLow), sizeof(DWORD), &cbActual, 0,
NULL));
// CreateTimeHigh
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_CTHIGH_INTERNAL_INDEX],
&(adsi[i].CreateTimeHigh), sizeof(DWORD), &cbActual, 0,
NULL));
// DisconnectTimeLow
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_DTLOW_INTERNAL_INDEX],
&(adsi[i].DisconnectTimeLow), sizeof(DWORD), &cbActual, 0,
NULL));
// DisconnectTimeHigh
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_DTHIGH_INTERNAL_INDEX],
&(adsi[i].DisconnectTimeHigh), sizeof(DWORD), &cbActual, 0,
NULL));
// State
// This is retrieving a byte that is 0xff or 0x0 into a DWORD
// pointer.
CALL(JetRetrieveColumn(sesid, sessdirtableid,
sesdircolumnid[SESSDIR_STATE_INTERNAL_INDEX],
&(adsi[i].State), sizeof(BYTE), &cbActual, 0,
NULL));
i += 1;
}
// Move to the next matching record.
err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
}
*pNumSessions = i;
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, clusdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
#ifdef DBG
OutputAllTables();
#endif // DBG
return 0;
HandleError:
// Deallocate memory.
for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
MIDL_user_free(adsi[j].ServerAddress);
MIDL_user_free(adsi[j].AppType);
}
// Can't really recover. Just bail out.
if (sesid != JET_sesidNil) {
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed.
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
// Delete the server and close the context handle. Their states are bad.
TSSDPurgeServer(PtrToUlong(*hCI));
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcCreateSession
//
// Called on a session logon.
/****************************************************************************/
DWORD TSSDRpcCreateSession(
handle_t Binding,
HCLIENTINFO *hCI,
WCHAR __RPC_FAR *UserName,
WCHAR __RPC_FAR *Domain,
DWORD SessionID,
DWORD TSProtocol,
WCHAR __RPC_FAR *AppType,
DWORD ResolutionWidth,
DWORD ResolutionHeight,
DWORD ColorDepth,
DWORD CreateTimeLow,
DWORD CreateTimeHigh)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
unsigned count;
int zero = 0;
unsigned long cbActual;
char state = 0;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"Inside TSSDRpcCreateSession, ServID=%d, "
L"UserName=%s, Domain=%s, SessID=%d, TSProt=%d, AppType=%s, "
L"ResWidth=%d, ResHeight=%d, ColorDepth=%d\n", *pCI, UserName,
Domain, SessionID, TSProtocol, AppType, ResolutionWidth,
ResolutionHeight, ColorDepth);
TSDISErrorTimeOut(L" CreateTime=%s\n", CreateTimeLow, CreateTimeHigh);
memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
scSessDir[count].columnid = sesdircolumnid[count];
scSessDir[count].cbData = 4; // most of them, set the rest individually
scSessDir[count].itagSequence = 1;
}
scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(UserName) + 1) * sizeof(WCHAR);
scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(Domain) + 1) * sizeof(WCHAR);
scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(AppType) + 1) * sizeof(WCHAR);
scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserName;
scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = Domain;
scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData = &SessionID;
scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData = &TSProtocol;
scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData = &CreateTimeLow;
scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData = &CreateTimeHigh;
scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData = &zero;
scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData = &zero;
scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = AppType;
scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData = &ResolutionWidth;
scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData = &ResolutionHeight;
scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData = &ColorDepth;
scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
CALL(JetSetColumns(sesid, sessdirtableid, scSessDir, NUM_SESSDIRCOLUMNS));
CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed.
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
// Delete the server and close the context handle. Their states are bad.
TSSDPurgeServer(PtrToUlong(*hCI));
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcDeleteSession
//
// Called on a session logoff.
/****************************************************************************/
DWORD TSSDRpcDeleteSession(
handle_t Binding,
HCLIENTINFO *hCI,
DWORD SessionID)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In DelSession, ServID=%d, "
L"SessID=%d\n", *pCI, SessionID);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
// Delete all sessions in session directory that have this serverid
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
CALL(JetMakeKey(sesid, sessdirtableid, pCI,
sizeof(*pCI), JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(SessionID),
0));
err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
CALL(JetDelete(sesid, sessdirtableid));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed.
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
// Delete the server and close the context handle. Their states are bad.
TSSDPurgeServer(PtrToUlong(*hCI));
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcSetSessionDisconnected
//
// Called on a session disconnection.
/****************************************************************************/
DWORD TSSDRpcSetSessionDisconnected(
handle_t Binding,
HCLIENTINFO *hCI,
DWORD SessionID,
DWORD DiscTimeLow,
DWORD DiscTimeHigh)
{
unsigned long cbActual;
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
char one = 1;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In SetSessDisc, ServID=%d, SessID=%d\n", *pCI, SessionID);
TSDISErrorTimeOut(L" DiscTime=%s\n", DiscTimeLow, DiscTimeHigh);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
// find the record with the serverid, sessionid we are looking for
CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_STATE_INTERNAL_INDEX], &one, sizeof(one), 0, NULL));
CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
// Delete the server and close the context handle. Their states are bad.
TSSDPurgeServer(PtrToUlong(*hCI));
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcSetSessionReconnected
//
// Called on a session reconnection.
/****************************************************************************/
DWORD TSSDRpcSetSessionReconnected(
handle_t Binding,
HCLIENTINFO *hCI,
DWORD SessionID,
DWORD TSProtocol,
DWORD ResWidth,
DWORD ResHeight,
DWORD ColorDepth)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
char zero = 0;
unsigned long cbActual;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"In SetSessRec, ServID=%d, SessID=%d, TSProt=%d, "
L"ResWid=%d, ResHt=%d, ColDepth=%d\n", *pCI,
SessionID, TSProtocol, ResWidth, ResHeight,
ColorDepth);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
// Find the record with the serverid, sessionid we are looking for.
CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
JET_bitNewKey));
CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_TSPROTOCOL_INTERNAL_INDEX], &TSProtocol, sizeof(TSProtocol),
0, NULL));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESWIDTH_INTERNAL_INDEX], &ResWidth, sizeof(ResWidth),
0, NULL));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_RESHEIGHT_INTERNAL_INDEX], &ResHeight, sizeof(ResHeight),
0, NULL));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_COLORDEPTH_INTERNAL_INDEX], &ColorDepth, sizeof(ColorDepth),
0, NULL));
CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
SESSDIR_STATE_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed.
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
// Delete the server and close the context handle. Their states are bad.
TSSDPurgeServer(PtrToUlong(*hCI));
*hCI = NULL;
return (DWORD) E_FAIL;
}
DWORD TSSDRpcSetServerReconnectPending(
handle_t Binding,
WCHAR __RPC_FAR *ServerAddress,
DWORD AlmostTimeLow,
DWORD AlmostTimeHigh)
{
// Ignored parameters
Binding;
AlmostTimeLow;
AlmostTimeHigh;
return TSSDSetServerAITInternal(ServerAddress, FALSE, NULL);
}
/****************************************************************************/
// TSSDRpcUpdateConfigurationSetting
//
// Extensible interface to update a configuration setting.
/****************************************************************************/
DWORD TSSDSetServerAddress(HCLIENTINFO *hCI, WCHAR *ServerName)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID servdirtableid;
unsigned long cbActual;
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
// Find the server in the server directory
CALL(JetBeginTransaction(sesid));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *)hCI, sizeof(DWORD),
JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
// Prepare to update.
CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
// Now set the column to what we want
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_SERVADDR_INTERNAL_INDEX], (void *) ServerName,
(unsigned) (wcslen(ServerName) + 1) * sizeof(WCHAR), 0,
NULL));
CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
CALL(JetCommitTransaction(sesid, 0));
// Clean up.
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
TSSDPurgeServer(PtrToUlong(*hCI));
// Close the context handle.
*hCI = NULL;
return (DWORD) E_FAIL;
}
/****************************************************************************/
// TSSDRpcUpdateConfigurationSetting
//
// Extensible interface to update a configuration setting.
/****************************************************************************/
DWORD TSSDRpcUpdateConfigurationSetting(
handle_t Binding,
HCLIENTINFO *hCI,
DWORD dwSetting,
DWORD dwSettingLength,
BYTE __RPC_FAR *pbValue)
{
// Unreferenced parameters.
Binding;
hCI;
dwSetting;
dwSettingLength;
pbValue;
if (dwSetting == SDCONFIG_SERVER_ADDRESS) {
TSDISErrorOut(L"Server is setting its address as %s\n",
(WCHAR *) pbValue);
return TSSDSetServerAddress(hCI, (WCHAR *) pbValue);
}
return (DWORD) E_NOTIMPL;
}
/****************************************************************************/
// TSSDSetServerAITInternal
//
// Called on a client redirection from one server to another, to let the
// integrity service determine how to ping the redirection target machine.
//
// Args:
// ServerAddress (in) - the server address to set values for
// bResetToZero (in) - whether to reset all AIT values to 0
// FailureCount (in/out) - Pointer to nonzero on entry means increment the
// failure count. Returns the result failure count.
/****************************************************************************/
DWORD TSSDSetServerAITInternal(
WCHAR *ServerAddress,
DWORD bResetToZero,
DWORD *FailureCount)
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID servdirtableid;
DWORD AITFromServDirLow;
DWORD AITFromServDirHigh;
unsigned long cbActual;
TSDISErrorOut(L"SetServAITInternal: ServAddr=%s, bResetToZero=%d, bIncFail"
L"=%d\n", ServerAddress, bResetToZero, (FailureCount == NULL) ?
0 : *FailureCount);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
(wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
// Algorithm for set reconnect pending:
// 1) If server is not already pending a reconnect,
// 2) Set the AlmostTimeLow and High to locally computed times (using
// the times from the wire is dangerous and requires clocks to be the
// same).
// Retrieve the current values of AlmostInTimeLow and High
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITLOW_INTERNAL_INDEX], &AITFromServDirLow,
sizeof(AITFromServDirLow), &cbActual, 0, NULL));
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITHIGH_INTERNAL_INDEX], &AITFromServDirHigh,
sizeof(AITFromServDirHigh), &cbActual, 0, NULL));
// If it's time to reset, reset to 0.
if (bResetToZero != 0) {
DWORD zero = 0;
CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
// Set the columns: Low, High, and NumFailedPings.
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITLOW_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITHIGH_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], &zero, sizeof(zero), 0,
NULL));
CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
}
// Otherwise, if the server isn't already pending a reconnect,
else if ((AITFromServDirLow == 0) && (AITFromServDirHigh == 0)) {
FILETIME ft;
SYSTEMTIME st;
// Retrieve the time.
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
// Set the columns.
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITLOW_INTERNAL_INDEX], &(ft.dwLowDateTime),
sizeof(ft.dwLowDateTime), 0, NULL));
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_AITHIGH_INTERNAL_INDEX], &(ft.dwHighDateTime),
sizeof(ft.dwHighDateTime), 0, NULL));
CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
}
// Else if we were told to increment the failure count
else if (FailureCount != NULL) {
if (*FailureCount != 0) {
DWORD FailureCountFromServDir;
// Get the current failure count.
CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
&FailureCountFromServDir, sizeof(FailureCountFromServDir),
&cbActual, 0, NULL));
// Set return value, also value used for update.
*FailureCount = FailureCountFromServDir + 1;
CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
// Set the column.
CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
FailureCount, sizeof(*FailureCount), 0, NULL));
CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
}
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return (DWORD) E_FAIL;
}
DWORD TSSDRpcRepopulateAllSessions(
handle_t Binding,
HCLIENTINFO *hCI,
DWORD NumSessions,
TSSD_RepopInfo rpi[])
{
JET_ERR err;
JET_SESID sesid = JET_sesidNil;
JET_DBID dbid;
JET_TABLEID sessdirtableid;
JET_TABLEID servdirtableid;
JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
CLIENTINFO *pCI = (CLIENTINFO *) hCI;
unsigned count; // inside each record
unsigned iCurrSession;
unsigned long cbActual;
char State;
// "unreferenced" parameter (referenced by RPC)
Binding;
TSDISErrorOut(L"RepopAllSess: ServID = %d, NumSessions = %d, ...\n",
*pCI, NumSessions);
memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
CALL(JetBeginSession(g_instance, &sesid, "user", ""));
CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
&sessdirtableid));
CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
&servdirtableid));
CALL(JetBeginTransaction(sesid));
// Verify that the ServerID passed in was OK.
if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
TSDISErrorOut(L"Invalid ServerID was passed in\n");
goto HandleError;
}
// Set up some constants for all updates.
for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
scSessDir[count].columnid = sesdircolumnid[count];
scSessDir[count].cbData = 4; // most of them, set the rest individually
scSessDir[count].itagSequence = 1;
}
scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
// Now do each update in a loop.
for (iCurrSession = 0; iCurrSession < NumSessions; iCurrSession += 1) {
err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(rpi[iCurrSession].UserName) + 1) *
sizeof(WCHAR);
scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(rpi[iCurrSession].Domain) + 1) *
sizeof(WCHAR);
scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
(unsigned) (wcslen(rpi[iCurrSession].AppType) + 1) *
sizeof(WCHAR);
scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData =
rpi[iCurrSession].UserName;
scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData =
rpi[iCurrSession].Domain;
scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].SessionID;
scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].TSProtocol;
scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].CreateTimeLow;
scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].CreateTimeHigh;
scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].DisconnectTimeLow;
scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].DisconnectTimeHigh;
scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData =
rpi[iCurrSession].AppType;
scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].ResolutionWidth;
scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].ResolutionHeight;
scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData =
&rpi[iCurrSession].ColorDepth;
State = (char) rpi[iCurrSession].State;
scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &State;
CALL(JetSetColumns(sesid, sessdirtableid, scSessDir,
NUM_SESSDIRCOLUMNS));
CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
}
CALL(JetCommitTransaction(sesid, 0));
CALL(JetCloseTable(sesid, sessdirtableid));
CALL(JetCloseTable(sesid, servdirtableid));
CALL(JetCloseDatabase(sesid, dbid, 0));
CALL(JetEndSession(sesid, 0));
return 0;
HandleError:
if (sesid != JET_sesidNil) {
// Can't really recover. Just bail out.
(VOID) JetRollback(sesid, JET_bitRollbackAll);
// Force the session closed
(VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
}
return (DWORD) E_FAIL;
}
// Called to determine whether a ServerID passed in is valid. TRUE if valid,
// FALSE otherwise.
//
// Must be inside a transaction, and sesid and servdirtableid must be ready to
// go.
BOOL TSSDVerifyServerIDValid(JET_SESID sesid, JET_TABLEID servdirtableid,
DWORD ServerID)
{
JET_ERR err;
CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
CALL(JetMakeKey(sesid, servdirtableid, (const void *) &ServerID,
sizeof(DWORD), JET_bitNewKey));
// If the ServerID is there, this will succeed, otherwise it will fail and
// jump to HandleError.
CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
return TRUE;
HandleError:
return FALSE;
}
// Rundown procedure for when a CLIENTINFO is destroyed as a result of a
// connection loss or client termination.
void HCLIENTINFO_rundown(HCLIENTINFO hCI)
{
CLIENTINFO CI = PtrToUlong(hCI);
TSDISErrorOut(L"In HCLIENTINFO_rundown: ServerID=%d\n", CI);
if (CI != NULL)
TSSDPurgeServer(CI);
hCI = NULL;
}
#pragma warning (pop)