2
0

WMTCPTracker.Mod 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. MODULE WMTCPTracker; (** AUTHOR "pjm"; PURPOSE "Watch TCP connections"; *)
  2. (* 21.11.2002 - tf : rewritten to use grid component... *)
  3. (* 11.01.2004 - tf : rewritten to use string grid, added discard button *)
  4. IMPORT
  5. Modules, Commands, WMStandardComponents,
  6. IP, TCP, Kernel, WMRestorable, WMMessages,
  7. WMWindowManager, WMGraphics, WMComponents,
  8. Messages := WMMessages, Strings, WMGrids, WMStringGrids;
  9. CONST
  10. Running = 0; Closing = 1; Closed = 2; (* states *)
  11. TYPE
  12. Closer = OBJECT
  13. VAR c: TCP.Connection;
  14. PROCEDURE &Init*(c: TCP.Connection);
  15. BEGIN
  16. SELF.c := c
  17. END Init;
  18. BEGIN {ACTIVE}
  19. c.Close
  20. END Closer;
  21. Discarder = OBJECT
  22. VAR c: TCP.Connection;
  23. PROCEDURE &Init*(c: TCP.Connection);
  24. BEGIN
  25. SELF.c := c
  26. END Init;
  27. BEGIN {ACTIVE}
  28. c.Discard
  29. END Discarder;
  30. ConnectionArray = POINTER TO ARRAY OF TCP.Connection;
  31. Window = OBJECT (WMComponents.FormWindow)
  32. VAR grid : WMStringGrids.StringGrid;
  33. delay : LONGINT;
  34. timer : Kernel.Timer;
  35. state : LONGINT;
  36. currentIndex, nofConnections : LONGINT;
  37. currentList : ConnectionArray;
  38. colWidth : WMGrids.Spacings;
  39. selectedConnection : TCP.Connection;
  40. detailPanel : WMStandardComponents.Panel;
  41. closeBtn, discardBtn : WMStandardComponents.Button;
  42. PROCEDURE CreateForm(): WMComponents.VisualComponent;
  43. VAR
  44. panel : WMStandardComponents.Panel;
  45. toolbar: WMStandardComponents.Panel;
  46. cBtn, dBtn : WMStandardComponents.Button;
  47. BEGIN
  48. NEW(panel); panel.bounds.SetExtents(800, 400);
  49. panel.takesFocus.Set(TRUE);
  50. NEW(toolbar); toolbar.fillColor.Set(000FF00FFH); toolbar.bounds.SetHeight(20);
  51. toolbar.alignment.Set(WMComponents.AlignBottom);
  52. panel.AddContent(toolbar);
  53. detailPanel := toolbar;
  54. NEW(cBtn); cBtn.caption.SetAOC("Close selected connection (think 2x !)");
  55. cBtn.bounds.SetWidth(panel.bounds.GetWidth() DIV 2);
  56. cBtn.alignment.Set(WMComponents.AlignLeft);
  57. toolbar.AddContent(cBtn);
  58. cBtn.clDefault.Set(0FF0000FFH);
  59. SELF.closeBtn := cBtn;
  60. NEW(dBtn); dBtn.caption.SetAOC("Discard selected connection (think 2x !)");
  61. dBtn.bounds.SetWidth(panel.bounds.GetWidth() DIV 2);
  62. dBtn.alignment.Set(WMComponents.AlignLeft);
  63. toolbar.AddContent(dBtn);
  64. dBtn.clDefault.Set(0FF0000FFH);
  65. SELF.discardBtn := dBtn;
  66. NEW(grid); grid.alignment.Set(WMComponents.AlignClient);
  67. panel.AddContent(grid);
  68. RETURN panel
  69. END CreateForm;
  70. PROCEDURE &New*(delay : LONGINT; c : WMRestorable.Context);
  71. VAR str : ARRAY 256 OF CHAR;
  72. i, dx, dy, minWidth : LONGINT;
  73. vc : WMComponents.VisualComponent;
  74. f : WMGraphics.Font;
  75. BEGIN
  76. SELF.delay := delay;
  77. NEW(timer);
  78. NEW(currentList, 16 * 1024);
  79. vc := CreateForm();
  80. Init(vc.bounds.GetWidth(), vc.bounds.GetHeight(), FALSE);
  81. SetContent(vc);
  82. f := WMGraphics.GetFont("Oberon", 12, {});
  83. grid.fixedCols.Set(4); grid.fixedRows.Set(1);
  84. grid.SetSelectionMode(WMGrids.GridSelectSingleRow);
  85. grid.Acquire;
  86. grid.model.Acquire;
  87. grid.model.SetNofCols(33);
  88. grid.model.SetNofRows(1);
  89. NEW(colWidth, 33);
  90. f.GetStringSize("-999999999", minWidth, dy);
  91. FOR i := 0 TO 33 - 1 DO
  92. GetTitleStr(i, str);
  93. f.GetStringSize(str, dx, dy);
  94. colWidth[i] := MAX(dx + 4, minWidth);
  95. grid.model.SetCellText(i, 0, Strings.NewString(str));
  96. grid.model.SetTextAlign(i, 0, WMGraphics.AlignCenter);
  97. END;
  98. f.GetStringSize("999.999.999.999:99999", dx, dy); colWidth[0] := dx + 4;
  99. f.GetStringSize("SynReceived", dx, dy); colWidth[2] := dx + 4;
  100. f.GetStringSize("999.999.999.999", dx, dy); colWidth[3] := dx + 4;
  101. grid.SetColSpacings(colWidth);
  102. grid.model.Release;
  103. grid.Release;
  104. grid.onClick.Add(Click);
  105. detailPanel.visible.Set(FALSE);
  106. closeBtn.onClick.Add(CloseConnection);
  107. discardBtn.onClick.Add(DiscardConnection);
  108. IF c # NIL THEN WMRestorable.AddByContext(SELF, c)
  109. ELSE WMWindowManager.DefaultAddWindow(SELF)
  110. END;
  111. SetTitle(Strings.NewString("TCP Tracker"));
  112. SetIcon(WMGraphics.LoadImage("WMIcons.tar://WMTCPTracker.png", TRUE));
  113. ScanConnections;
  114. grid.SetTopPosition(3, 1, TRUE);
  115. state := Running
  116. END New;
  117. PROCEDURE GetTitleStr(col: LONGINT; VAR x : ARRAY OF CHAR);
  118. BEGIN
  119. CASE col OF
  120. |0 : COPY("Remote", x)
  121. |1 : COPY("Local Port", x)
  122. |2 : COPY("State", x)
  123. |3 : COPY("Local IP", x)
  124. |4 : COPY("Idle", x)
  125. |5 : COPY("RecvAdv", x)
  126. |6 : COPY("SendNext", x)
  127. |7 : COPY("SendBuf", x)
  128. |8 : COPY("SendFree", x)
  129. |9 : COPY("SendWnd", x)
  130. |10 : COPY("SendCWnd", x)
  131. |11 : COPY("RecvFree", x)
  132. |12 : COPY("RecvWnd", x)
  133. |13 : COPY("RecvHW", x)
  134. |14 : COPY("SendUnack", x)
  135. |15 : COPY("SendMax", x)
  136. |16 : COPY("RTSN", x)
  137. |17 : COPY("WUSAN", x)
  138. |18 : COPY("RecvNext", x)
  139. |19 : COPY("WUSSN", x)
  140. |20 : COPY("LASN", x)
  141. |21 : COPY("SRTT", x)
  142. |22 : COPY("DupAcks", x)
  143. |23 : COPY("ReXmitT", x)
  144. |24 : COPY("Backoff", x)
  145. |25 : COPY("RTT", x)
  146. |26 : COPY("RTTVar", x)
  147. |27 : COPY("RTTMin", x)
  148. |28 : COPY("MaxSeg", x)
  149. |29 : COPY("ISS", x)
  150. |30 : COPY("IRS", x)
  151. |31 : COPY("SSThresh", x)
  152. |32 : COPY("Track", x)
  153. ELSE COPY("", x);
  154. END
  155. END GetTitleStr;
  156. PROCEDURE Click(sender, data : ANY);
  157. BEGIN
  158. IF (data # NIL) & (data IS TCP.Connection) (* & (data(TCP.Connection).state # TCP.Listen)*) THEN
  159. selectedConnection := data(TCP.Connection);
  160. detailPanel.visible.Set(TRUE)
  161. ELSE detailPanel.visible.Set(FALSE)
  162. END
  163. END Click;
  164. PROCEDURE CloseConnection(sender, data : ANY);
  165. VAR tc : TCP.Connection;
  166. killer : Closer;
  167. BEGIN
  168. tc := selectedConnection;
  169. IF tc # NIL THEN
  170. NEW(killer, tc);
  171. selectedConnection := NIL;
  172. detailPanel.visible.Set(FALSE)
  173. END
  174. END CloseConnection;
  175. PROCEDURE DiscardConnection(sender, data : ANY);
  176. VAR tc : TCP.Connection;
  177. killer : Discarder;
  178. BEGIN
  179. tc := selectedConnection;
  180. IF tc # NIL THEN
  181. NEW(killer, tc);
  182. selectedConnection := NIL;
  183. detailPanel.visible.Set(FALSE)
  184. END
  185. END DiscardConnection;
  186. PROCEDURE GetAlign(col : LONGINT) : LONGINT;
  187. BEGIN
  188. CASE col OF
  189. 0..3 : RETURN WMGraphics.AlignCenter;
  190. ELSE RETURN WMGraphics.AlignRight
  191. END
  192. END GetAlign;
  193. PROCEDURE StateToString(state : LONGINT; VAR str : ARRAY OF CHAR);
  194. BEGIN
  195. CASE state OF
  196. TCP.Closed: COPY("Closed", str)
  197. |TCP.Listen: COPY("Listen", str)
  198. |TCP.SynSent: COPY("SynSent", str)
  199. |TCP.SynReceived: COPY("SynReceived", str)
  200. |TCP.Established: COPY("Established", str)
  201. |TCP.CloseWait: COPY("CloseWait", str)
  202. |TCP.FinWait1: COPY("FinWait1", str)
  203. |TCP.Closing: COPY("Closing", str)
  204. |TCP.LastAck: COPY("LastAck", str)
  205. |TCP.FinWait2: COPY("FinWait2", str)
  206. |TCP.TimeWait: COPY("TimeWait", str)
  207. ELSE COPY("Unknown", str)
  208. END
  209. END StateToString;
  210. PROCEDURE GetConnectionStr(x, col: LONGINT; VAR str : ARRAY OF CHAR);
  211. VAR c : TCP.Connection;
  212. t : ConnectionArray;
  213. s : ARRAY 64 OF CHAR;
  214. BEGIN
  215. t := currentList; (* to prevent problems with not yet implemented shrinking *)
  216. COPY("", str);
  217. IF x < LEN(t) THEN
  218. c := t[x];
  219. IF c # NIL THEN
  220. CASE col OF
  221. |0 : IP.AdrToStr(c.fip, str); Strings.Append(str, ":"); Strings.IntToStr(c.fport, s); Strings.Append(str, s)
  222. |1 : Strings.IntToStr(c.lport, str)
  223. |2 : StateToString(c.state, str)
  224. |3 : IF c.int # NIL THEN IP.AdrToStr(c.int.localAdr, str); ELSE COPY("n/a", str); END;
  225. |4: Strings.IntToStr(c.idle, str)
  226. |5 : Strings.IntToStr(c.rcvadv - c.irs, str)
  227. |6 : Strings.IntToStr(c.sndnxt - c.iss, str)
  228. |7: Strings.IntToStr(c.sndcc, str)
  229. |8 : Strings.IntToStr(c.sndspace, str)
  230. |9 : Strings.IntToStr(c.sndwnd, str)
  231. |10 : Strings.IntToStr(c.sndcwnd, str)
  232. |11 : Strings.IntToStr(c.rcvspace, str)
  233. |12 : Strings.IntToStr(c.rcvwnd, str)
  234. |13 : Strings.IntToStr(c.rcvhiwat, str)
  235. |14: Strings.IntToStr(c.snduna - c.iss, str)
  236. |15 : Strings.IntToStr(c.sndmax - c.iss, str)
  237. |16 : Strings.IntToStr(c.rtseq - c.iss, str)
  238. |17 : Strings.IntToStr(c.sndwl2 - c.iss, str)
  239. |18 : Strings.IntToStr(c.rcvnxt - c.irs, str)
  240. |19 : Strings.IntToStr(c.sndwl1 - c.irs, str)
  241. |20 : Strings.IntToStr(c.lastacksent - c.irs, str)
  242. |21 : Strings.IntToStr(c.srtt, str)
  243. |22 : Strings.IntToStr(c.dupacks, str)
  244. |23 : Strings.IntToStr(c.rxtcur, str)
  245. |24 : Strings.IntToStr(c.rxtshift, str)
  246. |25 : Strings.IntToStr(c.rtt, str)
  247. |26 : Strings.IntToStr(c.rttvar, str)
  248. |27 : Strings.IntToStr(c.rttmin, str)
  249. |28 : Strings.IntToStr(c.maxseg, str)
  250. |29 : Strings.IntToStr(c.iss, str)
  251. |30 : Strings.IntToStr(c.irs, str)
  252. |31 : Strings.IntToStr(c.sndssthresh, str)
  253. |32 : Strings.IntToStr(c.traceflow, str)
  254. ELSE
  255. END
  256. END;
  257. END
  258. END GetConnectionStr;
  259. PROCEDURE AddConnection(c : TCP.Connection);
  260. VAR t : ConnectionArray; i : LONGINT;
  261. BEGIN
  262. IF currentIndex >= LEN(currentList) THEN (* grow the list *)
  263. NEW(t, LEN(currentList) * 2); FOR i := 0 TO currentIndex - 1 DO t[i] := currentList[i] END;
  264. currentList := t
  265. END;
  266. currentList[currentIndex] := c;
  267. INC(currentIndex)
  268. END AddConnection;
  269. PROCEDURE ScanConnections;
  270. BEGIN {EXCLUSIVE}
  271. currentIndex := 0;
  272. TCP.pool.Enumerate(AddConnection);
  273. nofConnections := currentIndex
  274. END ScanConnections;
  275. PROCEDURE Update;
  276. VAR i, j : LONGINT; s : Strings.String;
  277. BEGIN
  278. ScanConnections;
  279. grid.model.Acquire;
  280. grid.model.SetNofRows(nofConnections + 1);
  281. FOR i := 0 TO nofConnections - 1 DO
  282. FOR j := 0 TO 33 - 1 DO
  283. s := grid.model.GetCellText(j, i + 1); (* recycle the string *)
  284. IF s = NIL THEN NEW(s, 64) END;
  285. GetConnectionStr(i, j, s^);
  286. grid.model.SetTextAlign(j, i + 1, GetAlign(j));
  287. grid.model.SetCellData(j, i + 1, currentList[i]);
  288. grid.model.SetCellText(j, i + 1, s)
  289. END
  290. END;
  291. grid.model.Release;
  292. END Update;
  293. PROCEDURE Join;
  294. BEGIN {EXCLUSIVE}
  295. AWAIT(state = Closed)
  296. END Join;
  297. PROCEDURE Close; (* override *)
  298. BEGIN
  299. BEGIN {EXCLUSIVE}
  300. IF state = Running THEN state := Closing END; (* multiple calls possible *)
  301. timer.Wakeup
  302. END;
  303. FreeWindow;
  304. Close^
  305. END Close;
  306. PROCEDURE Handle(VAR x: WMMessages.Message);
  307. BEGIN
  308. IF (x.msgType = WMMessages.MsgExt) & (x.ext # NIL) THEN
  309. IF (x.ext IS WMRestorable.Storage) THEN
  310. x.ext(WMRestorable.Storage).Add("WMTCPTracker", "WMTCPTracker.Restore", SELF, NIL)
  311. ELSE Handle^(x)
  312. END
  313. ELSE Handle^(x)
  314. END
  315. END Handle;
  316. BEGIN {ACTIVE}
  317. WHILE state = Running DO
  318. Update; grid.Invalidate(); timer.Sleep(delay)
  319. END;
  320. BEGIN {EXCLUSIVE} state := Closed END
  321. END Window;
  322. VAR window : Window;
  323. PROCEDURE FreeWindow;
  324. BEGIN {EXCLUSIVE}
  325. window := NIL
  326. END FreeWindow;
  327. PROCEDURE Open*(context : Commands.Context); (** [ms] *)
  328. VAR delay: LONGINT;
  329. BEGIN
  330. IF TCP.pool # NIL THEN
  331. IF ~context.arg.GetInteger(delay, FALSE) OR (delay < 1) THEN delay := 250 END; (* default delay *)
  332. BEGIN {EXCLUSIVE}
  333. IF window = NIL THEN NEW(window, delay, NIL)
  334. ELSE WMWindowManager.DefaultBringToView(window, TRUE)
  335. END
  336. END
  337. ELSE context.error.String("TCP.pool = NIL"); context.error.Ln;
  338. END;
  339. END Open;
  340. PROCEDURE Restore*(context : WMRestorable.Context);
  341. BEGIN{EXCLUSIVE}
  342. IF window = NIL THEN
  343. NEW(window, 250, context)
  344. ELSE
  345. WMWindowManager.DefaultBringToView(window, TRUE)
  346. END;
  347. END Restore;
  348. PROCEDURE Close*;
  349. VAR w: Window;
  350. BEGIN
  351. BEGIN {EXCLUSIVE} w := window END; (* avoid race between Join call and FreeWindow *)
  352. IF w # NIL THEN w.Close; w.Join END;
  353. END Close;
  354. PROCEDURE Cleanup;
  355. BEGIN
  356. Close;
  357. END Cleanup;
  358. BEGIN
  359. window := NIL;
  360. Modules.InstallTermHandler(Cleanup)
  361. END WMTCPTracker.
  362. System.Free WMTCPTracker WMStringGrids
  363. WMTCPTracker.Open 250
  364. TestServer.Open
  365. TestServer.Close
  366. WMTCPTracker.Close ~