**Purpose** This page is dedicated to the asyncroneous socket connect, started by 'socket -async'. See the [socket] page for a general description. It also serves as communication page for development and compares current TCL 8.5.15, TCL 8.6.1 and future versions. Async connect got more complicated in TCL 8.6, as multiple destination IPs are internally supported (due to IPV6 or DNS lookup resulting in multiple IPs). **Command behaviour** ***socket -async*** 'socket -async' ''host'' first does a syncroneous DNS lookup. Then the connect is started as background process. * In TCL8.5, this terminates without any interaction by background processes. * In TCL8.6, the event loop or command invocation is required to check multiple IPs. %|Version|Status|% &|8.5.15|ok|& &|8.5.16+|ok|& &|8.6.1 unix|ok, requires event loop|& &|8.6.1 win|only first IP (broken)|& &|8.6.2+|ok, requires event loop|& &|ideas|may be moved in own thread to not require event loop and not to pause between connect tries|& ***update,vwait*** Starting the event loop allows in TCL8.6 to continue with the next try or to fail finally ***close on error*** As a start point for all other commands: if a failed async connect socket is not closed after the first reported error, bad things like unreported errors etc. may happen. ''Please'' close an async socket connect after the first reported error. ***fileevent writable*** Fires when async connect terminates with success or error. %|Version|Status|% &|8.5.15|ok, see bugs|& &|8.5.16+|ok|& &|8.6.1 win|only first IP (broken)|& &|8.6.1 unix|ok|& &|8.6.2+|ok|& An installed writable fileevent assures also that pending flushs are executed on connect (see todo section). ****Warning**** The event even fires, if the error is already reported. This may lead to a miss of the error. Windows TCL 8.5 had the bug to report connect errors many times: ====== % set h [socket -async localhost 30001] sock472 % fileevent $h writable {puts WE:[fconfigure $h -error];close $h} % read $h error reading "sock448": connection refused WE:connection refused ====== which is fixed in TCL8.6.2+: ====== % set h [socket -async localhost 30001] sock01A49DA8 % fileevent $h writable {puts WE:[fconfigure $h -error];close $h} % read $h error reading "sock01A49DA8": connection refused WE: ====== ***fileevent readable*** Fires when async connect terminates with error. %|Version|Status|% &|8.5.15 unix|ok|& &|8.5.15 win|only works when also writable event installed, see bugs|& &|8.5.16+|ok|& &|8.6.1 win|only first IP and only with writable event (broken)|& &|8.6.1 unix|ok|& &|8.6.2+|ok|& ***blocking gets,read,puts,flush*** Remark: a puts may be delayed to a following flush. The async connect is terminated syncroneously. On success, the operation is performed. On connect failure, the connect error is returned by this command and cleared. Thus, the error is not reported again by ''fconfigure -error''. A second call will return "socket is not connected". %|Version|Status|% &|8.5.15 unix|ok|& &|8.5.15 win|ok. Small bug, that only the error "socket is not connected" is returned.|& &|8.5.16+ unix|ok|& &|8.5.16+|ok. Small bug still present which is acceptable|& &|8.6.1 win|only first IP tested (broken).|& &|8.6.1 unix|ok|& &|8.6.2+|ok|& ***non blocking gets,read,puts,flush*** Remark: a puts may be delayed to a following flush. The async connect state is checked or continued (next IP) in a non-blocking way. Possible results: %|Number|Condition|Action|% &|NB1|async connect still in progress|write operation is buffered and sheduled for background flush.<
>Read operation returns empty string|& &|NB2|async connect succeeded|operation is directly executed|& &|NB3|async connect failed|connect error (if first call after fail) or error "socket is not connected" is returned|& Implementation status: %|Version|Status|% &|8.5.15 unix|?|& &|8.5.15 win|ok. Small bug that NB3 returns directly "socket is not connected"|& &|8.5.16+ unix|?|& &|8.5.16+ win|ok. Small bug that NB3 returns directly "socket is not connected" which is acceptable|& &|8.6.1 win|only first IP (broken)|& &|8.6.1 unix|?|& &|8.6.2+ win|ok|& &|8.6.2+ unix|?|& ***close*** A close while connection is in progress or after a succesful connection should succeed. A close after a failed connection succeeds. If a background flush is pending (or already resulted in an error), an error may be shown %|Version|Status|% &|8.5.15 unix|?|& &|8.5.15 win|ok|& &|8.5.16+ unix|?|& &|8.5.16+ win|ok|& &|8.6.1 unix|?|& &|8.6.1 win|ok|& &|8.6.2+|ok|& ***eof*** eof should be active: * After a read on a socket closed from the other side. * never active with async sockets and may not be used to detect the connection status %|Version|Status|% &|8.5.15|ok|& &|8.5.16+|ok|& &|8.6.1|ok|& &|8.6.2+|ok|& ***fconfigure*** Any fconfigure command on the socket continues the connect process. %|Version|Status|% &|8.6.1 win|no|& &|8.6.1 unix|no|& &|8.6.2+|ok|& ***fconfigure -error*** A final connect error should be returned by 'fconfigure -error'. No error should be flagged while connection is running. Implementation status: %|Version|Status|% &|8.5.15 unix|ok.|& &|8.5.15 win|ok. Small bug: Failed socket connect error is reported indefinitely|& &|8.5.16+ unix|ok.|& &|8.5.16+ win|ok. Small bug: Failed socket connect error is reported indefinitely|& &|8.6.1 win|result of first tested IP (broken)|& &|8.6.1 unix|The errors of all tested IPs show temporarely up|& &|8.6.2+|ok|& To fix the small bug, that a connect error is repeated indefinitively may introduce compatibility issues of programs which rely on that. Example TCL 8.5: ======tcl # no server on 30001 % set h [socket -async localhost 30001] sock448 % read $h error reading "sock448": socket is not connected % fconfigure $h -error connection refused % fconfigure $h -error connection refused ====== and TCL 8.6.2+: ======tcl # no server on 30001 % set h [socket -async localhost 30001] sock448 % read $h error reading "sock448": connection refused % fconfigure $h -error ====== ***fconfigure -sockname*** My own IP of the socket connection. Returns list of IP, Name, Port. Since IPV6, this value may change within connect tries from "127.0.0.1" to "::1". Also the port may change. Implementation status: %|Version|Status|% &|8.5.15 win|returns "0.0.0.0 0.0.0.0 51063"|& &|8.5.16+|?|& &|8.6.1 win|returns ":: :: 51070" if first try is IPV6, otherwise an IP V4 address|& &|8.6.1 unix|?|& &|8.6.2+|?|& Idea (see TIP): The connection process should not be reflected. A compatibility value or an error should returned while connecting. If we reflect the connection process, we would have issues later, if we would push the connect process to an own thread. ***fconfigure -peername*** The destination IP. Returns list of IP, Name, Port. Since IPV6, this value may change within connect tries. Also the port may change (if auto). Implementation status: %|Version|Status|% &|8.5.15 win|returns information of tried IP while connecting. Error if connection failed|& &|8.5.16+|?|& &|8.6.1 win|returns information of first tried IP. Error if first connect try failed|& &|8.6.1 unix|reflects connection process|& &|8.6.2+|?|& Idea (see TIP): The connection process should not be reflected. A compatibility value or an error should returned while connecting. **TIPs** ***Behaviour of fconfigure -peername, -sockname, -error, -connecting*** A discussion tip on the behaviour of those commands while connecting was drafted. A new option '-connecting' should return 1 if connection is still in process. Reason for that: there are use cases for socket -async without event loop. Example: Within Web-Server verify multiple servers for connectivity. Open many sockets in the background, do some other calculations, check if connect terminated by "-connecting". ***fconfigure -errorno*** A possibility to return the full POSIX information of a background error was drafted. Two possible solutions: * fconfigure -errordict: returns a dict as 'catch {} e d' * fconfigure -invokeerror: throws the stored background error or does nothing if no error present **Bugs** ***Win TCL8.6.1 only tries first IP*** [https://core.tcl.tk/tcl/tktview?name=13d3af3ad5%|%Bug 13d3af3ad5%|%] TCL8.6.1 only tries the first of eventual multiple IP addresses to connect. This may cause serious connect issues with IPV6. This is fixed in branch [https://core.tcl.tk/tcl/timeline?r=bug-13d3af3ad5&unhide%|%bug-13d3af3ad5%|%] which also serves as main branch to fix all bugs in TCL8.6.1 and to test enhancements too. ***Win connect ignored*** [https://core.tcl.tk/tcl/info/336441ed59%|%Bug 336441ed59%|%] When a connect terminates to quick so the notifier is not ready yet, the connect is ignored and thus it waits forever for it. %|Version|Status|% &|8.5.15|bug present|& &|8.5.16+|fixed|& &|8.6.1|bug present|& &|8.6.2+|fixed in branch [https://core.tcl.tk/tcl/timeline?r=bug-13d3af3ad5&unhide%|%bug-13d3af3ad5%|%]|& Test is timing dependent and may ignore issue on some machines. ***Empty error message on close on failed background flush*** [https://core.tcl.tk/tcl/info/97069ea11a%|%Bug 97069ea11a%|%] %|Version|Status|% &|8.5.15|bug present|& &|8.5.16+|fixed|& &|8.6.1|bug present|& &|8.6.2+|fixed|& <> Test proposal The test is difficult, as an async connect must fail after a puts is issued on the channel. Idea: write a dummy channel driver, which may be set to an error state by fconfigure -seterror and where the readbale/writable state may be set. So one could: ======tcl set h [open dummy] fconfigure $h -seterror EWOULDBLOCK fileevent $h writable {set x writable} fconfigure $h -blocking 0 puts $h abc fconfigure $h -setwritable 1 vwait x catch {close $h} e d ====== <> ***No readable event on async socket connect failure*** [https://core.tcl.tk/tcl/info/581937ab1e%|%Bug 581937ab1e%|%] %|Version|Status|% &|8.5.15 win|bug present|& &|8.5.16+ win|Fixed|& &|8.6.1 win|bug present|& &|8.6.2+ win|Fixed in [https://core.tcl.tk/tcl/timeline?r=bug-13d3af3ad5&unhide%|%bug-13d3af3ad5%|%]|& **ToDo's** ***Clarify demanded functionality*** * What returns fconfigure -peername,-sockname ? ***prioritize connect errors and return most appropriate*** If a socket connect fails, the error in the latest connect stage should be returned. This would prioritize "access denied" (e.g. socket in use) before "network unreachable" (no route). Project stage for Win and Unix. This is already implemented for Unix server sockets. ***TclWinGetSockOpt() stubs entry may return wrong state*** The Win TCL stubs table contains an entry for '''TclWinGetSockOpt()''' which returns the info from '''getsockopt()'''. In TCL8.5, the result of '''fconfigure -error''' was always the return value of the system call '''getsockopt()'''. In TCL8.6, a connect failure is cached in a variable and returned by '''fconfigure -error'''. Eventually, this should also be done by the routine called by the '''TclWinGetSockOpt''' stubs entry. The purpose of this stub entry seams to be from the times of Windows 98 where a WinSock2.dll may not be present. There are no known usage of this. Thus it was decided to leave it as depreciated and to remove it for Tcl9.0. ***Inform driver about a flush which may happen now*** If a write is pending on connection, it should be sent when the socket is connected. At the moment, this happens internally, if a writable event is installed. In the communication of the framework and the driver, it should be clarified, that the information "writable now" is also passed when there is no writable event. Thus the code: ======tcl set h [connect -async far-away-host 30001] fconfigure $h -blocking 0 puts $h Hi flush $h after 10000 {set x 1} vwait x ====== should send the data autmatically when the socket connects within the vwait. <>Tcl syntax | Arts and crafts of Tcl-Tk programming | Command | Networking | Channel