Welcome, guest | Sign In | My Account | Store | Cart

A simlpe Telnet Client Class utilizing Todd Martin's telnet package available at http://www.tmartin.org/tcltelnet .

Tcl, 152 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package require Itcl 3.3
package require telnet 2.0.0

itcl::class TelnetClient {
    public variable host ""
    public variable port 23
    public variable user "admin"
    public variable password "password"
    public variable timeout 10
    public variable debug 0
    private variable my_sock ""

    private variable out_buffer ""
    public variable xwait ""
    common xtimeout 
    
    constructor {args} {}
    destructor {
        disconnect
    }
    
    public method connect {args}
    public method send {args}
    public method disconnect {}
    private method get_data {}
    private method wait_complete {}
    private method timeout {}
    private method reset_timeout {}
    private method wait_or_timeout {}
}

# Lowercase access procedure
proc telnetclient {args} {
    uplevel ::TelnetClient $args
}

itcl::body TelnetClient::constructor {args} {
    eval configure $args
    
    if {($ip == "") || ($port == "")} {
        error "IP and Port must be specified"
    }
}

itcl::body TelnetClient::connect {args} {
    if {![catch {telnet::open $host $port} conn]} {
        set my_sock $conn
        fconfigure $my_sock -blocking false -buffering none -translation auto -eofchar {}
        flush $my_sock
        fileevent $my_sock readable [itcl::code $this get_data]
        wait_or_timeout
        if {[regexp -nocase {(username|login|user)\s?:} $out_buffer]} {
            set login [send "$user"]
            if {[regexp -nocase {(password)\s?:} $login]} {
                set passdRes [send "$password"]
                if {[regexp {(.>)} $passdRes]} {
                    return 0
                } else {
                    close $conn
                    error "Error: Unexpected System Prompt"
                }
            } else {
                close $conn
                error "Error: Unexpectd Password Prompt"
            }
        } else {
            close $conn
            error "Error: Unexpected Login Prompt"
        }
        
    } else {
        error "Error: Connection Refused"
    }
}

itcl::body TelnetClient::get_data {} {
    if {[eof $my_sock]} {
        close $my_sock
        set connected 0
    } else {
        if {![catch {telnet::read  $my_sock} data]} {
            switch -regexp $data {
                # Add login and password patterns as needed
                {([Uu]sername|[Ll]ogin|[Pp]assword)\s?:} {
                    append out_buffer $data
                    wait_complete
                    return
                }
                # Change this value to your Telnet Prompt
                {.>} {
                    append out_buffer $data
                    wait_complete
                    return
                }
                default {
                    append out_buffer $data
                    reset_timeout
                }
            }
        } else {
            wait_complete
            close $mySocked
            return
        }
    }
}

itcl::body TelnetClient::timeout {} {
    catch {after cancel $xwait}
    set xtimeout($this) 1
    puts "Timeout of after [expr {$timeout * 1000}] seconds"
    return
}

itcl::body TelnetClient::wait_or_timeout {} {
    set xwait [after [expr {$timeout * 1000}] [itcl::code $this timeout]]
    vwait [itcl::scope xtimeout($this)]
    return
}

itcl::body tti::TelnetClient::reset_timeout {} {
    catch {after cancel $xwait}
    set xwait [after [expr {$timeout * 1000}] [itcl::code $this timeout]]
    return
}
itcl::body TelnetClient::wait_complete {} {
    catch {after cancel $xwait} wres
    set xtimeout($this) 1
    return
}

itcl::body TelnetClient::send {data} {
    
    set out_buffer ""
    if {![eof $my_sock]} {
        if {![catch {telnet::write $my_sock "$data\r"} err]} {
            flush $my_sock
            fileevent $my_sock readable [itcl::code $this get_data]
            wait_or_timeout
            return $out_buffer
        } else {
            error "$err"
        }
    } else {
        error "Error: Connection Closed"
    }

}

itcl::body TelnetClient::disconnect {} {
    catch { close $my_sock }
}

Useful when wrapping an existing client with Expect is too slow or not convinient due to the limitations with Expect and 64 bit apps in Windows.

To use the client create a telnet client object:

set tn1 [telnetclient #auto -host 192.168.165.100 -user user -password password]

Open the conncetion to the telnet server $tn1 connect

Send a command to to be executed. The result of the command is returned or an error.

set commandResult [$tn1 send "systeminfo"]

Close the connection to the telnet server $tn1 disconnect

1 comment

Rich Kaminski 17 years, 3 months ago  # | flag

Should this recipe work as is? I would like to use this code, but I can not get it to work.

I notice the value of "$data" is empty when telneting to the windows xp machine and then the script closes the telnet session.

Any thoughts?

Created by Flavio Salgueiro on Fri, 25 Aug 2006 (MIT)
Tcl recipes (162)
Flavio Salgueiro's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks