Closed ThoSap closed 5 months ago
This doesn't look like a bug on the Milo side of things to me, it looks like a bug in the server, likely triggered by your unbounded recursive browse attempt.
Get a Wireshark capture of the whole thing with security disabled and we'll be able to see if the sequence numbers error is legit or not.
Do you have a basic how to guide on how you want the Wireshark log to be filtered? This could also be added to the GitHub issue template, so it is easier for people to report such issues.
Usually it’s enough to just filter on the IP addresses and optionally port (49320 by default for Kepware). I don’t usually care if it’s filtered or not because I can do it as well, but it can help keep the file size down in some cases.
I will provide you a Wireshark log on Thursday, I'm on PTO tomorrow.
Do you have a suggestion on how I could improve the small recursive method BadSecurityCheckFailedExample#browseRecursive
or could you suggest a better/proper solution?
Recursion is okay, it's the unbounded parallelism that becomes a problem for many servers.
Here you have the Wireshark .pcap
dump file, created with eldadru/ksniff as follows.
KEPServerEX_knsiff_dump.zip
Also, I give you my OPC UA client log that uses the simplified Java code from above, with Eclipse Milo 0.6.12 in DEBUG
log mode.
https://gist.github.com/ThoSap/c2254a949804bca3b5d1c6035801fe25
I restarted the container to have a complete dump and on 2024-05-02T08:32:36.614Z
(time reported by my OPC UA Client) the connection was established to the KEPserverEX 6.15.154.0 (see the log Gist above).
In the Wireshark dump, you can see the connection establishment at 2024-05-02T08:32:36.83059Z
.
[myuser@myk8svm ~]$ kubectl sniff my-k8s-pod -n my-k8s-namespace -c my-container -p -f "tcp port 49320" -o KEPServerEX.pcap
INFO[0000] sniffing method: privileged pod
INFO[0000] sniffing on pod: 'my-k8s-pod' [namespace: 'my-k8s-namespace', container: 'my-container', filter: 'tcp port 49320', interface: 'any']
INFO[0000] creating privileged pod on node: 'myk8svm'
INFO[0000] pod: 'ksniff-972zt' created successfully in namespace: 'my-k8s-namespace'
INFO[0000] waiting for pod successful startup
INFO[0002] pod: 'ksniff-972zt' created successfully on node: 'myk8svm'
INFO[0002] output file option specified, storing output in: 'KEPServerEX.pcap'
INFO[0002] starting remote sniffing using privileged pod
# tcpdump config is here ⬇️
INFO[0002] executing command: '[docker --host unix:///var/run/docker.sock run --rm --name=ksniff-container-PFymuGXh --net=container:8c478e520d6044ed920fb36eba2041fd73bae301a9bdc545abb5b9bd99e152cb maintained/tcpdump -i any -U -w - tcp port 49320]'
I found a similar issue where you tracked down the root cause: https://forum.inductiveautomation.com/t/anyone-know-of-a-way-to-dump-all-the-current-tag-values-from-the-opc-ua-server/74481/16
Thanks, the capture and logs are perfect, I'm looking at this now.
I suspect the problem is that you sending and receiving thousands of requests/responses concurrently and triggering this logic that was added to prevent DoS attacks: https://github.com/eclipse/milo/issues/1147
You could effectively disable it and revert to previous behavior by setting the milo.stack.serialization.maxQueueSize
property, e.g. -Dmilo.stack.serialization.maxQueueSize=2147483647
Unfortunately setting -Dmilo.stack.serialization.maxQueueSize=2147483647
did not help, I get the same exceptions.
My client may be able to handle more requests as I compiled this Java 21.0.2
code AoT using GraalVM native-image
.
The funny thing is, that I suddenly got this error without changing the Eclipse Milo version (0.6.11
) or KEPserverEX version, even though the same code (same container image hash) ran for half a year (even with some container restarts in between K8s node maintenance -> e.g. move POD to other worker nodes).
We also did not add any new OPC UA Objects or Variables in this time frame, so literally nothing changed in this time frame, and then suddenly this issue appeared.
Also, this previous version using Eclipse Milo version 0.6.11
ran for months and was also AoT compiled using GraalVM native-image
and Java 17.0.8.1+1
.
Now these exceptions appear when starting the client, even though this worked before without such issues.
To try to mitigate this issue, I then updated everything (Eclipse Milo 0.6.12
, Java 21.0.2
, Quarkus, KEPserverEX 6.15.154.0
, etc.) to see if this fixes this issue (possible bugfix in any of these components), but no luck as you can see.
After these same exceptions, the cron schedule that runs the BadSecurityCheckFailedExample#scrapeNodes
ran again and there I got the new error message Could not get NodeId NodeId{ns=2, id=BRU_ENRG_0001} -> status=Bad_SecureChannelIdInvalid, description=The specified secure channel is no longer valid.
➡️ try/catch from line client.getAddressSpace().getNode(exampleRootNodeId);
.
I'm pretty sure that's the issue... it's the only thing I can see that would cause it. I don't have any logging in place that can prove it, but I can add some if you're able to build and test against snapshot/dev releases.
The problem is that as of 0.6.11 SerializationQueue::decode
can return false
if it rejected the message, and the client isn't checking that: https://github.com/eclipse/milo/blob/7bd466ecae599f7651286e5d75709eb96edc0e08/opc-ua-stack/stack-client/src/main/java/org/eclipse/milo/opcua/stack/client/transport/uasc/UascClientMessageHandler.java#L617
Not that a check would do much good, because the only thing that can be done in that case it shut the channel down, and that ends up happening anyway.
The whole thing is non-deterministic and timing based.
So I guess it would probably be best to throttle the async browse recursion BadSecurityCheckFailedExample#scrapeNodes
using a Semaphore, right?
If you can get something like that working, yes.
The absolute safest thing to do is not use concurrency at all, like the other browse examples do. KEPServerEX happens to be able to handle this concurrent load well enough, but if you did this against a server in a PLC or something it would certainly fail.
I am a bit curious why the maxQueueSize system property didn't work. Was it the exact same errors about sequence numbers that preceded other errors? Are you sure it took effect?
I am a bit curious why the maxQueueSize system property didn't work. Was it the exact same errors about sequence numbers that preceded other errors? Are you sure it took effect?
I just figured out why the "fix" with the system property did not work.
As I did not runtime initialize class org.eclipse.milo.opcua.stack.core.channel.SerializationQueue
in the GraalVM AoT compiled native-image, the private static final int MAX_QUEUE_SIZE = Integer.getInteger("milo.stack.serialization.maxQueueSize", 256);
was effectively inlined in the GraalVM native-image.
After configuring the class org.eclipse.milo.opcua.stack.core.channel.SerializationQueue
to be runtime initialized by GraalVM native-image, I no longer get the exceptions above when I use -Dmilo.stack.serialization.maxQueueSize=2147483647
(instead of the default of 256
).
https://www.graalvm.org/jdk21/reference-manual/native-image/optimizations-and-performance/ClassInitialization/
https://www.graalvm.org/jdk21/reference-manual/native-image/guides/specify-class-initialization/
https://medium.com/graalvm/updates-on-class-initialization-in-graalvm-native-image-generation-c61faca461f7
If you find it worthwhile you could add a check if this class was AoT compiled by GraalVM native-image without runtime initializing it using this approach: https://github.com/FasterXML/jackson-databind/blob/jackson-databind-2.17.0/src/main/java/com/fasterxml/jackson/databind/util/NativeImageUtil.java
https://github.com/eclipse/milo/blob/v0.6.12/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/channel/SerializationQueue.java#L23 https://github.com/eclipse/milo/blob/v0.6.12/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/Session.java#L67
The GraalVM technology is now part of the OpenJDK (called Project Galahad and Project Leyden), so this check could be important. https://www.graalvm.org/2022/openjdk-announcement/ https://www.infoworld.com/article/3661359/project-leyden-set-to-bring-faster-startups-to-java.html
To get Eclipse Milo to work with in a GraalVM AoT compiled native-image I added the following runtime initialization and reflection config:
Runtime initialization
The org.google.common.* classes are needed to be runtime initialized for Guava used in Eclipse Milo.
Quarkus specific: Don't forget to escape ,
with \\,
if you are using application.properties
instead of application.yaml
.
--initialize-at-run-time=com.digitalpetri.netty.fsm.ChannelFsmConfigBuilder$SharedExecutor,com.google.common.cache.LongAddables,com.google.common.cache.Striped64,com.google.common.cache.Striped64$Cell,org.eclipse.milo.opcua.stack.core.channel.SerializationQueue,org.eclipse.milo.opcua.stack.core.util.BufferUtil,org.eclipse.milo.opcua.stack.core.util.NonceUtil
Also add the following classes for the server/client configuration to also print the Eclipse Milo and Java version in the native-image
also add the following to the list above:
org.eclipse.milo.opcua.sdk.client.OpcUaClient
org.eclipse.milo.opcua.sdk.server.OpcUaServer,org.eclipse.milo.opcua.sdk.server.Session
Reflection
To register necessary classes for reflection in the native-image
, else the client won't work:
package com.example.graal;
import io.quarkus.runtime.annotations.RegisterForReflection;
/**
}
- For a plain Java or Spring Boot project with GraalVM
Add `native-image` switch `-H:ReflectionConfigurationFiles=reflection-config.json`
Write the following file in `src/main/rersources/reflection-config.json`
Spring Boot: https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
```json
[
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.AxisScaleEnumeration",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.AxisScaleEnumeration$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseDirection$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseResultMask",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.BrowseResultMask$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.DataChangeTrigger",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.DataChangeTrigger$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.DeadbandType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.DeadbandType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ExceptionDeviationFormat",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ExceptionDeviationFormat$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.FilterOperator",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.FilterOperator$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.HistoryUpdateType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.HistoryUpdateType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.IdType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.IdType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ModelChangeStructureVerbMask",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ModelChangeStructureVerbMask$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NamingRuleType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NamingRuleType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NodeAttributesMask",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NodeAttributesMask$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.OpenFileMode",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.OpenFileMode$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.PerformUpdateType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.RedundancySupport",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.RedundancySupport$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.SecurityTokenRequestType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.SecurityTokenRequestType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ServerState",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.ServerState$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.StructureType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.StructureType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.TrustListMasks",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.TrustListMasks$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
},
{
"name": "org.eclipse.milo.opcua.stack.core.types.enumerated.UserTokenType$Codec",
"allDeclaredConstructors": true,
"allPublicConstructors": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allDeclaredFields": true,
"allPublicFields": true
}
]
Why do the enums to need get registered for anything to do with reflection? Is that because your application may use reflection to instantiate them?
If I do not add these to the reflection config I will get the following error when connecting as a client. This is probably due to how GraalVM optimizes the Bytecode to a Linux ELF native-image, see https://www.graalvm.org/latest/reference-manual/native-image/#native-image-and-third-party-libraries.
@ctron probably registered the same UaEnumeration classes here in this issue. https://github.com/quarkusio/quarkus/issues/13114#issuecomment-1257630131
You use Java reflection here to call the org.eclipse.milo.opcua.stack.core.types.enumerated.*#from
method.
https://github.com/eclipse/milo/blob/v0.6.12/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/serialization/OpcUaBinaryStreamDecoder.java#L679-L691
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2024-05-03T14:33:53.815Z INFO [kafka] (smallrye-kafka-producer-thread-0) SRMSG18258: Kafka producer kafka-producer-message, connected to Kafka brokers 'kafka-bootstrap.example.com:443', is configured to write records to 'message'
2024-05-03T14:33:53.818Z INFO [StartupOpcUaClient] (main) Eclipse Milo milo.stack.serialization.maxQueueSize: 2147483647
2024-05-03T14:33:53.818Z INFO [StartupOpcUaClient] (main) Starting OPC UA client for address: opc.tcp://mykepwarevm.example.com:49320
2024-05-03T14:33:53.819Z INFO [OpcUaClient] (main) Java version: 21.0.2
2024-05-03T14:33:53.819Z INFO [OpcUaClient] (main) Eclipse Milo OPC UA Stack version: 0.6.12
2024-05-03T14:33:53.819Z INFO [OpcUaClient] (main) Eclipse Milo OPC UA Client SDK version: 0.6.12
2024-05-03T14:33:53.885Z ERROR [UascClientMessageHandler] (milo-shared-thread-pool-0) Error decoding UaResponseMessage: org.eclipse.milo.opcua.stack.core.UaSerializationException: java.lang.NoSuchMethodException: org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType.from(int)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readEnum(OpcUaBinaryStreamDecoder.java:689)
at org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription$Codec.decode(ApplicationDescription.java:119)
at org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription$Codec.decode(ApplicationDescription.java:108)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStruct(OpcUaBinaryStreamDecoder.java:700)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.lambda$readStruct$0(OpcUaBinaryStreamDecoder.java:712)
at java.base@21.0.2/java.util.Optional.map(Optional.java:260)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStruct(OpcUaBinaryStreamDecoder.java:712)
at org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription$Codec.decode(EndpointDescription.java:125)
at org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription$Codec.decode(EndpointDescription.java:116)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStructArray(OpcUaBinaryStreamDecoder.java:1207)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStructArray(OpcUaBinaryStreamDecoder.java:1222)
at org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse$Codec.decode(GetEndpointsResponse.java:78)
at org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse$Codec.decode(GetEndpointsResponse.java:69)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readMessage(OpcUaBinaryStreamDecoder.java:669)
at org.eclipse.milo.opcua.stack.client.transport.uasc.UascClientMessageHandler.lambda$onSecureMessage$14(UascClientMessageHandler.java:654)
at org.eclipse.milo.opcua.stack.core.channel.SerializationQueue.lambda$decode$1(SerializationQueue.java:63)
at org.eclipse.milo.opcua.stack.core.util.TaskQueue$TaskWrapper.run(TaskQueue.java:273)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596)
at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:833)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211)
Caused by: java.lang.NoSuchMethodException: org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType.from(int)
at java.base@21.0.2/java.lang.Class.checkMethod(DynamicHub.java:1075)
at java.base@21.0.2/java.lang.Class.getDeclaredMethod(DynamicHub.java:1165)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readEnum(OpcUaBinaryStreamDecoder.java:685)
... 25 more
2024-05-03T14:33:53.951Z ERROR [UascClientMessageHandler] (milo-shared-thread-pool-2) Error decoding UaResponseMessage: org.eclipse.milo.opcua.stack.core.UaSerializationException: java.lang.NoSuchMethodException: org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType.from(int)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readEnum(OpcUaBinaryStreamDecoder.java:689)
at org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription$Codec.decode(ApplicationDescription.java:119)
at org.eclipse.milo.opcua.stack.core.types.structured.ApplicationDescription$Codec.decode(ApplicationDescription.java:108)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStruct(OpcUaBinaryStreamDecoder.java:700)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.lambda$readStruct$0(OpcUaBinaryStreamDecoder.java:712)
at java.base@21.0.2/java.util.Optional.map(Optional.java:260)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStruct(OpcUaBinaryStreamDecoder.java:712)
at org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription$Codec.decode(EndpointDescription.java:125)
at org.eclipse.milo.opcua.stack.core.types.structured.EndpointDescription$Codec.decode(EndpointDescription.java:116)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStructArray(OpcUaBinaryStreamDecoder.java:1207)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readStructArray(OpcUaBinaryStreamDecoder.java:1222)
at org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse$Codec.decode(GetEndpointsResponse.java:78)
at org.eclipse.milo.opcua.stack.core.types.structured.GetEndpointsResponse$Codec.decode(GetEndpointsResponse.java:69)
at org.eclipse.milo.opcua.stack.core.serialization.codecs.GenericDataTypeCodec$GenericBinaryDataTypeCodec.decode(GenericDataTypeCodec.java:47)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readMessage(OpcUaBinaryStreamDecoder.java:669)
at org.eclipse.milo.opcua.stack.client.transport.uasc.UascClientMessageHandler.lambda$onSecureMessage$14(UascClientMessageHandler.java:654)
at org.eclipse.milo.opcua.stack.core.channel.SerializationQueue.lambda$decode$1(SerializationQueue.java:63)
at org.eclipse.milo.opcua.stack.core.util.TaskQueue$TaskWrapper.run(TaskQueue.java:273)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base@21.0.2/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base@21.0.2/java.lang.Thread.runWith(Thread.java:1596)
at java.base@21.0.2/java.lang.Thread.run(Thread.java:1583)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:833)
at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:211)
Caused by: java.lang.NoSuchMethodException: org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType.from(int)
at java.base@21.0.2/java.lang.Class.checkMethod(DynamicHub.java:1075)
at java.base@21.0.2/java.lang.Class.getDeclaredMethod(DynamicHub.java:1165)
at org.eclipse.milo.opcua.stack.core.serialization.OpcUaBinaryStreamDecoder.readEnum(OpcUaBinaryStreamDecoder.java:685)
... 25 more
2024-05-03T14:33:53.951Z ERROR [StartupOpcUaClient] (main) Could not create the OPC UA client
java.util.concurrent.ExecutionException: org.eclipse.milo.opcua.stack.core.UaSerializationException: java.lang.NoSuchMethodException: org.eclipse.milo.opcua.stack.core.types.enumerated.ApplicationType.from(int)
2024-05-03T14:33:53.951Z INFO [StartupOpcUaClient] (main) Waiting 5 seconds to make another connection attempt...
I don't think this will be an issue in 1.0. The enum decoding, at least in this spot, no longer uses reflection: https://github.com/eclipse/milo/blob/a79fe4613e346db08c2f3bef96f34c6b00e10420/opc-ua-stack/stack-core/src/main/java/org/eclipse/milo/opcua/stack/core/encoding/binary/OpcUaBinaryDecoder.java#L689-L691
But I guess the classes that need to be runtime-initialized with a GraalVM native-image will not change.
Yes that pattern is pretty widely used. If there is some kind of Graal configuration file projects can provide that might be worth pursuing for the 1.0 release. I'm interested in supporting Graal native image, but not currently a user, so I'm not familiar with this and wouldn't able to verify anything.
The metadata can be gathered automatically and then published in the official GraalVM Reachability Metadata Repository.
"Manual" using the Tracing Agent https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/ https://www.graalvm.org/latest/reference-manual/native-image/guides/configure-with-tracing-agent/
Using the Maven plugin (enable the native-image-agent
here)
https://graalvm.github.io/native-build-tools/latest/maven-plugin.html
https://graalvm.github.io/native-build-tools/latest/index.html
https://github.com/graalvm/native-build-tools
GraalVM Reachability Metadata Repository https://github.com/oracle/graalvm-reachability-metadata https://github.com/oracle/graalvm-reachability-metadata/tree/master/metadata
Describe the bug Hi, I currently have the issue that I get the following error messages when using recursion with
OpcUaClient.getAddressSpace().browseNodesAsync(UaNode).thenCompose()
. Basically, I get aERROR [UascClientMessageHandler] (milo-shared-thread-pool-0) Error decoding symmetric message: org.eclipse.milo.opcua.stack.core.channel.MessageDecodeException: UaException: status=Bad_SecurityChecksFailed, message=bad sequence number: 2626, lastSequenceNumber=2566
followed by aWARN [AddressSpace] (milo-shared-thread-pool-2) Failed to create Node from Reference to ExpandedNodeId{ns=2, id=BRU_ENRG_0001.10_90_129_10.BRU.BAR.S1p2.activeEnergy._Description, serverIndex=0}: java.util.concurrent.CompletionException: UaException: status=Bad_ConnectionClosed, message=connection closed
Expected behavior I should not get the
MessageDecodeException
withBad_SecurityChecksFailed, message=bad sequence number
Logs and Packet Captures N/A
Additional context Client e.g. Eclipse Milo version: 0.6.12 Server: KEPserverEX 6.15.154.0
Simplified code where this occurs
Error logs