B4J Library SSHJ - ssh, scp, sftp for Java

JackKirk

Well-Known Member
Licensed User
Longtime User
Firstly, thank you for this effort - it has greatly helped me in trying to understand how I could implement SSH.

I am trying to programmatically control a Netonix WISP switch ( https://www.netonix.com/wisp-switch/ws-8-150-dc.html ) at a remote location.

But I am not having much luck doing it with B4J.

I can successfully communicate with it with Putty - the following is an excerpt from a Putty session:

My B4J code looks like:
B4X:
    'See https://www.b4x.com/android/forum/threads/sshj-ssh-scp-sftp-for-java.88615/#post-584009
    Private  ssh As SSHJ
    ssh.Initialize("ssh")

    ssh.AddHostKeyPromiscuousVerifier
    ssh.AddAuthPassword("fortotalrecall1")

    ssh.SetTimeout(30000)
    ssh.SetConnectTimeout(30000)
    ssh.Connect("xxx.xxx.xxx.xxx", 23, "admin")   'Port 23 is port forwarded to port 22 on device

    Private senderfilter As Object = ssh.Exec("help", 0)

    Wait For (senderfilter) ssh_ExecFinished(Success As Boolean, Command_Executed As String, ExitCode As Int, Output As String, Error As String)
    Log("help")
    Log("Success " & Success)
    Log("Command_Executed " & Command_Executed)
    Log("ExitCode " & ExitCode)
    Log("Output " & CRLF & Output)
    Log("Error " & Error)

Which results in a log as follows:

The SLF4J messages are trivial

But I am automatically landing in the devices command line shell (as evidenced by the identical lists of built-in commands).

Why is my B4J code not behaving identically to Putty?

Or: what BusyBox command can I issue to get to the Netonix shell (I've been googling and experimenting with this for about 6 hours without success).

Any help greatly appreciated - a solution has some serious value to my project.
 

mindful

Active Member
Licensed User
Why is my B4J code not behaving identically to Putty?
This is because putty is a terminal (interactive shell) ... Exec from ssh just executes a command and returns the result (exit code and output) and then the "session" closes. You cant (at least I do not use it for this purpose) use this to run someting like step by step installer or something like that where the program needs some comfirmation from the user .. instead most software can handle attributes (parameters) something like: yum install php -y (the -y stands for confirming the are you sure you want to install ...)
 

JackKirk

Well-Known Member
Licensed User
Longtime User
Mindful,

Thanks for your prompt response.

As I understand it Putty uses SSH (or at least that is the option I am using), so what SSH command/s does it use to be a terminal?

Please excuse if this is a stupid question - first time I have scratched SSH/Putty etc.

Thanks....
 

mindful

Active Member
Licensed User
SSHJ (the java library that this wrapper is based) supports interactive shell (aka terminal), but I haven't wrapped it and I don't have any plans to do so, I can't think of any other reason to use this feature than to write your on terminal.

Quote from wikipedia:
PuTTY (/ˈpʌti/)[3] is a free and open-source terminal emulator, serial console and network file transfer application.

This library is not a terminal emulator.

Secure Shell (SSH) is a cryptographic network protocol for operating network services securely over an unsecured network.

This library make use of this network protocol so is putty.

Please provide more details on what are you trying to accomplish or what is the purpose of using this library, maybe you are looking at it the wrong way and there is a simple way to do what you are trying to do.
 

mindful

Active Member
Licensed User
Ok now I understand ... You could try to issue multiple commands with the Exec method by using ; as separator.

something like:
B4X:
ssh.Exec("conf; interface port 1; poe 24V; exit; exit", 0)
I think this will enable poe with 24V on port 1

The php script you posted uses indeed an ssh connection with interactive shell.

I will have a look at SSHJ library and see if I can do something like that, but no promises.
 

JackKirk

Well-Known Member
Licensed User
Longtime User
mindful,

I have tried stringing several commands together, using && as the concatenation operator.

The concept works but the execution doesn't.

The "conf", "interface port .." etc must be put on the command line interface generated by the "switch -s" command.

The full sequence looks something like:

ssh.Exec("switch -s && conf && interface port 4 && poe off|24v|48v|48vh && exit && exit" & CRLF", 0)

The trouble is that "switch -s" bombs with an "illegal argument" style error - because ssh.Exec is batch not interactive (as you pointed out before) therefor a CLI can't be created and there is nothing to put the "conf" etc on.

If you don't want to enhance your library - I'm guessing something like what Oliver A is suggesting in this post:

https://www.b4x.com/android/forum/threads/php-some-guidance-required.92754/#post-586872

would it be possible for you to suggest some inline java to work around it?

I appreciate your efforts greatly...
 

mindful

Active Member
Licensed User
ssh.Exec("switch -s && conf && interface port 4 && poe off|24v|48v|48vh && exit && exit" & CRLF", 0)

This bombs with illegal arguments because && doesn't mean anything it's just a string. And the way you put poe off|24v|48v will not work because you haven't set a value. | means "or" in some programming languages.

To run multiple commands in bash you use ; as separator.

Can you activate the poe manual port manual via putty using the commands above ? If you can please copy paste the putty window here so I can have a look.

I am not at the office right now but once i get there I'll have a look if I can add the interactive shell or expose something for someone to help you with inline java or javaobject, but the command you tried will not work on any system. So if you comnect via putty and you are able to achive your purpose using manual commands please post the putty window contents here so i can understand better or even better will be a manual of the switch commands.
 

JackKirk

Well-Known Member
Licensed User
Longtime User
mindful,

Sorry, my fault, being too quick on the response - I'm trying lots of different options here.

The && stuff comes from my mucking around with the -m file option in plink.

There && works as a concatenator - and it looks like ; does too.

The off|24v|48v|48vh stuff is "artistic license" - I didn't mean to imply that was what was put in verbatim

Maybe we should just forget my last post.

----------------------------------------------------

This is the help on the switch command:


and this is a sample Putty session doing what I want to do (I have asked for help at every step with ?):

I hope this helps...
 

mindful

Active Member
Licensed User
Updated the first post with version 1.40

It now supports emulating a terminal by using the command Shell.

@JackKirk you can try to run the command:
B4X:
    Dim ssh As SSHJ
    ssh.Initialize2("", 15)
    ssh.AddHostKeyPromiscuousVerifier
    ssh.AddAuthPassword("YourPassword")
    ssh.Connect("8.8.8.8", 22, "YourUser")

    Dim sf As Object = ssh.Shell("switch -s" & CRLF & "config" & CRLF & "interface port 4" & CRLF & "poe 24V" & CRLF & "exit" & CRLF & "exit" & CRLF & CRLF, 5)
    Wait For (sf) ShellFinished(Success As Boolean, ShellCommandsExecuted As String, Output As String, Error As String)

    Log("Success = " & Success)
    Log("ShellCommandsExecuted = " & ShellCommandsExecuted)
    Log("Output = " & Output)
    Log("Error = " & Error)
 

mindful

Active Member
Licensed User
The implementation of the Shell command is not a traditional one as it can send one or more commands in one go. It works like the Exec command the only difference is that it's emulating a terminal.

So this can't be used as it should be. More exactly a shell is meant to stay open so you can run a command, get the output, analyze it, declare a variable in the enviroment, run another command in the same shell, analyze it, update that previously set variable, run another command, etc .... so with some gui interface you could do an application like Putty.

Right now the shell and session is closed after running commands, so issuing another Shell command will open a new session with a new shell.

Somewhere in the future I will have the need to make something in my project that acts like putty, and I will put more effort in wrapping it nicely so that it would be easy to use for everyone, but until then this would have to do as for most uses it will work.
 

JackKirk

Well-Known Member
Licensed User
Longtime User
mindful,

Sorry for the delay in responding - I had to go get batteries recharged at the remote test site before I could test your new version.

I am happy - no ecstatic - to report it works beautifully.

You have saved me a major amount of toil installing PHP, fumbling with it and writing a B4J wrapper to run it.

I will be using this to intelligently manage the IP cameras at 5 sites each with 20-30 cameras.

Why? because it is all solar powered - every watt saved is one we don't have to generate and store - and I suspect this will reduce our power budget by between 1/2 and 2/3rds.

I owe you big time...
 

JackKirk

Well-Known Member
Licensed User
Longtime User
And a couple of comments and questions:
  1. Comment: for anyone who stumbles across this who is also trying to manage a Netronix switch there is no need for the initial
    "switch -s" command - when using the .Shell call you automatically land in the "netronix shell" - which is where PuTTy also lands you so it is all very consistent. In fact if you leave the "switch -s" command in it gets pretty upset.
  2. Question: I'm a bit confused with the TimeoutInSeconds parameter in the .Shell call - I'm finding 1 sec gives me everything - do I have a good link? what impacts how much time should be left? is there any relevant documentation?
Thanks again...
 

mindful

Active Member
Licensed User
I'm a bit confused with the TimeoutInSeconds parameter in the .Shell call
In your case a timeout of 1 is all you need, your commands will be executed. This timeout is about when you call some programs that you will need to wait for the output, think something like a scrapper you call the scrapper program and its output will not be available immediately, so this is the reason why this timeout exists, another thing is that you need to provide a timeout because the library doesn't know when the command you called has outputed everything, in most cases a timeout of 1 second will be enough.
 

JackKirk

Well-Known Member
Licensed User
Longtime User

mindful,

I have my camera controller all ready for final testing and have been going through my normal packaging exercises.

My experience with #MergeLibraries is the exact reverse of your NOTE2 in the first post.

That is if I set #MergeLibraries: False the resulting jar will not run - if I set #MergeLibraries: True (or comment it out which probably means it is defaulting to True) then everything works as per Debug mode.

Could you comment?
 

mindful

Active Member
Licensed User
#MergeLibraries: False the resulting jar will not run
When MergeLibraries is set to False then all the libraries in your project will not be merged into jar file. When you run your project in release mode from the ide in the window the outputs you can see a message like: "The following libraries should be distributed in the libs folder:" and then it lists all of the libraries needed to be copied to a folder named libs that sits near your jar.

MergeLibraries - True or False. Whether libraries should be merged into the generated jar file. If set to False then you need to copy the libraries to a folder named libs under the main jar folder (when distributing the app).
source: https://b4x.com/android/forum/threads/modules-attributes.35451/
 

JackKirk

Well-Known Member
Licensed User
Longtime User

Could I suggest you try this if you haven't already - it is not what I am seeing.

The only thing in the log when I run in Release mode with "#MergeLibraries: False" commented out is:

The WARNINGS Erel says to ignore.

The SLF4J I have ignored as they look harmless and haven't affected anything.

I am running B4J 6.01 and Java 9 if that makes any difference.

I also have the jars that you reference in post 1 in the Additional Libraries folder in both my development and run environments.
 
Last edited:

mindful

Active Member
Licensed User
t is not what I am seeing
When you run your app in release mode from the IDE just after you hit play a windows appears with thw build log. There you will see what I meant.

Also when run from the ide in release mode from the IDE you don't need to copy the libraries but when you distribute your app you need to.

So when you run in Release mode from the IDE with MergeLibraries: False the IDE will create a jar file that contains only the code that you wrote, you copy that jar to the production device and then you create a folder named libs that sits near the jar in which you copy all the libraries(jars) that you refernced in your project (B4J included libraries and additional libraries) - all of these libraries names appear in the little windows textarea that is shown after you hit the play arrow to build your project.

That error that you see in the log should be ignored as erel said, it's because you are using java 9 - it's just a warning.

The slfj warning appear because you haven't set a reference to slfj additional jars (it is meant for logging purposes).
 

JackKirk

Well-Known Member
Licensed User
Longtime User
mindful,

Sorry I was looking in the logs rather than the Compile popup.

If I use #MergeLibraries: False I get exactly what you describe.

And the reason the resultant jar was not running was I wasn't constructing the libs folder - when I do that it all works.

My apologies for the run around but I have a lot going on and I wasn't obeying the old dictum "more haste, less speed".

-----------------------------------------------

However that does not explain why if I comment out #MergeLibraries: False and thus create a jar with all the libraries embedded in it - it works also - with no libs folder in sight.

Maybe the documentation you are relying on is out of date?, maybe java 9 + B4J 6.01 don't behave as per your documentation?

Have you actually tested with #MergeLibraries: False commented out in a java 9 + B4J 6.01 environment?

Regards...
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…