UDP in Java thinks that UDP has "connections" - java

UDP in Java thinks that UDP has "connections". This surprised me, coming from a C background where I had always used UDP as a fire-and-forget type of protocol.
When testing UDP in Java, I noticed that if the remote UDP port is not listening, I get an error in Java before I attempt to send anything.
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
(The code below is run in the receiving thread for the socket. Sending is done in a different thread.)
try {
socket = new DatagramSocket(udpPort);
socket.connect(udpAddr, udpPort);
} catch (SocketException e) {
Log.d(TAG, "disconnected", e);
}
...
while (true) {
// TODO: don't create a new datagram for each iteration
DatagramPacket packet = new DatagramPacket(new byte[BUF_SIZE], BUF_SIZE);
try {
socket.receive(packet); // line 106
} catch (IOException e) {
Log.d(TAG, "couldn't recv", e);
}
...
produces the error below, if the remote socket is not listening.
java.net.PortUnreachableException:
at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:556)
at libcore.io.IoBridge.recvfrom(IoBridge.java:516)
at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
at java.net.DatagramSocket.receive(DatagramSocket.java:253)
at com.example.mypkg.MyClass.run(MyClass.java:106)
at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: recvfrom failed: ECONNREFUSED (Connection refused)
at libcore.io.Posix.recvfromBytes(Native Method)
at libcore.io.Posix.recvfrom(Posix.java:131)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
...

First of all, it is clear that this is not implemented using real Java. The "libcore.io" packages are not part of the Java SE libraries. These are Android stacktraces. (This doesn't change anything ... but it could.)
OK, so lets start with the exception. The javadoc for java.net.PortUnreachableException says:
"Signals that an ICMP Port Unreachable message has been received on a connected datagram."
And for DatagramSocket.connect(...):
"If the remote destination to which the socket is connected does not exist, or is otherwise unreachable, and if an ICMP destination unreachable packet has been received for that address, then a subsequent call to send or receive may throw a PortUnreachableException. Note, there is no guarantee that the exception will be thrown."
So here's what I think has happened. Prior to creating the incoming socket, something on the client system has sent a UDP packet to the server on that port, and the server has responded with an ICMP Port Unreachable. Then your socket is created, and connected, and you call receive. This does a recvfrom syscall, and network stack responds with an ECONREFUSED error code ... which Java turns into a PortUnreachableException,
So does this mean that UDP is connection oriented?
Not really, IMO. It is simply reporting the that it received an ICMP message in response to something that happened earlier.
What about the connect methods, and the "connected socket" / "connected datagram" phraseology?
IMO, this is just some clumsy wording. The "connection" is really just referring to the fact that the datagram socket has been bound to a specific remote address and port ... so that you can send and receive datagrams without specifying the IP and port1.
These "connections" are pretty tenuous and certainly don't amount to making UDP "connection oriented".
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
It is not doing anything. Java is simply reporting information from a previous ICMP message.
1 - Actually, there is a bit more to it than that. For example, binding tells the client-side OS to buffer UDP packets from that host / port an route UDP packets (and ICMP notifications) to the application. It also tells it not to respond with an ICMP Port Unreachable.

UDP in Java thinks that UDP has "connections".
No it doesn't, but UDP (regardless of Java) does have connected sockets. Not the same thing.
This surprised me, coming from a C background where I had always used UDP as a fire-and-forget type of protocol.
You can connect() a UDP socket in C too. Look it up. What you describe has nothing to do with Java specifically.
When testing UDP in Java, I noticed that if the remote UDP port is not listening, I get an error in Java before I attempt to send anything.
That's because you connected the socket. One of the side-effects of that is that incoming ICMP messages can be routed back to the sending socket in the form of errors.
What does Java do (without me asking it to) in order to be able to tell whether a remote UDP port is listening?
It calls the BSD Sockets connect() method.

The UDP server needs to listen on a local port.
Here's a code stub for a server.
int portNumber = 59123;
DatagramSocket server = new DatagramSocket(portNumber);
// read incoming packets
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while(true)
{
server.receive(packet);
byte[] data = packet.getData();
String text = new String(data, 0, packet.getLength());
echo(packet.getAddress().getHostAddress() + ":" + packet.getPort() + " received: '" + text + "'");
}

Related

Trouble with UDP ports and DatagramSockets

I'm working on a project that is suppose to send a file from one machine to another using DatagramPackets and DatagramSockets. The implementation is suppose to mimic the TCP protocol. So once the receiver gets a packet it sends back an ACK to the sender, confirming the packet was delivered. My program so far without making any checks for ACKs. Im having trouble implementing the ACK messages. On my receiver program, it shows that the ACKs are being sent, but the sender application is not getting them.
I keep getting an error from creating the socket. "java.net.BindException: Address already in use: Cannot bind". I'm confused because nowhere else in the sender applicaion have a specified the port. I simply use DatagramSocket socket = new DatagramSocket();
but I do use
DatagramPacket packet = new DatagramPacket(packetData, packetData.length, internetAddress, 49000);
socket.send(packet); when sending packets.
I have tried removing the datagram declaration in my waitForAck() method and used the same datagramSocket I used to send packets. But socket.receive(packet); will hang and never recieve anything because it hasnt been assigned a port to listen on.
This is my method to listen for ACKs:
public void waitForACK(){
//listen for ack for a period of time
//if ACK received, then break send next packet
//if ACK not received or time out, send last packet
//TODO: implement a timeout
System.out.println("### Sender waiting for ACK");
try {
DatagramSocket receivingSocket = new DatagramSocket(49000);
while (!ACKreceived) {
byte[] buf = new byte[1500]; // Actual Ethernet packet size is 1500 bytes
// receive request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
receivingSocket.receive(packet); //socket.receive(packet); <--
byte[] packetData = Arrays.copyOf(packet.getData(), packet.getLength());
ACKreceived = checkACK(packetData);//check the recieved packet contains an ACK message
}
System.out.println("### Sender recieved ACK");
} catch (Exception e) {
System.out.println("### never got ACK");
System.out.println(e);
}
}
I've also tried this but the scoket will hang and never actualy recieve anything. Even though the application that recieves the file successfully reports sending an ACK. I'm guessing its because it does not know to recieve the ACK on port 49000.
public void waitForACK(){
//listen for ack for a period of time
//if ACK received, then break send next packet
//if ACK not received or time out, send last packet
//TODO: implement a timeout
System.out.println("### Sender waiting for ACK");
try {
while (!ACKreceived) {
byte[] buf = new byte[1500]; // Actual Ethernet packet size is 1500 bytes
// receive request
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet); //<--- HANGS RIGHT HERE
byte[] packetData = Arrays.copyOf(packet.getData(), packet.getLength());
ACKreceived = checkACK(packetData);//check the recieved packet contains an ACK message
}
System.out.println("### Sender recieved ACK");
} catch (Exception e) {
System.out.println("### never got ACK");
System.out.println(e);
}
}
You're leaking sockets.
Don't create a new socket just to wait for an ACK. You should have exactly one DatagramSocket open for the life of the application.
Try to use the netstat command to check if another program (or even your program) is active on the port. On unix netstat -lp as su will show you, on windows netstat exists too with different command line options
Before we get into the problems with your code: Why is the client trying to listen on port 49000?
If you don't already realize this: the local port and peer port do not have to be the same, and generally are not. When you call DatagramSocket(), you get an arbitrary local port assigned by the OS. The fact that you sent to 49000 doesn't change your local port. And if the other side of the connection just sends back to the tuple it received a packet from, that won't arrive at 49000, it will arrive at your local port.
If that's your problem, the fix is to use the second version (just use your existing socket to listen as well as sending), and then fix the other side (that you haven't shown us the code for) to send the ACK to the complete address tuple of the packet's sender, not port 49000 on the sender's host.
If you realize that, but think that both sides need to have local port 49000 for some reason… well, they probably don't. Generally, a protocol needs one side (the "server") to have a well-known port to connect, but the other side (the "client") doesn't need that. That's why you can use DatagramSocket() instead of DatagramSocket(49000) on the client and things work.
Again, same fix.
In the rare cases where both sides really do need to have a well-known port (e.g., so you can explicit open it in your company's internal firewalls), you almost certainly want the sending to also happen on that port.
So, instead of creating a DatagramSocket() to send from, and a DatagramSocket(48000) to listen on, just create a DatagramSocket(48000) in the first place and use it for both.
However, note that this solution, like any solution that uses a fixed port, has two additional problems:
First, if client and server both want to bind port 48000, they can't both run on the same machine. You can renumber one of them to 48001, or just accept that.
Second, if you expect to start and stop the client frequently, it's often going to try to bind port 49000 while the OS still has a socket for that port in TIME_WAIT state, so you're going to get a bind error. This is what SO_REUSEADDR is for; use it.
What if you really do want to use an arbitrary-port sender on the client, but a fixed-port listener? There are some cases where that makes sense, but unless you can explain why you really need this, you don't have one.
If you do, then, and only then, could you use something like your first version. But you still probably want to create the listener socket once, not each time you listen for ACKs; it just should be a different attribute from the sending socket. (And of course you still need to deal with the same things as in the last section.)
And if you really do want to create a new listener socket for each ACK, then you have to make sure you close it immediately, rather than waiting for the Java GC and the OS to collectively get around to closing it for you, or the next time you wait for an ACK, you're likely to get a bind error, because the old listener socket is still bound to it.

Socket TCP connection write failure

I have tcp communication via socket code like :
public void openConnection() throws Exception
{
socket = new Socket();
InetAddress iNet = InetAddress.getByName("server");
InetSocketAddress sock = new InetSocketAddress(iNet, Integer.parseInt(port));
socket.connect(sock, 0);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
and send method as :
synchronized void send(String message)
{
try
{
out.println(message);
}
catch (Exception e)
{
throw new RuntimeException(this.getClass() + ": Error Sending Message: "
+ message, e);
}
}
This writes message on socket and communicated through tcp. (non-blocking call)
My doubt is, how can we determine if this packet was successfully sent or if dropped, what was the reason through java code?
TCP acknowledgement indicates that the data is pushed to the other end of the TCP/IP stack & it necessarily doesn't mean that the receiver application has processed the data. In windows/linux a successful send completion indicates the buffer is copied to the kernel mode socket buffer.
You can try setting the socket buffer to zero which makes the TCP/IP stack to complete the send call only after receiving acknowledgement for the buffer. This happens at least in windows & this behavior can't be assumed in java.
TCP provides reliable communication with the endpoint. If there is no error then the message was received. The wikipedia page on TCP states that:
TCP provides reliable, ordered and error-checked delivery of a stream
of octets between programs running on computers connected to a local
area network, intranet or the public Internet.
https://en.wikipedia.org/wiki/Transmission_Control_Protocol
If the communication fails then you can inspect the specific exception that has been thrown. You should review the API documentation to determine the specific exceptions that are thrown and the reason for them. To help with this it is useful to be more specific with your exception handling (handle specific types of exception separately rather than just catching Exception).

UDP port scanning Java finds only 1 open UDP port

I have an assigment about port scanning. I am scanning UDP ports of some IP addresses in Java.In my program (assuming everything is OK) I can only find one open UDP port. In the other hands port scanning over "nmap" I get 4 open UDP ports. Can somebody tell me why I can not find more than one ports via Java code?
By the way I can find the true open port in my code.
int startPortRange=1;
int stopPortRange=1024;
InetAddress address = InetAddress.getByName("bigblackbox.cs.binghamton.edu");
int counter=0;
for(int i=startPortRange; i <=stopPortRange; i++)
{
counter++;
try{
byte [] bytes = new byte[128];
DatagramSocket ds = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
ds.setSoTimeout(100);
ds.connect(address, i);
ds.send(dp);
ds.isConnected();
dp = new DatagramPacket(bytes, bytes.length);
ds.receive(dp);
ds.close();
System.out.println("open");
System.out.println(counter);
}
catch(InterruptedIOException e){
//System.out.println("closed");
}
catch(IOException e){
//System.out.println("closed");
}
}
Output of above code is
135 open
When I make same operation in command line using nmap I get more open ports.
I could not upload an image because I am a new user.
Thank you
It is impossible to provide a concrete answer, unless you provide at least:
The source code of your program.
An example of the (incorrect) output that you are getting.
The expected output for the same scenario.
Without this information there is no way for us to tell you what is wrong. For all we know, it could even be a simple case of your program terminating prematurely after finding an open port. Or a case of the open port that was last found overwriting the entries of the previous ones before being displayed.
In any case, it might be worthwhile to investigate what is being sent and received using a network sniffer, such as Wireshark. By comparing an nmap session with a session created by your program, you might be able to spot some significant difference that would help pinpoint the issue.
EDIT:
After having a look at your code and comparing with nmap, it seems that you are mistakenly handling the case of a SocketTimeoutException as a closed port, while it could simply be the port of a server that refuses to answer to the packet that you sent.
EDIT 2:
Here's the full story:
When a port is properly closed, the server sends back an ICMP Destination Unreachable packet with the Port unreachable error code. Java interprets this error to an IOException that you correctly consider to indicate a closed port.
An open port, on the other hand may result into two different responses from the server:
The server sends back a UDP packet, which is received by your program and definitely indicates an open port. DNS servers, for example, often respond with a Format error response. nmap shows these ports are open.
The server ignores your probe packet because it is malformed w.r.t. to the provided service. This results in a network timeout and a SocketTimeoutException in your program.
Unfortunately there is no way to tell whether a network timeout is because an active server ignored a malformed probe packet or because a packet filter cut down the probe. This is why nmap displays ports that time out as open|filtered.

What will happen to a TCP/UDP serversocket when I switch wifi network?

what will happen to the serversocket in my app when I suddenly change the wifi network? I guess it will shut down since my device will get a new IP, at least in TCP, is the UDP MulticastSocket prone to this as well? And how to end the previous Server socket thread and start a new one when the network changes? One solution is using time outs, another is using a flag that will indicate whether the infinite loop should end or not but since listening to a socket is a blocking function it will produce an exception/error anyways.
Any thoughts will be appreciated! :)
EDIT: sample of my server thread.
ServerSocket ss = new ServerSocket(4445);
while(true){
Socket socket = ss.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
Object obj = in.readObject();
Log.i("TAG", "Received: " + obj.toString());
in.close();
socket.close();
}
TCPIP connection will break. So client would have to connect again.
UDP will be ok provided your IP does not change after reconnection. Of course if you transmit UDP its not going to make a difference for that machine.
You should get an exception in case of TCPIP which you can handle.
UDP sockets that are not bound to the address will remain open, as they are stateless. TCP listening sockets not bound to the address will remain open as well.
Conntected TCP sockets may be severed (RST) or just linger until a timeout hits.
It is a little known fact that IP mandates it that a device by default will accept packets directed to any address it has configured on any interface, no matter on which interface the packet arrives. If this were not so, routing would be broken. One can use packet filters to filter out packets with non-matching addresses depending on the interface.

when to close and reopen socket after HL7 message sent

I am trying to open a basic connection to an HL7 server where I send a request and get the ACK response. This will be done continuously.
If this is being done continuously, when do I close the socket? Am I implementing this correctly, in this case?
If I close the socket, how do I open it again? The javadocs for ConnectionHub indicates the following:
attach(java.lang.String host, int port, Parser parser,
java.lang.Class<? extends LowerLayerProtocol> llpClass)
Returns a Connection to the given address, opening this Connection if necessary.
However, in real life, it will not open a new connection if it was already closed.
Patient patient = appt.getPatient();
Parser parser = new GenericParser();
Message hl7msg = parser.parse(wlp.getORMString(appt));
//Connect to listening servers
ConnectionHub connectionHub = ConnectionHub.getInstance();
// A connection object represents a socket attached to an HL7 server
Connection connection = connectionHub.attach(serverIP, serverPort,
new PipeParser(), MinLowerLayerProtocol.class);
if (!connection.isOpen()) {
System.out.println("CONNNECTION is CLOSED");
connection = connectionHub.attach(serverIP, serverPort, new PipeParser(),
MinLowerLayerProtocol.class);
if (!connection.isOpen()) {
System.out.println("CONNNECTION is still CLOSED");
}
}
Initiator initiator = connection.getInitiator();
Message response = initiator.sendAndReceive(hl7msg);
String responseString = parser.encode(response);
System.out.println("Received response:\n" + responseString);
connection.close();
Result:
The first pass goes through perfectly, with request sent and ACK received. Any subsequent call to this method results in java.net.SocketException: Socket closed" on the client side.
If I remove the connection.close() call, then it will run fine for a certain amount of time then the socket will close itself.
If you are communicating via HL7 2.X, the expected behavior on the socket is to never disconnect -- you allocate the connection and keep the socket active. Said another way, an HL7 application does not act like a web browser wherein it connects as needed and disconnects when done. Rather, both ends work to keep the socket continuously connected. Most applications will be annoyed if you disconnect. Further, most integration engines have alerts that will fire if you are disconnected for too long.
Once the socket is connected, you need to use the HL7 Minimum Lower Layer Protocol (MLLP or MLP) to communicate the HL7 2.X content. If you are sending data, you should wait for an HL7 Acknowledgment before you send the next message. If you are receiving data, you should generate the HL7 Ack.
References:
MLP - http://www.hl7standards.com/blog/2007/05/02/hl7-mlp-minimum-layer-protocol-defined
Acks - http://www.corepointhealth.com/resource-center/hl7-resources/hl7-acknowledgement

Categories

Resources