Hi everyone,
I have a large program running well except for when I try to implement the socket factory example of MQTT into the program. I get the following error (I have stripped this back to the exact example of socket factory, which I have running in itself.)
this is the following error I get:
this is the code I have:
I'm out of ideas on things to try in relation to making this work, I have the same additional jars, and package properties as in my socket factory example.
#AdditionalJar: bcprov-jdk18on-172
#AdditionalJar: bcpkix-jdk15to18-172
#PackagerProperty: VMArgs = --add-opens b4j/org.bouncycastle.jcajce.provider.asymmetric.x509=java.base
any help or direction would be greatly appreciated!
I have a large program running well except for when I try to implement the socket factory example of MQTT into the program. I get the following error (I have stripped this back to the exact example of socket factory, which I have running in itself.)
this is the following error I get:
error:
Error occurred on line: 11476 (Main)
java.lang.RuntimeException: java.net.SocketException: Socket closed
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA$3.run(BA.java:267)
at anywheresoftware.b4a.keywords.SimpleMessageLoop.runMessageLoop(SimpleMessageLoop.java:47)
at anywheresoftware.b4a.StandardBA.startMessageLoop(StandardBA.java:43)
at anywheresoftware.b4a.shell.ShellBA.startMessageLoop(ShellBA.java:121)
at anywheresoftware.b4a.keywords.Common.StartMessageLoop(Common.java:180)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:309)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(
Method.java:566)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at b4j.collator1.main.main(main.java:51)
Caused by: java.net.SocketException: Socket closed
at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)
at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)
at anywheresoftware.b4a.shell.ShellConnector.sendControlMessage(ShellConnector.java:55)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:189)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
at jdk.internal.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base
/java.lang.reflect.Method.invoke(Method.java:566)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
... 16 more
java.lang.RuntimeException: java.util.NoSuchElementException
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at b4j.collator1.main.main(main.java:51)
this is the code I have:
Socket factory implemented code:
Sub MQTTStart
'MQTT
Dim cafile As String = File.GetUri (File.DirAssets, "mqtt-ca.crt").SubString(6)
Dim certfile As String = File.GetUri(File.DirAssets, "client-11.crt").SubString(6)
Dim keyfile As String = File.GetUri(File.DirAssets, "client-11-nopassword.key").SubString(6)
Dim url As String ="ssl://mqtt.1.smarttwin.app:8883"
Dim clientId As String = "Test"
Dim user As String = "password"
Dim password As String = "password"
Dim keyFilePassword As String = Null
'Initial cmqtt client
client.Initialize("client", url, clientId)
'setup Paho MqttCallbackExtended
Dim Mjo As JavaObject = client
Dim event As Object = Mjo.CreateEventFromUI("org.eclipse.paho.client.mqttv3.MqttCallback", "MqttCallback", Null)
Mjo.GetFieldJO("client").RunMethod("setCallback", Array(event))
'set Paho Options
mo.Initialize(user,password)
Dim result As String
Dim MqttConnectOptions1 As JavaObject = mo
result = MqttConnectOptions1.RunMethod("setMqttVersion",Array(3))
result = MqttConnectOptions1.RunMethod("setKeepAliveInterval",Array(60))
result = MqttConnectOptions1.RunMethod("setConnectionTimeout",Array(60))
'setup SocketFactory => does not work
Dim jo As JavaObject = Me
jo.InitializeNewInstance("b4j.example.main.SslUtil", Array(Null))
MqttConnectOptions1.RunMethod("setSocketFactory",Array(jo.RunMethod("getSocketFactory", Array As String (cafile, certfile, keyfile, keyFilePassword))))
ConnectMe
End Sub
Sub ConnectMe
client.Connect2(mo)
End Sub
Private Sub client_Connected (Success As Boolean)
If Success Then
Log("Client Connected")
client.Subscribe("#",0)
Else
Log("Connection Failed")
End If
End Sub
Private Sub client_Disconnected
Log("Client Disconnected")
End Sub
private Sub MqttCallback_Event (MethodName As String, Args() As Object ) As Object
If MethodName = "messageArrived" Then
'Log("Message Arrived!")
handleMessageArrived(Args)
Return Null
else If MethodName = "deliveryComplete" Then
Log("Delivery Complete!")
Return Null
else If MethodName = "connectionLost" Then
Log("Connection lost!")
Return Null
End If
End Sub
Sub handleMessageArrived(args() As Object)
Dim topic As String = args(0)
Dim mA As JavaObject = args(1)
Dim payload() As Byte = mA.RunMethod("getPayload", Null)
If payload.Length > 0 Then
Log(topic & " -> " & (BytesToString(payload, 0, payload.Length, "utf8").Trim))
End If
End Sub
#If JAVA
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileReader;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
public class SslUtil
{
public SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile, final String keyFile,
final String password) {
try {
/**
* Add BouncyCastle as a Security Provider
*/
Security.addProvider(new BouncyCastleProvider());
JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter().setProvider("BC");
/**
* Load Certificate Authority (CA) certificate
*/
PEMParser reader = new PEMParser(new FileReader(caCrtFile));
X509CertificateHolder caCertHolder = (X509CertificateHolder) reader.readObject();
reader.close();
X509Certificate caCert = certificateConverter.getCertificate(caCertHolder);
/**
* Load client certificate
*/
reader = new PEMParser(new FileReader(crtFile));
X509CertificateHolder certHolder = (X509CertificateHolder) reader.readObject();
reader.close();
X509Certificate cert = certificateConverter.getCertificate(certHolder);
/**
* Load client private key
*/
reader = new PEMParser(new FileReader(keyFile));
Object keyObject = reader.readObject();
reader.close();
PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder().build(password.toCharArray());
JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair key;
if (keyObject instanceof PEMEncryptedKeyPair) {
key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject).decryptKeyPair(provider));
} else {
key = keyConverter.getKeyPair((PEMKeyPair) keyObject);
}
/**
* CA certificate is used to authenticate server
*/
KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
caKeyStore.load(null, null);
caKeyStore.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(caKeyStore);
/**
* Client key and certificates are sent to server so it can authenticate the client
*/
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
clientKeyStore.load(null, null);
clientKeyStore.setCertificateEntry("certificate", cert);
clientKeyStore.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(),
new Certificate[]{cert});
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
/**
* Create SSL socket factory
*/
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
/**
* Return the newly created socket factory object
*/
return context.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
#End If
I'm out of ideas on things to try in relation to making this work, I have the same additional jars, and package properties as in my socket factory example.
#AdditionalJar: bcprov-jdk18on-172
#AdditionalJar: bcpkix-jdk15to18-172
#PackagerProperty: VMArgs = --add-opens b4j/org.bouncycastle.jcajce.provider.asymmetric.x509=java.base
any help or direction would be greatly appreciated!