Java NIO FileChannel - Empty reads from Android TUN network interface - java

Context: I've recently started using java.nio for my project which leverages Android's VpnService. In my implementation, I've wrapped the FileDescriptor that is returned by the establish() method of the VpnService into a java.nio.FileChannel as shown below.
private val outboundNetworkChannel = FileInputStream(fd).channel
After that, I've a kotlin coroutine which reads from the FileChannel indefinitely and processes the outbound IPv4 / IPv6 packets.
Issue: The below mentioned snippet works, but I see a lot of empty reads happening from the FileChannel which in turn spins the while loop unnecessarily.
fun reader() = scope.launch(handler) {
while (isActive) {
val pkt = read()
if(pkt !== DUMMY){
// Send the read IPv4/IPv6 packet for processing
}
}
}
private suspend fun read(): IPDatagram =
withContext(Dispatchers.IO) {
val bytes = ByteBufferPool.acquire()
outboundChannel.read(bytes) // Returns a lot of empty reads with return value as 0
return#withContext marshal(bytes) // Read IPv4/IPv6 headers and wrap the packet
}
What I'm looking for: For a fact, I know that FileChannel is a blocking channel and in this case since the channel is backed by a network interface, it might not have packets ready to be read. Is there a better approach with / without FileChannel which would lead to a more efficient implementation without wasting precious CPU cycles? I'm open to new ideas as well :)

I managed to figure this out after digging through the Android Docs for VpnService. By default, when a VPN connection is established using VpnService.Builder the fd is in non-blocking mode. Starting API level 21, one can setBlocking(true).
As stated in the docs for public VpnService.Builder setBlocking (boolean blocking)
Sets the VPN interface's file descriptor to be in
blocking/non-blocking mode. By default, the file descriptor returned
by establish() is non-blocking.

Related

How to write MappedByteBuffer to socket outputstream (server to client) with no copy

In Java code, I have a region of file mapped using MappedByteBuffer and I need to send this to the client (write to Outputstream). I need to make sure that while sending/writing to socket, it does not create any copy due to memory constraints. How can I achieve this? Will Bytebuffer.array() serve this purpose?
Sharing the code. Note: FileChannel is read-only and I need to send ByteBuffer data as it is.
private void writeData(Socket clientSocket, MappedByteBuffer byteBuffer){
Path path = Paths.get(myfile);
MappedByteBuffer memoryMappedBuffer = null;
try (FileChannel fChannel = FileChannel.open(path, StandardOpenOption.READ)) {
memoryMappedBuffer = fChannel.map(FileChannel.MapMode.READ_ONLY, location, size);
}catch(){
//How can i write memoryMappedBuffer to socket outputStream without copying data...? like
clientSocket.getOutputStream().write(memoryMappedBuffer .array());
}
If you are creating the socket yourself, you can use SocketChannel.open() instead, and use write(ByteBuffer). It manages the socket internally.
InetSocketAddress address = ...
SocketChannel channel = SocketChannel.open(address);
channel.write(memoryMappedBuffer);
// ...
channel.close(); // Closes the connection
If you have a pre-existing socket, you can create a Channel from the socket's output stream. However this allocates a (reused) temporary buffer.
WritableByteChannel channel = Channels.newChannel(clientSocket.getOutputStream());
channel.write(memoryMappedBuffer);
// ...
channel.close();
Based on your description you want to write to a socket the content of a file, or a slice of the file, slice that it is mapped to the virtual address space of your java process.
The memory-mapped files is used in general to share memory between multiple processes or to minimize the I/O operations on disk when your process is writing and reading data to/from the same files (a concrete example is Kafka which uses this procedure).
In your case, when you write the data to a socket, that socket has a buffer (regardless if it's blocking or non-blocking). When the buffer is full you will not be able to write, until the receiver acknowledge the data, and the buffer is cleared. Now, if the receiver is slow, you will remain with that portion of the file loaded to your main memory for a long time which can affect the performance of your server (I suppose you will not have a single consumer/client for your server).
One good and efficient solution is to use pipe streaming which sends data from your server to a consumer (in this case a socket) in a producer/consumer way. By default the PipeInputStream uses a buffer of 1024 bytes (you can increase it), meaning that only 1024 bytes will be kept in the memory at one moment in time for a specific execution thread. If your process has 500 clients, then you will consume only 500*1024 bytes = 512Kb. If one reader is slow, then that producer will be slow also without putting pressure on your process memory.
If all you have to do is to write the content of various files to sockets, I don't know how using memory-mapped files can helps you.

UDP library for Java that works garbage free

I'm looking for a UDP library for Java that works garbage free.
The reason is that i'm developing a daemon application for a real-time system.
My requirement is latency of 5 micro-sec per request (from arrival to my socket until the response gets to destination).
There are a couple of messaging services who support UDP and produce no garbage (Tibco FTL & Aeron), but both require that all communicating components will use the flatform.
My situation is that I have no control over the other components, all I know is that i'm going to get UDP messages to my socket and I need to handle them without producing any garbage.
Will appreciate any ideas :)
What do you mean by no garbage ? In UDP you may lose messages, this is inherent to this protocol. If you want to have some reliability on top of UDP you need to have an additional layer to manage acks, retransmissions and etc.. This means that your producer and consumer applications have to use this layer API to send / receive messages.
A very short example of this is just:
import java.lang.System;
public class UdpNoGc {
public static void main(String[] args) throws Exception {
var buf = new byte[1024];
var pkt = new java.net.DatagramPacket(buf, buf.length);
try (var sock = new java.net.DatagramSocket(4321)) {
for (;;) {
sock.receive(pkt);
System.out.write(buf, 0, pkt.getLength());
System.gc();
}
}
}
}
the explicit System.gc() call is just there so you can run with:
java "-Xlog:gc,heap*" UdpNoGc
and see that it doesn't allocate anything after startup. Note that writing code that doesn't allocate is somewhat difficult in Java, it might be easier using another language that provides more support for this.

java: Single socket on read write operation. Full duplex

I have to implement sending data with specific source port and in the same time listen to that port. Full duplex. Does anybody know how to implement it on java. I tried to create separate thread for listening on socket input stream but it doesnt work. I cannot bind ServerSocket and client socket to the same source port and the the same with netty.
It there any solution for dull duplex?
init(){
socket = new Socket(InetAddress.getByName(Target.getHost()), Target.getPort(), InetAddress.getByName("localhost"), 250);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
}
private static void writeAndFlush(OutputStream out, byte[] b) throws IOException {
out.write(b);
out.flush();
}
public class MessageReader implements Runnable {
#Override
public void run() {
//this method throw exception EOF
read(in);
}
private void read(DataInputStream in){
while (isConnectionAlive()) {
StringBuffer strBuf = new StringBuffer();
byte[] b = new byte[1000];
while ((b[0] = bufferedInputStream.read(b)) != 3) {
strBuf.append(new String(b));
}
log.debug(strBuf.toString());
}
}
}
What you're trying to do is quite strange: A ServerSocket is a fully implemented socket that accepts connections, it handles its own messages and you definitely cannot piggy-back another socket on top of it.
Full duplex is fairly simple to do with NIO:
Create a Channel for your Socket in non-blocking mode
Add read to the interest OPs
Sleep with a Selector's select() method
Read any readable bytes, write any writable bytes
If writing is done, remove write from interest OPs
GOTO 3.
If you need to write, add bytes to a buffer, add write to interest OPs and wake up selector. (slightly simplified, but I'm sure you can find your way around the Javadoc)
This way you will be completely loading the outgoing buffer every time there is space and reading from the incoming one at the same time (well, single thread, but you don't have to finish writing to start reading etc).
I had run into the same question and decided to answer it myself. I would like to share with you guys the code repo. It is really simple, you can get the idea to make your stuff work. It is an elaborate example. The steps accidentally look like Ordous's solution.
https://github.com/khanhhua/full-duplex-chat
Feel free to clone! It's my weekend homework.
Main thread:
Create background thread(s) that will connect to any target machines(s).
These threads will connect to target machines and transmit data and die
Create an infinite loop
Listen for incoming connections.
Thread off any connection to handle I/O
Classes:
Server
Listens for incoming connections and threads off a Client object
Client
This class is created upon the server accepting the incoming connection, the TcpClient or NetClient (i forget what java calls it) is used to send data. Upon completion it dies.
Target
Is created during the start up and connects to a specific target and send data.
once complete it dies.

playframework 1.2.5, continuations, how to close the response/socket?

I have some code like their example like so(untested as of yet)....
Promise<Object> promise = new Promise<Object>();
response.contentType = "application/json";
JsonStreamer streamer = new JsonStreamer(columns, promise);
while(streamer.hasMoreData()) {
await(promise);
response.writeChunk(streamer.nextDataChunk());
}
What I don't get is how do I release the socket that the client opened? I am streaming some very large data back in json. I need some kind of response.releaseSocket() after writing the last chunk. I see WebSockets has that but what about when I am using the await stuff?
thanks,
Dean
ah, I think it is noticing I never called await and in that case closes the socket. If I call await, it knows to keep the socket open. That makes sense.

How to detect FIN - tcp flag in java application?

I have long-lasting TCP connection between two computers (second not under my control). Second computer can send FIN flag at every moment, and first must close connection corrent (send FIN flag back to second computer).
How can I know that the second computer sending a FIN flag and when I must cause socket.close() method of my Java application?
Normally, you have to read the connection and when this returns -1 for EOF or an appropriate IOException, you can close the connection. Note: SocketTimeoutException doesn't mean the connection is closed.
an example.
boolean ok = false;
try {
int b = in.read();
ok = b >= 0;
if (!ok)
throw new EOFException();
} finally {
if (!ok)
in.close();
}
Detecting a soft connection close by the other side (when they manage to send FIN/RST flags) is only partially possible with the old Java I/O library. You will learn of a broken connection only via a timeout, so it may be far from immediate. Your threads may hang for a long time before they realize that the party at the other end is long gone.
In order to handle it better, you need to use nio. There, such a situation will be recognized by the Selector saying there is data ready for reading but then read on the channel returning less than zero. This will allow you to learn about soft connection resets almost immediately.
On the other hand, a hard connection termination (e.g. someone cutting the wire or network being down) can only be detected via timeouts regardless of which libraries you use as it's a property of the TCP protocol itself.
As explained above, the Socket's properties (isClosed, isConnected, etc) are not helpful. A proper solution would be to set a reasonable SO_TIMEOUT and read from the socket:
In case of connection closed by the peer, the read operation would return with '-1'
In case of read timeout, the read operation would throw SocketTimeoutException.
(Scala code)
val socket = new Socket("localhost", 8888)
socket.setSoTimeout(10000) /* Set reasonable read timeout */
try {
val res = socket.getInputStream().read()
if (res < 0)
... /* Socket closed */
else
... /* Socket read succeeded */
} catch {
case _: SocketTimeoutException => ... /* Socket not closed */
case _ => ... /* Merde */
}

Categories

Resources