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

395 lines
13 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. tcbmon.c
  5. Abstract:
  6. This module contains code for a utility program which monitors
  7. the variables for the active TCP control blocks in the system.
  8. The program optionally maintains a log for a specified TCB
  9. in CSV format in a file specified by the user.
  10. Author:
  11. Abolade Gbadegesin (aboladeg) January-25-1999
  12. Revision History:
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <winsock2.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <ntddip.h>
  21. #include <ntddtcp.h>
  22. #include <ipinfo.h>
  23. #include <iphlpapi.h>
  24. #include <iphlpstk.h>
  25. HANDLE ConsoleHandle;
  26. CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
  27. ULONG DisplayInterval = 500;
  28. SOCKADDR_IN LogLocal;
  29. PCHAR LogPath;
  30. SOCKADDR_IN LogRemote;
  31. HANDLE StopEvent;
  32. HANDLE TcpipHandle;
  33. VOID
  34. WriteLine(
  35. COORD Coord,
  36. CHAR* Format,
  37. ...
  38. )
  39. {
  40. va_list arglist;
  41. char Buffer[256];
  42. ULONG Count;
  43. ULONG Length;
  44. va_start(arglist, Format);
  45. Count = vsprintf(Buffer, Format, arglist);
  46. FillConsoleOutputCharacter(
  47. ConsoleHandle, ' ', ConsoleInfo.dwSize.X, Coord, &Length
  48. );
  49. WriteConsoleOutputCharacter(
  50. ConsoleHandle, (LPCTSTR)Buffer, Count, Coord, &Length
  51. );
  52. }
  53. VOID
  54. ClearToEnd(
  55. COORD Coord,
  56. COORD End
  57. )
  58. {
  59. ULONG Length;
  60. while (Coord.Y <= End.Y) {
  61. FillConsoleOutputCharacter(
  62. ConsoleHandle, ' ', ConsoleInfo.dwSize.X, Coord, &Length
  63. );
  64. ++Coord.Y;
  65. }
  66. }
  67. ULONG WINAPI
  68. DisplayThread(
  69. PVOID Unused
  70. )
  71. {
  72. COORD End = {0,0};
  73. FILE* LogFile = NULL;
  74. do {
  75. COORD Coord = {0, 0};
  76. DWORD Error;
  77. ULONG i;
  78. ULONG Length;
  79. CHAR LocalAddr[20];
  80. CHAR RemoteAddr[20];
  81. char *DestString;
  82. char *SrcString;
  83. TCP_FINDTCB_REQUEST Request;
  84. TCP_FINDTCB_RESPONSE Response;
  85. PMIB_TCPTABLE Table;
  86. if (LogPath && !LogFile) {
  87. LogFile = fopen(LogPath, "w+");
  88. if (!LogFile) {
  89. perror("fopen");
  90. break;
  91. } else {
  92. fprintf(
  93. LogFile,
  94. "#senduna,sendnext,sendmax,sendwin,unacked,maxwin,cwin,"
  95. "mss,rtt,smrtt,rexmitcnt,rexmittimer,rexmit,retrans,state,"
  96. "flags,rto,delta\n"
  97. );
  98. }
  99. }
  100. Error =
  101. AllocateAndGetTcpTableFromStack(
  102. &Table,
  103. TRUE,
  104. GetProcessHeap(),
  105. 0
  106. );
  107. if (Error) {
  108. COORD Top = {0, 0};
  109. WriteLine(Top, "AllocateAndGetTcpTableFromStack: %d", Error);
  110. if (WaitForSingleObject(StopEvent, DisplayInterval)
  111. == WAIT_OBJECT_0) {
  112. break;
  113. } else {
  114. continue;
  115. }
  116. }
  117. for (i = 0; i < Table->dwNumEntries; i++) {
  118. if (Table->table[i].dwState < MIB_TCP_STATE_SYN_SENT ||
  119. Table->table[i].dwState > MIB_TCP_STATE_TIME_WAIT) {
  120. continue;
  121. }
  122. Request.Src = Table->table[i].dwLocalAddr;
  123. Request.Dest = Table->table[i].dwRemoteAddr;
  124. Request.SrcPort = (USHORT)Table->table[i].dwLocalPort;
  125. Request.DestPort = (USHORT)Table->table[i].dwRemotePort;
  126. if (!DeviceIoControl(
  127. TcpipHandle,
  128. IOCTL_TCP_FINDTCB,
  129. &Request,
  130. sizeof(Request),
  131. &Response,
  132. sizeof(Response),
  133. &Length,
  134. NULL
  135. )) {
  136. COORD Top = {0, 0};
  137. WriteLine(Top, "DeviceIoControl: %d", GetLastError());
  138. continue;
  139. }
  140. SrcString = inet_ntoa(*(PIN_ADDR)&Request.Src);
  141. DestString = inet_ntoa(*(PIN_ADDR)&Request.Dest);
  142. if (!SrcString || !DestString) {
  143. continue;
  144. }
  145. lstrcpy(LocalAddr, SrcString);
  146. lstrcpy(RemoteAddr, DestString);
  147. ++Coord.Y;
  148. WriteLine(
  149. Coord, "%s:%d %s:%d",
  150. LocalAddr, ntohs(Request.SrcPort),
  151. RemoteAddr, ntohs(Request.DestPort)
  152. );
  153. ++Coord.Y;
  154. WriteLine(
  155. Coord, " smrtt: %-8d rexmit: %-8d rexmitcnt: %-8d",
  156. Response.tcb_smrtt, Response.tcb_rexmit, Response.tcb_rexmitcnt
  157. );
  158. ++Coord.Y;
  159. if (Request.Src == LogLocal.sin_addr.s_addr &&
  160. Request.Dest == LogRemote.sin_addr.s_addr &&
  161. (LogLocal.sin_port == 0 ||
  162. Request.SrcPort == LogLocal.sin_port) &&
  163. (LogRemote.sin_port == 0 ||
  164. Request.DestPort == LogRemote.sin_port)) {
  165. LogLocal.sin_port = Request.SrcPort;
  166. LogRemote.sin_port = Request.DestPort;
  167. // senduna, sendnext
  168. fprintf(
  169. LogFile, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,"
  170. "%x,%u,%u\n",
  171. Response.tcb_senduna,
  172. Response.tcb_sendnext,
  173. Response.tcb_sendmax,
  174. Response.tcb_sendwin,
  175. Response.tcb_unacked,
  176. Response.tcb_maxwin,
  177. Response.tcb_cwin,
  178. Response.tcb_mss,
  179. Response.tcb_rtt,
  180. Response.tcb_smrtt,
  181. Response.tcb_rexmitcnt,
  182. Response.tcb_rexmittimer,
  183. Response.tcb_rexmit,
  184. Response.tcb_retrans,
  185. Response.tcb_state,
  186. 0,
  187. 0,
  188. 0
  189. );
  190. }
  191. }
  192. HeapFree(GetProcessHeap(), 0, Table);
  193. ClearToEnd(Coord, End);
  194. End = Coord;
  195. } while (WaitForSingleObject(StopEvent, DisplayInterval) != WAIT_OBJECT_0);
  196. if (LogFile) { fclose(LogFile); }
  197. NtClose(TcpipHandle);
  198. CloseHandle(ConsoleHandle);
  199. return 0;
  200. }
  201. void
  202. DisplayUsage(
  203. void
  204. )
  205. {
  206. printf("tcbmon [-?] [-refresh <ms>] [-log <path> <session>\n");
  207. printf("\t<session> = <local endpoint> <remote endpoint>\n");
  208. printf("\t<endpoint> = <address> { <port> | * }\n");
  209. }
  210. void
  211. DisplayTcbHelp(
  212. void
  213. )
  214. {
  215. printf("tcbmon: TCB Help\n");
  216. printf("tcb fields:\n");
  217. printf("\tsenduna = seq. of first unack'd byte\n");
  218. printf("\tsendnext = seq. of next byte to send\n");
  219. printf("\tsendmax = max. seq. sent so far\n");
  220. printf("\tsendwin = size of send window in bytes\n");
  221. printf("\tunacked = number of unack'd bytes\n");
  222. printf("\tmaxwin = max. send window offered\n");
  223. printf("\tcwin = size of congestion window in bytes\n");
  224. printf("\tmss = max. segment size\n");
  225. printf("\trtt = timestamp of current rtt measurement\n");
  226. printf("\tsmrtt = smoothed rtt measurement\n");
  227. printf("\trexmitcnt = number of rexmit'd segments\n");
  228. printf("\trexmittimer = rexmit timer in ticks\n");
  229. printf("\trexmit = rexmit timeout last computed\n");
  230. printf("\tretrans = total rexmit'd segments (all sessions)\n");
  231. printf("\tstate = connection state\n");
  232. printf("\tflags = connection flags (see below)\n");
  233. printf("\trto = real-time rto (compare rexmit)\n");
  234. printf("\tdelta = rtt variance\n");
  235. printf("\n");
  236. printf("flags:\n");
  237. printf("\t00000001 = window explicitly set\n");
  238. printf("\t00000002 = has client options\n");
  239. printf("\t00000004 = from accept\n");
  240. printf("\t00000008 = from active open\n");
  241. printf("\t00000010 = client notified of disconnect\n");
  242. printf("\t00000020 = in delayed action queue\n");
  243. printf("\t00000040 = completing receives\n");
  244. printf("\t00000080 = in receive-indication handler\n");
  245. printf("\t00000100 = needs receive-completes\n");
  246. printf("\t00000200 = needs to send ack\n");
  247. printf("\t00000400 = needs to output\n");
  248. printf("\t00000800 = delayed sending ack\n");
  249. printf("\t00001000 = probing for path-mtu bh\n");
  250. printf("\t00002000 = using bsd urgent semantics\n");
  251. printf("\t00004000 = in 'DeliverUrgent'\n");
  252. printf("\t00008000 = seen urgent data and urgent data fields valid\n");
  253. printf("\t00010000 = needs to send fin\n");
  254. printf("\t00020000 = using nagle's algorithm\n");
  255. printf("\t00040000 = in 'TCPSend'\n");
  256. printf("\t00080000 = flow-controlled (received zero-window)\n");
  257. printf("\t00100000 = disconnect-notif. pending\n");
  258. printf("\t00200000 = time-wait transition pending\n");
  259. printf("\t00400000 = output being forced\n");
  260. printf("\t00800000 = send pending after receive\n");
  261. printf("\t01000000 = graceful-close pending\n");
  262. printf("\t02000000 = keepalives enabled\n");
  263. printf("\t04000000 = processing urgent data inline\n");
  264. printf("\t08000000 = inform acd about connection\n");
  265. printf("\t10000000 = fin sent since last retransmit\n");
  266. printf("\t20000000 = unack'd fin sent\n");
  267. printf("\t40000000 = need to send rst when closing\n");
  268. printf("\t80000000 = in tcb table\n");
  269. }
  270. int __cdecl
  271. main(
  272. int argc,
  273. char* argv[]
  274. )
  275. {
  276. LONG i;
  277. IO_STATUS_BLOCK IoStatus;
  278. OBJECT_ATTRIBUTES ObjectAttributes;
  279. NTSTATUS Status;
  280. HANDLE ThreadHandle;
  281. ULONG ThreadId;
  282. UNICODE_STRING UnicodeString;
  283. for (i = 1; i < argc; i++) {
  284. if (lstrcmpi(argv[i], "-?") == 0 || lstrcmpi(argv[i], "/?") == 0) {
  285. DisplayUsage();
  286. return 0;
  287. } else if (lstrcmpi(argv[i], "-tcbhelp") == 0) {
  288. DisplayTcbHelp();
  289. return 0;
  290. } else if (lstrcmpi(argv[i], "-refresh") == 0 && (i + 1) >= argc) {
  291. DisplayInterval = atol(argv[++i]);
  292. if (!DisplayInterval) {
  293. DisplayUsage();
  294. return 0;
  295. }
  296. } else if (lstrcmpi(argv[i], "-log") == 0) {
  297. if ((i + 5) >= argc) {
  298. DisplayUsage();
  299. return 0;
  300. }
  301. LogPath = argv[++i];
  302. LogLocal.sin_addr.s_addr = inet_addr(argv[++i]);
  303. if (lstrcmpi(argv[i+1], "*") == 0) {
  304. LogLocal.sin_port = 0; ++i;
  305. } else {
  306. LogLocal.sin_port = htons((SHORT)atol(argv[++i]));
  307. }
  308. LogRemote.sin_addr.s_addr = inet_addr(argv[++i]);
  309. if (lstrcmpi(argv[i+1], "*") == 0) {
  310. LogRemote.sin_port = 0; ++i;
  311. } else {
  312. LogRemote.sin_port = htons((SHORT)atol(argv[++i]));
  313. }
  314. if (LogLocal.sin_addr.s_addr == INADDR_NONE ||
  315. LogRemote.sin_addr.s_addr == INADDR_NONE) {
  316. DisplayUsage();
  317. return 0;
  318. }
  319. }
  320. }
  321. StopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  322. ConsoleHandle =
  323. CreateConsoleScreenBuffer(
  324. GENERIC_READ|GENERIC_WRITE,
  325. FILE_SHARE_READ|FILE_SHARE_WRITE,
  326. NULL,
  327. CONSOLE_TEXTMODE_BUFFER,
  328. NULL
  329. );
  330. SetConsoleActiveScreenBuffer(ConsoleHandle);
  331. GetConsoleScreenBufferInfo(ConsoleHandle, &ConsoleInfo);
  332. ConsoleInfo.dwSize.Y = 1000;
  333. SetConsoleScreenBufferSize(ConsoleHandle, ConsoleInfo.dwSize);
  334. RtlInitUnicodeString(&UnicodeString, DD_TCP_DEVICE_NAME);
  335. InitializeObjectAttributes(
  336. &ObjectAttributes,
  337. &UnicodeString,
  338. OBJ_CASE_INSENSITIVE,
  339. NULL,
  340. NULL
  341. );
  342. Status =
  343. NtCreateFile(
  344. &TcpipHandle,
  345. GENERIC_EXECUTE,
  346. &ObjectAttributes,
  347. &IoStatus,
  348. NULL,
  349. FILE_ATTRIBUTE_NORMAL,
  350. FILE_SHARE_READ|FILE_SHARE_WRITE,
  351. FILE_OPEN_IF,
  352. 0,
  353. NULL,
  354. 0
  355. );
  356. if (!NT_SUCCESS(Status)) {
  357. printf("NtCreateFile: %x\n", Status);
  358. return 0;
  359. }
  360. ThreadHandle =
  361. CreateThread(
  362. NULL,
  363. 0,
  364. DisplayThread,
  365. NULL,
  366. 0,
  367. &ThreadId
  368. );
  369. CloseHandle(ThreadHandle);
  370. getchar();
  371. SetEvent(StopEvent);
  372. return 0;
  373. }