Windows.TCP.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. (* Aos Runtime: TCP, Copyright 2005, Emil J. Zeller *)
  2. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  3. MODULE TCP; (** AUTHOR "pjm, mvt"; PURPOSE "TCP protocol"; *)
  4. IMPORT
  5. WSock32, Modules, Kernel, Streams, IP, Objects, KernelLog,SYSTEM;
  6. CONST
  7. Trace = FALSE;
  8. NilPort* = 0;
  9. (** Error codes *)
  10. Ok* = 0; ConnectionRefused* = 3701; NotConnected* = 3705; TimedOut* = 3704;
  11. (** TCP connection states *)
  12. (** TCP connection states *)
  13. NumStates* = 12; Closed* = 0; Listen* = 1; SynSent* = 2;
  14. SynReceived* = 3; Established* = 4; CloseWait* = 5; FinWait1* = 6;
  15. Closing* = 7; LastAck* = 8; FinWait2* = 9; TimeWait* = 10;
  16. Unused* = 11; (* no real state, only used in this implementation *)
  17. OpenStates* = {Listen, SynReceived, Established, CloseWait, FinWait1, FinWait2};
  18. ClosedStates* = {Unused, Closed, Closing, LastAck, TimeWait};
  19. HalfClosedStates* = ClosedStates + {FinWait1, FinWait2};
  20. FinStates* = {Unused, Closed, CloseWait, Closing, LastAck, TimeWait}; Timeout = 14;
  21. (*AckNow = 0; *) (* send Ack immediately *)
  22. (* DelAck = 1;*) (* send Ack, but try to delay it *)
  23. NoDelay = 2; (* don't delay packets tocoalesce (disable Nagle algorithm) *)
  24. DoKeepAlive = 3; (* enable keep-alive timer *)
  25. TYPE
  26. (** Connection object. NOTE: Only one process should access a Connection! *)
  27. Connection* = OBJECT (Streams.Connection)
  28. VAR
  29. (* assigned interface *)
  30. int-: IP.Interface;
  31. (* local protocol address *)
  32. lport-: LONGINT;
  33. (* foreign protocol address *)
  34. fip-: IP.Adr;
  35. fport-: LONGINT;
  36. state*: SHORTINT; (* TCP state *)
  37. (* send sequence *)
  38. sndnxt-: LONGINT; (* send next *)
  39. iss-: LONGINT; (* initial send sequence number *)
  40. (* receive sequence *)
  41. rcvnxt-: LONGINT; (* receive next *)
  42. irs-: LONGINT; (* initial receive sequence number *)
  43. socket: WSock32.Socket;
  44. sndwnd-: LONGINT; (* send window *)
  45. sndcwnd-: LONGINT; (* congestion-controlled window *)
  46. sndcc-: LONGINT; (* number of bytes in send buffer *)
  47. rcvwnd-: LONGINT; (* receive window *)
  48. srtt-: LONGINT; (* smoothed round trip time *)
  49. (* receiver: Receiver; *)
  50. (* sender: Sender; *)
  51. (* lip: IP.Adr; *)
  52. timeout: Objects.Timer;
  53. flags: SET;
  54. (* Initialization for internal use only. *)
  55. PROCEDURE & Init*;
  56. BEGIN
  57. state := Unused;
  58. socket := WSock32.InvalidSocket; (* NEW(inbuf,receive,send); *) (*NEW( receiver, SELF.receive ); *)
  59. (*NEW( sender, SELF.send ); *)
  60. END Init;
  61. (** Open a TCP connection (only use once per Connection instance).
  62. Use TCP.NilPort for lport to automatically assign an unused local port.
  63. *)
  64. PROCEDURE Open*( lport: LONGINT; fip: IP.Adr; fport: LONGINT; VAR res: LONGINT );
  65. VAR adr: WSock32.sockaddrIn; err: LONGINT; str: ARRAY 64 OF CHAR;
  66. BEGIN {EXCLUSIVE}
  67. IF Trace THEN
  68. KernelLog.Enter; KernelLog.String( "Open connection: lport=" ); KernelLog.Int( lport, 1 );
  69. KernelLog.String( " ,fip=" ); IP.AdrToStr( fip, str ); KernelLog.String( str );
  70. KernelLog.String( " ,fport=" ); KernelLog.Int( fport, 1 ); Report( SELF ); KernelLog.Exit;
  71. END;
  72. ASSERT ( (state = Unused) & (lport >= 0) & (lport < 10000H) & (fport >= 0) & (fport < 10000H) );
  73. IF (fip.usedProtocol # IP.IPv4) THEN
  74. KernelLog.String("TCP.Connection.Open: Warning: Connection to non-IPv4 host not supported!"); KernelLog.Ln;
  75. res := NotConnected;
  76. RETURN;
  77. END;
  78. IF socket = WSock32.InvalidSocket THEN
  79. socket := WSock32.socket( WSock32.AFINet, WSock32.SockStream, WSock32.IPProtoTCP );
  80. ASSERT ( socket # WSock32.InvalidSocket );
  81. pool.Add( SELF, SELF.Finalize )
  82. END;
  83. IF ~IP.IsNilAdr(fip) & (fport # NilPort) THEN (* active open (connect) *)
  84. IF Trace THEN KernelLog.Enter; KernelLog.String( "Active open" ); Report( SELF ); KernelLog.Exit; END;
  85. int := IP.InterfaceByDstIP( fip );
  86. SELF.lport := lport; SELF.fip := fip; SELF.fport := fport;
  87. IF lport # NilPort THEN
  88. adr.sinFamily := WSock32.PFINet; adr.sinAddr := 0;
  89. adr.sinPort := WSock32.htons( SHORT( lport ) );
  90. err := WSock32.bind( socket, adr, SIZEOF( WSock32.sockaddrIn ) );
  91. IF err # 0 THEN
  92. res := NotConnected; state := Closed; WSock32.DispError;
  93. RETURN
  94. END
  95. END;
  96. adr.sinFamily := WSock32.PFINet; (* SYSTEM.MOVE( ADDRESSOF( fip ), ADDRESSOF( adr.sinAddr ), 4 ); *)
  97. adr.sinAddr := (fip.ipv4Adr); adr.sinPort := WSock32.htons( SHORT( fport ) );
  98. err := WSock32.connect( socket, adr, SIZEOF( WSock32.sockaddrIn ) );
  99. IF err # 0 THEN
  100. res := NotConnected; WSock32.DispError; state := Closed;
  101. err := WSock32.closesocket( socket );
  102. ELSE res := Ok; state := Established; SetPortAndIp;
  103. END
  104. ELSE
  105. IF Trace THEN KernelLog.Enter; KernelLog.String( "Passive open" ); Report( SELF ); KernelLog.Exit; END;
  106. (* passive open (listen) *)
  107. ASSERT ( (fport = NilPort) & IP.IsNilAdr(fip));
  108. SELF.int := NIL; SELF.lport := lport; SELF.fip := IP.NilAdr;
  109. SELF.fport := NilPort; adr.sinFamily := WSock32.PFINet;
  110. adr.sinAddr := 0; adr.sinPort := WSock32.htons( SHORT( lport ) );
  111. err := WSock32.bind( socket, adr, SIZEOF( WSock32.sockaddrIn ) );
  112. IF err = 0 THEN err := WSock32.listen( socket, WSock32.SOMaxConn ) END;
  113. IF err # 0 THEN
  114. res := NotConnected; state := Closed;
  115. WSock32.DispError;
  116. ELSE
  117. SetPortAndIp; res := Ok; state := Listen
  118. END
  119. END;
  120. IF Trace THEN
  121. KernelLog.Enter; KernelLog.String( "Open connection, result = " ); ReportResult( res ); Report( SELF ); KernelLog.Exit;
  122. END;
  123. IF state = Established THEN (* receiver.Start*) END;
  124. END Open;
  125. (** Send data on a TCP connection. *)
  126. PROCEDURE Send*( CONST data: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT );
  127. VAR err : LONGINT;
  128. BEGIN
  129. ASSERT((ofs >= 0) & (ofs + len <= LEN(data)));
  130. IF state = Closed THEN res := NotConnected; RETURN
  131. ELSIF state = Closing THEN
  132. ELSE
  133. ASSERT ((*state = Established) & *) (socket # WSock32.InvalidSocket) );
  134. END;
  135. res := Streams.Ok;
  136. err := WSock32.send( socket, data[ofs], len, {} );
  137. IF (err < 0) OR ((err = 0) & (len > 0)) THEN
  138. KernelLog.String( "TCP.Send :" ); WSock32.DispError; res := NotConnected;
  139. END;
  140. END Send;
  141. (** Receive data on a TCP connection. The data parameter specifies the buffer. The ofs parameters specify the position in the buffer where data should be received (usually 0), and the size parameters specifies how many bytes of data can be received in the buffer. The min parameter specifies the minimum number of bytes to receive before Receive returns and must by <= size. The len parameter returns the number of bytes received, and the res parameter returns 0 if ok, or a non-zero error code otherwise (e.g. if the connection is closed by the communication partner, or by a call of the Close method). *)
  142. PROCEDURE Receive*( VAR data: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT );
  143. VAR ret: LONGINT;
  144. BEGIN
  145. ASSERT ( (ofs >= 0) & (ofs + size <= LEN( data )) & (min <= size) );
  146. len := 0; res := Streams.Ok;
  147. BEGIN {EXCLUSIVE}
  148. IF state = Closed THEN res := NotConnected; RETURN
  149. ELSIF state=CloseWait THEN res := Streams.EOF; RETURN
  150. END;
  151. END;
  152. IF socket = WSock32.InvalidSocket THEN res := NotConnected; RETURN
  153. END;
  154. IF (size = 0) OR ((min = 0) & (Available() = 0)) THEN res := Streams.Ok; RETURN
  155. END;
  156. REPEAT
  157. ret := WSock32.recv( socket, data[ofs], size, {} );
  158. IF ret > 0 THEN INC( len, ret ); INC(ofs, ret); DEC(size, ret); END;
  159. UNTIL (size <= 0) OR (len >= min) OR (ret <= 0);
  160. IF ret < 0 THEN
  161. IF Trace THEN KernelLog.String( "TCP.Receiver.Receive" ); WSock32.DispError; END;
  162. BEGIN {EXCLUSIVE}
  163. res := WSock32.shutdown( socket, WSock32.SDboth );
  164. res := WSock32.closesocket( socket );
  165. state := Closed; res := Streams.EOF
  166. END;
  167. ELSIF ret = 0 THEN (* connection has been gracefully shut down by remote side, otherwise recv would block *)
  168. IF Trace THEN
  169. KernelLog.Enter; KernelLog.String( "TCP.Connection.Receive, graceful shutdown by remote side " ); Report( SELF ); KernelLog.Exit;
  170. END;
  171. BEGIN {EXCLUSIVE}
  172. IF state = Established THEN res := WSock32.shutdown( socket, WSock32.SDReceive ); (* may not receive any more *) state := CloseWait;
  173. ELSIF state IN {FinWait1, FinWait2, Closing} THEN state := Closed; res := WSock32.shutdown( socket, WSock32.SDboth );
  174. res := WSock32.closesocket( socket ); socket := WSock32.InvalidSocket; pool.Remove( SELF );
  175. END;
  176. res := Streams.EOF
  177. END;
  178. IF Trace THEN
  179. KernelLog.Enter; KernelLog.String( "Receive Result " ); ReportResult( res );
  180. Report( SELF ); KernelLog.Exit;
  181. END;
  182. END;
  183. END Receive;
  184. (** Return connection state. *)
  185. PROCEDURE State*( ): LONGINT;
  186. BEGIN {EXCLUSIVE}
  187. RETURN state
  188. END State;
  189. PROCEDURE HandleTimeout;
  190. BEGIN {EXCLUSIVE}
  191. INCL( flags, Timeout )
  192. END HandleTimeout;
  193. PROCEDURE AwaitState*( good, bad: SET; ms: LONGINT; VAR res: LONGINT );
  194. BEGIN {EXCLUSIVE}
  195. IF ~(state IN (good + bad)) THEN
  196. IF ms # -1 THEN
  197. IF timeout = NIL THEN NEW( timeout ) END;
  198. Objects.SetTimeout( timeout, SELF.HandleTimeout, ms )
  199. END;
  200. EXCL( flags, Timeout );
  201. AWAIT( (state IN (good + bad)) OR (Timeout IN flags) );
  202. IF ms # -1 THEN Objects.CancelTimeout( timeout ) END
  203. END;
  204. IF state IN good THEN res := Ok
  205. ELSIF state IN bad THEN res := NotConnected
  206. ELSE res := TimedOut
  207. END
  208. END AwaitState;
  209. (** Close a TCP connection (half-close). *)
  210. PROCEDURE Close*;
  211. VAR res: LONGINT; closetimer: Objects.Timer; (* fof 070102 *)
  212. BEGIN {EXCLUSIVE}
  213. IF state = Closed THEN RETURN END;
  214. (*IF receiver # NIL THEN receiver.Terminate END; *)
  215. IF Trace THEN
  216. KernelLog.Enter; KernelLog.String( "TCP.Connection.Close, " ); Report( SELF ); KernelLog.Exit;
  217. END;
  218. (* ASSERT ( ((state = Listen) OR (state = Established) OR (state=Closing) ) & (socket # WSock32.InvalidSocket) ); *)
  219. IF socket # WSock32.InvalidSocket THEN
  220. IF state = CloseWait THEN
  221. res := WSock32.shutdown( socket, WSock32.SDboth );
  222. state := Closed; res := WSock32.closesocket( socket );
  223. socket := WSock32.InvalidSocket; pool.Remove( SELF );
  224. ELSIF state = Established THEN
  225. res := WSock32.shutdown( socket, WSock32.SDSend ); (* may not send any more *)
  226. state := FinWait1;
  227. NEW(closetimer);
  228. Objects.SetTimeout(closetimer,SELF.Close,5000); (* 5 seconds time for receiving rest of data, i.e. by calling Available etc. *) (* fof 070102 *)
  229. ELSIF state IN {FinWait1, FinWait2, Closing, TimeWait} THEN
  230. res := WSock32.shutdown( socket, WSock32.SDboth );
  231. res := WSock32.closesocket( socket );
  232. socket := WSock32.InvalidSocket; pool.Remove( SELF );
  233. state := Closed;
  234. ELSIF state = Listen THEN
  235. res := WSock32.shutdown( socket, WSock32.SDboth );
  236. state := Closed; res := WSock32.closesocket( socket );
  237. socket := WSock32.InvalidSocket; pool.Remove( SELF );
  238. END;
  239. IF Trace THEN KernelLog.Enter; KernelLog.String( "Close done." ); Report( SELF ); KernelLog.Exit; END;
  240. (* half-close: use shutdown? *)
  241. END;
  242. (*state := Closed*) (* fof 070102 *)
  243. END Close;
  244. PROCEDURE SetPortAndIp;
  245. VAR sockname: WSock32.sockaddrIn; lensockname: LONGINT; res: LONGINT;
  246. BEGIN
  247. lensockname := SIZEOF( WSock32.sockaddrIn );
  248. res := WSock32.getsockname( socket, sockname, lensockname );
  249. IF res = Ok THEN
  250. (* lip := sockname.sinAddr; *)
  251. lport := WSock32.ntohs( sockname.sinPort ); (* lip := WSock32.ntohl( lip ); *)
  252. END;
  253. lensockname := SIZEOF( WSock32.sockaddrIn );
  254. res := WSock32.getpeername( socket, sockname, lensockname );
  255. IF res = Ok THEN
  256. fip.usedProtocol := IP.IPv4;
  257. fip.ipv4Adr := sockname.sinAddr; fport := WSock32.ntohs( sockname.sinPort );
  258. END;
  259. IF Trace THEN KernelLog.Enter; KernelLog.String( "SetPortAndIp " ); Report( SELF ); KernelLog.Exit; END;
  260. END SetPortAndIp;
  261. (** Accept a client waiting on a listening connection. Blocks until a client is available or the connection is closed. *)
  262. PROCEDURE Accept*( VAR client: Connection; VAR res: LONGINT );
  263. VAR s: WSock32.Socket; adr: WSock32.sockaddrIn; adrlen: LONGINT;
  264. str: ARRAY 64 OF CHAR;
  265. BEGIN
  266. IF Trace THEN KernelLog.Enter; KernelLog.String( "Accepting connections" ); Report( SELF ); KernelLog.Exit; END;
  267. ASSERT ( (state = Listen) & (socket # WSock32.InvalidSocket) );
  268. adr.sinFamily := WSock32.PFINet; adrlen := SIZEOF( WSock32.sockaddrIn );
  269. s := WSock32.accept( socket, adr, adrlen ); (* blocks ! *)
  270. BEGIN {EXCLUSIVE}
  271. IF s # WSock32.InvalidSocket THEN
  272. NEW( client ); client.lport := NilPort;
  273. IF (adrlen = SIZEOF( WSock32.sockaddrIn )) &
  274. (adr.sinFamily = WSock32.PFINet) THEN
  275. client.fip.usedProtocol := IP.IPv4;
  276. client.fip.ipv4Adr := adr.sinAddr; (* WSock32.ntohl( adr.sinAddr ); *)
  277. client.fport := WSock32.ntohs( adr.sinPort )
  278. ELSE client.fip := IP.NilAdr; client.fport := NilPort
  279. END;
  280. client.int := IP.InterfaceByDstIP( client.fip );
  281. pool.Add( client, client.Finalize ); client.socket := s;
  282. client.state := Established; res := Ok; client.SetPortAndIp;
  283. (*client.receiver.Start; *)
  284. IF Trace THEN
  285. KernelLog.Enter; KernelLog.String( "Accepted connection: client lport=" ); KernelLog.Int( client.lport, 1 );
  286. KernelLog.String( " ,fip=" ); IP.AdrToStr( client.fip, str );
  287. KernelLog.String( str ); KernelLog.String( " ,fport=" );
  288. KernelLog.Int( client.fport, 1 ); Report( SELF ); KernelLog.Exit;
  289. END;
  290. ELSE client := NIL; res := ConnectionRefused
  291. END;
  292. END;
  293. END Accept;
  294. PROCEDURE DelaySend*( enable: BOOLEAN );
  295. BEGIN {EXCLUSIVE}
  296. IF enable THEN EXCL( flags, NoDelay ); ELSE INCL( flags, NoDelay ); END;
  297. END DelaySend;
  298. PROCEDURE KeepAlive*( enable: BOOLEAN );
  299. BEGIN {EXCLUSIVE}
  300. IF enable THEN INCL( flags, DoKeepAlive ); ELSE EXCL( flags, DoKeepAlive ); END;
  301. END KeepAlive;
  302. PROCEDURE Discard*;
  303. BEGIN
  304. (* SetState( Closed ); *) Close; (* ConnectionFinalizer( SELF ); *)
  305. END Discard;
  306. PROCEDURE Requested*( ): BOOLEAN;
  307. BEGIN {EXCLUSIVE}
  308. RETURN FALSE;
  309. END Requested;
  310. PROCEDURE Available*( ): LONGINT;
  311. VAR ret, res: LONGINT; fdset: WSock32.FDSet;
  312. data: ARRAY 256 OF CHAR;
  313. BEGIN (* {EXCLUSIVE} *)
  314. (* IF Trace THEN KernelLog.String("available: "); KernelLog.Int(receiver.Available(),1); KernelLog.Ln END; *)
  315. ret := WSock32.ioctlsocket( socket, WSock32.FIONRead, res );
  316. IF ret # 0 THEN KernelLog.String( "TCP.Available " ); WSock32.DispError; END;
  317. IF res = 0 THEN (* check socket for shutdown *)
  318. fdset.fdcount := 1; fdset.socket[0] := socket;
  319. (* KernelLog.String("select..."); *)
  320. ret := WSock32.select( 0, fdset, NIL , NIL , selectTimeout );
  321. IF ret = 1 THEN (* nothing available but we can receive, try it: *)
  322. (* KernelLog.Enter; KernelLog.String( " Available: trying to receive " ); KernelLog.Exit; *)
  323. res := WSock32.recv( socket, data, 256, {1} );
  324. IF res = 0 THEN
  325. BEGIN {EXCLUSIVE}
  326. IF state = Established THEN state := CloseWait; res := WSock32.shutdown( socket, WSock32.SDReceive ); (* may not receive any more *)
  327. ELSIF state IN {FinWait1, FinWait2, Closing} THEN
  328. state := Closed; res := WSock32.shutdown( socket, WSock32.SDboth ); res := WSock32.closesocket( socket );
  329. socket := WSock32.InvalidSocket; pool.Remove( SELF );
  330. END;
  331. END;
  332. IF Trace THEN
  333. KernelLog.Enter; KernelLog.String( "TCP.Connection.Available: graceful shutdown by remote side." ); Report( SELF ); KernelLog.Exit;
  334. END;
  335. ELSIF res < 0 THEN
  336. IF Trace THEN KernelLog.String( "TCP.Receiver.Receive: " ); WSock32.DispError; END;
  337. res := 0;
  338. BEGIN {EXCLUSIVE}
  339. state := CloseWait;
  340. END;
  341. END;
  342. END;
  343. END;
  344. RETURN res;
  345. END Available;
  346. (* Finalize the Connection object *)
  347. PROCEDURE Finalize( ptr: ANY );
  348. VAR res: LONGINT;
  349. BEGIN {EXCLUSIVE}
  350. IF Trace THEN KernelLog.Enter; KernelLog.String( "TCP.Finalize " ); Report( SELF ); KernelLog.Exit; END;
  351. ASSERT ( ptr = SELF );
  352. IF socket # WSock32.InvalidSocket THEN
  353. res := WSock32.shutdown( socket, WSock32.SDboth );
  354. res := WSock32.closesocket( socket );
  355. (* ASSERT ( res = 0 ); *)
  356. socket := WSock32.InvalidSocket;
  357. (* pool.Remove(SELF) *) (* done outside !*)
  358. END;
  359. state := Unused
  360. END Finalize;
  361. END Connection;
  362. VAR
  363. pool*: Kernel.FinalizedCollection; (* pool of all Connections *)
  364. selectTimeout: WSock32.TimeVal;
  365. PROCEDURE Init;
  366. BEGIN
  367. NEW( pool ); NEW(selectTimeout); (* zero *)
  368. END Init;
  369. PROCEDURE Finalize( obj: ANY; VAR cont: BOOLEAN );
  370. BEGIN
  371. obj( Connection ).Finalize( obj ); cont := TRUE
  372. END Finalize;
  373. PROCEDURE Cleanup;
  374. BEGIN
  375. pool.Enumerate( Finalize )
  376. END Cleanup;
  377. PROCEDURE ReportState( state: LONGINT );
  378. BEGIN
  379. KernelLog.String( "State=" );
  380. CASE state OF
  381. Closed:
  382. KernelLog.String( "Closed" )
  383. | Listen:
  384. KernelLog.String( "Listen" );
  385. | SynSent:
  386. KernelLog.String( "SynSent" );
  387. | SynReceived:
  388. KernelLog.String( "SynReceived" );
  389. | Established:
  390. KernelLog.String( "Established" );
  391. | CloseWait:
  392. KernelLog.String( "CloseWait" );
  393. | FinWait1:
  394. KernelLog.String( "FinWait1" );
  395. | FinWait2:
  396. KernelLog.String( "FinWait2" );
  397. | TimeWait:
  398. KernelLog.String( "TimeWait" );
  399. | Unused:
  400. KernelLog.String( "Unused" );
  401. ELSE KernelLog.String( "????" );
  402. END;
  403. END ReportState;
  404. PROCEDURE Report( c: Connection );
  405. VAR str: ARRAY 64 OF CHAR;
  406. BEGIN
  407. KernelLog.String( " [lport=" ); KernelLog.Int( c.lport, 1 ); KernelLog.String( " ,fip=" );
  408. IP.AdrToStr( c.fip, str ); KernelLog.String( str ); KernelLog.String( " ,fport=" );
  409. KernelLog.Int( c.fport, 1 ); KernelLog.String( "," ); ReportState( c.state );
  410. KernelLog.String( "]" );
  411. END Report;
  412. PROCEDURE ReportResult( res: LONGINT );
  413. BEGIN
  414. IF res = Ok THEN KernelLog.String( "Ok" );
  415. ELSIF res = ConnectionRefused THEN KernelLog.String( "ConnectionRefused" )
  416. ELSIF res = NotConnected THEN KernelLog.String( "NotConnected" )
  417. ELSIF res = TimedOut THEN KernelLog.String( "TimedOut" );
  418. ELSIF res = Streams.EOF THEN KernelLog.String( "Streams.EOF" );
  419. ELSE KernelLog.String( "Unknown result code=" ); KernelLog.Int( res, 1 );
  420. END;
  421. END ReportResult;
  422. BEGIN
  423. Init; Modules.InstallTermHandler( Cleanup )
  424. END TCP.
  425. state diagram in this version of TCP very much simplified (rest done by Windows):
  426. either
  427. closed -> Listen -> Established -> CloseWait | FinWait1 -> Closed
  428. or
  429. closed -> Established -> CloseWait | FinWait1 -> Closed