Scripting Telnet sessions using Java
This article will demonstrate how using the SSH Factory Telnet
component you can automate telnet commands in non-interactive (batch
mode) process. This is especially useful in scheduled jobs where
you want to log into a telnet server, execute one or more commands,
possibly evaluate the results of those commands and then logout
from the telnet server. To see what else SSH Factory has to offer
Download a FREE 30 day SSH Factory
Evaluation.
As a prerequisite to this article please see the article Telnet
using Java which explains the basic concepts of using the SSH Factory Telnet classes not covered in this article.
To execute telnet commands non-interactively you will need the
ability to programmatically send data to the telnet server and interpret
the results returned. For example to login to a telnet server the
following process is used:
- Wait for login prompt.
- Submit username to telnet server
- Wait for password prompt indicating that username has been
submitted.
- Submit password to telnet server.
- Wait for shell prompt indicating that login has completed.
This process is further explained using the screenshots below.
These screenshots show an example of logging into a telnet server
using an interactive telnet GUI client.

Figure 1. Login prompt

Figure 2. Password prompt

Figure 3. Shell prompt.
The above example screens contains three critical pieces of information
needed in scripting our telnet session. These are the login prompt,
password prompt and shell prompt which are "login:", "Password:"
and "[vglass@localhost vglass]$" respectively. Using this
information and the Telnet classes provided in SSH Factory you
can easily automate any Telnet session.
As a real world example we will take on the task of automating
the archival of data located on a server with telnet access. This
process is broken down into the following steps.
- Login to telnet server.
- Go to archive directory
- Create archive of all files in this directory ending with .log
extension
- Delete all files in this directory ending with Log extension
- Logout
At the end of this article is a source code example demonstrating
how to perform this task.
A TelnetScript consists of a set of tasks to be performed upon
establishing a connection with the telnet server. These tasks are
performed in the order that they are added to the TelnetScript instance
using the TelnetScript#addTask method. When creating a new TelnetScript
instance you must provide a Telnet instance to its constructor.
TelnetScript script = new TelnetScript(telnet);
TelnetTask task = new TelnetTask(startPrompt,command,endPrompt);
In a TelnetScript each task is represented by a TelnetTask. Each
TelnetTask has a lifecycle that indicates the current status of
the task. A TelnetTask starts off with a pending status,
moves to active, running and finally completed.
A pending TelnetTask is a task that is not yet eligible
for execution. This is usually due to the fact that other tasks
are in front of this task have not yet completed. For a TelnetTask
to move out of the pending state all other TelnetTask in front of
it must have a completed status.
An active TelnetTask is eligible for execution but is waiting
for a conditional set of data to be returned by the telnet server.
This conditional data is known as the startPrompt and is provided
in the constructor when creating a new TelnetTask. Typically the
startPrompt for a TelnetTask is the shell prompt displayed when
the telnet server is ready to accept more data.
A running TelnetTask is a task that is currently in progress
executing the command parameter provided in the TelnetTask constructor.
The command parameter represents the data to send to the telnet
server after it has encountered the startPrompt. A running TelnetTask
will continue to run until it encounters the endPrompt returned
by the telnet server. As with the startPrompt the endPrompt is typically
the shell prompt displayed when the telnet server is ready to accept
more data.
A completed TelnetTask is a task that has successfully sent
the command data provided in the constructor and has received the
endPrompt from the telnet server. Once a TelnetTask is completed
you can capture the data received in response to the command using
the TelnetTask#getResponse method. This will return all data sent
by the telnet server between the time the TelnetTask had a status
active and completed. Alternatively you can capture all data sent
by the Telnet server by overloading the TelnetAdapter#dataReceived
method or implementing the TelnetListener#dataReceived method.
It is very important that when creating a TelnetTask that you set
the startPrompt and endPrompt variables correctly. Since a TelnetTask
cannot start execution until the startPrompt is received a TelnetTask
could be stuck in an endless pending state if the incorrect startPrompt
is provided. As stated before the startPrompt is in most cases the
same as the shell prompt displayed after logging into the system.
On some systems the shell prompt will change based on the current
directory. In this case rather than provide the entire shell prompt
as a startPrompt you can provide just the right hand side of the
shell prompt that is unique.
For example:
Assume that the following shell prompt is displayed upon login:
[vglass@localhost vglass]$
Upon changing the directory to archive the shell prompt displays
the following:
[vglass@localhost archive]$
In this case only the last two characters of the shell prompt "]$"
remain the same. Assuming that all of our TelnetTask use the shell
prompt as the startPrompt and endPrompt variables we would set these
to be "]$"
For example:
To create a TelnetTask that issues the ls -al command you could
do the following:
String shellPropt = "]$";
String startPrompt = shellPrompt;
String endPrompt = shellPrompt;
String command = "Ls -al";
TelnetTask task = new TelnetTask(startPrompt, command, endPrompt);
// where script is a TelnetScript instance
script.addTask(task);
In some cases you may not know all the tasks to be run at design
time. For example you may want to create a TelnetTask dynamically
based on the output of a previously completed TelnetTask. In this
case you will need to provide a null value for the startPrompt of
the dynamic task to be executed.
For example:
String taskAResponse = taskA.getResponse();
// if response to taskA == "error" create new task
dynamically
if(taskAResponse.equals("error")) {
TelnetTask taskB = new TelnetTask(null,"rm *.txt",endPrompt);
script.addTask(taskB);
}
The source code below demonstrates a real-world example of how
to login to a telnet server and archive data. The process is as
follows:
- Login to telnet server.
- Go to archive directory.
- Create archive of all files in this directory ending with .log
extension
- Delete all files in this directory ending with .log extension
- Logout
001 /*
002 * @(#)TelnetScriptExample.java
003 *
004 * Copyright (c) 2001-2002 JScape
005 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
006 * All rights reserved.
007 *
008 * This software is the confidential and proprietary information of
009 * JScape. ("Confidential Information"). You shall not disclose such
010 * Confidential Information and shall use it only in accordance with
011 * the terms of the license agreement you entered into with JScape.
012 */
013
014 package com.jscape.inet.telnet;
015
016 import com.jscape.inet.telnet.*;
017
018 public class TelnetScriptExample extends TelnetAdapter {
019
020 private Telnet telnet = null;
021 private TelnetScript script = null;
022 private String hostname = "10.0.0.2";
023 private String loginPrompt = "login:";
024 private String login = "vglass";
025 private String passwordPrompt = "Password:";
026 private String password = "secret";
027 private String shellPrompt = "]$";
028
029
030 public TelnetScriptExample() {
031 // data used for establishing connection
032
033 // create new Telnet instance
034 telnet = new Telnet(hostname);
035
036 // register for events
037 telnet.addTelnetListener(this);
038 }
039
040 /**
041 * Creates all tasks and executes script
042 * @throws TelnetException
043 */
044 public void execute() throws TelnetException {
045 // create new script
046 script = new TelnetScript(telnet);
047
048 // build task to submit username
049 TelnetTask loginTask = new TelnetTask(loginPrompt,login,passwordPrompt);
050
051 // build task to submit password
052 TelnetTask passwordTask = new TelnetTask(passwordPrompt,password,shellPrompt);
053
054 // build task to execute change directory command
055 String cdCommand = "cd archive";
056 TelnetTask cdCommandTask = new TelnetTask(shellPrompt,cdCommand,shellPrompt);
057
058 // build task to execute tar command
059 String tarCommand = "tar -cvf archive.tar *.log";
060 TelnetTask tarCommandTask = new TelnetTask(shellPrompt,tarCommand,shellPrompt);
061
062 // build task to delete files after tar command completed
063 String delCommand = "rm *.log";
064 TelnetTask delCommandTask = new TelnetTask(shellPrompt,delCommand,shellPrompt);
065
066 // add all tasks to script
067 script.addTask(loginTask);
068 script.addTask(passwordTask);
069 script.addTask(cdCommandTask);
070 script.addTask(tarCommandTask);
071 script.addTask(delCommandTask);
072
073 // connect to Telnet server and execute all tasks associated with script
074 telnet.connect();
075
076 // wait until last task is complete
077 while(!delCommandTask.isComplete()) {
078 try {
079
080 Thread.sleep(1000);
081 } catch(Exception e) {}
082 }
083
084 // disconnect from server
085 telnet.disconnect();
086 }
087
088 /** Invoked when Telnet socket is connected.
089 * @see TelnetConnectedEvent
090 * @see Telnet#connect
091 */
092 public void connected(TelnetConnectedEvent event) {
093 System.out.println("Connected");
094 }
095
096 /**
097 * Invoked when Telnet socket is disconnected. Disconnect can
098 * occur in many circumstances including IOException during socket read/write.
099 * @see TelnetDisconnectedEvent
100 * @see Telnet#disconnect
101 */
102 public void disconnected(TelnetDisconnectedEvent event) {
103 System.out.println("Disconnected");
104 }
105
106
107 /**
108 * Invoked when <code>TelnetOption</code>
is requested by server.
109 * @param event a <code>DoOptionEvent</code>
110 * @see DoOptionEvent
111 * @see TelnetOption
112 */
113 public void doOption(DoOptionEvent event) {
114 telnet.sendWontOption(event.getOption());
115 }
116
117 /**
118 * Invoked when <code>TelnetOption</code>
is offered by server.
119 * @param event a <code>WillOptionEvent</code>
120 * @see WillOptionEvent
121 * @see TelnetOption
122 */
123 public void willOption(WillOptionEvent event) {
124 telnet.sendDontOption(event.getOption());
125 }
126
127 /**
128 * Invoked when data is received from Telnet server.
129 * @param event a <code>TelnetDataReceivedEvent</code>
130 * @see TelnetDataReceivedEvent
131 */
132 public void dataReceived(TelnetDataReceivedEvent event) {
133 System.out.print(event.getData());
134 }
135
136 /**
137 * Main method to execute this program
138 * @param args
139 */
140 public static void main(String[] args) {
141 try {
142 TelnetScriptExample example = new TelnetScriptExample();
143 example.execute();
144 } catch(Exception e) {
145 e.printStackTrace(System.out);
146 }
147 }
148 }
- Line 16. Add necessary import statements
- Lines 20-27. Initialize data variables.
- Lines 30-38. Constructor for TelnetScriptExample class. Creates
new Telnet instance and registers TelnetScriptExample class as
a listener for Telnet related events. Note that TelnetScriptExample
extends the TelnetAdapter method.
- Lines 44-46. Beginning of TelnetScriptExample#execute method
responsible for execution of tasks. A new TelnetScript is created.
- Line 49. A TelnetTask for handling the submission of username
to telnet server is created.
- Line 52. A TelnetTask for handling the submission of password
to telnet server is created.
- Line 56. A TelnetTask for handling change of directory to "archive"
directory is created.
- Line 60. A TelnetTask for handling the archival of all matching
files in "archive" directory is created.
- Line 64. A TelnetTask for handling deletion of all matching
files in "archive" directory is created.
- Lines 67-71. Tasks are added to TelnetScript in the order they
are to be run.
- Line 74. Connection to telnet server is made and tasks associated
with TelnetScript are run in the order they were added.
- Lines 77-82. Waits for last task to complete.
- Line 85. Disconnects from telnet server.
- Lines 92-94. Overloads TelnetAdapter#connected method to handle
TelnetConnectedEvent event.
- Lines 102-104. Overloads TelnetAdapter#disconnected method to
handle TelnetDisconnectedEvent event.
- Lines 113-125. Overloads TelnetAdapter#doOption and TelnetAdapter#willOption
methods to handle option negotiation with telnet server. Note:
This is an important section of code. Failure to properly handle
option negotiation will result in the inability to login to telnet
server. See Telnet
using Java for more information on option negotiation.
- Lines 132-135. Prints all data sent by telnet server to System.out
- Lines 140-147. main() method for running this program.
In this article you learned how to automate telnet commands in
a non-interactive (batch mode) process. The Telnet components in
SSH Factory make this easy removing the complexities of the Telnet
protocols. To see what else SSH Factory has to offer Download a FREE 30 day SSH Factory Evaluation.
|