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.

723 lines
17 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: client.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin July-25-1995 Created
  8. //
  9. // Client struct routines and I/O routines for tracing dll
  10. //============================================================================
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <stdlib.h>
  16. #include <rtutils.h>
  17. #include "trace.h"
  18. //
  19. // assumes server is locked for writing
  20. //
  21. DWORD
  22. TraceCreateClient(
  23. LPTRACE_CLIENT *lplpclient
  24. ) {
  25. DWORD dwErr;
  26. LPTRACE_CLIENT lpclient;
  27. lpclient = HeapAlloc(GetProcessHeap(), 0, sizeof(TRACE_CLIENT));
  28. if (lpclient == NULL) {
  29. return ERROR_NOT_ENOUGH_MEMORY;
  30. }
  31. //
  32. // initialize fields in the client structure
  33. //
  34. lpclient->TC_ClientID = MAX_CLIENT_COUNT;
  35. lpclient->TC_Flags = 0;
  36. lpclient->TC_File = NULL;
  37. lpclient->TC_Console = NULL;
  38. lpclient->TC_ConfigKey = NULL;
  39. lpclient->TC_ConfigEvent = NULL;
  40. lpclient->TC_MaxFileSize = DEF_MAXFILESIZE;
  41. ZeroMemory(lpclient->TC_ClientNameA, MAX_CLIENTNAME_LENGTH * sizeof(CHAR));
  42. ZeroMemory(lpclient->TC_ClientNameW, MAX_CLIENTNAME_LENGTH * sizeof(WCHAR));
  43. lstrcpy(lpclient->TC_FileDir, DEF_FILEDIRECTORY);
  44. #ifdef UNICODE
  45. wcstombs(
  46. lpclient->TC_FileDirA, lpclient->TC_FileDirW,
  47. lstrlenW(lpclient->TC_FileDirW) + 1
  48. );
  49. #else
  50. mbstowcs(
  51. lpclient->TC_FileDirW, lpclient->TC_FileDirA,
  52. lstrlenA(lpclient->TC_FileDirA) + 1
  53. );
  54. #endif
  55. __try {
  56. TRACE_STARTUP_LOCKING(lpclient);
  57. dwErr = NO_ERROR;
  58. }
  59. __except(EXCEPTION_EXECUTE_HANDLER) {
  60. dwErr = GetExceptionCode();
  61. HeapFree(GetProcessHeap(), 0, lpclient);
  62. lpclient = NULL;
  63. }
  64. InterlockedExchangePointer(lplpclient, lpclient);
  65. return dwErr;
  66. }
  67. //
  68. // assumes server is locked for writing and client is locked for writing
  69. //
  70. DWORD
  71. TraceDeleteClient(
  72. LPTRACE_SERVER lpserver,
  73. LPTRACE_CLIENT *lplpclient
  74. ) {
  75. LPTRACE_CLIENT lpclient;
  76. if (lplpclient == NULL || *lplpclient == NULL) {
  77. return ERROR_INVALID_PARAMETER;
  78. }
  79. lpclient = *lplpclient;
  80. InterlockedExchangePointer(lplpclient, NULL);
  81. InterlockedExchange(lpserver->TS_FlagsCache + lpclient->TC_ClientID, 0);
  82. TRACE_CLEANUP_LOCKING(lpclient);
  83. //
  84. // closing this key will cause the event to be signalled
  85. // however, we hold the lock on the table so the server thread
  86. // will be blocked until the cleanup completes
  87. //
  88. if (lpclient->TC_ConfigKey != NULL) {
  89. RegCloseKey(lpclient->TC_ConfigKey);
  90. }
  91. if (lpclient->TC_ConfigEvent != NULL) {
  92. CloseHandle(lpclient->TC_ConfigEvent);
  93. }
  94. if (TRACE_CLIENT_USES_CONSOLE(lpclient)) {
  95. TraceCloseClientConsole(lpserver, lpclient);
  96. }
  97. if (TRACE_CLIENT_USES_FILE(lpclient)) {
  98. TraceCloseClientFile(lpclient);
  99. }
  100. HeapFree(GetProcessHeap(), 0, lpclient);
  101. return 0;
  102. }
  103. //
  104. // assumes server is locked for reading or for writing
  105. //
  106. LPTRACE_CLIENT
  107. TraceFindClient(
  108. LPTRACE_SERVER lpserver,
  109. LPCTSTR lpszClient
  110. ) {
  111. DWORD dwClient;
  112. LPTRACE_CLIENT *lplpc, *lplpcstart, *lplpcend;
  113. lplpcstart = lpserver->TS_ClientTable;
  114. lplpcend = lplpcstart + MAX_CLIENT_COUNT;
  115. for (lplpc = lplpcstart; lplpc < lplpcend; lplpc++) {
  116. if (*lplpc != NULL &&
  117. lstrcmp((*lplpc)->TC_ClientName, lpszClient) == 0) {
  118. break;
  119. }
  120. }
  121. return (lplpc < lplpcend) ? *lplpc : NULL;
  122. }
  123. //
  124. // assumes that the server is locked for writing,
  125. // and that the client is locked for writing
  126. // also assumes the client is not already a console client
  127. //
  128. DWORD TraceOpenClientConsole(LPTRACE_SERVER lpserver,
  129. LPTRACE_CLIENT lpclient) {
  130. DWORD dwErr;
  131. COORD screen;
  132. HANDLE hConsole;
  133. //
  134. // if all console tracing is disabled, do nothing
  135. //
  136. if ((lpserver->TS_Flags & TRACEFLAGS_USECONSOLE) == 0) {
  137. return 0;
  138. }
  139. //
  140. // create the console if it isn't already created
  141. //
  142. if (lpserver->TS_Console == NULL) {
  143. COORD screen;
  144. //
  145. // allocate a console and set the buffer size
  146. //
  147. AllocConsole();
  148. lpserver->TS_Console = GetStdHandle(STD_INPUT_HANDLE);
  149. if (lpserver->TS_Console == INVALID_HANDLE_VALUE )
  150. return GetLastError();
  151. }
  152. //
  153. // allocate a console for this client
  154. //
  155. hConsole = CreateConsoleScreenBuffer(
  156. GENERIC_READ | GENERIC_WRITE, 0, NULL,
  157. CONSOLE_TEXTMODE_BUFFER, NULL
  158. );
  159. if (hConsole == INVALID_HANDLE_VALUE) { return GetLastError(); }
  160. //
  161. // set the buffer to the standard size
  162. // and save the console buffer handle
  163. //
  164. screen.X = DEF_SCREENBUF_WIDTH;
  165. screen.Y = DEF_SCREENBUF_HEIGHT;
  166. SetConsoleScreenBufferSize(hConsole, screen);
  167. lpclient->TC_Console = hConsole;
  168. //
  169. // see if there was a previous console client;
  170. // if not, set this new one's screen buffer to be
  171. // the active screen buffer
  172. //
  173. if (lpserver->TS_ConsoleOwner == MAX_CLIENT_COUNT) {
  174. TraceUpdateConsoleOwner(lpserver, 1);
  175. }
  176. return 0;
  177. }
  178. //
  179. // assumes that the server is locked for writing,
  180. // and that the client is locked for writing
  181. // also assumes the client is already a console client
  182. //
  183. DWORD
  184. TraceCloseClientConsole(
  185. LPTRACE_SERVER lpserver,
  186. LPTRACE_CLIENT lpclient
  187. ) {
  188. HANDLE hConsole;
  189. //
  190. // if all console tracing is disabled, do nothing
  191. //
  192. if ((lpserver->TS_Flags & TRACEFLAGS_USECONSOLE) == 0) {
  193. return 0;
  194. }
  195. //
  196. // close the client's screen buffer and associated handles
  197. //
  198. if (lpclient->TC_Console != NULL) {
  199. CloseHandle(lpclient->TC_Console);
  200. lpclient->TC_Console = NULL;
  201. }
  202. //
  203. // if the client owned the screen, find another owner
  204. //
  205. if (lpserver->TS_ConsoleOwner == lpclient->TC_ClientID) {
  206. TraceUpdateConsoleOwner(lpserver, 1);
  207. }
  208. //
  209. // if no owner was found, free the server's console
  210. //
  211. if (lpserver->TS_ConsoleOwner == MAX_CLIENT_COUNT ||
  212. lpserver->TS_ConsoleOwner == lpclient->TC_ClientID) {
  213. lpserver->TS_ConsoleOwner = MAX_CLIENT_COUNT;
  214. CloseHandle(lpserver->TS_Console);
  215. lpserver->TS_Console = NULL;
  216. FreeConsole();
  217. }
  218. return 0;
  219. }
  220. //
  221. // assumes that the server is locked for reading or writing
  222. // and that the client is locked for writing
  223. //
  224. DWORD
  225. TraceCreateClientFile(
  226. LPTRACE_CLIENT lpclient
  227. ) {
  228. DWORD dwErr;
  229. HANDLE hFile;
  230. LPOVERLAPPED lpovl;
  231. TCHAR szFilename[MAX_PATH];
  232. //
  233. // create the directory in case it doesn't exist
  234. //
  235. CreateDirectory(lpclient->TC_FileDir, NULL);
  236. //
  237. // figure out the file name
  238. //
  239. lstrcpy(szFilename, lpclient->TC_FileDir);
  240. lstrcat(szFilename, STR_DIRSEP);
  241. lstrcat(szFilename, lpclient->TC_ClientName);
  242. lstrcat(szFilename, STR_LOGEXT);
  243. //
  244. // open the file, disabling write sharing
  245. //
  246. hFile = CreateFile(
  247. szFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
  248. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
  249. );
  250. if (hFile == INVALID_HANDLE_VALUE) {
  251. return GetLastError();
  252. }
  253. SetFilePointer(hFile, 0, NULL, FILE_END);
  254. lpclient->TC_File = hFile;
  255. return 0;
  256. }
  257. //
  258. // assumes that the server is locked for reading or writing
  259. // and that the client is locked for writing
  260. //
  261. DWORD
  262. TraceMoveClientFile(
  263. LPTRACE_CLIENT lpclient
  264. ) {
  265. TCHAR szDestname[MAX_PATH], szSrcname[MAX_PATH];
  266. lstrcpy(szSrcname, lpclient->TC_FileDir);
  267. lstrcat(szSrcname, STR_DIRSEP);
  268. lstrcat(szSrcname, lpclient->TC_ClientName);
  269. lstrcpy(szDestname, szSrcname);
  270. lstrcat(szSrcname, STR_LOGEXT);
  271. lstrcat(szDestname, STR_OLDEXT);
  272. //
  273. // close the file handle if it is open
  274. //
  275. TraceCloseClientFile(lpclient);
  276. //
  277. // do the move
  278. //
  279. MoveFileEx(
  280. szSrcname, szDestname,
  281. MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED
  282. );
  283. //
  284. // re-open the log file
  285. //
  286. return TraceCreateClientFile(lpclient);
  287. }
  288. //
  289. // assumes that the server is locked for reading or writing
  290. // and that the client is locked for writing
  291. //
  292. DWORD
  293. TraceCloseClientFile(
  294. LPTRACE_CLIENT lpclient
  295. ) {
  296. if (lpclient->TC_File != NULL) {
  297. CloseHandle(lpclient->TC_File);
  298. lpclient->TC_File = NULL;
  299. }
  300. return 0;
  301. }
  302. //
  303. // assumes that the server is locked for reading or writing
  304. // and that the client is locked for reading
  305. //
  306. DWORD
  307. TraceWriteOutput(
  308. LPTRACE_SERVER lpserver,
  309. LPTRACE_CLIENT lpclient,
  310. DWORD dwFlags,
  311. LPCTSTR lpszOutput
  312. ) {
  313. BOOL bSuccess;
  314. DWORD dwFileMask, dwConsoleMask;
  315. DWORD dwErr, dwFileSize, dwBytesToWrite, dwBytesWritten, dwChars;
  316. dwBytesWritten = 0;
  317. dwBytesToWrite = lstrlen(lpszOutput) * sizeof(TCHAR);
  318. dwFileMask = dwConsoleMask = 1;
  319. //
  320. // if the client uses output masking, compute the mask for this message
  321. //
  322. if (dwFlags & TRACE_USE_MASK) {
  323. dwFileMask = (dwFlags & lpclient->TC_FileMask);
  324. dwConsoleMask = (dwFlags & lpclient->TC_ConsoleMask);
  325. }
  326. if (TRACE_CLIENT_USES_FILE(lpclient) &&
  327. dwFileMask != 0 && lpclient->TC_File != NULL) {
  328. //
  329. // check the size of the file to see if it needs renaming
  330. //
  331. dwFileSize = GetFileSize(lpclient->TC_File, NULL);
  332. if ((dwFileSize + dwBytesToWrite) > lpclient->TC_MaxFileSize) {
  333. TRACE_READ_TO_WRITELOCK(lpclient);
  334. //
  335. // move the existing file over and start with an empty one
  336. //
  337. dwErr = TraceMoveClientFile(lpclient);
  338. if (dwErr!=NO_ERROR)
  339. return dwErr;
  340. dwFileSize = 0;
  341. TRACE_WRITE_TO_READLOCK(lpclient);
  342. }
  343. //
  344. // perform the write operation
  345. //
  346. bSuccess =
  347. WriteFile(
  348. lpclient->TC_File, lpszOutput, dwBytesToWrite,
  349. &dwBytesWritten, NULL
  350. );
  351. }
  352. if (TRACE_CLIENT_USES_CONSOLE(lpclient) &&
  353. dwConsoleMask != 0 && lpclient->TC_Console != NULL) {
  354. //
  355. // write to the console directly; this is less costly
  356. // than writing to a file, which is fortunate since we
  357. // cannot use completion ports with console handles
  358. //
  359. dwChars = dwBytesToWrite / sizeof(TCHAR);
  360. bSuccess =
  361. WriteConsole(
  362. lpclient->TC_Console, lpszOutput, dwChars, &dwChars, NULL
  363. );
  364. }
  365. return dwBytesWritten;
  366. }
  367. //----------------------------------------------------------------------------
  368. // Function: TraceDumpLine
  369. //
  370. // Parameters:
  371. // LPTRACE_CLIENT lpclient pointer to client struct for caller
  372. // LPBYTE lpbBytes address of buffer to dump
  373. // DWORD dwLine length of line in bytes
  374. // DWORD dwGroup size of byte groupings
  375. // BOOL bPrefixAddr if TRUE, prefix lines with addresses
  376. // LPBYTE lpbPrefix address with which to prefix lines
  377. // LPTSTR lpszPrefix optional string with which to prefix lines
  378. //----------------------------------------------------------------------------
  379. DWORD
  380. TraceDumpLine(
  381. LPTRACE_SERVER lpserver,
  382. LPTRACE_CLIENT lpclient,
  383. DWORD dwFlags,
  384. LPBYTE lpbBytes,
  385. DWORD dwLine,
  386. DWORD dwGroup,
  387. BOOL bPrefixAddr,
  388. LPBYTE lpbPrefix,
  389. LPCTSTR lpszPrefix
  390. ) {
  391. INT offset;
  392. LPTSTR lpszHex, lpszAscii;
  393. TCHAR szBuffer[256] = TEXT("\r\n");
  394. TCHAR szAscii[BYTES_PER_DUMPLINE + 2] = TEXT("");
  395. TCHAR szHex[(3 * BYTES_PER_DUMPLINE) + 1] = TEXT("");
  396. TCHAR szDigits[] = TEXT("0123456789ABCDEF");
  397. //
  398. // prepend prefix string if necessary
  399. //
  400. if (lpszPrefix != NULL) {
  401. lstrcat(szBuffer, lpszPrefix);
  402. }
  403. //
  404. // prepend address if needed
  405. //
  406. if (bPrefixAddr) {
  407. LPTSTR lpsz;
  408. ULONG_PTR ulpAddress = (ULONG_PTR) lpbPrefix;
  409. ULONG i;
  410. //
  411. // each line prints out a hex-digit
  412. // with the most-significant digit leftmost in the string
  413. // prepend address to lpsz[1]..lpsz[2*sizeof(ULONG_PTR)]
  414. //
  415. lpsz = szBuffer + lstrlen(szBuffer);
  416. for (i=0; i<2*sizeof(ULONG_PTR); i++) {
  417. lpsz[2*sizeof(ULONG_PTR)-i] = szDigits[ulpAddress & 0x0F];
  418. ulpAddress >>= 4;
  419. }
  420. lpsz[2*sizeof(ULONG_PTR) + 1] = TEXT(':');
  421. lpsz[2*sizeof(ULONG_PTR) + 2] = TEXT(' ');
  422. lpsz[2*sizeof(ULONG_PTR) + 3] = TEXT('\0');
  423. }
  424. lpszHex = szHex;
  425. lpszAscii = szAscii;
  426. //
  427. // rather than test the size of the grouping every time through
  428. // a loop, have a loop for each group size
  429. //
  430. switch(dwGroup) {
  431. //
  432. // single byte groupings
  433. //
  434. case 1: {
  435. while (dwLine >= sizeof(BYTE)) {
  436. //
  437. // print hex digits
  438. //
  439. *lpszHex++ = szDigits[*lpbBytes / 16];
  440. *lpszHex++ = szDigits[*lpbBytes % 16];
  441. *lpszHex++ = TEXT(' ');
  442. //
  443. // print ascii characters
  444. //
  445. *lpszAscii++ =
  446. (*lpbBytes >= 0x20 && *lpbBytes < 0x80) ? *lpbBytes
  447. : TEXT('.');
  448. ++lpbBytes;
  449. --dwLine;
  450. }
  451. break;
  452. }
  453. //
  454. // word-sized groupings
  455. //
  456. case 2: {
  457. WORD wBytes;
  458. BYTE loByte, hiByte;
  459. //
  460. // should already be aligned on a word boundary
  461. //
  462. while (dwLine >= sizeof(WORD)) {
  463. wBytes = *(LPWORD)lpbBytes;
  464. loByte = LOBYTE(wBytes);
  465. hiByte = HIBYTE(wBytes);
  466. // print hex digits
  467. *lpszHex++ = szDigits[hiByte / 16];
  468. *lpszHex++ = szDigits[hiByte % 16];
  469. *lpszHex++ = szDigits[loByte / 16];
  470. *lpszHex++ = szDigits[loByte % 16];
  471. *lpszHex++ = TEXT(' ');
  472. // print ascii characters
  473. *lpszAscii++ =
  474. (hiByte >= 0x20 && hiByte < 0x80) ? hiByte : TEXT('.');
  475. *lpszAscii++ =
  476. (loByte >= 0x20 && loByte < 0x80) ? loByte : TEXT('.');
  477. dwLine -= sizeof(WORD);
  478. lpbBytes += sizeof(WORD);
  479. }
  480. break;
  481. }
  482. //
  483. // double-word sized groupings
  484. //
  485. case 4: {
  486. DWORD dwBytes;
  487. BYTE loloByte, lohiByte, hiloByte, hihiByte;
  488. //
  489. // should already be aligned on a double-word boundary
  490. //
  491. while (dwLine >= sizeof(DWORD)) {
  492. dwBytes = *(LPDWORD)lpbBytes;
  493. hihiByte = HIBYTE(HIWORD(dwBytes));
  494. lohiByte = LOBYTE(HIWORD(dwBytes));
  495. hiloByte = HIBYTE(LOWORD(dwBytes));
  496. loloByte = LOBYTE(LOWORD(dwBytes));
  497. // print hex digits
  498. *lpszHex++ = szDigits[hihiByte / 16];
  499. *lpszHex++ = szDigits[hihiByte % 16];
  500. *lpszHex++ = szDigits[lohiByte / 16];
  501. *lpszHex++ = szDigits[lohiByte % 16];
  502. *lpszHex++ = szDigits[hiloByte / 16];
  503. *lpszHex++ = szDigits[hiloByte % 16];
  504. *lpszHex++ = szDigits[loloByte / 16];
  505. *lpszHex++ = szDigits[loloByte % 16];
  506. *lpszHex++ = TEXT(' ');
  507. // print ascii characters
  508. *lpszAscii++ =
  509. (hihiByte >= 0x20 && hihiByte < 0x80) ? hihiByte
  510. : TEXT('.');
  511. *lpszAscii++ =
  512. (lohiByte >= 0x20 && lohiByte < 0x80) ? lohiByte
  513. : TEXT('.');
  514. *lpszAscii++ =
  515. (hiloByte >= 0x20 && hiloByte < 0x80) ? hiloByte
  516. : TEXT('.');
  517. *lpszAscii++ =
  518. (loloByte >= 0x20 && loloByte < 0x80) ? loloByte
  519. : TEXT('.');
  520. // on to the next double-word
  521. dwLine -= sizeof(DWORD);
  522. lpbBytes += sizeof(DWORD);
  523. }
  524. break;
  525. }
  526. default:
  527. break;
  528. }
  529. *lpszHex = *lpszAscii = TEXT('\0');
  530. lstrcat(szBuffer, szHex);
  531. lstrcat(szBuffer, TEXT("|"));
  532. lstrcat(szBuffer, szAscii);
  533. lstrcat(szBuffer, TEXT("|"));
  534. return TraceWriteOutput(lpserver, lpclient, dwFlags, szBuffer);
  535. }