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

  1. /****************************************************************************/
  2. // jetrpcfn.cpp
  3. //
  4. // TS Directory Integrity Service Jet RPC server-side implementations.
  5. //
  6. // Copyright (C) 2000, Microsoft Corporation
  7. /****************************************************************************/
  8. #include "dis.h"
  9. #include "tssdshrd.h"
  10. #include "jetrpc.h"
  11. #include "jetsdis.h"
  12. #pragma warning (push, 4)
  13. /****************************************************************************/
  14. // MIDL_user_allocate
  15. // MIDL_user_free
  16. //
  17. // RPC-required allocation functions.
  18. /****************************************************************************/
  19. void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t Size)
  20. {
  21. return LocalAlloc(LMEM_FIXED, Size);
  22. }
  23. void __RPC_USER MIDL_user_free(void __RPC_FAR *p)
  24. {
  25. LocalFree(p);
  26. }
  27. /****************************************************************************/
  28. // OutputAllTables (debug only)
  29. //
  30. // Output all tables to debug output.
  31. /****************************************************************************/
  32. #ifdef DBG
  33. void OutputAllTables()
  34. {
  35. JET_ERR err;
  36. JET_SESID sesid = JET_sesidNil;
  37. JET_DBID dbid;
  38. JET_TABLEID sessdirtableid;
  39. JET_TABLEID servdirtableid;
  40. JET_TABLEID clusdirtableid;
  41. JET_RETRIEVECOLUMN rcSessDir[NUM_SESSDIRCOLUMNS];
  42. WCHAR UserNameBuf[256];
  43. WCHAR DomainBuf[127];
  44. WCHAR ApplicationBuf[256];
  45. WCHAR ServerNameBuf[128];
  46. WCHAR ClusterNameBuf[128];
  47. unsigned count;
  48. long num_vals[NUM_SESSDIRCOLUMNS];
  49. char state;
  50. char SingleSessMode;
  51. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  52. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  53. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  54. &sessdirtableid));
  55. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  56. &servdirtableid));
  57. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  58. &clusdirtableid));
  59. CALL(JetBeginTransaction(sesid));
  60. TSDISErrorOut(L"SESSION DIRECTORY\n");
  61. err = JetMove(sesid, sessdirtableid, JET_MoveFirst, 0);
  62. if (JET_errNoCurrentRecord == err) {
  63. TSDISErrorOut(L" (empty database)\n");
  64. }
  65. while (JET_errNoCurrentRecord != err) {
  66. // Retrieve all the columns
  67. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  68. NUM_SESSDIRCOLUMNS);
  69. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  70. rcSessDir[count].columnid = sesdircolumnid[count];
  71. rcSessDir[count].pvData = &num_vals[count];
  72. rcSessDir[count].cbData = sizeof(long);
  73. rcSessDir[count].itagSequence = 1;
  74. }
  75. // fix up pvData, cbData for non-int fields
  76. rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserNameBuf;
  77. rcSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData = sizeof(UserNameBuf);
  78. rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = DomainBuf;
  79. rcSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData = sizeof(DomainBuf);
  80. rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = ApplicationBuf;
  81. rcSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  82. sizeof(ApplicationBuf);
  83. rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
  84. rcSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(state);
  85. CALL(JetRetrieveColumns(sesid, sessdirtableid, &rcSessDir[0],
  86. NUM_SESSDIRCOLUMNS));
  87. TSDISErrorOut(L"%8s, %s, %d, %d, %d\n",
  88. UserNameBuf,
  89. DomainBuf,
  90. num_vals[SESSDIR_SERVERID_INTERNAL_INDEX],
  91. num_vals[SESSDIR_SESSIONID_INTERNAL_INDEX],
  92. num_vals[SESSDIR_TSPROTOCOL_INTERNAL_INDEX]);
  93. TSDISErrorTimeOut(L" %s, ",
  94. num_vals[SESSDIR_CTLOW_INTERNAL_INDEX],
  95. num_vals[SESSDIR_CTHIGH_INTERNAL_INDEX]);
  96. TSDISErrorTimeOut(L"%s\n",
  97. num_vals[SESSDIR_DTLOW_INTERNAL_INDEX],
  98. num_vals[SESSDIR_DTHIGH_INTERNAL_INDEX]);
  99. TSDISErrorOut(L" %s, %d, %d, %d, %s\n",
  100. ApplicationBuf ? L"(no application)" : ApplicationBuf,
  101. num_vals[SESSDIR_RESWIDTH_INTERNAL_INDEX],
  102. num_vals[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
  103. num_vals[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
  104. state ? L"disconnected" : L"connected");
  105. err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
  106. }
  107. // Output Server Directory (we are reusing the rcSessDir structure).
  108. TSDISErrorOut(L"SERVER DIRECTORY\n");
  109. err = JetMove(sesid, servdirtableid, JET_MoveFirst, 0);
  110. if (JET_errNoCurrentRecord == err) {
  111. TSDISErrorOut(L" (empty database)\n");
  112. }
  113. while (JET_errNoCurrentRecord != err) {
  114. // Retrieve all the columns.
  115. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  116. NUM_SERVDIRCOLUMNS);
  117. for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
  118. rcSessDir[count].columnid = servdircolumnid[count];
  119. rcSessDir[count].pvData = &num_vals[count];
  120. rcSessDir[count].cbData = sizeof(long);
  121. rcSessDir[count].itagSequence = 1;
  122. }
  123. rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerNameBuf;
  124. rcSessDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
  125. sizeof(ServerNameBuf);
  126. rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
  127. rcSessDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSessMode);
  128. CALL(JetRetrieveColumns(sesid, servdirtableid, &rcSessDir[0],
  129. NUM_SERVDIRCOLUMNS));
  130. TSDISErrorOut(L"%d, %s, %d, %d, %d, %d, %s\n", num_vals[
  131. SERVDIR_SERVID_INTERNAL_INDEX], ServerNameBuf, num_vals[
  132. SERVDIR_CLUSID_INTERNAL_INDEX], num_vals[
  133. SERVDIR_AITLOW_INTERNAL_INDEX], num_vals[
  134. SERVDIR_AITHIGH_INTERNAL_INDEX], num_vals[
  135. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], SingleSessMode ?
  136. L"single session mode" : L"multi-session mode");
  137. err = JetMove(sesid, servdirtableid, JET_MoveNext, 0);
  138. }
  139. // Output Cluster Directory
  140. TSDISErrorOut(L"CLUSTER DIRECTORY\n");
  141. err = JetMove(sesid, clusdirtableid, JET_MoveFirst, 0);
  142. if (JET_errNoCurrentRecord == err) {
  143. TSDISErrorOut(L" (empty database)\n");
  144. }
  145. while (JET_errNoCurrentRecord != err) {
  146. memset(&rcSessDir[0], 0, sizeof(JET_RETRIEVECOLUMN) *
  147. NUM_CLUSDIRCOLUMNS);
  148. for (count = 0; count < NUM_CLUSDIRCOLUMNS; count++) {
  149. rcSessDir[count].columnid = clusdircolumnid[count];
  150. rcSessDir[count].pvData = &num_vals[count];
  151. rcSessDir[count].cbData = sizeof(long);
  152. rcSessDir[count].itagSequence = 1;
  153. }
  154. rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].pvData = ClusterNameBuf;
  155. rcSessDir[CLUSDIR_CLUSNAME_INTERNAL_INDEX].cbData =
  156. sizeof(ClusterNameBuf);
  157. rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSessMode;
  158. rcSessDir[CLUSDIR_SINGLESESS_INTERNAL_INDEX].cbData =
  159. sizeof(SingleSessMode);
  160. CALL(JetRetrieveColumns(sesid, clusdirtableid, &rcSessDir[0],
  161. NUM_CLUSDIRCOLUMNS));
  162. TSDISErrorOut(L"%d, %s, %s\n", num_vals[CLUSDIR_CLUSID_INTERNAL_INDEX],
  163. ClusterNameBuf, SingleSessMode ? L"single session mode" :
  164. L"multi-session mode");
  165. err = JetMove(sesid, clusdirtableid, JET_MoveNext, 0);
  166. }
  167. TSDISErrorOut(L"\n");
  168. CALL(JetCommitTransaction(sesid, 0));
  169. CALL(JetCloseTable(sesid, servdirtableid));
  170. CALL(JetCloseTable(sesid, sessdirtableid));
  171. CALL(JetCloseTable(sesid, clusdirtableid));
  172. CALL(JetCloseDatabase(sesid, dbid, 0));
  173. CALL(JetEndSession(sesid, 0));
  174. return;
  175. HandleError:
  176. if (sesid != JET_sesidNil) {
  177. // Can't really recover. Just bail out.
  178. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  179. // Force the session closed
  180. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  181. }
  182. }
  183. #endif //DBG
  184. typedef DWORD CLIENTINFO;
  185. /****************************************************************************/
  186. // TSSDRpcServerOnline
  187. //
  188. // Called for server-active indications on each cluster TS machine.
  189. /****************************************************************************/
  190. DWORD TSSDRpcServerOnline(
  191. handle_t Binding,
  192. WCHAR __RPC_FAR *ClusterName,
  193. /* out */ HCLIENTINFO *hCI,
  194. DWORD SrvOnlineFlags)
  195. {
  196. JET_ERR err;
  197. JET_SESID sesid = JET_sesidNil;
  198. JET_DBID dbid;
  199. JET_TABLEID clusdirtableid;
  200. JET_TABLEID servdirtableid;
  201. JET_SETCOLUMN scServDir[NUM_SERVDIRCOLUMNS];
  202. WCHAR *StringBinding = NULL;
  203. WCHAR *ServerAddress = NULL;
  204. RPC_BINDING_HANDLE ServerBinding = 0;
  205. unsigned long cbActual;
  206. long ClusterID;
  207. long ServerID = 0;
  208. long zero = 0;
  209. char czero = 0;
  210. // The single session mode of this server.
  211. char SingleSession = (char) SrvOnlineFlags & SINGLE_SESSION_FLAG;
  212. char ClusSingleSessionMode;
  213. unsigned count;
  214. // "unreferenced" parameter (referenced by RPC)
  215. Binding;
  216. TSDISErrorOut(L"In ServOnline, ClusterName=%s, SrvOnlineFlags=%u\n",
  217. ClusterName, SrvOnlineFlags);
  218. // Determine client address.
  219. if (RpcBindingServerFromClient(Binding, &ServerBinding) != RPC_S_OK) {
  220. TSDISErrorOut(L"ServOn: BindingServerFromClient failed!\n");
  221. goto HandleError;
  222. }
  223. if (RpcBindingToStringBinding(ServerBinding, &StringBinding) != RPC_S_OK) {
  224. TSDISErrorOut(L"ServOn: BindingToStringBinding failed!\n");
  225. goto HandleError;
  226. }
  227. if (RpcStringBindingParse(StringBinding, NULL, NULL, &ServerAddress, NULL,
  228. NULL) != RPC_S_OK) {
  229. TSDISErrorOut(L"ServOn: StringBindingParse failed!\n");
  230. goto HandleError;
  231. }
  232. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  233. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  234. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  235. &clusdirtableid));
  236. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  237. &servdirtableid));
  238. // First, delete all entries for this server from the session/server
  239. //directories
  240. CALL(JetBeginTransaction(sesid));
  241. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
  242. CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
  243. (wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
  244. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  245. if (JET_errSuccess == err) {
  246. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  247. SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  248. &cbActual, 0, NULL));
  249. if (TSSDPurgeServer(ServerID) != 0)
  250. TSDISErrorOut(L"ServOn: PurgeServer %d failed.\n", ServerID);
  251. } else if (JET_errRecordNotFound != err) {
  252. CALL(err);
  253. }
  254. CALL(JetCommitTransaction(sesid, 0));
  255. // We have to do the add in a loop, because we have to:
  256. // 1) Check if the record is there.
  257. // 2) If it's not, add it. (The next time through the loop, therefore,
  258. // we'll go step 1->3, and we're done.)
  259. // 3) If it is, retrieve the value of clusterID and break out.
  260. //
  261. // There is an additional complication in that someone else may be in the
  262. // thread simultaneously, doing the same thing. Therefore, someone might
  263. // be in step 2 and try to add a new cluster, but fail because someone
  264. // else added it. So they have to keep trying, because though the other
  265. // thread has added it, it may not have committed the change. To try to
  266. // keep that to a minimum, we sleep a short time before trying again.
  267. for ( ; ; ) {
  268. // Now do the actual add.
  269. CALL(JetBeginTransaction(sesid));
  270. // Search for the cluster in the cluster directory.
  271. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusNameIndex"));
  272. CALL(JetMakeKey(sesid, clusdirtableid, ClusterName, (unsigned)
  273. (wcslen(ClusterName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  274. err = JetSeek(sesid, clusdirtableid, JET_bitSeekEQ);
  275. // If the cluster does not exist, create it.
  276. if (JET_errRecordNotFound == err) {
  277. CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepInsert));
  278. // ClusterName
  279. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  280. CLUSDIR_CLUSNAME_INTERNAL_INDEX], ClusterName,
  281. (unsigned) (wcslen(ClusterName) + 1) * sizeof(WCHAR), 0,
  282. NULL));
  283. // SingleSessionMode
  284. // Since this is the only server in the cluster, the single session
  285. // mode is simply the mode of this server.
  286. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  287. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
  288. sizeof(SingleSession), 0, NULL));
  289. err = JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual);
  290. // If it's a duplicate key, someone else made the key so we should
  291. // be ok. Yield the processor and try the query again, next time
  292. // through the loop.
  293. if (JET_errKeyDuplicate == err) {
  294. CALL(JetCommitTransaction(sesid, 0));
  295. Sleep(100);
  296. }
  297. else {
  298. CALL(err);
  299. // Now we've succeeded. Just continue through the loop.
  300. // The next time through, we will retrieve the autoincrement
  301. // column we just added and break out.
  302. CALL(JetCommitTransaction(sesid, 0));
  303. }
  304. }
  305. else {
  306. CALL(err);
  307. // If the above check makes it here, we have found the row.
  308. // Now retrieve the clusid, commit, and break out of the loop.
  309. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  310. CLUSDIR_CLUSID_INTERNAL_INDEX], &ClusterID,
  311. sizeof(ClusterID), &cbActual, 0, NULL));
  312. CALL(JetCommitTransaction(sesid, 0));
  313. break;
  314. }
  315. }
  316. CALL(JetBeginTransaction(sesid));
  317. // Insert the servername, clusterid, 0, 0 into the server directory table
  318. err = JetMove(sesid, servdirtableid, JET_MoveLast, 0);
  319. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepInsert));
  320. memset(&scServDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SERVDIRCOLUMNS);
  321. for (count = 0; count < NUM_SERVDIRCOLUMNS; count++) {
  322. scServDir[count].columnid = servdircolumnid[count];
  323. scServDir[count].cbData = 4; // most of them, set the rest individually
  324. scServDir[count].itagSequence = 1;
  325. }
  326. scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].pvData = ServerAddress;
  327. scServDir[SERVDIR_SERVADDR_INTERNAL_INDEX].cbData =
  328. (unsigned) (wcslen(ServerAddress) + 1) * sizeof(WCHAR);
  329. scServDir[SERVDIR_CLUSID_INTERNAL_INDEX].pvData = &ClusterID;
  330. scServDir[SERVDIR_AITLOW_INTERNAL_INDEX].pvData = &zero;
  331. scServDir[SERVDIR_AITHIGH_INTERNAL_INDEX].pvData = &zero;
  332. scServDir[SERVDIR_NUMFAILPINGS_INTERNAL_INDEX].pvData = &zero;
  333. scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].pvData = &SingleSession;
  334. scServDir[SERVDIR_SINGLESESS_INTERNAL_INDEX].cbData = sizeof(SingleSession);
  335. // Don't set the first column (index 0)--it is autoincrement.
  336. CALL(JetSetColumns(sesid, servdirtableid, &scServDir[
  337. SERVDIR_SERVADDR_INTERNAL_INDEX], NUM_SERVDIRCOLUMNS - 1));
  338. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  339. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
  340. CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
  341. (wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
  342. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  343. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  344. SERVDIR_SERVID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  345. &cbActual, 0, NULL));
  346. *hCI = ULongToPtr(ServerID);
  347. // Now that the server is all set up, we have to set the cluster to the
  348. // correct mode. If any server in the cluster is in multisession mode, then
  349. // we stick with multisession. If they are all single session, though, we
  350. // turn on single session in this cluster. We do some database magic
  351. // to make this work. We have an index on the ClusterID and the Single
  352. // Session mode. We query for this cluster with single session mode 0
  353. // (i.e., multi-session mode). If we get any results back, we are multi-
  354. // session, otherwise we're single session.
  355. // Set up the key.
  356. CALL(JetSetCurrentIndex(sesid, servdirtableid, "SingleSessionIndex"));
  357. CALL(JetMakeKey(sesid, servdirtableid, &ClusterID, sizeof(ClusterID),
  358. JET_bitNewKey));
  359. CALL(JetMakeKey(sesid, servdirtableid, &czero, sizeof(czero), 0));
  360. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
  361. // NOTE REUSE OF SingleSession VARIABLE! Up there it meant what the flag
  362. // passed in meant. Here it means what we determine the cluster's state to
  363. // be based on our logic.
  364. if (err == JET_errRecordNotFound) {
  365. SingleSession = 1;
  366. }
  367. else {
  368. // CALL the error value to make sure it's success
  369. CALL(err);
  370. // If we got here then everything is ok.
  371. SingleSession = 0;
  372. }
  373. // Check the cluster to see if it is already in that mode.
  374. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  375. CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&ClusterID,
  376. sizeof(ClusterID), JET_bitNewKey));
  377. CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
  378. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  379. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &ClusSingleSessionMode, sizeof(
  380. ClusSingleSessionMode), &cbActual, 0, NULL));
  381. // If not, change the mode.
  382. if (SingleSession != ClusSingleSessionMode) {
  383. CALL(JetPrepareUpdate(sesid, clusdirtableid, JET_prepReplace));
  384. CALL(JetSetColumn(sesid, clusdirtableid, clusdircolumnid[
  385. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &SingleSession,
  386. sizeof(SingleSession), 0, NULL));
  387. CALL(JetUpdate(sesid, clusdirtableid, NULL, 0, &cbActual));
  388. }
  389. CALL(JetCommitTransaction(sesid, 0));
  390. CALL(JetCloseTable(sesid, servdirtableid));
  391. CALL(JetCloseTable(sesid, clusdirtableid));
  392. CALL(JetCloseDatabase(sesid, dbid, 0));
  393. CALL(JetEndSession(sesid, 0));
  394. if (ServerBinding != NULL)
  395. RpcBindingFree(&ServerBinding);
  396. if (StringBinding != NULL)
  397. RpcStringFree(&StringBinding);
  398. if (ServerAddress != NULL)
  399. RpcStringFree(&ServerAddress);
  400. return 0;
  401. HandleError:
  402. if (sesid != JET_sesidNil) {
  403. // Can't really recover. Just bail out.
  404. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  405. // Force the session closed
  406. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  407. }
  408. if (ServerBinding != NULL)
  409. RpcBindingFree(&ServerBinding);
  410. if (StringBinding != NULL)
  411. RpcStringFree(&StringBinding);
  412. if (ServerAddress != NULL)
  413. RpcStringFree(&ServerAddress);
  414. // Just in case we got to commit.
  415. TSSDPurgeServer(ServerID);
  416. // Close the context handle.
  417. *hCI = NULL;
  418. return (DWORD) E_FAIL;
  419. }
  420. /****************************************************************************/
  421. // TSSDRpcServerOffline
  422. //
  423. // Called for server-shutdown indications on each cluster TS machine.
  424. /****************************************************************************/
  425. DWORD TSSDRpcServerOffline(
  426. handle_t Binding,
  427. HCLIENTINFO *hCI)
  428. {
  429. DWORD retval = 0;
  430. // "unreferenced" parameter (referenced by RPC)
  431. Binding;
  432. TSDISErrorOut(L"In ServOff, hCI = 0x%x\n", *hCI);
  433. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  434. if (pCI != NULL)
  435. retval = TSSDPurgeServer(*pCI);
  436. *hCI = NULL;
  437. return retval;
  438. }
  439. /****************************************************************************/
  440. // TSSDPurgeServer
  441. //
  442. // Delete a server and all its sessions from the session directory.
  443. /****************************************************************************/
  444. DWORD TSSDPurgeServer(
  445. DWORD ServerID)
  446. {
  447. JET_SESID sesid = JET_sesidNil;
  448. JET_TABLEID sessdirtableid;
  449. JET_TABLEID servdirtableid;
  450. JET_DBID dbid;
  451. JET_ERR err;
  452. TSDISErrorOut(L"In PurgeServer, ServerID=%d\n", ServerID);
  453. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  454. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  455. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  456. &sessdirtableid));
  457. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  458. &servdirtableid));
  459. CALL(JetBeginTransaction(sesid));
  460. // Delete all sessions in session directory that have this serverid
  461. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "ServerIndex"));
  462. CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
  463. JET_bitNewKey));
  464. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
  465. while (0 == err) {
  466. CALL(JetDelete(sesid, sessdirtableid));
  467. CALL(JetMakeKey(sesid, sessdirtableid, &ServerID, sizeof(ServerID),
  468. JET_bitNewKey));
  469. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
  470. }
  471. // Should be err -1601 -- JET_errRecordNotFound
  472. // Delete the server in the server directory with this serverid
  473. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  474. CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
  475. JET_bitNewKey));
  476. err = JetSeek(sesid, servdirtableid, JET_bitSeekEQ);
  477. if (JET_errSuccess == err)
  478. CALL(JetDelete(sesid, servdirtableid));
  479. CALL(JetCommitTransaction(sesid, 0));
  480. CALL(JetCloseTable(sesid, servdirtableid));
  481. CALL(JetCloseTable(sesid, sessdirtableid));
  482. CALL(JetCloseDatabase(sesid, dbid, 0));
  483. CALL(JetEndSession(sesid, 0));
  484. return 0;
  485. HandleError:
  486. if (sesid != JET_sesidNil) {
  487. // Can't really recover. Just bail out.
  488. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  489. // Force the session closed
  490. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  491. }
  492. return (DWORD) E_FAIL;
  493. }
  494. /****************************************************************************/
  495. // TSSDRpcGetUserDisconnectedSessions
  496. //
  497. // Queries disconnected sessions from the session database.
  498. /****************************************************************************/
  499. DWORD TSSDRpcGetUserDisconnectedSessions(
  500. handle_t Binding,
  501. HCLIENTINFO *hCI,
  502. WCHAR __RPC_FAR *UserName,
  503. WCHAR __RPC_FAR *Domain,
  504. /* out */ DWORD __RPC_FAR *pNumSessions,
  505. /* out */ TSSD_DiscSessInfo __RPC_FAR __RPC_FAR **padsi)
  506. {
  507. JET_ERR err;
  508. JET_SESID sesid = JET_sesidNil;
  509. JET_DBID dbid;
  510. JET_TABLEID sessdirtableid;
  511. JET_TABLEID servdirtableid;
  512. JET_TABLEID clusdirtableid;
  513. *pNumSessions = 0;
  514. unsigned i = 0;
  515. unsigned j = 0;
  516. unsigned long cbActual;
  517. DWORD tempClusterID;
  518. DWORD CallingServersClusID;
  519. long ServerID;
  520. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  521. TSSD_DiscSessInfo *adsi = NULL;
  522. char one = 1;
  523. char bSingleSession = 0;
  524. // "unreferenced" parameter (referenced by RPC)
  525. Binding;
  526. TSDISErrorOut(L"In GetUserDiscSess: ServID = %d, User: %s, "
  527. L"Domain: %s\n", *pCI, UserName, Domain);
  528. *padsi = (TSSD_DiscSessInfo *) MIDL_user_allocate(sizeof(TSSD_DiscSessInfo) *
  529. TSSD_MaxDisconnectedSessions);
  530. adsi = *padsi;
  531. if (adsi == NULL) {
  532. TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
  533. goto HandleError;
  534. }
  535. // Set the pointers to 0 to be safe, and so that we can free uninitialized
  536. // ones later without AVing.
  537. for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
  538. adsi[j].ServerAddress = NULL;
  539. adsi[j].AppType = NULL;
  540. }
  541. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  542. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  543. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  544. &sessdirtableid));
  545. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  546. &servdirtableid));
  547. CALL(JetOpenTable(sesid, dbid, "ClusterDirectory", NULL, 0, 0,
  548. &clusdirtableid));
  549. CALL(JetBeginTransaction(sesid));
  550. // Verify that the ServerID passed in was OK.
  551. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  552. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  553. goto HandleError;
  554. }
  555. // First, get the cluster ID for the server making the query.
  556. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  557. CALL(JetMakeKey(sesid, servdirtableid, (const void *)pCI, sizeof(DWORD),
  558. JET_bitNewKey));
  559. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  560. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  561. SERVDIR_CLUSID_INTERNAL_INDEX], &CallingServersClusID, sizeof(
  562. CallingServersClusID), &cbActual, 0, NULL));
  563. // Now that we have the cluster id, check to see whether this cluster
  564. // is in single session mode.
  565. CALL(JetSetCurrentIndex(sesid, clusdirtableid, "ClusIDIndex"));
  566. CALL(JetMakeKey(sesid, clusdirtableid, (const void *)&CallingServersClusID,
  567. sizeof(CallingServersClusID), JET_bitNewKey));
  568. CALL(JetSeek(sesid, clusdirtableid, JET_bitSeekEQ));
  569. CALL(JetRetrieveColumn(sesid, clusdirtableid, clusdircolumnid[
  570. CLUSDIR_SINGLESESS_INTERNAL_INDEX], &bSingleSession, sizeof(
  571. bSingleSession), &cbActual, 0, NULL));
  572. // Now, get all the disconnected or all sessions for this cluster, depending
  573. // on the single session mode retrieved above.
  574. if (bSingleSession == FALSE) {
  575. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "DiscSessionIndex"));
  576. CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
  577. (wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  578. CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
  579. (wcslen(Domain) + 1) * sizeof(WCHAR), 0));
  580. CALL(JetMakeKey(sesid, sessdirtableid, &one, sizeof(one), 0));
  581. }
  582. else {
  583. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "AllSessionIndex"));
  584. CALL(JetMakeKey(sesid, sessdirtableid, UserName, (unsigned)
  585. (wcslen(UserName) + 1) * sizeof(WCHAR), JET_bitNewKey));
  586. CALL(JetMakeKey(sesid, sessdirtableid, Domain, (unsigned)
  587. (wcslen(Domain) + 1) * sizeof(WCHAR), 0));
  588. }
  589. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ | JET_bitSetIndexRange);
  590. while ((i < TSSD_MaxDisconnectedSessions) && (JET_errSuccess == err)) {
  591. // Remember the initial retrieval does not have cluster id in the
  592. // index, so filter by cluster id for each one.
  593. // Get the ServerID for this record.
  594. CALL(JetRetrieveColumn(sesid, sessdirtableid, sesdircolumnid[
  595. SESSDIR_SERVERID_INTERNAL_INDEX], &ServerID, sizeof(ServerID),
  596. &cbActual, 0, NULL));
  597. // Get the clusterID
  598. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  599. CALL(JetMakeKey(sesid, servdirtableid, &ServerID, sizeof(ServerID),
  600. JET_bitNewKey));
  601. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  602. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  603. SERVDIR_CLUSID_INTERNAL_INDEX], &tempClusterID,
  604. sizeof(tempClusterID), &cbActual, 0, NULL));
  605. // Compare to the passed-in cluster id.
  606. if (tempClusterID == CallingServersClusID) {
  607. // Allocate space.
  608. adsi[i].ServerAddress = (WCHAR *) MIDL_user_allocate(64 *
  609. sizeof(WCHAR));
  610. adsi[i].AppType = (WCHAR *) MIDL_user_allocate(256 * sizeof(WCHAR));
  611. if ((adsi[i].ServerAddress == NULL) || (adsi[i].AppType == NULL)) {
  612. TSDISErrorOut(L"GetUserDisc: Memory alloc failed!\n");
  613. goto HandleError;
  614. }
  615. // ServerAddress comes out of the server table
  616. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  617. SERVDIR_SERVADDR_INTERNAL_INDEX], adsi[i].ServerAddress,
  618. 128, &cbActual, 0, NULL));
  619. // The rest come out of the session directory
  620. // Session ID
  621. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  622. sesdircolumnid[SESSDIR_SESSIONID_INTERNAL_INDEX],
  623. &(adsi[i].SessionID), sizeof(DWORD), &cbActual, 0, NULL));
  624. // TSProtocol
  625. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  626. sesdircolumnid[SESSDIR_TSPROTOCOL_INTERNAL_INDEX],
  627. &(adsi[i].TSProtocol), sizeof(DWORD), &cbActual, 0, NULL));
  628. // Application Type
  629. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  630. sesdircolumnid[SESSDIR_APPTYPE_INTERNAL_INDEX],
  631. adsi[i].AppType, 512, &cbActual, 0, NULL));
  632. // ResolutionWidth
  633. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  634. sesdircolumnid[SESSDIR_RESWIDTH_INTERNAL_INDEX],
  635. &(adsi[i].ResolutionWidth), sizeof(DWORD), &cbActual, 0,
  636. NULL));
  637. // ResolutionHeight
  638. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  639. sesdircolumnid[SESSDIR_RESHEIGHT_INTERNAL_INDEX],
  640. &(adsi[i].ResolutionHeight), sizeof(DWORD), &cbActual, 0,
  641. NULL));
  642. // Color Depth
  643. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  644. sesdircolumnid[SESSDIR_COLORDEPTH_INTERNAL_INDEX],
  645. &(adsi[i].ColorDepth), sizeof(DWORD), &cbActual, 0, NULL));
  646. // CreateTimeLow
  647. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  648. sesdircolumnid[SESSDIR_CTLOW_INTERNAL_INDEX],
  649. &(adsi[i].CreateTimeLow), sizeof(DWORD), &cbActual, 0,
  650. NULL));
  651. // CreateTimeHigh
  652. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  653. sesdircolumnid[SESSDIR_CTHIGH_INTERNAL_INDEX],
  654. &(adsi[i].CreateTimeHigh), sizeof(DWORD), &cbActual, 0,
  655. NULL));
  656. // DisconnectTimeLow
  657. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  658. sesdircolumnid[SESSDIR_DTLOW_INTERNAL_INDEX],
  659. &(adsi[i].DisconnectTimeLow), sizeof(DWORD), &cbActual, 0,
  660. NULL));
  661. // DisconnectTimeHigh
  662. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  663. sesdircolumnid[SESSDIR_DTHIGH_INTERNAL_INDEX],
  664. &(adsi[i].DisconnectTimeHigh), sizeof(DWORD), &cbActual, 0,
  665. NULL));
  666. // State
  667. // This is retrieving a byte that is 0xff or 0x0 into a DWORD
  668. // pointer.
  669. CALL(JetRetrieveColumn(sesid, sessdirtableid,
  670. sesdircolumnid[SESSDIR_STATE_INTERNAL_INDEX],
  671. &(adsi[i].State), sizeof(BYTE), &cbActual, 0,
  672. NULL));
  673. i += 1;
  674. }
  675. // Move to the next matching record.
  676. err = JetMove(sesid, sessdirtableid, JET_MoveNext, 0);
  677. }
  678. *pNumSessions = i;
  679. CALL(JetCommitTransaction(sesid, 0));
  680. CALL(JetCloseTable(sesid, servdirtableid));
  681. CALL(JetCloseTable(sesid, sessdirtableid));
  682. CALL(JetCloseTable(sesid, clusdirtableid));
  683. CALL(JetCloseDatabase(sesid, dbid, 0));
  684. CALL(JetEndSession(sesid, 0));
  685. #ifdef DBG
  686. OutputAllTables();
  687. #endif // DBG
  688. return 0;
  689. HandleError:
  690. // Deallocate memory.
  691. for (j = 0; j < TSSD_MaxDisconnectedSessions; j++) {
  692. MIDL_user_free(adsi[j].ServerAddress);
  693. MIDL_user_free(adsi[j].AppType);
  694. }
  695. // Can't really recover. Just bail out.
  696. if (sesid != JET_sesidNil) {
  697. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  698. // Force the session closed.
  699. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  700. }
  701. // Delete the server and close the context handle. Their states are bad.
  702. TSSDPurgeServer(PtrToUlong(*hCI));
  703. *hCI = NULL;
  704. return (DWORD) E_FAIL;
  705. }
  706. /****************************************************************************/
  707. // TSSDRpcCreateSession
  708. //
  709. // Called on a session logon.
  710. /****************************************************************************/
  711. DWORD TSSDRpcCreateSession(
  712. handle_t Binding,
  713. HCLIENTINFO *hCI,
  714. WCHAR __RPC_FAR *UserName,
  715. WCHAR __RPC_FAR *Domain,
  716. DWORD SessionID,
  717. DWORD TSProtocol,
  718. WCHAR __RPC_FAR *AppType,
  719. DWORD ResolutionWidth,
  720. DWORD ResolutionHeight,
  721. DWORD ColorDepth,
  722. DWORD CreateTimeLow,
  723. DWORD CreateTimeHigh)
  724. {
  725. JET_ERR err;
  726. JET_SESID sesid = JET_sesidNil;
  727. JET_DBID dbid;
  728. JET_TABLEID sessdirtableid;
  729. JET_TABLEID servdirtableid;
  730. JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
  731. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  732. unsigned count;
  733. int zero = 0;
  734. unsigned long cbActual;
  735. char state = 0;
  736. // "unreferenced" parameter (referenced by RPC)
  737. Binding;
  738. TSDISErrorOut(L"Inside TSSDRpcCreateSession, ServID=%d, "
  739. L"UserName=%s, Domain=%s, SessID=%d, TSProt=%d, AppType=%s, "
  740. L"ResWidth=%d, ResHeight=%d, ColorDepth=%d\n", *pCI, UserName,
  741. Domain, SessionID, TSProtocol, AppType, ResolutionWidth,
  742. ResolutionHeight, ColorDepth);
  743. TSDISErrorTimeOut(L" CreateTime=%s\n", CreateTimeLow, CreateTimeHigh);
  744. memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
  745. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  746. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  747. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  748. &sessdirtableid));
  749. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  750. &servdirtableid));
  751. CALL(JetBeginTransaction(sesid));
  752. // Verify that the ServerID passed in was OK.
  753. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  754. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  755. goto HandleError;
  756. }
  757. err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
  758. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
  759. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  760. scSessDir[count].columnid = sesdircolumnid[count];
  761. scSessDir[count].cbData = 4; // most of them, set the rest individually
  762. scSessDir[count].itagSequence = 1;
  763. }
  764. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
  765. (unsigned) (wcslen(UserName) + 1) * sizeof(WCHAR);
  766. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
  767. (unsigned) (wcslen(Domain) + 1) * sizeof(WCHAR);
  768. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  769. (unsigned) (wcslen(AppType) + 1) * sizeof(WCHAR);
  770. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
  771. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData = UserName;
  772. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData = Domain;
  773. scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
  774. scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData = &SessionID;
  775. scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData = &TSProtocol;
  776. scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData = &CreateTimeLow;
  777. scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData = &CreateTimeHigh;
  778. scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData = &zero;
  779. scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData = &zero;
  780. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData = AppType;
  781. scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData = &ResolutionWidth;
  782. scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData = &ResolutionHeight;
  783. scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData = &ColorDepth;
  784. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &state;
  785. CALL(JetSetColumns(sesid, sessdirtableid, scSessDir, NUM_SESSDIRCOLUMNS));
  786. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  787. CALL(JetCommitTransaction(sesid, 0));
  788. CALL(JetCloseTable(sesid, sessdirtableid));
  789. CALL(JetCloseTable(sesid, servdirtableid));
  790. CALL(JetCloseDatabase(sesid, dbid, 0));
  791. CALL(JetEndSession(sesid, 0));
  792. return 0;
  793. HandleError:
  794. if (sesid != JET_sesidNil) {
  795. // Can't really recover. Just bail out.
  796. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  797. // Force the session closed.
  798. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  799. }
  800. // Delete the server and close the context handle. Their states are bad.
  801. TSSDPurgeServer(PtrToUlong(*hCI));
  802. *hCI = NULL;
  803. return (DWORD) E_FAIL;
  804. }
  805. /****************************************************************************/
  806. // TSSDRpcDeleteSession
  807. //
  808. // Called on a session logoff.
  809. /****************************************************************************/
  810. DWORD TSSDRpcDeleteSession(
  811. handle_t Binding,
  812. HCLIENTINFO *hCI,
  813. DWORD SessionID)
  814. {
  815. JET_ERR err;
  816. JET_SESID sesid = JET_sesidNil;
  817. JET_DBID dbid;
  818. JET_TABLEID sessdirtableid;
  819. JET_TABLEID servdirtableid;
  820. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  821. // "unreferenced" parameter (referenced by RPC)
  822. Binding;
  823. TSDISErrorOut(L"In DelSession, ServID=%d, "
  824. L"SessID=%d\n", *pCI, SessionID);
  825. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  826. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  827. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  828. &sessdirtableid));
  829. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  830. &servdirtableid));
  831. CALL(JetBeginTransaction(sesid));
  832. // Verify that the ServerID passed in was OK.
  833. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  834. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  835. goto HandleError;
  836. }
  837. // Delete all sessions in session directory that have this serverid
  838. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  839. CALL(JetMakeKey(sesid, sessdirtableid, pCI,
  840. sizeof(*pCI), JET_bitNewKey));
  841. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(SessionID),
  842. 0));
  843. err = JetSeek(sesid, sessdirtableid, JET_bitSeekEQ);
  844. CALL(JetDelete(sesid, sessdirtableid));
  845. CALL(JetCommitTransaction(sesid, 0));
  846. CALL(JetCloseTable(sesid, sessdirtableid));
  847. CALL(JetCloseTable(sesid, servdirtableid));
  848. CALL(JetCloseDatabase(sesid, dbid, 0));
  849. CALL(JetEndSession(sesid, 0));
  850. return 0;
  851. HandleError:
  852. if (sesid != JET_sesidNil) {
  853. // Can't really recover. Just bail out.
  854. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  855. // Force the session closed.
  856. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  857. }
  858. // Delete the server and close the context handle. Their states are bad.
  859. TSSDPurgeServer(PtrToUlong(*hCI));
  860. *hCI = NULL;
  861. return (DWORD) E_FAIL;
  862. }
  863. /****************************************************************************/
  864. // TSSDRpcSetSessionDisconnected
  865. //
  866. // Called on a session disconnection.
  867. /****************************************************************************/
  868. DWORD TSSDRpcSetSessionDisconnected(
  869. handle_t Binding,
  870. HCLIENTINFO *hCI,
  871. DWORD SessionID,
  872. DWORD DiscTimeLow,
  873. DWORD DiscTimeHigh)
  874. {
  875. unsigned long cbActual;
  876. JET_ERR err;
  877. JET_SESID sesid = JET_sesidNil;
  878. JET_DBID dbid;
  879. JET_TABLEID sessdirtableid;
  880. JET_TABLEID servdirtableid;
  881. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  882. char one = 1;
  883. // "unreferenced" parameter (referenced by RPC)
  884. Binding;
  885. TSDISErrorOut(L"In SetSessDisc, ServID=%d, SessID=%d\n", *pCI, SessionID);
  886. TSDISErrorTimeOut(L" DiscTime=%s\n", DiscTimeLow, DiscTimeHigh);
  887. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  888. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  889. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  890. &sessdirtableid));
  891. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  892. &servdirtableid));
  893. CALL(JetBeginTransaction(sesid));
  894. // Verify that the ServerID passed in was OK.
  895. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  896. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  897. goto HandleError;
  898. }
  899. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  900. // find the record with the serverid, sessionid we are looking for
  901. CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
  902. JET_bitNewKey));
  903. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
  904. CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
  905. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
  906. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  907. SESSDIR_STATE_INTERNAL_INDEX], &one, sizeof(one), 0, NULL));
  908. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  909. CALL(JetCommitTransaction(sesid, 0));
  910. CALL(JetCloseTable(sesid, sessdirtableid));
  911. CALL(JetCloseTable(sesid, servdirtableid));
  912. CALL(JetCloseDatabase(sesid, dbid, 0));
  913. CALL(JetEndSession(sesid, 0));
  914. return 0;
  915. HandleError:
  916. if (sesid != JET_sesidNil) {
  917. // Can't really recover. Just bail out.
  918. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  919. // Force the session closed
  920. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  921. }
  922. // Delete the server and close the context handle. Their states are bad.
  923. TSSDPurgeServer(PtrToUlong(*hCI));
  924. *hCI = NULL;
  925. return (DWORD) E_FAIL;
  926. }
  927. /****************************************************************************/
  928. // TSSDRpcSetSessionReconnected
  929. //
  930. // Called on a session reconnection.
  931. /****************************************************************************/
  932. DWORD TSSDRpcSetSessionReconnected(
  933. handle_t Binding,
  934. HCLIENTINFO *hCI,
  935. DWORD SessionID,
  936. DWORD TSProtocol,
  937. DWORD ResWidth,
  938. DWORD ResHeight,
  939. DWORD ColorDepth)
  940. {
  941. JET_ERR err;
  942. JET_SESID sesid = JET_sesidNil;
  943. JET_DBID dbid;
  944. JET_TABLEID sessdirtableid;
  945. JET_TABLEID servdirtableid;
  946. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  947. char zero = 0;
  948. unsigned long cbActual;
  949. // "unreferenced" parameter (referenced by RPC)
  950. Binding;
  951. TSDISErrorOut(L"In SetSessRec, ServID=%d, SessID=%d, TSProt=%d, "
  952. L"ResWid=%d, ResHt=%d, ColDepth=%d\n", *pCI,
  953. SessionID, TSProtocol, ResWidth, ResHeight,
  954. ColorDepth);
  955. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  956. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  957. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  958. &sessdirtableid));
  959. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  960. &servdirtableid));
  961. CALL(JetBeginTransaction(sesid));
  962. // Verify that the ServerID passed in was OK.
  963. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  964. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  965. goto HandleError;
  966. }
  967. CALL(JetSetCurrentIndex(sesid, sessdirtableid, "primaryIndex"));
  968. // Find the record with the serverid, sessionid we are looking for.
  969. CALL(JetMakeKey(sesid, sessdirtableid, pCI, sizeof(DWORD),
  970. JET_bitNewKey));
  971. CALL(JetMakeKey(sesid, sessdirtableid, &SessionID, sizeof(DWORD), 0));
  972. CALL(JetSeek(sesid, sessdirtableid, JET_bitSeekEQ));
  973. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepReplace));
  974. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  975. SESSDIR_TSPROTOCOL_INTERNAL_INDEX], &TSProtocol, sizeof(TSProtocol),
  976. 0, NULL));
  977. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  978. SESSDIR_RESWIDTH_INTERNAL_INDEX], &ResWidth, sizeof(ResWidth),
  979. 0, NULL));
  980. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  981. SESSDIR_RESHEIGHT_INTERNAL_INDEX], &ResHeight, sizeof(ResHeight),
  982. 0, NULL));
  983. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  984. SESSDIR_COLORDEPTH_INTERNAL_INDEX], &ColorDepth, sizeof(ColorDepth),
  985. 0, NULL));
  986. CALL(JetSetColumn(sesid, sessdirtableid, sesdircolumnid[
  987. SESSDIR_STATE_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  988. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  989. CALL(JetCommitTransaction(sesid, 0));
  990. CALL(JetCloseTable(sesid, sessdirtableid));
  991. CALL(JetCloseTable(sesid, servdirtableid));
  992. CALL(JetCloseDatabase(sesid, dbid, 0));
  993. CALL(JetEndSession(sesid, 0));
  994. return 0;
  995. HandleError:
  996. if (sesid != JET_sesidNil) {
  997. // Can't really recover. Just bail out.
  998. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  999. // Force the session closed.
  1000. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1001. }
  1002. // Delete the server and close the context handle. Their states are bad.
  1003. TSSDPurgeServer(PtrToUlong(*hCI));
  1004. *hCI = NULL;
  1005. return (DWORD) E_FAIL;
  1006. }
  1007. DWORD TSSDRpcSetServerReconnectPending(
  1008. handle_t Binding,
  1009. WCHAR __RPC_FAR *ServerAddress,
  1010. DWORD AlmostTimeLow,
  1011. DWORD AlmostTimeHigh)
  1012. {
  1013. // Ignored parameters
  1014. Binding;
  1015. AlmostTimeLow;
  1016. AlmostTimeHigh;
  1017. return TSSDSetServerAITInternal(ServerAddress, FALSE, NULL);
  1018. }
  1019. /****************************************************************************/
  1020. // TSSDRpcUpdateConfigurationSetting
  1021. //
  1022. // Extensible interface to update a configuration setting.
  1023. /****************************************************************************/
  1024. DWORD TSSDSetServerAddress(HCLIENTINFO *hCI, WCHAR *ServerName)
  1025. {
  1026. JET_ERR err;
  1027. JET_SESID sesid = JET_sesidNil;
  1028. JET_DBID dbid;
  1029. JET_TABLEID servdirtableid;
  1030. unsigned long cbActual;
  1031. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1032. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1033. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1034. &servdirtableid));
  1035. // Find the server in the server directory
  1036. CALL(JetBeginTransaction(sesid));
  1037. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  1038. CALL(JetMakeKey(sesid, servdirtableid, (const void *)hCI, sizeof(DWORD),
  1039. JET_bitNewKey));
  1040. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1041. // Prepare to update.
  1042. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1043. // Now set the column to what we want
  1044. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1045. SERVDIR_SERVADDR_INTERNAL_INDEX], (void *) ServerName,
  1046. (unsigned) (wcslen(ServerName) + 1) * sizeof(WCHAR), 0,
  1047. NULL));
  1048. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1049. CALL(JetCommitTransaction(sesid, 0));
  1050. // Clean up.
  1051. CALL(JetCloseTable(sesid, servdirtableid));
  1052. CALL(JetCloseDatabase(sesid, dbid, 0));
  1053. CALL(JetEndSession(sesid, 0));
  1054. return 0;
  1055. HandleError:
  1056. if (sesid != JET_sesidNil) {
  1057. // Can't really recover. Just bail out.
  1058. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1059. // Force the session closed
  1060. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1061. }
  1062. TSSDPurgeServer(PtrToUlong(*hCI));
  1063. // Close the context handle.
  1064. *hCI = NULL;
  1065. return (DWORD) E_FAIL;
  1066. }
  1067. /****************************************************************************/
  1068. // TSSDRpcUpdateConfigurationSetting
  1069. //
  1070. // Extensible interface to update a configuration setting.
  1071. /****************************************************************************/
  1072. DWORD TSSDRpcUpdateConfigurationSetting(
  1073. handle_t Binding,
  1074. HCLIENTINFO *hCI,
  1075. DWORD dwSetting,
  1076. DWORD dwSettingLength,
  1077. BYTE __RPC_FAR *pbValue)
  1078. {
  1079. // Unreferenced parameters.
  1080. Binding;
  1081. hCI;
  1082. dwSetting;
  1083. dwSettingLength;
  1084. pbValue;
  1085. if (dwSetting == SDCONFIG_SERVER_ADDRESS) {
  1086. TSDISErrorOut(L"Server is setting its address as %s\n",
  1087. (WCHAR *) pbValue);
  1088. return TSSDSetServerAddress(hCI, (WCHAR *) pbValue);
  1089. }
  1090. return (DWORD) E_NOTIMPL;
  1091. }
  1092. /****************************************************************************/
  1093. // TSSDSetServerAITInternal
  1094. //
  1095. // Called on a client redirection from one server to another, to let the
  1096. // integrity service determine how to ping the redirection target machine.
  1097. //
  1098. // Args:
  1099. // ServerAddress (in) - the server address to set values for
  1100. // bResetToZero (in) - whether to reset all AIT values to 0
  1101. // FailureCount (in/out) - Pointer to nonzero on entry means increment the
  1102. // failure count. Returns the result failure count.
  1103. /****************************************************************************/
  1104. DWORD TSSDSetServerAITInternal(
  1105. WCHAR *ServerAddress,
  1106. DWORD bResetToZero,
  1107. DWORD *FailureCount)
  1108. {
  1109. JET_ERR err;
  1110. JET_SESID sesid = JET_sesidNil;
  1111. JET_DBID dbid;
  1112. JET_TABLEID servdirtableid;
  1113. DWORD AITFromServDirLow;
  1114. DWORD AITFromServDirHigh;
  1115. unsigned long cbActual;
  1116. TSDISErrorOut(L"SetServAITInternal: ServAddr=%s, bResetToZero=%d, bIncFail"
  1117. L"=%d\n", ServerAddress, bResetToZero, (FailureCount == NULL) ?
  1118. 0 : *FailureCount);
  1119. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1120. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1121. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1122. &servdirtableid));
  1123. CALL(JetBeginTransaction(sesid));
  1124. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServNameIndex"));
  1125. CALL(JetMakeKey(sesid, servdirtableid, ServerAddress, (unsigned)
  1126. (wcslen(ServerAddress) + 1) * sizeof(WCHAR), JET_bitNewKey));
  1127. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1128. // Algorithm for set reconnect pending:
  1129. // 1) If server is not already pending a reconnect,
  1130. // 2) Set the AlmostTimeLow and High to locally computed times (using
  1131. // the times from the wire is dangerous and requires clocks to be the
  1132. // same).
  1133. // Retrieve the current values of AlmostInTimeLow and High
  1134. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1135. SERVDIR_AITLOW_INTERNAL_INDEX], &AITFromServDirLow,
  1136. sizeof(AITFromServDirLow), &cbActual, 0, NULL));
  1137. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1138. SERVDIR_AITHIGH_INTERNAL_INDEX], &AITFromServDirHigh,
  1139. sizeof(AITFromServDirHigh), &cbActual, 0, NULL));
  1140. // If it's time to reset, reset to 0.
  1141. if (bResetToZero != 0) {
  1142. DWORD zero = 0;
  1143. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1144. // Set the columns: Low, High, and NumFailedPings.
  1145. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1146. SERVDIR_AITLOW_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  1147. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1148. SERVDIR_AITHIGH_INTERNAL_INDEX], &zero, sizeof(zero), 0, NULL));
  1149. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1150. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX], &zero, sizeof(zero), 0,
  1151. NULL));
  1152. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1153. }
  1154. // Otherwise, if the server isn't already pending a reconnect,
  1155. else if ((AITFromServDirLow == 0) && (AITFromServDirHigh == 0)) {
  1156. FILETIME ft;
  1157. SYSTEMTIME st;
  1158. // Retrieve the time.
  1159. GetSystemTime(&st);
  1160. SystemTimeToFileTime(&st, &ft);
  1161. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1162. // Set the columns.
  1163. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1164. SERVDIR_AITLOW_INTERNAL_INDEX], &(ft.dwLowDateTime),
  1165. sizeof(ft.dwLowDateTime), 0, NULL));
  1166. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1167. SERVDIR_AITHIGH_INTERNAL_INDEX], &(ft.dwHighDateTime),
  1168. sizeof(ft.dwHighDateTime), 0, NULL));
  1169. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1170. }
  1171. // Else if we were told to increment the failure count
  1172. else if (FailureCount != NULL) {
  1173. if (*FailureCount != 0) {
  1174. DWORD FailureCountFromServDir;
  1175. // Get the current failure count.
  1176. CALL(JetRetrieveColumn(sesid, servdirtableid, servdircolumnid[
  1177. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
  1178. &FailureCountFromServDir, sizeof(FailureCountFromServDir),
  1179. &cbActual, 0, NULL));
  1180. // Set return value, also value used for update.
  1181. *FailureCount = FailureCountFromServDir + 1;
  1182. CALL(JetPrepareUpdate(sesid, servdirtableid, JET_prepReplace));
  1183. // Set the column.
  1184. CALL(JetSetColumn(sesid, servdirtableid, servdircolumnid[
  1185. SERVDIR_NUMFAILPINGS_INTERNAL_INDEX],
  1186. FailureCount, sizeof(*FailureCount), 0, NULL));
  1187. CALL(JetUpdate(sesid, servdirtableid, NULL, 0, &cbActual));
  1188. }
  1189. }
  1190. CALL(JetCommitTransaction(sesid, 0));
  1191. CALL(JetCloseTable(sesid, servdirtableid));
  1192. CALL(JetCloseDatabase(sesid, dbid, 0));
  1193. CALL(JetEndSession(sesid, 0));
  1194. return 0;
  1195. HandleError:
  1196. if (sesid != JET_sesidNil) {
  1197. // Can't really recover. Just bail out.
  1198. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1199. // Force the session closed
  1200. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1201. }
  1202. return (DWORD) E_FAIL;
  1203. }
  1204. DWORD TSSDRpcRepopulateAllSessions(
  1205. handle_t Binding,
  1206. HCLIENTINFO *hCI,
  1207. DWORD NumSessions,
  1208. TSSD_RepopInfo rpi[])
  1209. {
  1210. JET_ERR err;
  1211. JET_SESID sesid = JET_sesidNil;
  1212. JET_DBID dbid;
  1213. JET_TABLEID sessdirtableid;
  1214. JET_TABLEID servdirtableid;
  1215. JET_SETCOLUMN scSessDir[NUM_SESSDIRCOLUMNS];
  1216. CLIENTINFO *pCI = (CLIENTINFO *) hCI;
  1217. unsigned count; // inside each record
  1218. unsigned iCurrSession;
  1219. unsigned long cbActual;
  1220. char State;
  1221. // "unreferenced" parameter (referenced by RPC)
  1222. Binding;
  1223. TSDISErrorOut(L"RepopAllSess: ServID = %d, NumSessions = %d, ...\n",
  1224. *pCI, NumSessions);
  1225. memset(&scSessDir[0], 0, sizeof(JET_SETCOLUMN) * NUM_SESSDIRCOLUMNS);
  1226. CALL(JetBeginSession(g_instance, &sesid, "user", ""));
  1227. CALL(JetOpenDatabase(sesid, JETDBFILENAME, "", &dbid, 0));
  1228. CALL(JetOpenTable(sesid, dbid, "SessionDirectory", NULL, 0, 0,
  1229. &sessdirtableid));
  1230. CALL(JetOpenTable(sesid, dbid, "ServerDirectory", NULL, 0, 0,
  1231. &servdirtableid));
  1232. CALL(JetBeginTransaction(sesid));
  1233. // Verify that the ServerID passed in was OK.
  1234. if (TSSDVerifyServerIDValid(sesid, servdirtableid, PtrToUlong(*hCI)) == FALSE) {
  1235. TSDISErrorOut(L"Invalid ServerID was passed in\n");
  1236. goto HandleError;
  1237. }
  1238. // Set up some constants for all updates.
  1239. for (count = 0; count < NUM_SESSDIRCOLUMNS; count++) {
  1240. scSessDir[count].columnid = sesdircolumnid[count];
  1241. scSessDir[count].cbData = 4; // most of them, set the rest individually
  1242. scSessDir[count].itagSequence = 1;
  1243. }
  1244. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].cbData = sizeof(char);
  1245. // Now do each update in a loop.
  1246. for (iCurrSession = 0; iCurrSession < NumSessions; iCurrSession += 1) {
  1247. err = JetMove(sesid, sessdirtableid, JET_MoveLast, 0);
  1248. CALL(JetPrepareUpdate(sesid, sessdirtableid, JET_prepInsert));
  1249. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].cbData =
  1250. (unsigned) (wcslen(rpi[iCurrSession].UserName) + 1) *
  1251. sizeof(WCHAR);
  1252. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].cbData =
  1253. (unsigned) (wcslen(rpi[iCurrSession].Domain) + 1) *
  1254. sizeof(WCHAR);
  1255. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].cbData =
  1256. (unsigned) (wcslen(rpi[iCurrSession].AppType) + 1) *
  1257. sizeof(WCHAR);
  1258. scSessDir[SESSDIR_USERNAME_INTERNAL_INDEX].pvData =
  1259. rpi[iCurrSession].UserName;
  1260. scSessDir[SESSDIR_DOMAIN_INTERNAL_INDEX].pvData =
  1261. rpi[iCurrSession].Domain;
  1262. scSessDir[SESSDIR_SERVERID_INTERNAL_INDEX].pvData = pCI;
  1263. scSessDir[SESSDIR_SESSIONID_INTERNAL_INDEX].pvData =
  1264. &rpi[iCurrSession].SessionID;
  1265. scSessDir[SESSDIR_TSPROTOCOL_INTERNAL_INDEX].pvData =
  1266. &rpi[iCurrSession].TSProtocol;
  1267. scSessDir[SESSDIR_CTLOW_INTERNAL_INDEX].pvData =
  1268. &rpi[iCurrSession].CreateTimeLow;
  1269. scSessDir[SESSDIR_CTHIGH_INTERNAL_INDEX].pvData =
  1270. &rpi[iCurrSession].CreateTimeHigh;
  1271. scSessDir[SESSDIR_DTLOW_INTERNAL_INDEX].pvData =
  1272. &rpi[iCurrSession].DisconnectTimeLow;
  1273. scSessDir[SESSDIR_DTHIGH_INTERNAL_INDEX].pvData =
  1274. &rpi[iCurrSession].DisconnectTimeHigh;
  1275. scSessDir[SESSDIR_APPTYPE_INTERNAL_INDEX].pvData =
  1276. rpi[iCurrSession].AppType;
  1277. scSessDir[SESSDIR_RESWIDTH_INTERNAL_INDEX].pvData =
  1278. &rpi[iCurrSession].ResolutionWidth;
  1279. scSessDir[SESSDIR_RESHEIGHT_INTERNAL_INDEX].pvData =
  1280. &rpi[iCurrSession].ResolutionHeight;
  1281. scSessDir[SESSDIR_COLORDEPTH_INTERNAL_INDEX].pvData =
  1282. &rpi[iCurrSession].ColorDepth;
  1283. State = (char) rpi[iCurrSession].State;
  1284. scSessDir[SESSDIR_STATE_INTERNAL_INDEX].pvData = &State;
  1285. CALL(JetSetColumns(sesid, sessdirtableid, scSessDir,
  1286. NUM_SESSDIRCOLUMNS));
  1287. CALL(JetUpdate(sesid, sessdirtableid, NULL, 0, &cbActual));
  1288. }
  1289. CALL(JetCommitTransaction(sesid, 0));
  1290. CALL(JetCloseTable(sesid, sessdirtableid));
  1291. CALL(JetCloseTable(sesid, servdirtableid));
  1292. CALL(JetCloseDatabase(sesid, dbid, 0));
  1293. CALL(JetEndSession(sesid, 0));
  1294. return 0;
  1295. HandleError:
  1296. if (sesid != JET_sesidNil) {
  1297. // Can't really recover. Just bail out.
  1298. (VOID) JetRollback(sesid, JET_bitRollbackAll);
  1299. // Force the session closed
  1300. (VOID) JetEndSession(sesid, JET_bitForceSessionClosed);
  1301. }
  1302. return (DWORD) E_FAIL;
  1303. }
  1304. // Called to determine whether a ServerID passed in is valid. TRUE if valid,
  1305. // FALSE otherwise.
  1306. //
  1307. // Must be inside a transaction, and sesid and servdirtableid must be ready to
  1308. // go.
  1309. BOOL TSSDVerifyServerIDValid(JET_SESID sesid, JET_TABLEID servdirtableid,
  1310. DWORD ServerID)
  1311. {
  1312. JET_ERR err;
  1313. CALL(JetSetCurrentIndex(sesid, servdirtableid, "ServerIDIndex"));
  1314. CALL(JetMakeKey(sesid, servdirtableid, (const void *) &ServerID,
  1315. sizeof(DWORD), JET_bitNewKey));
  1316. // If the ServerID is there, this will succeed, otherwise it will fail and
  1317. // jump to HandleError.
  1318. CALL(JetSeek(sesid, servdirtableid, JET_bitSeekEQ));
  1319. return TRUE;
  1320. HandleError:
  1321. return FALSE;
  1322. }
  1323. // Rundown procedure for when a CLIENTINFO is destroyed as a result of a
  1324. // connection loss or client termination.
  1325. void HCLIENTINFO_rundown(HCLIENTINFO hCI)
  1326. {
  1327. CLIENTINFO CI = PtrToUlong(hCI);
  1328. TSDISErrorOut(L"In HCLIENTINFO_rundown: ServerID=%d\n", CI);
  1329. if (CI != NULL)
  1330. TSSDPurgeServer(CI);
  1331. hCI = NULL;
  1332. }
  1333. #pragma warning (pop)