I am using Java Secure Channel to connect with hosts in a network.
I am using following code:
int port = 22;JSch jsch = new JSch();
try {
session=jsch.getSession(username,hostname,port);
}
catch (JSch Exception e1){
e1.printStackTrace();
}
session.setPassword("mypassword");
try {
session.connect();
}catch (JSchException e1){
System.out.println("Did not connect");
return;
}
By using this code I am able to connect to host.
But if host is unavailable/offline then I have to wait for JSchException.
1) I want to first check whether host is available for communication or not and if available then only try to connect.
2) Also I want to set timeout for connection,if connection doesn't established within that time interval must give exception.
How to check if host is available? and set timeout for connection?
Testing before connecting makes no big sense, as port can become unavailable right after test. Try to use session.setTimeout() to set timeout in millis.
How to check whether specified port is available for communication?
How to check whether specified X is available for Y:
Try to use it for Y. It's an infallible test. Any other technique has timing-window problems.
Related
I'm trying to build a project where I must pilot an IoT device from smartphone via Wifi.
This device has the SPWF01 Wifi Module integrated, and is configured as an access point (that has no Internet access) with security type WEP. On this access point configuration we also have a TCP Socket Server that intercepts smartphone communications.
On the smartphone side, we have the part which scans and connects to our device's access point(which works, although i get the esclamation point on the wifi icon since it has no Internet access). After we've connected, we start the Client Socket which connects to the server on our IoT device(the ip address of the server socket is actually the gateway of the access point). And here is where the trouble starts, because the client socket won't start. Here is the code:
public void SocketInit(String ip, int port) throws IOException {
InetAddress addr = InetAddress.getByName(ip);
SocketAddress sockaddr = new InetSocketAddress(addr, port);
nsocket = new Socket();
nsocket.setReuseAddress(true);
nsocket.setTcpNoDelay(false);
nsocket.setReceiveBufferSize(700); //Must be less than 730byte witch is the module buffer
nsocket.setSendBufferSize(700);
nsocket.connect(sockaddr, 5000); //5 second connection timeout
}
And here is the exception i get:
java.net.SocketException: socket failed: ENONET (Machine is not on the network)
And I get that error even before reaching nsocket.connect(), precisely on setReuseAddress.
Since the exception I get is ENONET, I thought that it must be because the access point has no internet access so I used the solution proposed here for testing purpose:
adb shell settings put global captive_portal_detection_enabled 0
This is a solution that can't be done programmatically without having root access, but I wanted to test if that was the problem. But although the exclamation mark on the wifi icon had disappeared, the client socket still gave me the same exception error.
Does anybody have a solution for this behaviour? Thank you in advance!
Sometimes the client socket manages to open, with a success rate of 1 out of 20 times. But when it does, i usually get another exception after a couple of messages sent:
java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
Here is the code I used to connect to the access point from the smartphone:
WifiConfiguration wc=new WifiConfiguration();
wc.SSID= host;
wc.status = WifiConfiguration.Status.ENABLED;
wc.priority = 40;
wc.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wc.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wc.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wc.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
wc.allowedGroupCiphers.clear();
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
wc.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
wc.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
wc.wepKeys[0] = password;
wc.wepTxKeyIndex = 0;
int netId = mainWifi.addNetwork(wc);
try {
//mainWifi.setWifiEnabled(true);
mainWifi.disconnect();
mainWifi.enableNetwork(netId, true);
mainWifi.reconnect();
startConnectionCheck = true;
System.out.println("enabled network");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
The access point's security type is WEP. That is because the Wifi module can't implement WPA.
Tests done on Marshmallow.
I am not 100% certain if this issue is the same.
I had to do a project a whileback and used Java sockets.
When doing intial testing, I used the local loopback and used ports on the same computer and multiple threads. Eventually it worked well enough to test between two computers. I found it didn't work between two computers. After turning off all my firewalls and protections etc on the network and getting desperate enough to use direct connection ethernet cables, I figured out the issue.
Sockets cares which gateway you use. The solution was for me to use the gateway rather than the loopback... It is obvious looking back now...
Anyway, it is likely that your mobile gateway, wifi gateway, and local loopback are all different.
Here is an ugly code blurbe that I hope gives direction with very little inspiration...
Socket socket = null;
try {
socket = new Socket(ip, port, InetAddress.getLoopbackAddress(), localServerPort);
}
catch (Exception e) {
}
if (socket == null) {
try {
socket = new Socket(ip, port, InetAddress.getLocalHost(), localServerPort);
}
catch (Exception e) {
}
}
if(socket == null) {
throw new Exception("Neither the loop back nor the host could find this sucker.");
}
I have Android client which connect to server. For some reason, the source port of android change while the connection still active.
channel = DatagramChannel.open();
if (!protect(channel.socket())) {
throw new IllegalStateException("Cannot protect the channel");
}
channel.connect(server);
while (true) {
//Send something
}
While it keep sending data, suddenly the source port change. Is there any reason why that is happening ? If so, is there a way to prevent it ?
Regards
Adrian
Edit:
It seem the port keep changing and server cannot reach the original port.
I'm transferring files using FTP with JAVA.
I'm using FTPClient and FTPServer from Apache. But in a specific environment, sometimes the file isn't transferred. I call the enterLocalPassiveMode method from FTPClient before the login method call and yet sometimes the files aren't transferred.
The storeFile method returns "false".
The getReplyString method returns "200 Command TYPE okay".
The list method returns "227".
When the file is transferred successfully:
The list method returns 150.
The getReplyString method returns "150 File status okay; about to open data connection".
Client code:
this.getFtpClientUtil().connect(settingsService.getServer(), settingsService.getFtpServerCommandChannelPort());
int reply = this.getFtpClientUtil().getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
logger.error("Fail to connect to FTP Server");
this.getFtpClientUtil().disconnect();
isConnect = false;
return false;
}
logger.info("FTP Server connected successfully");
this.getFtpClientUtil().enterLocalPassiveMode();
isConnect = this.getFtpClientUtil().login(settingsService.getftpUsername(), settingsService.getftpPassword());
Server Code:
// Data Configuration
this.dataConfigurationFactory = new DataConnectionConfigurationFactory();
dataConfigurationFactory.setPassiveAddress(this.ipAddress);
dataConfigurationFactory.setPassiveExternalAddress(this.ipAddress);
dataConfigurationFactory.setPassivePorts(this.settingsService.getFtpServerTransferChannelPort());
// Listener
listenerFactory = new ListenerFactory();
listenerFactory.setPort(this.settingsService.getFtpServerCommandChannelPort());
listenerFactory.setDataConnectionConfiguration(dataConfigurationFactory.createDataConnectionConfiguration());
// Desliga SSL
listenerFactory.setImplicitSsl(false);
// User
PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
UserManager um = userManagerFactory.createUserManager();
this.serverFactory = new FtpServerFactory();
serverFactory.addListener("default", listenerFactory.createListener());
serverFactory.setUserManager(um);
UserFactory userFactory = new UserFactory();
userFactory.setName(this.settingsService.getftpUsername());
userFactory.setPassword(this.settingsService.getftpPassword());
userFactory.setMaxIdleTime(60);
final String absolutePath = this.settingsService.getftpHomeDirectory();
userFactory.setHomeDirectory(absolutePath);
userFactory.setAuthorities(Arrays.asList((Authority) new WritePermission()));
User user = userFactory.createUser();
um.save(user);
// Connection Config
connectionConfigFactory = new ConnectionConfigFactory();
connectionConfigFactory.setAnonymousLoginEnabled(false);
connectionConfigFactory.setMaxLogins(100);
serverFactory.setConnectionConfig(connectionConfigFactory.createConnectionConfig());
Is this a firewall problem?
I tried set passive port ranges on the server side using the setPassivePorts method from DataConnectionConfigurationFactory class, but the problem continues.
Is there any form to set port ranges on the Client side?
How can I check if the connection is really using passive mode?
Thanks in advance.
Is this a firewall problem?
In these cases, the correct way would be turn off the firewall to test or set a range of ports that the application can to connect. But in the production environment this wasn't an option. So, the only thing I know is that in the development environment works fine and in the production environment the problem arise. My assumption is that the firewall is blocking the ports.
Is there any form to set port ranges on the Client side? How can I check if the connection is really using passive mode?
The local port can be set on connect() method from FTPClient:
this.getFtpClientUtil().connect(settingsService.getServer(), settingsService.getFtpServerCommandChannelPort(),
InetAddress.getLocalHost(), getLocalPort());
It's possible to verify if the connection is using the passive mode in two ways:
The getPassivePort() method from FTPClient will return -1 if the passive mode isn't in use.
In the question, I mentioned that the list() method from FTPClient returns the 227 code. This code also indicates that the passive mode is in use. I thought that this code was an error. What really happened was an error after entering in passive mode, but was returned the code from previous command.
Setting local port didn't resolve the problem. Perhaps because the local port that I'm configuring is only for the command channel. The transfer channel still uses random ports on client side. The solution is trying to transfer the file again. If the transfer fails, I disconnect the client, then I connect the client again using other ports and then I try to transfer the file again. In all my tests, the files was transferred successfully in the second time. I put 3 attempts if the transferring fails.
When connecting the client again, if the same port was used, the java could throw "java.net.BindException: Address already in use". Even after disconnect the client, the port continues locked for a few moments. In this case, I verify if the port is available before trying to connect, if necessary I try to connect the client in another port.
I wrote a method which will help us finding whether the system using the proxy to connect with internet which is as follows,
try {
System.out.println("Checking internet connection availability.....");
URL u = new URL("http://www.google.com/");
HttpURLConnection uc = (HttpURLConnection) u.openConnection();
uc.setReadTimeout(1);//I have tried this without timeout and with it too. But it didnt work
System.out.println(uc.getResponseCode());
} catch (Exception ex) {
System.out.println("Unable to connect to internet without proxy.....");
System.out.println("Checking for any proxy settings from the PC");
System.setProperty("java.net.useSystemProxies", "true");
try {
System.setProperty("java.net.useSystemProxies", "true");
URL u = new URL("http://www.google.com/");
HttpURLConnection uc = (HttpURLConnection) u.openConnection();
System.out.println(uc.getResponseCode());
System.out.println("Internet connection available");
} catch (Exception e) {
System.out.println("Internet connection not available :(");
}
}
Initially, I am trying to open the URL connection without proxy (assuming the system don't have proxy to connect with internet).I have set the timeout to 1 ms. Trying to get the response code from the site.
If any error occurs means (like timeout), then in the catch block i am trying to connect to internet with system's proxy, by means of setting the useSystemProxies to true.
But even after that also, I am not able to get the response from the site.
I am using a system with proxy settings.
I have tried the following too in the catch block
Proxy next = ProxySelector.getDefault().select(new URI("http://www.google.com/")).iterator().next();
if (next.address() != null) {
System.out.println("Detecting Proxy configurations.....");
String proxy = next.address().toString();
String proxyHost = proxy.substring(0, proxy.indexOf(":"));
String proxyPort = proxy.substring(proxy.indexOf(":") + 1);
System.out.println("Proxy Configuration : " + proxyHost + " # " + proxyPort);
}
The above block of code also is not working. Can anyone help me out with this?
InetAddress.isReachable
Test whether that address is reachable. Best effort is made by the
implementation to try to reach the host, but firewalls and server
configuration may block requests resulting in a unreachable status
while some specific ports may be accessible. A typical implementation
will use ICMP ECHO REQUESTs if the privilege can be obtained,
otherwise it will try to establish a TCP connection on port 7 (Echo)
of the destination host. The timeout value, in milliseconds, indicates
the maximum amount of time the try should take. If the operation times
out before getting an answer, the host is deemed unreachable. A
negative value will result in an IllegalArgumentException being
thrown.
In your first code snippet in the catch block try setting the following codes.
System.setProperty("http.proxyHost", "Proxy host");
System.setProperty("http.proxyPort", "Proxy Port");
Seems like your proxy is registered as system proxy and not visible to the JVM.
Because I didn't want to implement a communication protocol for my client-server based application, I implemented a RMI client and a RMI server on both sides for the information exchange between the two components.
If I try to use my application by starting the two components on the same machine, everything is working fine. But if I split the components to two different computers (Kubuntu 9.04 within as a virtual machine within an Windows 7 RC environment with disabled firewall and a native Ubuntu 9.04 environment), it seems like the RMI client is not able to execute the methods which are defined on the server side. (Every functions call leads to a RMI exception.)
Currently I only set the system property "java.rmi.server.hostname" on both sides to the network interface which should be used for the data exchange and registered the default port for the communication with rmi daemon (?) rmid.
Does somebody has an idea what might be going wrong? Do I have to set some other parameters like "java.rmi.server.codebase" (http://java.sun.com/j2se/1.4.2/docs/guide/rmi/javarmiproperties.html) to be able to use the RMI functionality within my application?
Edit: Okay, here is some additional information for you:
In the initialization phase my client tries to establish a connection to the RMI server of server component, which was initialized using the following two methods:
private void initialize()
{
// set ip address of rmi server
System.setProperty("java.rmi.server.hostname", ipAddress);
// try to register rmi server
try
{
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
}
catch (Exception e)
{
// ignore
}
}
public void start()
{
System.out.print("starting master control RMI server ...");
try
{
Naming.rebind("MasterControl", this);
}
catch (Exception e)
{
System.out.println("error: could not initialize master control RMI server");
System.exit(1);
}
// set running flag
isRunning = true;
System.out.println(" done");
}
"ipAddress" is here the ip address of the network interface of the server component.
The method which is used by the client component to establish the connection looks like this:
public void connect()
{
// build connection url
String url = "rmi://" + masterControlIpAddress + "/MasterControl";
System.out.println(url);
System.out.print("connecting to master control ...");
// try to connect to master control server
while (connection == null)
{
try
{
connection = (MasterControlInterface) Naming.lookup(url);
id = connection.register(localIpAddress);
}
catch (Exception e)
{
// ignore
}
if (connection == null)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
System.out.println(" done");
}
As you can see my client calls a function to register the connection at the server:
#Override
public int register(String ipAddress) throws RemoteException
{
// add connection to registrationHandler
masterControl.registrationHandler.addConnection(ipAddress);
// log
int connectionCount = masterControl.registrationHandler.getConnectionCount();
System.out.println("slave control (" + ipAddress + ") instance has been registered at the master control server under the following id: " + connectionCount);
return connectionCount;
}
If I run my program using a real network connection, the text "slave control ..." is not displayed on the server side. Therefore I'm not sure, if the function is really called by the client component.
After the client component is intialized it tries to notify the server component by calling the following method using it's RMI connection to the server:
public void sendInitializationDone()
{
try
{
connection.initializationDone();
}
catch (RemoteException e)
{
System.out.println("error: could not send 'initializationDone' message to master control");
System.out.println(e);
System.exit(1);
}
}
to set a flag on the server side.
The error occures inside this function on the client side:
java.rmi.ConnectException: Connection refused to host 127.0.1.1; nested exception is: java.net.ConnectException: Connection refused.
I have no idea why the host is here 127.0.1.1 ...
#nos
Of course, I disabled the windows firewall and the protection mechanismn of Kaspersky Internet Security. I don't think that there is a running firewall in my Kubuntu. In generell it is possible to establish a connection, because I already used scp to copy my program to the other machine.
Edit2:
Mhhh, after setting the entry in /etc/hosts which refers to the machine to the ip address of the machine it seems to work, but don't really understand why it does ...
BR,
Markus
You need to add an entry to the hosts file of the machines containing an entry of the form
machinename privateip
e.g.
virtualmachine 192.168.1.16
This will prevent RMI from sending the localhost host name as a 'call me back' address.
To test this approach, run the following code before and after performing the change.
System.out.println(java.net.InetAddress.getLocalHost());
It should output a local address before the changes and a non-local address after the changes.
Using different versions of the JDK on each server could cause this problem.
Use the
java -version
command to make sure that you are using the same version of the jre.