Bug 194473 - [telnet] Telnet should handle invalid prompt character more gracefully
Summary: [telnet] Telnet should handle invalid prompt character more gracefully
Status: NEW
Alias: None
Product: Target Management
Classification: Tools
Component: RSE (show other bugs)
Version: 2.0   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: dsdp.tm.rse-inbox CLA
QA Contact: Martin Oberhuber CLA
URL:
Whiteboard:
Keywords: helpwanted
Depends on: 186570
Blocks:
  Show dependency tree
 
Reported: 2007-06-26 14:31 EDT by Martin Oberhuber CLA
Modified: 2012-11-19 04:56 EST (History)
1 user (show)

See Also:


Attachments
Read with timeout: tThe modified and original files (12.88 KB, application/octet-stream)
2012-05-23 04:11 EDT, jose ferreiro CLA
no flags Details
Read with timeout + my local settings (2.85 KB, patch)
2012-05-23 07:00 EDT, jose ferreiro CLA
no flags Details | Diff
Read with timeout + my local settings + no prompt wait (3.48 KB, patch)
2012-05-28 16:03 EDT, jose ferreiro CLA
no flags Details | Diff
patch v3 (5.14 KB, patch)
2012-05-30 11:04 EDT, Martin Oberhuber CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Oberhuber CLA 2007-06-26 14:31:19 EDT
+++ This bug was initially created as a clone of Bug #186570 +++

Create a Telnet connection.

On the connection properties page, specify a "prompt" character that does not happen to match the prompt character on the remote side; for instance, keep the default "$" character and connect to a remote side using a tcsh default shell.

--> The telnet connection tries connecting without success, no useful error
    message is given when it finally fails.
--> When right-click > Launch shell was done, even the entire Eclipse IDE
    is blocked (see also bug #186569).

I think that the following enhancements are needed:

1. During the login sequence in TelnetConnectorService, all prompts from the
   remote side should be recorded for user feedback and problem reporting.
   f connect is unsuccessful for any reason, a dialog should be opened
   ("Connect unsuccessful. Remote side said:") 
   in order to allow users fix the issue. The text for the dialog can be
   handled via a SystemMessageException, I think.

2. The entire login sequence should have a user-configurable timeout (via
   the PropertySet). If the expected pattern for login/password/prompt is 
   not received until the timeout, connect should be canceled and the 
   error message (1) should be shown.

3. The default PROMPT expected should be more fuzzy. Tyipcal systems prompt
   with any character like #>%$ -- all of these should be allowed. In the 
   PropertySet, either the special value AUTO should be used for this fallback,
   or a regular expression should be allowed to be able and pass multiple
   possible prompts.

4. (Optional) The TelnetConnectorService should be able to connect if the 
   prompt is received even if login: and password: were not queried. This 
   would allow for more successful logins even if the user doesn't configure
   the PropertySet properly. Especially in case the PROMPT is set to AUTO,
   any from the prompt characters can be matched at any time even before 
   login: or password: were matched.

The default prompt is not fault tolerant enough yet. Many people will have
different login prompts, so they will never get the "connected" status.
At the very least, a regular expression like [#>%$] should be used to check
for the prompt. Or, don't use a prompt by default at all and consider the
connection connected already. Actually, this might be a solution for (1)
as well -- show the entire login sequence in the shell being launched,
and being very tolerant by allowing the "connected" status almost 
unconditionally.
Comment 1 Martin Oberhuber CLA 2012-02-01 13:05:03 EST
Promoting to Major since it makes configuring and connecting a telnet connection practically impossible for anyone whose system doesn't send the expected prompt.

See also bug 251484 for problems with empty passwords.
Comment 2 jose ferreiro CLA 2012-04-12 09:03:09 EDT
I have resolved this introducing a inread_withtime() rutine that uses in.available before calling in.read(). The file is TelnetConnectorService.java at org.eclipse.rse.connectorservice.telnet


int read_withtime(InputStream in)  {
		long millisToEnd = System.currentTimeMillis() + 1000;
		try {
			while (System.currentTimeMillis()<millisToEnd)
			{
				if (in.available()>0)
					return in.read();
				else
					Thread.sleep(100);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}	
		return -1;
	}

Then, change in.read() for read_withtime(InputStream in)
Comment 3 Martin Oberhuber CLA 2012-05-22 14:41:12 EDT
Jose, could you attach your fix as a patch ?

Then I would try getting it in for 3.4RC2.

Ideally, could you also fix the "empty password" issue bug 251484 on the way ?
Comment 4 jose ferreiro CLA 2012-05-23 04:11:02 EDT
Created attachment 216097 [details]
Read with timeout: tThe modified and original files
Comment 5 jose ferreiro CLA 2012-05-23 04:13:19 EDT
Sorry, I do not know how to make the patch. I look for it on help and found "Team - Create patch" but I am not able to find this option in my view. 

I attach a zip with the original and modified files. If you can direct me to create the patch, I will try.

About the bug 251484, I already posted in it. This same file have my 'work around'. I was not able to get the system to read the local configuration, so I change the default values to that on my system.
Comment 6 Martin Oberhuber CLA 2012-05-23 06:31:34 EDT
Hello Jose,

for creating a patch here's what you do:

1.) Get the respective plugin out of Eclipse CVS HEAD:
    :pserver:dev.eclipse.org:/cvsroot/tools
    org.eclipse.tm.rse/plugins/org.eclipse.rse.subsystems.shells.telnet

2.) Apply your changes
3.) Right-click on project, Team > Create Patch : Save to File .

Let me know if you find issues, or check this page for more information :
http://wiki.eclipse.org/TM_and_RSE_FAQ#Working_on_TM_.2F_RSE

Getting your contribution in the form of a patch would be important in order to properly do the IP review.
Comment 7 jose ferreiro CLA 2012-05-23 07:00:18 EDT
Created attachment 216115 [details]
Read with timeout + my local settings

Perfect. It was there all the time :)

The patch includes my local default for the other bug. As I said, I was not able to do the reload local configuration thing on the Telnet connector.
Comment 8 Martin Oberhuber CLA 2012-05-23 12:27:47 EDT
Thanks for the patch - I just tried it - but I'm afraid it doesn't make the situation a lot better.

With Commons Net 3.1 at least, I could still quickly make the Workbench deadlock.
From a quick investigation, it looks like the Commons Net implementation of
TelnetInputStream.available() tries reading from the Socket and that never returns (so in some sense the Commons Net implementation of TelnetInputStream#available() is broken).

The TelnetConnectorService#loginTelnetClient() method has a hardcoded timeout
of 60 seconds, during which it tries to join() the LoginThread (so after 60 seconds it should return even if Commons Net messes up) but that also
somehow fails for me.

I think that at a minimum the telnet timeout should be configurable and it should tell me that it is busy rather than deadlocking my entire workbench (the nested event loop in TelnetConnectorService is also bad).

Over all, it looks just profoundly broken.
Comment 9 jose ferreiro CLA 2012-05-24 03:20:41 EDT
I do not understand anything :(. I changed the default prompt to $ to force the timeout and see if it locks my workbench (i think i can remeber it did not hung a month ago). But, to my surprise, I connect to my device without problems.

A month ago, eclipse was not using the local configuration Telnet set. Now it uses it! I have to change the local prompt to force the error. I have no idea when and why this has beginning to work :|

So, I forced the error changing the local set and the workbench does not lock. I tested it launching the plugin in Debug mode. At Console I can see a 'Invalid password or user ID' message (not the real error, but not locked).

I am testing this in a XP system. I don´t know about Common Net. If you want I can test it here, but you have to guide me about how to do it.
Comment 10 Martin Oberhuber CLA 2012-05-24 04:33:49 EDT
So here is my test case (running on Win7 64 bit but I don't think this matters):

1. Install and launch Eclipse 4.2 RC 1
2. Use Help > Install.. to get TM 3.4 RC 1 from
   http://download.eclipse.org/tm/updates/3.4milestones
3. Allow to restart
4. Import o.e.rse.connectorservice.telnet from CVS
5. Apply the patch
6. Launch as Debuggee ("EclipseApplication")
7. In debugge, open RSE Perspective
8. Create telnet connection to a device that doesn't require a password
9. Try following, each without success:
   - Right-click > Connect...
   - Right-click > Connect
   - Right-click > Launch Terminal
   - Right-click > Launch Shell

--> I observe a "Connecting..." progress.

Checking the status of Threads in the debugger, I see that the TelnetInputStream is blocked trying to read from the socket; the available() method is also blocked (I think this is a commons net bug !); and the connect worker sits on

   TelnetConnectorService line 198:
   checkLogin.join();

So all Threads are blocked waiting for input from TelnetInputStream while 
there is no more input to come.

Personally, I think it is just wrong to try doing some magic in the connector service matching patterns and sending a login... that's bound to fail. A Telnet
connection should be treated as "connected" as soon as the socket is connected.
When "needsLogin" is off (and that should be the default!), then the entire LoginThread should NOT be done at all and my Telnet Shell / Terminal should open immediately.
Comment 11 Martin Oberhuber CLA 2012-05-24 11:55:11 EDT
Given that I'm pretty sure there is a regression in Commons Net 3.1 at least part of the mix of problems we're seeing here, I filed this defect against Apache:

https://issues.apache.org/jira/browse/NET-466

For now I think it is better if we proceed testing with the older Commons Net 2.2 version (and TM 3.4 / Juno may actually revert back from Commons Net 3.1 to 2.2).

So in my instructions above, in step 2, please install TM 3.4 M7 rather than RC1, using this update site:
  http://download.eclipse.org/tm/updates/3.4milestones/M7

My testing still doesn't quite succeed with that version, and I still believe that in case no login is asked for the entire LoginThread should not be started at all - but at least it's more likely to succeed with that version.

In fact if we simply don't start the LoginThread when properties say there is no login required, it would likely be a good first step. COntributions appreciated.
Comment 12 jose ferreiro CLA 2012-05-24 14:56:35 EDT
TM 3.4 RC1 + patch gets also locked at in.available() thing.
TM 3.4 M7 + patch works well here (XP 32 bits).

LoginThread does not do only the login thing. It also waits for the first prompt from the device. If no login is required, it only waits for the prompt.
Comment 13 Martin Oberhuber CLA 2012-05-24 15:36:29 EDT
> LoginThread does not do only the login thing. It also waits for the first
> prompt from the device. If no login is required, it only waits for the prompt.

True, but personally I cannot see what's the value of waiting for the prompt.

If I remember right, there are higher layers in RSE which deal with the prompt... that shouldn't necessarily be done on the connector service.
Comment 14 jose ferreiro CLA 2012-05-28 16:03:31 EDT
Created attachment 216372 [details]
Read with timeout + my local settings + no prompt wait

I did a little test. I comment the prompt wait phase on the login routine and assign a succes code directly. 

After that, It did not worked. I have to a add a sleep (see new patch) to make it work. 

It seems as if the function returns too fast, the terminal window does not show the device output and it does not accept orders. No idea why.

Perhaps it fails with fast devices when the prompt come fast. Can that be the problem with your system?
Comment 15 Martin Oberhuber CLA 2012-05-30 11:04:09 EDT
Created attachment 216483 [details]
patch v3

So I played a bit more with this, and the good news is that after reverting to commons net 2.2 it now basically works. I like the basic idea using a timeout waiting for the prompt pattern - but there are still lots of things to do:

1.) The timeout must be configurable, so I added that to my patch. 1000 msec 
    may be too low on some connections. Especially when opening a legacy
    connection that used to work (connect timeout 60 sec hardcoded!), we must 
    not break that after upgrading to TM 3.4. Assuming new defaults for new
    connections is OK though.

2.) Improper error message when the connect fails because the remote doesn't
    ask the expected prompt: It says "invalid username or password" but it
    should say "timeout waiting for 'username' prompt after 1000 msec"
    or similar.

3.) When using a high timeout value and "canceling" the connect, I'm seeing
    tons of exceptions on stdout. It should return a simple "connect 
    canceled" instead.

I also found new unrelated issues bug 381055 and bug 381056 when working on this.

Given that this change is likely going to add UI (the "prompt timeout") we need to make up our mind quickly whether it should go into 3.4 or not.
Comment 16 Martin Oberhuber CLA 2012-05-30 11:08:04 EDT
Another (important) aspect of this is covered in bug 251484 :

When you connect a system that usually asks for both username and password, but your account happens to have an empty password, then the "password" is not asked. So the code needs to be graceful and either expect "password" to be sent or not. Or at least allow configuring the connection such that we don't hang at 100% forever.