Odd InetAddress.isReachable() issue - java

My work is developing software for network capable cameras for retail enviroments. One of the peices of software my team is developing is a webserver that retrieves various reports generated in HTML by the camera itself (which has its own embedded webserver) and stored on the camera. Our software will then GET these reports from the camera and store it on a central webserver.
While we are fine plugging in the IPs of the cameras into our software, I am developing a simple Java class that will query the network and locate all cameras on the network.
The problem though is that while it runs just fine on my PC, and my coworker's PC, when we attempt to run it on the actual webserver PC that will host our software... it runs, but says every IP in the subnet is offline / unreachable EXCEPT for the gateway IP.
For example, if I run it from my PC or my coworkers PC when plugged into the closed LAN, I get the following active IPs found along with a flag telling me if its a camera or not.
(gateway is 192.168.0.1, subnet mask is 255.255.255.0, which means full range of 256 devices to be looked for)
IP:/192.168.0.1 Active:true Camera:false
IP:/192.168.0.100 Active:true Camera:true <- this is camera 1
IP:/192.168.0.101 Active:true Camera:true <- this is camera 2
IP:/192.168.0.103 Active:true Camera:false <- my PC
IP:/192.168.0.104 Active:true Camera:false <- this is our webserver
But for some reason, when running the same program from the webserver PC, using the same JRE, I only get the following found
IP:/192.168.0.1 Active:true Camera:false
Now my code, instead of enumerating through each IP in order on the main Thread, instead creates a seperate Thread for each IP to be checked and runs them concurrently (else it would take little over 21 minutes to enumerate through the entire IP range at a timeout of 5000ms / IP). The main Thread then re-runs these IP scan threads every 15 seconds over and over.
I have checked that all the threads are running to completion on all the PCs, no exceptions are being thrown. Even verified that none of the threads are getting stuck. Each Thread takes about 5001 to 5050ms from start to complete, and those Threads that have an active IP finish sooner (>5000ms), so I know that its correctly waiting the full 5000ms in the ipAddr.isReachable(5000) method.
Me and my coworker are stumped at this point while it seems to reach those active IPs fine when run on our PCs, yet getting no response from the webserver PC???
We have ruled out firewall issues, admin access issues, etc.. The only difference is that our webserver is Embedded Win XP, and our PCs are Windows 7.
This has us stumped. Any ideas why?
Below is the code that is running each IP Thread:
public void CheckIP() {
new Thread() {
#Override
public void run() {
try {
isActive = ipAddr.isReachable(5000);
if (isActive) {
if (!isCamera) {
isCamera = new IpHttpManager().GetResponse(ipAddr.toString());
}
} else {
isCamera = false;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
EDIT: Here is the code that builds each IP to check after determining the range based on gateway and subnet...
for(int i=subMin; i<=subMax; i++) {
byte[] ip = new byte[] {(byte)oct[0],(byte)oct[1],(byte)oct[2],(byte)i};
try {
scanners[subCount] = new IpScan(InetAddress.getByAddress(ip));
subCount++;
} catch (UnknownHostException e) {
e.printStackTrace();
}}

Thanks everyone, but I never did figure out or pinpoint why this oddity was happening. Everything I checked for was not the cause, so this question can be closed.
In any case, I ended up working around it completely. Instead of using InetAddress, I just went native and built my own ICMP ping class instead, via JNA, invoking Windows libraries IPHLPAPI.DLL and WSOCK32.DLL. Here is what I used...
public interface InetAddr extends StdCallLibrary {
InetAddr INSTANCE = (InetAddr)
Native.loadLibrary("wsock32.dll", InetAddr.class);
ULONG inet_addr(String cp); //in_addr creator. Creates the in_addr C struct used below
}
public interface IcmpEcho extends StdCallLibrary {
IcmpEcho INSTANCE = (IcmpEcho)
Native.loadLibrary("iphlpapi.dll", IcmpEcho.class);
int IcmpSendEcho(
HANDLE IcmpHandle, //Handle to the ICMP
ULONG DestinationAddress, //Destination address, in the form of an in_addr C Struct defaulted to ULONG
Pointer RequestData, //Pointer to the buffer where my Message to be sent is
short RequestSize, //size of the above buffer. sizeof(Message)
byte[] RequestOptions, //OPTIONAL!! Can set this to NULL
Pointer ReplyBuffer, //Pointer to the buffer where the replied echo is written to
int ReplySize, //size of the above buffer. Normally its set to the sizeof(ICMP_ECHO_REPLY), but arbitrarily set it to 256 bytes
int Timeout); //time, as int, for timeout
HANDLE IcmpCreateFile(); //win32 ICMP Handle creator
boolean IcmpCloseHandle(HANDLE IcmpHandle); //win32 ICMP Handle destroyer
}
And then using those to create the following method...
public void SendReply(String ipAddress) {
final IcmpEcho icmpecho = IcmpEcho.INSTANCE;
final InetAddr inetAddr = InetAddr.INSTANCE;
HANDLE icmpHandle = icmpecho.IcmpCreateFile();
byte[] message = new String("thisIsMyMessage!".toCharArray()).getBytes();
Memory messageData = new Memory(32); //In C/C++ this would be: void *messageData = (void*) malloc(message.length);
messageData.write(0, message, 0, message.length); //but ignored the length and set it to 32 bytes instead for now
Pointer requestData = messageData;
Pointer replyBuffer = new Memory(256);
replyBuffer.clear(256);
// HERE IS THE NATIVE CALL!!
reply = icmpecho.IcmpSendEcho(icmpHandle,
inetAddr.inet_addr(ipAddress),
requestData,
(short) 32,
null,
replyBuffer,
256,
timeout);
// NATIVE CALL DONE, CHECK REPLY!!
icmpecho.IcmpCloseHandle(icmpHandle);
}
public boolean IsReachable () {
return (reply > 0);
}

My guess is that your iteration logic to determine the different ip address is based upon different configuration hence your pc's fetches all addresses but your webserver doesn't.
Try adding debug in the logic where you build up the list of ip adresses to check.

Related

How do I monitor connections to my Modbus Slave in android, using J2Mod?

I am currently writing a Modbus TCP/IP Slave using the J2Mod V 3.0. I have created the slave and have it listening on the correct port and can connect to it from my PC (using Simply Modbus). What I cannot seem to figure out is how do I monitor the connections that my Slave is receiving? How do I know when a Master writes to one of my registers? Any help is appreciated. I am including how I setup the slave just in case that helps.
void createSlave() {
try {
String ip = Model.getInstance().plcSettings().getIPAddress(true);
String[] ipStringArray = ip.split("\\.");
byte[] addr = new byte[4];
for (int i = 0; i < ipStringArray.length; i++) {
addr[i] = Byte.parseByte(ipStringArray[i]);
}
slave = ModbusSlaveFactory.createTCPSlave(InetAddress.getByAddress(addr), port, 5, false, (Model.getInstance().plcSettings().getIdleTimeout() * 60));
slave.addProcessImage(1, image);
slave.open();
} catch (NumberFormatException | ModbusException | UnknownHostException modException) {
modException.printStackTrace();
}
}
I have actually reached out and was responded to by Steve O'Hara. It turns out with J2mod there is currently no way to monitor a connection. Shout out to him for responding and being so cool about everything.

How to implement ping like functionality using pcap4j library

I want to implement basic network check functionality to test if the provided url is responding or not (eg. ping www.google.com).It must provide operational information indicating, for example, that a requested service is not available or that a host could not be reached. I am able to achive it using icmp4j library. But i want to achieve the same using pcap4j library. I want to put the url in text box and click on connect button which will call pcap4j api to check whether the host is responding or not.
You can create ICMPv4 Echo (ping) on Ethernet packets using the Builders of IcmpV4EchoPacket, IcmpV4CommonPacket, IpV4Packet, and EthernetPacket and send them by PcapHandle.sendPacket(). Please refer to org.pcap4j.sample.SendFragmentedEcho in pcap4j-sample project.
You will need to implement ARP to resolve IP addresses to MAC addresses like org.pcap4j.sample.SendArpRequest in pcap4j-sample project.
And you will also need to implement a feature to find the next hop (default gateway or so) from the given IP address somehow. Pcap4J doesn't provide API to support this implementation. (Java doesn't provide API to get routing table...)
You'd maybe better use java.net.InetAddress#isReachable() instead.
It took me more than a year to figure this out, as I wanted to make a traceroute with pcap4j, so here is what I did:
Get your IPv4 Address and Mac Address, this can be easily achieved by querying the PcapNetworkInterface
Get target IP Address, if you have a DNS Name you need to resolve it beforehand.
Get target Mac Address.
Target is in the same subnet: send an ARP Request to resolve the mac (alternatively, a mac broadcast will likely work fine too).
Target is in different subnet: you need to get the mac of your gateway server then, this is not as easy. Assuming you have other network traffic going on, you could listen for incoming packets and get the source mac, where the source IP address is from a different subnet, this is likely the mac address of your gateway server.
Create IcmpV4EchoPacket and sent it
Listen for incoming ICMP traffic, you will get one of these three:
A IcmpV4EchoReplyPacket which is likely to be an answer to your request (check identifier and sequence number to be sure)
A IcmpV4TimeExceededPacket if the target could not be reached with the time-to-live you specified
Nothing, routers and pinged targets are free to ignore and not answer your request
Variables that need to be filled:
short IDENTIFIER; // identifer may be any 16 bit interger
short SEQUENCE; // sequence may be any 16 bit integer
byte TTL; // time to live (1-255)
Inet4Address IP_TARGET; // ip address of your ping target
Inet4Address IP_ORIGIN; // your own ip address
MacAddress MAC_TARGET; // target or gateway mac address
MacAddress MAC_SOURCE; // your own mac address
PcapNetworkInterface PCAP4J_NETWORK_INTERFACE; // network interface used to execute the ping
How to make a ICMP Echo Request Packet (as payload of IcmpV4CommonPacket of IpV4Packet of EthernetPacket):
public Packet buildPacket() {
IcmpV4EchoPacket.Builder icmpV4Echo = new IcmpV4EchoPacket.Builder()
.identifier(IDENTIFIER) // optional, default zero
.sequenceNumber(SEQUENCE); // optional, default zero
IcmpV4CommonPacket.Builder icmpV4Common = new IcmpV4CommonPacket.Builder()
.type(IcmpV4Type.ECHO) // type is echo
.code(IcmpV4Code.NO_CODE) // echo request doesn't need this
.payloadBuilder(icmpV4Echo)
.correctChecksumAtBuild(true);
IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder()
.correctChecksumAtBuild(true)
.correctLengthAtBuild(true)
.dstAddr(IP_TARGET) // IPv4 Address where tp send the request
.payloadBuilder(icmpV4Common)
.protocol(IpNumber.ICMPV4) // payload is ICMPV4
.srcAddr(IP_ORIGIN) // Your own IPv4 Address
.tos(IpV4Rfc1349Tos.newInstance((byte) 0))
.ttl(TTL) // time to live (1-255)
.version(IpVersion.IPV4); // IP Version is IPv4
EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder()
.dstAddr(MAC_TARGET) // the targets mac address
.srcAddr(MAC_SOURCE) // your own mac address
.type(EtherType.IPV4) // payload protocl is IPv4
.payloadBuilder(ipv4Builder)
.paddingAtBuild(true);
return etherBuilder.build(); // build your packet
}
Listener for ICMP Echo Answers or timeouts:
public PacketListener buildListener() {
return new PacketListener() {
#Override
public void gotPacket(Packet packet) {
if (!(packet instanceof EthernetPacket))
return;
EthernetPacket ethernetPacket = (EthernetPacket) packet;
packet = ethernetPacket.getPayload();
if (!(packet instanceof IpV4Packet))
return;
IpV4Packet ipV4Packet = (IpV4Packet) packet;
IpV4Header ipV4Header = ipV4Packet.getHeader();
packet = ipV4Packet.getPayload();
if (!(packet instanceof IcmpV4CommonPacket))
return;
IcmpV4CommonPacket icmpPacket = (IcmpV4CommonPacket) packet;
packet = icmpPacket.getPayload();
// successful reply just measure time and done
if (packet instanceof IcmpV4EchoReplyPacket) {
IcmpV4EchoReplyPacket icmpV4EchoReplyPacket = (IcmpV4EchoReplyPacket) packet;
IcmpV4EchoReplyHeader icmpV4EchoReplyHeader = icmpV4EchoReplyPacket.getHeader();
if (icmpV4EchoReplyHeader.getIdentifier() != identifier)
return;
if (icmpV4EchoReplyHeader.getSequenceNumber() != sequence)
return;
// here you got an echo reply
System.out.println(packet);
return;
}
// try handle time to live exceeded messages
if (packet instanceof IcmpV4TimeExceededPacket) {
packet = packet.getPayload(); // original IPv4
if (!(packet instanceof IpV4Packet))
return;
packet = packet.getPayload(); // original ICMP common
if (!(packet instanceof IcmpV4CommonPacket))
return;
packet = packet.getPayload(); // original ICMP echo
if (!(packet instanceof IcmpV4EchoPacket))
return;
IcmpV4EchoHeader icmpV4EchoHeader = ((IcmpV4EchoPacket)packet).getHeader();
if (icmpV4EchoHeader.getIdentifier() != IDENTIFIER)
return;
if(icmpV4EchoHeader.getSequenceNumber() != SEQUENCE)
return;
// HERE you got an answer, that the time to live has been used up
System.out.println(packet);
return;
}
};
}
Combining it togther:
public static void main(String[] args) throws IOException, PcapNativeException, NotOpenException, InterruptedException {
try (PcapHandle handle = PCAP4J_NETWORK_INTERFACE.openLive(1024, PromiscuousMode.PROMISCUOUS, 1000)) {
// set filter to only get incoming ICMP traffic
handle.setFilter("icmp and dst host " + Pcaps.toBpfString(IP_ORIGIN), BpfCompileMode.OPTIMIZE);
// send ARP request
Packet p = buildPacket();
handle.sendPacket(p);
// wait (forever) for ARP answer
PacketListener listener = buildListener();
handle.loop(-1, listener);
}
}

Modbus TCP in Java / Android

I am working on a modbus TCP implementation in Java. I've tried 3 different libraries so far modbus4j, jamod, and j2mod. I can successfully access my slave device with the linux modpoll tool: http://www.modbusdriver.com/modpoll.html
michael#michael-G75VW:~/Documents/modbus-test-tool/linux$ ./modpoll -a255 -r1 -1 192.168.1.101
modpoll 3.4 - FieldTalk(tm) Modbus(R) Master Simulator
Copyright (c) 2002-2013 proconX Pty Ltd
Visit http://www.modbusdriver.com for Modbus libraries and tools.
Protocol configuration: MODBUS/TCP
Slave configuration...: address = 255, start reference = 1, count = 1
Communication.........: 192.168.1.101, port 502, t/o 1.00 s, poll rate 1000 ms
Data type.............: 16-bit register, output (holding) register table
-- Polling slave...
[1]: 256
This causes the barrier on my device to go up which is great. However, working in the Java implementation I am unable to reproduce this. I've tried many different steps but all fail. In J2mod/jamod I continually get a invalid slaveId error when using '255' which is the unit id i use in the above command. If I use anything else, I get a CRC failed error. In mod4j I get various errors including error code = 4. Here is my latest J2mod code which returns either CRC error (if not 255) or invalid slaveId. I know slaveId is mostly used for Serial communications, but my device only responds to a Unit ID of 255 when using other applications.
Integer value = Integer.decode(val).intValue();
Integer unitID = Integer.decode(uid).intValue();
Integer length = Integer.decode(len).intValue();
Integer ref = Integer.decode(reference).intValue();
SimpleRegister MyReg = new SimpleRegister(value);
try {
InetAddress address;
address = InetAddress.getByName(addr);
//2. Open the connection
TCPMasterConnection con = new TCPMasterConnection(address);
con.setPort(port);
con.connect();
//3. Prepare the requestWrite
WriteSingleRegisterRequest WriteReq = new WriteSingleRegisterRequest(ref,MyReg);
WriteReq.setDataLength(length);
WriteReq.setUnitID(unitID);
//4. Prepare the transaction
ModbusTCPTransaction trans = new ModbusTCPTransaction(con);
trans.setRequest(WriteReq);
trans.setRetries(0);
trans.execute();
Log.d(TAG, "Complete: " +trans.toString());
return trans.getResponse().getHexMessage();
} catch (UnknownHostException e) {
Log.d(TAG, "UnknownHostException: " + e.getMessage());
return e.getMessage();
} catch (Exception e) {
Log.d(TAG,"Exception: " + e.toString());
return e.getMessage();
}
My manual for the modbus interface is available here:
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CCsQFjAA&url=http%3A%2F%2Fwww.ac-magnetic.com%2Fgermany%2Fsites%2Fdefault%2Ffiles%2F58150001EN_00_Technical%2520Maunal%2520EM01.pdf&ei=Z1dxUv7qF4a9yAGpooHYBQ&usg=AFQjCNGGZnBx_A0fFjuW3qqgWjhS_ek-0w&bvm=bv.55617003,d.aWc
I can't speak to why, exactly, this is happening. I can tell you that both jamod and j2mod (j2mod is a bug-fixed fork of jamod) simply copy whatever you set as the unit number to the 7th byte of the TCP packet. It's then up to the PLC to respond to the packet, as sent.
For j2mod, setting the system property com.ghgande.modbus.debug equal to "true" from the JVM command line will enable debug messages. That will allow you to view a packet dump that should tell you what's happening.
You do make one very interesting comment, and that is that you are seeing CRC errors. You are aware that Modbus/TCP doesn't use a CRC at all?

Function hangs? on packet.setAddress()

Ok so the program is designed to take in connections, validate them, and resend that validation code. Before anyone get's angry it's just a simple little project and is not designed to be overly complex haha. However for some very strange reason the function is hanging on send.setAddess(packet.getAddress); I know this because I have commented out each individual line of code that deals with the Datagram packet "send" and have found that it "hangs" (or never progresses forward in the method again) on that particular line. Any thoughts? Am I doing something cluelessly wrong? I tried it on a linux server as well to make sure it didn't have anything to do with me and the same crap happened.
public static boolean authorize(String n, DatagramPacket packet) {
DatagramPacket send = new DatagramPacket(new byte[4096], 4096);
try {
System.out.println("in auth");
String[] t1 = n.split("%#");
String name = t1[1];
int k = genKey(name);
clients.put(name, k);
send.setAddress(packet.getAddress());
System.out.println("set add");
send.setPort(packet.getPort());
System.out.println("set port");
send.setData(("l-succeed%#" + Integer.toString(k)).getBytes());
System.out.println("set data");
main.dispathcer(send);
System.out.println("called send");
return true;
} catch(Exception e) {
send.setData("l-failed".getBytes());
main.dispathcer(send);
return false;
}
}
EDIT: it took 6 minutes before the authorization token was received by the client. So obviously the setAddress() works but is taking far too long...
It's possible that the process is hanging because there's an issue doing DNS resolution on the address for packet when you call .getAddress(). A few DNS calls are made in order to create the InetAddress object. On these machines, are you able to do a reverse DNS lookup on the IP that the packet packet came from? Try setting an entry for this IP in your /etc/hosts file.

How to read and write data to COM/Serial ports in Android? [duplicate]

This question already has answers here:
using serial port RS-232 in android?
(8 answers)
Closed 2 years ago.
I have to read and write data to the COM ports of a device using Android. I am using javax.comm package for that, but when I installed the apk file, it is not displaying any ports of the device. Is there any permission which I need to add in the manifest file?
Your problem is one with operating systems. Android runs Linux under the hood, and Linux treats serial ports differently than Windows does. javax.comm also contains win32com.dll, a driver file, which you won't be able to install on an Android device. If you do find a way to achieve what you're trying to do, you can't actually look for a "COM" port in a Linux environment. The serial ports will go by different names.
Windows Com Port Linux equivalent
COM 1 /dev/ttyS0
COM 2 /dev/ttyS1
COM 3 /dev/ttyS2
So, hypothetically, if your idea were to work, you have to look for these names.
Luckily for you, Android does have provisions for interfacing with USB devices (Which I assume you want to connect to, as opposed to parallel or RS-232 ports). To do this, you will set up your device as a USB Host. Here's what you'll want to do:
Get a USBManager.
Find your device.
Get the USBInterface and USBEndpoint.
Open a connection.
Transfer data.
Here's my rough estimate of how you'll do it. Your code will, of course, have a more mature way of doing things.
String YOUR_DEVICE_NAME;
byte[] DATA;
int TIMEOUT;
USBManager manager = getApplicationContext().getSystemService(Context.USB_SERVICE);
Map<String, USBDevice> devices = manager.getDeviceList();
USBDevice mDevice = devices.get(YOUR_DEVICE_NAME);
USBDeviceConnection connection = manager.openDevice(mDevice);
USBEndpoint endpoint = device.getInterface(0).getEndpoint(0);
connection.claimInterface(device.getInterface(0), true);
connection.bulkTransfer(endpoint, DATA, DATA.length, TIMEOUT);
Extra material for your reading pleasure: http://developer.android.com/guide/topics/connectivity/usb/host.html
I am no expert, but for all those who are looking to connect serial RS-232 ports or open a serial port and can't find their device trough the UsbManager, you can find all your devices using an approach like this:
mDrivers = new Vector<Driver>();
LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));
String l;
while ((l = r.readLine()) != null) {
String drivername = l.substring(0, 0x15).trim();
String[] w = l.split(" +");
if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) {
mDrivers.add(new Driver(drivername, w[w.length - 4]));
}
}
After finding all drivers, iterate trough all the drivers to get all of your devices, using something like this:
mDevices = new Vector<File>();
File dev = new File("/dev");
File[] files = dev.listFiles();
if (files != null) {
int i;
for (i = 0; i < files.length; i++) {
if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {
Log.d(TAG, "Found new device: " + files[i]);
mDevices.add(files[i]);
}
}
}
Here is the Driver class constructor, with two member variables:
public Driver(String name, String root) {
mDriverName = name;
mDeviceRoot = root;
}
For opening a serial port you can use the Android SerialPort API. Simply open the serial port at your device and write. (You must know your device path and baud rate. For example, my device is ttyMt2 with baud Rate 96000.)
int baudRate = Integer.parseInt("96000");
mSerialPort = new SerialPort(mDevice.getPath(), baudRate, 0);
mOutputStream = mSerialPort.getOutputStream();
byte[] bytes = hexStr2bytes("31CE");
mOutputStream.write(bytes);
Instead of wasting time on this code, you can download the complete project from https://github.com/licheedev/Android-SerialPort-Tool.

Categories

Resources