B4J Question Need Assistance to Implement WebSockets using SSL/TLS1.2 between Client and Server

Ed Brown

Active Member
Licensed User
Longtime User
Hello, and apologies for the long post.

I have spent the last several days trying to work out exactly how to implement a client/server connection using secure websockets. I have had no joy in getting this to work. Below is an outline of what the hardware infrastructure is, what the requirements are and what I've tried to date.

I have searched and read just about every example in the forum for websockets. But, I still have a few questions about how to communicate between the client and server.

Requirement:
I need to have a desktop app (later will need Android / iOS, and web app) that will connect to a web app server using TLS1.2 secure web sockets.

This is a requirement for the client. Previously, I had everything working nicely with simple TCP Sockets. The requirement has come about due to the need to increase security and provide encryption between the client (a device - Android/iOS/custom hardware) and the server.

If there is a way to communicate between a client and server using TCP sockets while using SSL/TLS1.2 then please do let me know how to implement it. I could not find anything in the forums or documentation that explains how to do this.

Infrastructure:
What I have is a VPS hosted with Amazon Web Services (AWS) and an Elastic Load Balancer (ELB) in front of the VPS. Also, I have used LetsEncrypt.com to obtain a SSL certificate and successfully installed the certificate onto the VPS and on the ELB.

To the ELB I have added a Listener for SSL traffic on port 65534 and this is the port I need the web socket to connect to. I have also added listeners for HTTP and HTTPS (80 / 443 respectively) on the ELB. All three listeners also have the equivalent ports open in the Security Group assigned to both the VPS and the ELB.

What I Have Tried:
The below code snippet is what I currently have for the client.

Client
B4X:
Sub Process_Globals
	Private webskt	As WebSocketClient
	Private uriRelayServer As String = $"wss://server.somedomain.com:65534"$
End Sub

Sub AppStart (Form1 As Form, Args() As String)
	webskt.Initialize("RelayServerSSL")
	webskt.Connect(uriRelayServer)
End Sub

Private Sub RelayServerSSL_Connected
' This sub never gets called - so far
	lblStatus.Text = "Connected to server."
End Sub

Server
The next code snippet is what I have implemented in the server.

B4X:
Sub Process_Globals
	Dim WebServer			As Server
	Dim mApplicationPort	As Int	= 65534
	Dim KeyStorePassword	As String	= "some_password"
End Sub

Sub AppStart (Args() As String)
	WebServer.Initialize("WebServer")
	ConfigureSSL(mApplicationPort)
	WebServer.AddWebSocket("", "App")
	WebServer.Start
	StartMessageLoop
End Sub

private Sub ConfigureSSL(SSLPort As Int)
	Dim ssl As SslConfiguration
	ssl.Initialize

'	Do the following lines really need to be there?
'	If they do then every time the SSL Cert expires a new keystore
'	will need to be used.
'	ssl.SetKeyStorePath(File.DirApp, "domain.keystore")
'	ssl.KeyStorePassword = KeyStorePassword
'	ssl.KeyManagerPassword = KeyStorePassword

	WebServer.SetSslConfiguration(ssl, SSLPort)
End Sub

The 'App' WebSocket Class is barebones right now...
B4X:
'WebSocket class
Sub Class_Globals
	Private ws As WebSocket
End Sub

Public Sub Initialize
	
End Sub

Private Sub WebSocket_Connected(WebSocket1 As WebSocket)
	ws = WebSocket1
End Sub

Private Sub WebSocket_Disconnected

End Sub

Questions:
I understand how TCP Sockets work very well and I'm probably (most likely) not fully understanding how websockets work.

I require the client (a device) to send a message to the server and then the server to respond by sending a message back. With TCP sockets this is rather trivial and I am hoping that websockets will be just as simple.

How can I retrieve the message on the server that is sent by the client? I am not seeing any documentation on any events that I can use to achieve this. With TCP sockets this is done using the NewData() event.

Once I have received the message from the client I need to send back a response but again, I cannot find anything in the documentation on how to simply do this. Again, with TCP sockets this is done by using the Write() method of Asyncstreams.

In addition, when adding the websocket class/handler to the server I am wanting the class to be tied to the root path '/' but if I use this then I get errors about multiple servlets attempting to bind to the same path. So for the websocket class I have simply left it as an empty string (""). Is this the way to do it? If not, how can I add the websocket class to the root path "/"?

The above questions are moot until I can work out how to make a successful connection. This leads me to the next section...

Connection Error
When I attempt to make the connection to the server I get the following error message.

B4X:
Program started.
2016-03-28 19:17:42.518:INFO::JavaFX Application Thread: Logging initialized @6499ms
java.io.IOException: Cannot init SSL
	at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newConnection(WebSocketClientSelectorManager.java:98)
	at org.eclipse.jetty.io.ManagedSelector.createEndPoint(ManagedSelector.java:411)
	at org.eclipse.jetty.io.ManagedSelector.access$1600(ManagedSelector.java:56)
	at org.eclipse.jetty.io.ManagedSelector$CreateEndPoint.run(ManagedSelector.java:587)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.execute(ExecuteProduceConsume.java:101)
	at org.eclipse.jetty.io.ManagedSelector.run(ManagedSelector.java:136)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
	at java.lang.Thread.run(Thread.java:745)
java.io.IOException: Cannot init SSL
	at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.newConnection(WebSocketClientSelectorManager.java:98)
	at org.eclipse.jetty.io.ManagedSelector.createEndPoint(ManagedSelector.java:411)
	at org.eclipse.jetty.io.ManagedSelector.access$1600(ManagedSelector.java:56)
	at org.eclipse.jetty.io.ManagedSelector$CreateEndPoint.run(ManagedSelector.java:587)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.execute(ExecuteProduceConsume.java:101)
	at org.eclipse.jetty.io.ManagedSelector.run(ManagedSelector.java:136)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
	at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.ExecutionException: java.io.IOException: Cannot init SSL
	at org.eclipse.jetty.util.FuturePromise.get(FuturePromise.java:123)
	at anywhersoftware.b4j.objects.WebSocketClientWrapper.Close(WebSocketClientWrapper.java:76)
	at anywhersoftware.b4j.objects.WebSocketClientWrapper$WSHandler.onWebSocketError(WebSocketClientWrapper.java:118)
	at org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver.onError(JettyListenerEventDriver.java:112)
	at org.eclipse.jetty.websocket.client.io.ConnectPromise.failed(ConnectPromise.java:58)
	at org.eclipse.jetty.websocket.client.io.WebSocketClientSelectorManager.connectionFailed(WebSocketClientSelectorManager.java:61)
	at org.eclipse.jetty.io.ManagedSelector$Connect.failed(ManagedSelector.java:636)
	at org.eclipse.jetty.io.ManagedSelector$Connect.access$1300(ManagedSelector.java:603)
	at org.eclipse.jetty.io.ManagedSelector$1.failed(ManagedSelector.java:355)
	at org.eclipse.jetty.io.ManagedSelector$CreateEndPoint.run(ManagedSelector.java:592)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
	at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.execute(ExecuteProduceConsume.java:101)
	at org.eclipse.jetty.io.ManagedSelector.run(ManagedSelector.java:136)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Cannot init SSL

I have tried changing the port number from 65534 to 443 without any luck. There are no other web servers (apache/nginx) running that would/could interfere with the websocket connections on the VPS.

I would be most grateful to anyone that has any ideas on what to try next or if someone has successfully implemented secure websockets and is able to share their experience.
 

dar2o3

Active Member
Licensed User
Longtime User
To me it has worked well this library:
https://www.b4x.com/android/forum/threads/websocket-over-https.41885/

over this sample:
https://www.b4x.com/android/forum/threads/websocket-client-library.40221/

uses the library above,
B4X:
Sub Process_Globals
    Private wsh As WebSocketHandler
    Private link As String = "wss://direccionweb.com:51044/ws"
End Sub

WinSocket uncheck the library and marks the library SecureWinsocket.

But like Erel said, it does not work if you use the local ip, you must use the web address for Let's Encrypt (advertising) do its work (ssl).
 
Last edited:
Upvote 0

dar2o3

Active Member
Licensed User
Longtime User
in this example changes in class WebsocketHandler:

B4X:
Sub Class_Globals
    Public ws As SecureWebSocket
    Private CallBack As Object
    Private EventName As String
End Sub
 
Upvote 0

Ed Brown

Active Member
Licensed User
Longtime User
@Erel thanks for that. I'll try your idea but time is not on my side.

@dar2o3 thank you for the links. I'll take a closer look. I did see these posts before but the examples are all UI based and I am needing a solution where there is no UI involved. Also, the link to the library is for B4A, does this work also for B4J?
 
Upvote 0

dar2o3

Active Member
Licensed User
Longtime User
I only use b4j as a server, not if the library can work with b4j, I think so but ... you have to try.
 
Upvote 0
Top