RMI seen from Internet but not from LAN - java

this is my first post in stackoverflow, i'm trying to implement a chat using RMI but i'm stuck, i am avoiding the use of rmiregistry, everything was binding well on localhost, but i need it to be accesible from the internet, the ports are forwarded, the firewall down, and actually i can retrieve through the internet an object, i've achived this using
System.setProperty("java.rmi.server.hostname","ruso.89.x.ignorelist.com");
So then my NameServer.java binds to that IP, but i lose all access through localhost, now let me explain this. This is the code for NameServer.java
public class NameServer
{
public static void main (String args [] )
{
String direscucha = "ruso.89.x.ignorelist.com";
int puertonombres = 5000;
try{
System.setProperty("java.rmi.server.hostname", direscucha);
System.setProperty("java.security.policy", "C:\\Users\\Antonio\\Desktop\\DistributedChat\\myServer.policy");
System.setSecurityManager(new RMISecurityManager());
NameService ns = new NameService();
Registry reg=LocateRegistry.createRegistry(puertonombres);
reg.rebind("ns",ns);
while(true){}
}catch(Exception e){
System.out.println(e);
}
}
}
This is my policy file:
grant {
permission java.security.AllPermission;
permission java.net.SocketPermission "ruso.89.x.ignorelist.com:*", "connect,resolve,accept";
permission java.net.SocketPermission "localhost:*", "connect,resolve,accept";
permission java.net.SocketPermission "127.0.0.1:*", "connect,resolve,accept";
};
Then I need the ChatServer.java to run, this takes ns and binds himself to it, so the ChatServer can be found, the problem is when i use it from outside my LAN I can get the server running! but when i use localhost i got an exception
ChatServer.java (Snippet)
public void work ()
{
String direscucha = "ruso.89.x.ignorelist.com";
int puertonombres = 5000;
System.setProperty("java.rmi.server.hostname", direscucha); //Binds to the Public IP
System.setProperty("java.security.policy", "C:\\Users\\Antonio\\Desktop\\DistributedChat\\myClient.policy"); //marca la politica
System.setSecurityManager(new RMISecurityManager()); //Ejecuta el RMISecurityManager
try
{
String[] list = Naming.list("//localhost:5000/"); //Debugging
System.out.println("Tamanyo: "+list.length);
for(int i=0; i<list.length; i++)
System.out.println(list[i]);
NameService_Stub ns = (NameService_Stub) Naming.lookup("rmi://localhost:5000/ns");
ns.rebind (conf.getServerName(), this);
System.out.println("Servidor registrado::");
}
catch (java.rmi.ConnectException e)
{
System.out.println (e);
System.exit(-1);
}
catch (Exception e)
{
System.out.println(e);
System.exit(-1);
}
So when the ServerChat is registered now any user can execute ChatClient.java to retrieve from the NameService the name of the ChatServer and then connect, but didn't got even there yet because i can't manage to the ChatServer to work. My first though was that when seting the hostname property the localhost get's blocked but nowhere is mentioned, afterwards i've though it may be a problem with the router NAT, could it be?
Exception:
java.rmi.ConnectException: Connection refused to host: ruso.89.x.ignorelist.com; nested exception is:
java.net.ConnectException: Connection refused: connect
Client and server policy files are identical.
Used WireShark to see what is happening, a SYN is send and a ACK,RST is recieved.
I've burnt all my ideas, any suggestions?

i've achived this using
System.setProperty("java.rmi.server.hostname","ruso.89.x.ignorelist.com");
So then my NameServer.java binds to that IP
No it doesn't. It's a common misperception, but incorrect. RMI always binds its ServerSockets to 0.0.0.0 unless you provide an RMIServerSocketFactory that does otherwise. The effect of java.rmi.server.hostname is to embed its value into the stub (essentially instead of the value returned by InetAddress.getLocalHost()).
while(true){}
You don't need to smoke your CPU by doing that, but you do need to make the Registry reference a static variable. RMI starts a thread when you export a remote object that will prevent the JVM from exiting until you unexport it. Unexporting happens automatically when the remote object is garbage-collected, and the static reference will prevent that.
Connection refused to host: ruso.89.x.ignorelist.com
That may mean that your internal firewall won't let you connect outwards to that host even though it's your own. Or that ruso.89.x.ignorelist.com has a different, incorrect DNS mapping inside your network.

Related

How to connect two Java clients that are using STUN to get around NATs for a P2P connection?

I've been working on a peer-to-peer file-sharing project in Java and have come to a wall that I don't begin to know how to break down. I have 2 clients running identical code, both behind NATs (probably, though assumedly not symmetrical NATs), who have accessed their public IP and port via a STUN server. When I attempt to make a connection between them, I get no response and the receiving client does not register an attempt to connect. This issue did not occur with the same code using local IP addresses.
Relevant connection code:
PeerConnection peerConn = new PeerConnection(pd);
PeerMessage toSend = new PeerMessage(msgType, msgData);
peerConn.sendData(toSend);
if (waitReply) {
PeerMessage oneReply = peerConn.receiveData();
while (oneReply != null) {
msgReply.add(oneReply);
oneReply = peerConn.receiveData();
}
}
peerConn.close();
public class PeerConnection {
private final PeerInfo pd;
private SocketInterface s;
public PeerConnection(PeerInfo info) throws IOException {
pd = info;
s = NormalSocketFactory.makeSocket(pd.getHost(), pd.getPort());
}
public void sendData(PeerMessage msg){ s.write(msg.toBytes()); }
public PeerMessage receiveData(){ return new PeerMessage(s); }
public void close() {if (s != null){ s.close(); s = null; } }
Extraneous comments/try-catch and other code bits are omitted for brevity.
I am manually passing in the IP and port given by a STUN server (for testing purposes) into this peer connection, and other code is creating the actual data (connection type, who it's connecting to, etc) but I don't believe the content has any bearing on this as it can handle the input packets being created (as LAN tested has verified).
Am I missing something here? The clients are sitting there listening for a packet but aren't receiving them. Using WireShark (a program I am admittedly brand-new to) shows me that the connections are being reset (specifically that the reset flag is set, something that I in no way do).
.... .... .1.. = Reset: Set
[Expert Info (Warning/Sequence): Connection reset (RST)]
[Connection reset (RST)]
[Severity level: Warning]
[Group: Sequence]
I do not have a signaling server handling this as I do not have plans to host anything for the time being, but I don't much understand how I'd not come across a similar issue with that.
EDIT: After using WaifUPnP to allow ports to open through the firewalls, I still had issues with most connections I tried to test. I don't know if this is a symmetric NAT problem but a few connections have been made. I'm not gonna delete this in case someone else needs it later.

How to get to know what ports are taken?

I am creating a simple learning project (chat using sockets) in Java and today I faced a problem. Maybe the point is an obvious one for somebody, but I am confused with it
The purpose
To get to know (at least one of the following):
A list of the currently opened free/taken ports on a PC
Whether the port I want to use is locked
What I tried
I've created a simple raw-project and run two ServerSocket on one port. In this case I have caught a java.net.BindException with notification that "...Address already in use: JVM_Bind...". But in this way I am able to check the port avaliability only if my JVM has captured it. In case if other program listens to the port, I do not know anything about it. I am adding a code below.
public class Main {
public static void main(String[] args) throws IOException {
MyThread myThread = new MyThread();
ServerSocket serverSocket = new ServerSocket(5940);
myThread.start();
serverSocket.accept();
}
}
public class MyThread extends Thread {
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(5940);// exception is thrown here
serverSocket.accept();
} catch (IOException e) {
System.err.println("SECOND SERVER");
e.printStackTrace();
interrupt();
}
}
}
PS Any advice is warmly welcomed
I've created a simple raw-project and run two ServerSocket on one
port. In this case I have caught a java.net.BindException with
notification that "...Address already in use: JVM_Bind...". But in
this way I am able to check the port avaliability only if my JVM has
captured it. In case if other program listens to the port, I do not
know anything about it.
I think you're misinterpreting your result. I have every reason to believe that if the port you request is already bound by any process then your attempt to bind it will fail with a BindException. That takes care of
Whether the port I want to use is locked
. As for
A list of the currently opened free/taken ports on a PC
, there are system utilities that can get you that information, but it is useless to you. Whichever end initiates the connection (i.e. the client) needs to know in advance what port to try to connect to. It cannot get that from the server, because that presents a chicken & egg problem.
The usual approach is that the server listens to a specific port chosen by its developer or its admin, and that port number is provided to clients out of band -- often simply by it being a standard, well-known port number. That's how most of the basic network protocols work; for example, HTTP servers run on port 80 by default. If the wanted port happens to be unavailable when the server attempts to bind to it then that indicates a misconfiguration of the machine, and the server simply fails to start.
The client, on the other hand, does not need to choose a port number at all. The system will choose one for it automatically when it attempts to connect to the server.

Android dealing with IoT devices with NO Internet connection

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.");
}

Socket does not throw an exception though he can’t connect

I'm trying to connect a socket to an non-existent server, and I really don't understand why an exception is not being raised.
Here is my code:
public class TestSocket extends Activity {
private static final String TAG = "TestSocket";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BasicThread t = new BasicThread();
t.start();
}
class BasicThread extends Thread {
#Override
public void run() {
Log.d(TAG, "Before");
try {
new Socket("42.42.42.42", 12345);
Log.d(TAG, "Connected");
} catch (Exception e) {
Log.d(TAG, "Exception");
}
Log.d(TAG, "After");
}
}
}
I also tried with my own IP address while running Wireshark, and I first get [SYN] from Android to my computer and then [RST, ACK] from my computer to Android (because nothing is listening at this port), but I still do not get an exception on Android.
Also I’m testing on a physical phone (Nexus S), and I do have the internet permission in my Manifest.
Why aren't I getting an Exception?
Edit:
More precisely, the output I get is
D/TestSocket(17745): Before
D/TestSocket(17745): Connected
D/TestSocket(17745): After
(and not Exception)
In the Socket constructor, it's thrown when the IP address of the host can't be determined, so I assume that because you aren't passing a hostname which needs resolution, a different exception would be getting thrown instead. I believe the exception actually comes from the URL class or such which does the resolution, and from nowhere else.
The connect(..) method should throw an exception but doesn't appear to, as you say.
Edit: apparently Android (some versions) doesn't work properly here, so it's probably a bug: http://code.google.com/p/android/issues/detail?id=6144. It doesn't look like the link refers to the emulator as I had thought.
There are a variety of things that can cause a socket connect to fail with an exception.
However, if the SYN message that the TCP protocol sends to start the connection process is
blocked by a firewall,
routed through a borked network, or
routed to some endpoint that doesn't respond,
then TCP stack on the initiating machine will just retry, and retry. If you have a connect timeout set, you will eventually get an exception, but it could take a long time.
The fact that it works on the Android emulator and not on the real device simply means that they are implemented or configured differently. (For instance, they may have different default connect timeouts ... of the emulator may be designed to give connection refused in that scenario.)
The bottom line is that you need to make your code work on the real device. Figure out the best way to make your device set a connect timeout, and check that that works when talking to the non-existent server.
Your try catch code doesn't catch IO Exceptions. Try something like this
try
{
// to get the ip address of the server by the name<br>
InetAddress ip =InetAddress.getByName("example.com");
sock= new Socket(ip,Server.PORT);
ps= new PrintStream(sock.getOutputStream());
ps.println(" Hi from client");
DataInputStream is = new
DataInputStream(sock.getInputStream());
System.out.println(is.readLine());
}catch(SocketException e){
System.out.println("SocketException " + e);
}catch(IOException e){
System.out.println("IOException " + e);
}

How do I have to configure a RMI environment so that I'm able to use it in a "real" network?

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.

Categories

Resources