Android dealing with IoT devices with NO Internet connection - java

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

Related

Setting source port on udp socket

We've developed a Java application that sends several UDP datagrams to the very same destination IP address. Obviously the destination port is always the same one, but we can't seem to be able to set the source port to remain the same on each datagram.
If the data package we send is bigger than MTU the package is properly splitted over the same source port, but once we send a new data package the source port changes, generating a new firewall session (which network admin has warned us to be very bad due to the amount of sessions the application is generating).
Right now we're sending the packages with the following statement:
We've tried several approaches and the result is always the same, we can't seem to be able to set the source port to a fixed value.
Edit- pasting actual code:
private boolean sendImage(byte[] imageData, InetAddress address,
int port) throws UnknownHostException, SocketException {
boolean ret = false;
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(imageData, imageData.length, address, PUERTO_UDP);
socket.send(dp);
ret = true;
} catch (IOException e) {
Main.lanzarExcepcion(e);
ret = false;
} finally {
if (socket != null) {
socket.close();
}
}
return ret;
}
Thanks for your time!
I think your issue is that you are closing the actual DatagramSocket instead of reusing the same , and simply call socket.send(DatagramPacket). If you cant keep the client socket open , then you could even define the clients port like : DatagramSocket clientSocket = new DatagramSocket(9743); so each time you are calling a new clientSocket , it will get the same port or it will throw a java.net.BindException: Address already in use: Cannot bind
This will not solve the network sessions issue, because you are opening a new UDP Socket. Also i suspect that your network admin , sees the previous sessions , because you are not closing the UDP Sockets at all , but simply spawning them
As mentioned by #AntJavaDev
The solution was to:
1.- keep the DatagramSocket open
2.- pass src port in the arguments
3.- reusing the unclosed DatagramSocket for every new data packet to the same destination!
Thanks all!
The source port is an ephemeral port, generated for you by the underlying networking implementation. There is no reason to set it to a particular port number.

Java webserver blocks connections on PC

At this point, I am testing a webserver client/host system to be run on my raspberry pi (host) and on my pc (client). The basic idea is that every 5 seconds, the client on my pc sends a message to the host located at "192.168.0.11" at port 7051. It processes it and sends a message back to my pc.
For this I am using the following client code:
public static String getData() throws Exception {
try {
Socket socket = new Socket(SERVER_ADDRESS, SERVER_PORT);
socket.setReuseAddress(true);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int msg = 71;
out.write("TEALBEE_CUR:" + msg);
out.flush();
String input;
String data = "";
while ((input = in.readLine()) != null) {
data += input;
}
socket.close();
return data;
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
The problem here is that while data-flow is consistent and can run for at least a week; I lost use of other sockets connections on my pc, namely my Kodi remote control (this is media centre which I can control through a socket connection on my smartphone). My pc at address "192.168.0.37" accepts connections at port 193 for Kodi but after running the Java client for some time and sending a lot of requests to the server, I notice that the remote cannot connect anymore to my PC.
I thought that this might be the case because the sockets cannot be reused and after a single use the socket becomes unusable. This does seem to be the case as my host detects a different socket port for each request.
I tried to solve this by adding the code socket.setReuseAddress(true) and properly closing the socket after each message, but the problem still occurs.
How can I fix this properly (if possible only use one client socket and close this properly so it can be used again the next time).
EDIT: also important to note I can access 192.168.0.37:193 from my PC, but not from my smartphone when the socket connection cannot be established. Yes I am sure that the PC and smartphone and RPI are on the same network and without the client program running I CAN access 192.168.0.37:193 from my smartphone.

Bind - Address Already in Use

So i'm setting up a VoIP software and my connection thread to another peer has a UDP socket (to send audio) and a tcp socket for signaling/text. Now, to bypass firewalls and NAT, i need to use a TCP Hole punching technique, meaning i need to try and connect from this side of the call, which will open up holes in the firewall and NAT, and then i await a connection on the same port and the other peer should be able to connect to me.
try {
// UDP Socket
DatagramSocket callSocket = new DatagramSocket(null);
callSocket.setReuseAddress(true);
callSocket.bind(new InetSocketAddress(myIP, 0));
//Send/receive a few packets on callSocket
// Addresses to use
InetSocketAddress myAddress = new InetSocketAddress(myIP, callSocket.getLocalPort());
InetSocketAddress targetAddress = new InetSocketAddress(InetAddress.getByName("192.168.1.1"), 6800);
// TCP Hole Punch
Socket tcpSocket = new Socket();
tcpSocket.setReuseAddress(true);
tcpSocket.bind(myAddress);
try {
tcpSocket.connect(targetAddress, 50);
// this never connects. it's just meant to open a hole in a firewall
} catch (SocketTimeoutException ignore) {
System.out.println("Timeout!");
}
tcpSocket.close();
// Open up TCP socket
ServerSocket tcpTempSocket = new ServerSocket();
tcpTempSocket.setReuseAddress(true);
tcpTempSocket.bind(myAddress);
// accept connection and do stuff
} catch (Exception ex) {
ex.printStackTrace();
}
When i get to the 3rd and final bind, i get the "Bind Exception: Address already in use". I googled it up and read that the previous socket could still be hanging on something and wasn't closing, etc.
EDIT: this only happens in some computers. On others, it binds everything without an issue
EDIT: using "netstat", i can see that the connection is being hung up on "SYN_SENT" state on the computer where the bind goes wrong
Anyone have any tips on why this happens or how to i go around it?
Ok, so. The answer is... You can't go around it. This is an OS feature, which makes tcp connections get hung up on this port. On some computers it may take 5seconds to clear. On others, it may take over 2minutes.
Now, what i've done to get around this was... well, the only thing i could think of. When the program starts, it checks whether it supports tcp hole punching, or other ways of bypassing firewalls. The peers, when establishing the call, will trade parameters based on what they can do and, from a given priority list, choose a method they both support.
In my case, on my computer, TCP Hole Punch works. In my mum's laptop it doesn't, and i resorted to other techniques (UDP Hole Punch, UPnP, SOCKS, etc etc)

Java Threadpool TCP Server (Port keeps changing!!)

Good Day,
I was taking a look at this tutorial to do a TCP Threadpool server.
http://tutorials.jenkov.com/java-multithreaded-servers/thread-pooled-server.html
It works great for listening/RECEIVING to clients and processing, and returning a response. There is a class inside that I pass in WorkerRunnable into, and that basically prints out the remote socket address (who it was sent from)
public void run(){
synchronized(this){
this.runningThread = Thread.currentThread();
}
openServerSocket();
while(! isStopped()){
Socket clientSocket = null;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
if(isStopped()) {
System.out.println("Server Stopped.") ;
return;
}
throw new RuntimeException(
"Error accepting client connection", e);
}
this.threadPool.execute(
new WorkerRunnable(clientSocket,
"Thread Pooled Server"));
}
this.threadPool.shutdown();
System.out.println("Server Stopped.") ;
}
The problem is. The remote address is supposed to stay fixed (I am working within my own home wifi router). However, the IP address of the sender stays the same, but the port keeps changing!!
This is a big problem for me..as I need to be able to return a response to the user for future tasks and I actually save this address to use again to send data. When I ran this in a single TCP thread..it stayed fixed (the port).
Why does the threadpool cause the TCP remote address port to keep changing?
With TCP, the client socket port is most of the time (almost 99%, except for specific protocols) randomly chosen. But to you don't have to know it, the only thing you have to do is to keep the clientSocket reference to write back data to the client. If you want to send data to the other host after that the connection is closed, you have to start a ServerSocket on both sides with a fixed port.
Even if you test from same machine the client port will be random by default. I am not sure if there is any way to set the client source port. However, if you use netstat or capture the packet you can be sure the source port is different for every connection.

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

Categories

Resources