# Read the greeting a server sends UNPROMPTED on connect, with a real timeout. # # Deliberately not xinetd-client.tcl: that one is shaped around request/response # (send a payload, read the answer), and every service it drives stays silent # until spoken to. SSH is the other shape -- RFC 4253 has the server send its # version string first, before the client says anything -- so the useful probe # here sends nothing at all and just reads. Keeping it separate also means the # openssh suite does not break if the xinetd suite is ever retired. # # busybox nc on this image is the minimal applet (no -w), so a server that holds # the connection open would hang the suite with no way to bound it; tcl's # socket + a bounded [after] is what makes this safe to run against a daemon # that may be half-working. # # argv: [timeout-ms] # prints exactly one line: # RESULT connfail -- connect() failed (nothing is listening) # RESULT ok banner= -- connected; first line, CR/LF stripped # RESULT ok banner= -- connected but the server said nothing in time proc onread {s} { if {[eof $s]} { set ::done 1; return } append ::buf [read $s] if {[string first "\n" $::buf] >= 0} { set ::done 1 } } set port [lindex $argv 0] set ms [lindex $argv 1] if {$ms eq ""} { set ms 5000 } if {[catch {set s [socket 127.0.0.1 $port]} err]} { puts "RESULT connfail $err" exit 0 } fconfigure $s -translation binary -blocking 0 -buffering none set ::buf "" set ::done 0 fileevent $s readable [list onread $s] set t [after $ms {set ::done 1}] vwait ::done after cancel $t catch {close $s} set line [lindex [split $::buf "\n"] 0] puts "RESULT ok banner=[string map {"\r" "" "\n" ""} $line]"