Java Multi-Threaded Non-Blocking IO(NIO) Secure Protocol Framework

Introducing XlogistX.IO Java Multi-Threaded Secure NIO framework for quick and easy networking protocol implementation and deployments.

The pillars of the framework are:

Usage

Architecture Overview Part I

The framework is an alternative to Netty or Mina with minimal dependencies and small code footprint. It can be easily deployed on a Raspberry PI Zero(for small IoT projects) or on high-end rack mountable servers without sacrificing performance, security and portability.

 

The framework takes care of all the complexity of networking accepting/closing connections, detecting incoming data, reading raw bytes from ServerSocketChannel, managing the thread allocation and finally invoking the SessionCallback where the protocol implementation takes place.

The SessionCallback is the heart of the implementation.t receives raw data via a ByteBuffer, it assembles the request, processes the request and creates/sends back a response to the caller. Two abstract implementations of the SessionCallback could be extended, the PlainSessionCallback and the SSLSessionCallback(Secure TLS). The user simply implements the accept(ByteBuffer bb) method, the EchoProtocol Java code illustrates a complete and functional  code of a simple echo protocol.

The SessionCallback is already implemented for following protocols:

HTTP proxy
TCP Clear tunnel

The tcp tunneling is mainly used to expose services through a firewall

TCP Secure tunnel
HTTP Web server

An experimental web server that supports

A simple example Echo

An echo chat protocol

NIO Protocols currently implemented and deployed

Preliminary Testing

System

OS

Core

HyperThread

RAM

Dell laptop

Linux Ubuntu 22.04

4

8

32GB

Tested Service

TimeStamp

Total duration

Count

Rate /second

Average/millis

HTTPS

Feb 17, 2023 12:57:39 PM

0:01:36

100000

1038.0767

59.8584

HTTP

Feb 17, 2023 6:50:36 PM

0:00:22

500000

22558

3.11532

Architecture Detailed Part II

Prerequisite

What is NIO

NIO stands for Non-blocking Input Output, it is the opposite of the standard stream architecture that requires a dedicated thread waiting for reading incoming data via the input stream. NIO uses signaling mechanism within the OS to detect packet activities such as:

How NIO works

To detect the different IO activities,a thread will be dedicated to poll on registered selection keys using a selector object. The selector object wakes up from the select mode once IO activities are detected. Based on the IO activities type a new connection is established, incoming data are available for reading or a connection closure is detected.

The design

To simplify and create an extensible multithreaded design 5 classes are used to implement the NIO framework:

  1. NIOSocket
  2. ProtocolFactory
  3. ProtocolHandler
  4. SessionCallback
  5. ChannelOutputStream

NIOSocket

The NIOSocket is the main entry point class or object of the framework it uses Executor to multithread activities of IO operations, it is responsible for:

  1. Registering ServerSocketChannel to ProtocolFactory instances
  2. Registering selection keys for nio Accept and Read
  3. Looping via a thread to detect SelectionKeys
  4. Managing the Selector instance to detect IO operations such as: Accepting new connection, Creating one ProtocolHandler per connection via the ProtocolFactory, Detecting incoming data, Invoking the appropriate ProtocolHandler

ProtocolFactory

The ProtocolFactory is responsible for:

  1. Managing the Protocol configuration
  2. Creating the associated ProtocolHandler and SessionCallback

ProtocolHandler

The ProtocolHandler is responsible for:

  1. Setting up the session
  2. Reading and filtering incoming raw data
  3. Invoking SessionCallback
  4. Detecting channel closing
  5. Closing the connection

SessionCallback

The SessionCallback is the callback instance invoked after reading raw data via the ProtocolHandler. The SessionCallback is responsible for:

  1. Assembling incoming raw data
  2. Building full requests
  3. Processing the request
  4. Generating the response
  5. Sending the response via the ChannelOutputStream

ChannelOutputStream

The ChannelOutputStream is an output stream based on a ChannelSocket which behaves similar to an OutputStream for all practical purposes.

NIO Framework Pseudo State Diagram

NIO Framework DataExchange Sequence Diagram

TLS secure socket integration with NIO framework

What is TLS

TLS stands for Transport Layer Security. It uses cryptographic keys to communicate securely between 2 parties (e.g.  client and server).

Two types of keys are used to establish secure communication, a public/private asymmetric keypair and a symmetric temporary/session key.

After establishing a connection between client and server, a key exchange process takes place to negottate the following:

  1. What protocol to use ie TLS1.2 or TLS1.3
  2. What type of cypher to use
  3. The generated symmetric key to be used post handshaking for encrypting/decrypting data over the connection socket

In a nutshell, this is a very simplified overview of how TLS works. The truth is it is way more complicated.

Integrating TLS with the NIO framework

Initially I was too lazy to do the hard work so I decided to google any existing reference implementation and surprise, surprise nothing really worked, the Java documentation was useless, any github implementation covered specific protocol version or specific ciphers, no luck on stackoverflow either.

I guess the main reason is the Java SSLEngine handshaking complexity and behavior. I even asked chatGBT recently to give a Java TLS example, guess what useless again!!!, it seems that it grabbed the code from stackoverflow or something similar.  

The SSLEngine is a state machine

The SSLEngine is the core object that manages the handshaking and data encryption/decryption in Java, it behaves as a state machine that generates handshake status and result status after every SSL operation.

Luckily, at the start of COVID,  I designed a simple and extensible State Machine package and then later on,  I decided to implement SSLNIOSocket as a state machine. It was a perfect solution for a very complex problem: no need to figure out how to start the handshake, what transition is next, when the handshake is done, no need to check protocol version or cipher type.

The solution

As mentioned earlier, the SSL Engine is a state machine so in order to implement SSLNIOSocket a state machine is implemented to process SSLEngine handshake stages. The state machine algorithm behaves as follow:

  1. Accept a connection
  2. Start the SSLEngine handshake
  3. Wait for data
  4. Trigger the SSLEngine transition based on the handshake status
  5. Process the trigger code
  6. Trigger the SSLEngine transition based the current handshake status
  7. Wait for NOT_HANDSHAKING status
  8. Decrypt incoming data
  9. Encrypt outgoing data

SSLEngine HandshakeStatuses

SSLEngine Status

State

Description

BeginHandshake

Init state

Triggering the handshake process and setting the configuration parameters of the sslengine like data buffers, supported protocol and ciphers

NEED_WRAP

Handshaking

Wrapping data to be sent back to the caller during handshake process like protocol and cipher agreement, or key exchange agreement

NEED_UNWRAP

Handshaking

Reading data from the caller during handshake

NEED_TASK

Handshaking

mainly used for key generating and singing

FINISHED

Handshaking

Last step of the handshaking state

NOT_HANDSHAKING

DataReady

No more handshake ready to exchange application encrypted and decrypted data

   

NIO Framework With TLS Socket Pseudo State Diagram