?
Solved

Indy IDTelnet Freezes with no error message in Delphi 7

Posted on 2005-03-08
8
Medium Priority
?
3,180 Views
Last Modified: 2008-02-07
I am writing an application to automate some work I do with Cisco Switches.  The easiest way to get data off the switches is by Telnet, so I am using Delphi and Indy's IDTelnet component.

I can connect and get the data I need off the switches - but when I disconnect, my application hangs with no error message.

I have written a component to do the IDTelnet handling, it appears to freeze whenever Disconnect is called.  I have written a test application that just calls TSwitchReader.Connect, and then TSwitchReader.Disconnect - even this freezes.

Any ideas?

I am running Delphi 7.

type
  TSwitchReader = class(TComponent)
  private
    fTelnet         : TIdTelnet;
    fLogonList      : TStringList;
    fLogon          : Boolean;
    fCurrentCommand : String;

    procedure TelnetStatus(ASender: TObject; const AStatus: TIdStatus;
      const AStatusText: String);
    procedure TelnetDataAvailable(Sender: TIdTelnet; const Buffer: String);
    procedure TelnetConnected(Sender: TObject);
    procedure TelnetDisconnected(Sender: TObject);

    function GetLast(Text: String): String;
  protected
    fBuffer: String;
    fCommandEnd: String;
    fEnablePassword: String;
    fHost: String;
    fTelnetPassword: String;

    fOnCompleted: TCompletedEvent;
    fOnConnected: TNotifyEvent;
    fOnDisconnected: TNotifyEvent;
    fOnStatus: TStatusChangeEvent;

    procedure SetHost(Value: String);
  public
    constructor Create(Owner: TComponent); override;
    destructor Destroy; override;

    procedure Connect;
    procedure Disconnect;
    procedure DoCommand(Command: String);
  published
    property EnablePassword: String read fEnablePassword write fEnablePassword;
    property Host: String read fHost write SetHost;
    property TelnetPassword: String read fTelnetPassword write fTelnetPassword;

    property OnCompleted: TCompletedEvent read fOnCompleted write fOnCompleted;
    property OnConnected: TNotifyEvent read fOnConnected write fOnConnected;
    property OnDisconnected: TNotifyEvent read fOnDisconnected write fOnDisconnected;
    property OnStatus: TStatusChangeEvent read fOnStatus write fOnStatus;
  end;

implementation

constructor TSwitchReader.Create;
begin
  inherited;
  fTelnet := TIDTelnet.Create(Self);
  fLogonList := TStringList.Create;

  // Setup out instance of the Indy Telnet client
  fTelnet.OnStatus := TelnetStatus;
  fTelnet.OnDataAvailable := TelnetDataAvailable;
  fTelnet.OnConnected := TelnetConnected;
  fTelnet.OnDisconnected := TelnetDisconnected;
  fLogon := False;
end;

destructor TSwitchReader.Destroy;
begin
  // Free all items used!
  fTelnet.Free;
  fLogonList.Free;
  inherited;
end;

procedure TSwitchReader.TelnetStatus(ASender: TObject; const AStatus: TIdStatus;
  const AStatusText: String);
begin
  // Pass status from Indy Client to our event
  if Assigned(fOnStatus) then
    fOnStatus(Self, AStatus, AStatusText);
end;

procedure TSwitchReader.TelnetDataAvailable(Sender: TIdTelnet; const Buffer: String);
var
  newBuffer: String;
begin
  // Cisco puts --more-- breaks in its readouts, this often breaks up input and the buffer
  // sometimes starts with garbage - if this is the case, trim off non printable characters.
  if (Length(Buffer) > 0) then begin
    if (ord(Buffer[1]) < 32) then
      newBuffer := TrimLeft(Buffer)
    else
      newBuffer := Buffer;
  end;

  // If we get a --more-- break, remove it from the buffer and send a ' ' to continue output.
  if LowerCase(Trim(GetLast(newBuffer))) = '--more--' then begin
    newBuffer := Copy(newBuffer, 1, Length(newBuffer)-10);
    fTelnet.write(' ')
  end;

  // Append to overall buffer until this command is complete.
  fBuffer := fBuffer + newBuffer;

  // Logon process
  if (fLogon) and (fLogonList.Count = 1) then begin
    fLogonList.Delete(0);
    // Set the syntax for the end of command.
    fCommandEnd := Trim(GetLast(Buffer));
    // Kill buffer so we don't flag the end of a command.
    newBuffer := '';
    // We are now logged on
    fLogon := False;
    if Assigned(fOnConnected) then fOnConnected(Self);
  end;
 
  // More logon stuff
  if (fLogon) and (GetLast(Buffer) = 'Password: ') then begin
    if (fLogonList.Count > 0) then
      fLogonList.Delete(0);
    if (fLogonList.Count > 0) then
      DoCommand(fLogonList.Strings[0]);
  end;

  // Command finished send out OnCompleted event.
  if (fLogon = False) and (GetLast(newBuffer) = fCommandEnd) then begin
    // Strip out our own echo, and the switch prompt after command completed
    if (LeftStr(fBuffer,Length(fCurrentCommand)) = fCurrentCommand) then
      fBuffer := Copy(fBuffer, Length(fCurrentCommand) + 1, Length(fBuffer));
    fBuffer := Copy(fBuffer, 1, Length(fBuffer) - Length(fCommandEnd));
    if Assigned(fOnCompleted) then fOnCompleted(Self, fBuffer);
  end;
end;

procedure TSwitchReader.TelnetConnected(Sender: TObject);
begin
  // Order of logon is:
  // 1) Give Telnet password
  // 2) Enter enable mode
  // 3) Give Enable password

  fLogonList.Add(fTelnetPassword);
  fLogonList.Add('enable');
  fLogonList.Add(fEnablePassword);
  fLogon := True;

  // Start log on going
  DoCommand(fLogonList.Strings[0]);
end;

procedure TSwitchReader.TelnetDisconnected(Sender: TObject);
begin
  // Disconnected, signal our own event for this.
  if Assigned(fOnDisconnected) then
    fOnDisconnected(Self);
end;

function TSwitchReader.GetLast(Text: String): String;
var
  List: TStringList;
begin
  // Get last line of a large block of text.
  List := TStringList.Create;
  List.Text := Text;
  if List.Count > 0 then
    Result := List.Strings[List.Count-1];
  List.Free;
end;

procedure TSwitchReader.SetHost(Value: String);
begin
  fHost := Value;
  fTelnet.Host := Value;
end;

procedure TSwitchReader.Connect;
begin
  // Start Telnet Session
  fTelnet.Connect(0);
end;

procedure TSwitchReader.Disconnect;
begin
  if fTelnet.Connected then begin
    fTelnet.Disconnect;
  end;
end;

procedure TSwitchReader.DoCommand(Command: String);
begin
  // Clear our own buffer ready for Indy's buffer to be appended to.
  fBuffer := '';
  fCurrentCommand := Command;
  fTelnet.WriteLn(Command);
end;
0
Comment
Question by:SpannerBracket
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
8 Comments
 
LVL 13

Expert Comment

by:BlackTigerX
ID: 13490310
have you tried dropping a
IdAntiFreeze component in your form?
(Indy Misc tab)
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 13490925
trydoing
    IdTelnet1.Disconnect(True);  // as in Disconnect(AImmediate: boolean);
calling this overloaded method (doesn't appear to matter whether you specify true or false) calls an overloaded procedure instead

btw, are you using Indy 9, or 10, or latest snapshot?
0
 
LVL 1

Author Comment

by:SpannerBracket
ID: 13491421
How do I tell what version I have - I couldn't find it any of the source.  Either way, im downloading the latest 10.0.74 and will try with that.

Couldn't find much info on IdAntiFreeze - I created one in my component - should I have to do anything else with it?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:SpannerBracket
ID: 13491429
Oh,

when I tried calling Disconnect(True) - it wouldn't compile, error - too many parameters for procedure Disconnect.
0
 
LVL 17

Accepted Solution

by:
TheRealLoki earned 1500 total points
ID: 13492114
Rught click on your TIdTelnet and it will tell you in the "about"
Indy 10 still has bugs, but they say to use it because indy 9 has more bugs - up to you.
Also, a lot of things changed between 9 and 10
If you have other Indy apps uding Indy 9 (e.g. relyingon TCPServer etc) I'd recommend not upgrading unless you want to undergo the learning curve for changing those apps too.

FWIW, I'm using the latest Indy 10, and have tried updating the old Indy Telnet Demo, doing a connect to my cisco router, and disconnecting, and then closing the app, and it works ok
0
 
LVL 1

Author Comment

by:SpannerBracket
ID: 13493983
I found I had an old version of the Indy clients - so I removed them and installed the new version.  Had to uninstall the whole IDE in the end to get the new version to work properly.

I made the few changes needed to get the application working - but I now get errors about a Canvas, and get dropped out in IDTelnet.pas where the OnDataAvailable event is fired.  This is intermittent, sometimes it just works, but then I still get the freeze on disconnect.  On the few occasions it doesn't freeze, I cant close my application - Close, Application.Terminate do nothing, and Application.Destroy creates an error.

I imagine I am not using the IDTelnet component exactly how I should be, but I haven't time to troubleshoot such random errors, so I am going to try moving to the ICS telnet component instead.

Thanks for your help, Ill award the poitns anyway, as Ive learned a lot more about Indy clients!
0
 
LVL 17

Expert Comment

by:TheRealLoki
ID: 13498866
Did you take a look at the OnDataAVailable event in the Indy Telnet demo?
I admit I had trouble with their telnet until I used the demo as a base for my app.
btw, I much prefer ICS too :-D
0
 
LVL 1

Author Comment

by:SpannerBracket
ID: 13503980
I must admit, I had trouble locating the demos, but I didn't spend a lot of time on it.  I got v frustrated on the Indy website as its not very well organized.

Last night I changed my component to use ICS telnet instead - it only needed minor modifications.  This works a treat with no freezes or errors!

I think me and Indy just dont mix!
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses
Course of the Month13 days, 17 hours left to enroll

801 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question