diff --git a/LICENSE b/LICENSE index 711f75f3ed9..7e649d5c796 100644 --- a/LICENSE +++ b/LICENSE @@ -203,11 +203,6 @@ =============================================================== -The files: -plc4j/transports/test/src/main/java/io/netty/channel/embedded/Plc4xEmbeddedChannel.java -plc4j/transports/test/src/main/java/io/netty/channel/embedded/Plc4xEmbeddedEventLoop.java -Are copyrighted by the The Netty Project which is distributed under the Apache 2.0 license. - The files: plc4go/spi/transports/serial/serialport/apply_linux.go plc4go/spi/transports/serial/serialport/apply_darwin.go diff --git a/NOTICE b/NOTICE index 7f56f7ce934..9fa88a2dbc6 100644 --- a/NOTICE +++ b/NOTICE @@ -6,8 +6,3 @@ The Apache Software Foundation (http://www.apache.org/). ---------------------------------------------- -This product includes software developed at -The Netty project (https://netty.io/). - ----------------------------------------------- - diff --git a/plc4go/protocols/bacnetip/readwrite/model/BACnetVendorId.go b/plc4go/protocols/bacnetip/readwrite/model/BACnetVendorId.go index 62f4516174a..329dc8f6a7e 100644 --- a/plc4go/protocols/bacnetip/readwrite/model/BACnetVendorId.go +++ b/plc4go/protocols/bacnetip/readwrite/model/BACnetVendorId.go @@ -1673,6 +1673,12 @@ const ( BACnetVendorId_SPEC_PROM_DIZAJNOOO BACnetVendorId = 1638 BACnetVendorId_FACTS_ENGINEERINGLLC BACnetVendorId = 1639 BACnetVendorId_G_ASERV_GMBH BACnetVendorId = 1640 + BACnetVendorId_LEEDS_ELECTRONICS_ENGINEERING_LIMITED BACnetVendorId = 1641 + BACnetVendorId_MITO_CONTRACTING_GROUP_INC BACnetVendorId = 1642 + BACnetVendorId_CALECTROAB BACnetVendorId = 1643 + BACnetVendorId_BMSOS_TECHNOLOGY_INC BACnetVendorId = 1644 + BACnetVendorId_VOSSLOH_SCHWABE_DEUTSCHAND_GMBH BACnetVendorId = 1645 + BACnetVendorId_IVIVA_PTE_LTD BACnetVendorId = 1646 BACnetVendorId_UNKNOWN_VENDOR BACnetVendorId = 0xFFFF ) @@ -3311,6 +3317,12 @@ func init() { BACnetVendorId_SPEC_PROM_DIZAJNOOO, BACnetVendorId_FACTS_ENGINEERINGLLC, BACnetVendorId_G_ASERV_GMBH, + BACnetVendorId_LEEDS_ELECTRONICS_ENGINEERING_LIMITED, + BACnetVendorId_MITO_CONTRACTING_GROUP_INC, + BACnetVendorId_CALECTROAB, + BACnetVendorId_BMSOS_TECHNOLOGY_INC, + BACnetVendorId_VOSSLOH_SCHWABE_DEUTSCHAND_GMBH, + BACnetVendorId_IVIVA_PTE_LTD, BACnetVendorId_UNKNOWN_VENDOR, } } @@ -6161,6 +6173,30 @@ func (e BACnetVendorId) VendorId() uint16 { { /* '1640' */ return 1640 } + case 1641: + { /* '1641' */ + return 1641 + } + case 1642: + { /* '1642' */ + return 1642 + } + case 1643: + { /* '1643' */ + return 1643 + } + case 1644: + { /* '1644' */ + return 1644 + } + case 1645: + { /* '1645' */ + return 1645 + } + case 1646: + { /* '1646' */ + return 1646 + } case 165: { /* '165' */ return 165 @@ -12703,6 +12739,30 @@ func (e BACnetVendorId) VendorName() string { { /* '1640' */ return "GAserv GmbH" } + case 1641: + { /* '1641' */ + return "Leeds Electronics Engineering Limited" + } + case 1642: + { /* '1642' */ + return "MITO Contracting Group Inc." + } + case 1643: + { /* '1643' */ + return "Calectro AB" + } + case 1644: + { /* '1644' */ + return "bmsOS Technology Inc." + } + case 1645: + { /* '1645' */ + return "Vossloh-Schwabe Deutschand GmbH" + } + case 1646: + { /* '1646' */ + return "Iviva Pte Ltd" + } case 165: { /* '165' */ return "Smart Temp Australia Pty. Ltd." @@ -17822,6 +17882,18 @@ func BACnetVendorIdByValue(value uint16) (enum BACnetVendorId, ok bool) { return BACnetVendorId_HSC_REGELUNGSTECHNIK_GMBH, true case 1640: return BACnetVendorId_G_ASERV_GMBH, true + case 1641: + return BACnetVendorId_LEEDS_ELECTRONICS_ENGINEERING_LIMITED, true + case 1642: + return BACnetVendorId_MITO_CONTRACTING_GROUP_INC, true + case 1643: + return BACnetVendorId_CALECTROAB, true + case 1644: + return BACnetVendorId_BMSOS_TECHNOLOGY_INC, true + case 1645: + return BACnetVendorId_VOSSLOH_SCHWABE_DEUTSCHAND_GMBH, true + case 1646: + return BACnetVendorId_IVIVA_PTE_LTD, true case 165: return BACnetVendorId_SMART_TEMP_AUSTRALIA_PTY_LTD, true case 166: @@ -21090,6 +21162,18 @@ func BACnetVendorIdByName(value string) (enum BACnetVendorId, ok bool) { return BACnetVendorId_HSC_REGELUNGSTECHNIK_GMBH, true case "G_ASERV_GMBH": return BACnetVendorId_G_ASERV_GMBH, true + case "LEEDS_ELECTRONICS_ENGINEERING_LIMITED": + return BACnetVendorId_LEEDS_ELECTRONICS_ENGINEERING_LIMITED, true + case "MITO_CONTRACTING_GROUP_INC": + return BACnetVendorId_MITO_CONTRACTING_GROUP_INC, true + case "CALECTROAB": + return BACnetVendorId_CALECTROAB, true + case "BMSOS_TECHNOLOGY_INC": + return BACnetVendorId_BMSOS_TECHNOLOGY_INC, true + case "VOSSLOH_SCHWABE_DEUTSCHAND_GMBH": + return BACnetVendorId_VOSSLOH_SCHWABE_DEUTSCHAND_GMBH, true + case "IVIVA_PTE_LTD": + return BACnetVendorId_IVIVA_PTE_LTD, true case "SMART_TEMP_AUSTRALIA_PTY_LTD": return BACnetVendorId_SMART_TEMP_AUSTRALIA_PTY_LTD, true case "COOPER_CONTROLS": @@ -24430,6 +24514,18 @@ func (e BACnetVendorId) PLC4XEnumName() string { return "HSC_REGELUNGSTECHNIK_GMBH" case BACnetVendorId_G_ASERV_GMBH: return "G_ASERV_GMBH" + case BACnetVendorId_LEEDS_ELECTRONICS_ENGINEERING_LIMITED: + return "LEEDS_ELECTRONICS_ENGINEERING_LIMITED" + case BACnetVendorId_MITO_CONTRACTING_GROUP_INC: + return "MITO_CONTRACTING_GROUP_INC" + case BACnetVendorId_CALECTROAB: + return "CALECTROAB" + case BACnetVendorId_BMSOS_TECHNOLOGY_INC: + return "BMSOS_TECHNOLOGY_INC" + case BACnetVendorId_VOSSLOH_SCHWABE_DEUTSCHAND_GMBH: + return "VOSSLOH_SCHWABE_DEUTSCHAND_GMBH" + case BACnetVendorId_IVIVA_PTE_LTD: + return "IVIVA_PTE_LTD" case BACnetVendorId_SMART_TEMP_AUSTRALIA_PTY_LTD: return "SMART_TEMP_AUSTRALIA_PTY_LTD" case BACnetVendorId_COOPER_CONTROLS: diff --git a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java index b15fb9acc2c..e57aa778892 100644 --- a/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java +++ b/plc4j/drivers/bacnet/src/main/generated/org/apache/plc4x/java/bacnetip/readwrite/BACnetVendorId.java @@ -3285,6 +3285,18 @@ public enum BACnetVendorId { G_ASERV_GMBH((int) 1640, (int) 1640, "GAserv GmbH"), + LEEDS_ELECTRONICS_ENGINEERING_LIMITED((int) 1641, (int) 1641, "Leeds Electronics Engineering Limited"), + + MITO_CONTRACTING_GROUP_INC((int) 1642, (int) 1642, "MITO Contracting Group Inc."), + + CALECTROAB((int) 1643, (int) 1643, "Calectro AB"), + + BMSOS_TECHNOLOGY_INC((int) 1644, (int) 1644, "bmsOS Technology Inc."), + + VOSSLOH_SCHWABE_DEUTSCHAND_GMBH((int) 1645, (int) 1645, "Vossloh-Schwabe Deutschand GmbH"), + + IVIVA_PTE_LTD((int) 1646, (int) 1646, "Iviva Pte Ltd"), + UNKNOWN_VENDOR((int) 0xFFFF, (int) 0xFFFF, "Unknown"); private static final Map map; diff --git a/plc4j/drivers/can/pom.xml b/plc4j/drivers/can/pom.xml index 3839149c09d..e227e196163 100644 --- a/plc4j/drivers/can/pom.xml +++ b/plc4j/drivers/can/pom.xml @@ -121,19 +121,6 @@ - - org.apache.maven.plugins - maven-dependency-plugin - - - - io.netty:netty-buffer - - - diff --git a/plc4j/drivers/canopen/pom.xml b/plc4j/drivers/canopen/pom.xml index 1108a0fb2fb..f967761e56c 100644 --- a/plc4j/drivers/canopen/pom.xml +++ b/plc4j/drivers/canopen/pom.xml @@ -125,19 +125,6 @@ - - org.apache.maven.plugins - maven-dependency-plugin - - - - io.netty:netty-buffer - - - diff --git a/plc4j/drivers/opcua/Dockerfile.test b/plc4j/drivers/opcua/Dockerfile.test deleted file mode 100644 index 4dbdd0a1ef8..00000000000 --- a/plc4j/drivers/opcua/Dockerfile.test +++ /dev/null @@ -1,21 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM eclipse-temurin:21 - -ADD "target/milo-testcontainer/*.jar" "/opt/milo/" -ADD "target/test-classes/org/eclipse/milo" "/opt/milo/org/eclipse/milo" - -CMD java -cp '/opt/milo/*:/opt/milo/' org.eclipse.milo.examples.server.TestMiloServer \ No newline at end of file diff --git a/plc4j/drivers/opcua/pom.xml b/plc4j/drivers/opcua/pom.xml index a2bcccecbc1..795c9e7b3e1 100644 --- a/plc4j/drivers/opcua/pom.xml +++ b/plc4j/drivers/opcua/pom.xml @@ -67,23 +67,6 @@ - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-milo-dependencies - - copy-dependencies - - test-compile - - server-examples - ${project.build.directory}/milo-testcontainer - - - - org.apache.felix maven-bundle-plugin @@ -226,42 +209,12 @@ 1.0.0-SNAPSHOT - - com.google.guava - guava - test - org.apache.plc4x plc4j-utils-test-utils 1.0.0-SNAPSHOT test - - org.eclipse.milo - sdk-client - test - - - org.eclipse.milo - sdk-core - test - - - org.eclipse.milo - stack-core - test - - - org.eclipse.milo - stack-client - test - - - org.eclipse.milo - server-examples - test - org.apache.plc4x @@ -271,12 +224,6 @@ test-jar test - - com.github.docker-java - docker-java-api - 3.7.1 - test - org.testcontainers testcontainers @@ -289,44 +236,8 @@ 1.21.4 test - - com.google.cloud.tools - jib-core - 0.28.1 - test - - - - - org.eclipse.milo - sdk-client - ${milo.version} - - - org.eclipse.milo - sdk-core - ${milo.version} - - - org.eclipse.milo - stack-core - ${milo.version} - - - org.eclipse.milo - stack-client - ${milo.version} - - - org.eclipse.milo - server-examples - ${milo.version} - - - - update-generated-code diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/KeystoreGenerator.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/KeystoreGenerator.java index c16f0b80e04..081a8790006 100644 --- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/KeystoreGenerator.java +++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/KeystoreGenerator.java @@ -21,20 +21,42 @@ import java.io.IOException; import java.io.OutputStream; +import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.Key; import java.security.KeyPair; +import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.PrivateKey; +import java.security.SecureRandom; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; +import java.time.Duration; +import java.time.Instant; import java.util.Base64; +import java.util.Date; import java.util.Set; -import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder; -import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; /** - * Utility to generate server certificate - based on Eclipse Milo stuff. + * Utility to generate the client / server keystores used by the OPC UA integration test. + * + *

The certificates mirror what Milo's {@code SelfSignedCertificateBuilder} produced before: + * a self-signed RSA certificate valid for a year, carrying the OPC UA application URI as a + * SAN URI entry - the test server refuses to start without one - plus the usual key usages an + * OPC UA stack expects. It is built with BouncyCastle here so that the test classpath does not + * need Milo (see {@code src/test/resources/opcua/server/Dockerfile}). */ public class KeystoreGenerator { @@ -65,27 +87,45 @@ public KeystoreGenerator(String password, int length, String applicationUri, Str private KeyStore generate(String password, int length, String applicationUri, String entryName, String commonName) throws Exception { KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(null, password.toCharArray()); - KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(length); - SelfSignedCertificateBuilder builder = (new SelfSignedCertificateBuilder( - keyPair)).setCommonName(commonName) - .setOrganization("Apache Software Foundation") - .setOrganizationalUnit("PLC4X") - .setLocalityName("PLC4J") - .setStateName("CA") - .setCountryCode("US") - .setApplicationUri(applicationUri); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(length, new SecureRandom()); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE) + .addRDN(BCStyle.CN, commonName) + .addRDN(BCStyle.O, "Apache Software Foundation") + .addRDN(BCStyle.OU, "PLC4X") + .addRDN(BCStyle.L, "PLC4J") + .addRDN(BCStyle.ST, "CA") + .addRDN(BCStyle.C, "US"); Set hostnames = Set.of("127.0.0.1"); - + GeneralName[] subjectAltNames = new GeneralName[hostnames.size() + 1]; + subjectAltNames[0] = new GeneralName(GeneralName.uniformResourceIdentifier, applicationUri); + int index = 1; for (String hostname : hostnames) { - if (hostname.startsWith("\\d+\\.")) { - builder.addIpAddress(hostname); - } else { - builder.addDnsName(hostname); - } + subjectAltNames[index++] = new GeneralName(GeneralName.dNSName, hostname); } - X509Certificate certificate = builder.build(); + Instant notBefore = Instant.now(); + JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder( + nameBuilder.build(), + new BigInteger(64, new SecureRandom()), + Date.from(notBefore), + Date.from(notBefore.plus(Duration.ofDays(365))), + nameBuilder.build(), + keyPair.getPublic() + ); + builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false)); + builder.addExtension(Extension.keyUsage, false, new KeyUsage( + KeyUsage.digitalSignature | KeyUsage.nonRepudiation | KeyUsage.keyEncipherment + | KeyUsage.dataEncipherment | KeyUsage.keyCertSign)); + builder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage( + new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth})); + builder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(subjectAltNames)); + + X509Certificate certificate = new JcaX509CertificateConverter().getCertificate( + builder.build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()))); keyStore.setKeyEntry(entryName, keyPair.getPrivate(), password.toCharArray(), new X509Certificate[]{ certificate }); return keyStore; } diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java index 817813fd542..b700b548730 100644 --- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java +++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java @@ -19,17 +19,20 @@ package org.apache.plc4x.java.opcua; -import java.nio.file.Path; -import java.nio.file.Paths; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.images.builder.ImageFromDockerfile; public class MiloTestContainer extends GenericContainer { - private final static Logger logger = LoggerFactory.getLogger(MiloTestContainer.class); + private final static String SERVER_RESOURCES = "opcua/server"; + + private final static String[] SERVER_SOURCES = { + "org/eclipse/milo/examples/server/EventNotifierTask.java", + "org/eclipse/milo/examples/server/Plc4xTestNamespace.java", + "org/eclipse/milo/examples/server/Plc4xTestStruct.java", + "org/eclipse/milo/examples/server/TestMiloServer.java" + }; private final static ImageFromDockerfile IMAGE = inlineImage(); @@ -52,13 +55,19 @@ public MiloTestContainer() { } private static ImageFromDockerfile inlineImage() { - Path absolutePath = Paths.get(".").toAbsolutePath(); - logger.info("Building milo server image from {}", absolutePath); - // Reuse the Docker layer cache across runs; the build context only changes when - // the milo jar or the compiled TestMiloServer classes change, so a cached build - // stays correct while turning a multi-minute rebuild into a near-instant one. - return new ImageFromDockerfile("plc4x-milo-test", false) - .withDockerfile(absolutePath.resolve("Dockerfile.test")); + // The build context is assembled from the test resources: the Dockerfile plus the + // sources of the test server, which are compiled inside the image against the Milo + // uber jar it downloads (see the Dockerfile for why Milo is not a Maven dependency). + // + // Keeping the named image around reuses the Docker layer cache across runs; the + // context only changes when the Dockerfile or those sources change, so a cached + // build stays correct while turning a multi-minute rebuild into a near-instant one. + ImageFromDockerfile image = new ImageFromDockerfile("plc4x-milo-test", false) + .withFileFromClasspath("Dockerfile", SERVER_RESOURCES + "/Dockerfile"); + for (String source : SERVER_SOURCES) { + image.withFileFromClasspath("src/" + source, SERVER_RESOURCES + "/src/" + source); + } + return image; } } diff --git a/plc4j/drivers/opcua/src/test/resources/opcua/server/Dockerfile b/plc4j/drivers/opcua/src/test/resources/opcua/server/Dockerfile new file mode 100644 index 00000000000..85a14966782 --- /dev/null +++ b/plc4j/drivers/opcua/src/test/resources/opcua/server/Dockerfile @@ -0,0 +1,48 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# OPC UA test server used by OpcuaPlcDriverTest. +# +# Eclipse Milo is deliberately NOT a Maven dependency of this module: it would drag its +# whole transitive tree (netty, jackson, guava, bouncycastle, ...) onto the test classpath, +# where every one of them shows up as a dependency-update / vulnerability alert for a jar +# that never leaves this container. Instead the server-examples uber jar - which already +# bundles the complete Milo stack plus its dependencies - is fetched here and the handful +# of PLC4X test-server classes under src/ are compiled against it inside the image. +# +# Consequence: the sources in src/ are not compiled by Maven, so the IDE will not flag +# breakage in them. Bumping MILO_VERSION is a manual step; a compile error surfaces as a +# failed image build when the integration test runs. + +ARG MILO_VERSION=0.6.16 + +FROM eclipse-temurin:21-jdk AS build +ARG MILO_VERSION +ADD "https://repo1.maven.org/maven2/org/eclipse/milo/server-examples/${MILO_VERSION}/server-examples-${MILO_VERSION}.jar" /opt/milo/server-examples.jar +COPY src /src +RUN javac -nowarn -cp /opt/milo/server-examples.jar -d /opt/milo/classes $(find /src -name '*.java') + +FROM eclipse-temurin:21-jre +COPY --from=build /opt/milo /opt/milo + +# The server binds this port and also advertises its endpoints on it, so the test container +# maps it 1:1 onto the host (see MiloTestContainer). +EXPOSE 12686 + +CMD ["java", "-cp", "/opt/milo/server-examples.jar:/opt/milo/classes", "org.eclipse.milo.examples.server.TestMiloServer"] diff --git a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/EventNotifierTask.java b/plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/EventNotifierTask.java similarity index 100% rename from plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/EventNotifierTask.java rename to plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/EventNotifierTask.java diff --git a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/Plc4xTestNamespace.java b/plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/Plc4xTestNamespace.java similarity index 100% rename from plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/Plc4xTestNamespace.java rename to plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/Plc4xTestNamespace.java diff --git a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/Plc4xTestStruct.java b/plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/Plc4xTestStruct.java similarity index 100% rename from plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/Plc4xTestStruct.java rename to plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/Plc4xTestStruct.java diff --git a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java b/plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/TestMiloServer.java similarity index 100% rename from plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java rename to plc4j/drivers/opcua/src/test/resources/opcua/server/src/org/eclipse/milo/examples/server/TestMiloServer.java diff --git a/plc4j/drivers/simulated/pom.xml b/plc4j/drivers/simulated/pom.xml index a51a58426b3..e0b935df812 100644 --- a/plc4j/drivers/simulated/pom.xml +++ b/plc4j/drivers/simulated/pom.xml @@ -142,6 +142,7 @@ logback-classic + nl.jqno.equalsverifier equalsverifier diff --git a/plc4j/tools/opm/pom.xml b/plc4j/tools/opm/pom.xml index 330171d21a7..0a6377b7c5e 100644 --- a/plc4j/tools/opm/pom.xml +++ b/plc4j/tools/opm/pom.xml @@ -79,17 +79,4 @@ - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - - - - - \ No newline at end of file diff --git a/plc4j/transports/socketcan/pom.xml b/plc4j/transports/socketcan/pom.xml deleted file mode 100644 index 44cfe6f26f2..00000000000 --- a/plc4j/transports/socketcan/pom.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - 4.1.0 - - - org.apache.plc4x - plc4j-transports - 1.0.0-SNAPSHOT - - - plc4j-transports-socketcan - PLC4J: Transports: SocketCAN - Base classes needed to implement plc4x drivers based on SocketCAN connections. Powered by javacan library. - - - 2025-08-02T13:55:11Z - - - - - - org.apache.felix - maven-bundle-plugin - true - - - ${project.groupId}.${project.artifactId} - org.apache.plc4x.java.osgi.TransportActivator - org.apache.plc4x.java.spi.transports.api.Transport,org.apache.plc4x.java.transport.socketcan.SocketCANTransport - - - - - - - - - org.apache.plc4x - plc4j-spi-buffers-api - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-spi-buffers-byte - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-spi-config - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-spi-fields - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-transports-api - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-utils-audit-log-api - 1.0.0-SNAPSHOT - - - tel.schich - javacan-core - - - org.slf4j - slf4j-api - - - - - - update-generated-code - - - - org.apache.plc4x.plugins - plc4x-maven-plugin - - - socketcan - generate-sources - - generate-driver - - - socketcan - java - read-write - src/main/generated - - - - - - - - - - org.apache.plc4x - plc4x-protocols-socketcan - 1.0.0-SNAPSHOT - provided - - - - org.apache.plc4x - plc4x-code-generation-language-java - 1.0.0-SNAPSHOT - provided - - - - - - diff --git a/plc4j/transports/socketcan/src/main/generated/org/apache/plc4x/java/socketcan/readwrite/SocketCANFrame.java b/plc4j/transports/socketcan/src/main/generated/org/apache/plc4x/java/socketcan/readwrite/SocketCANFrame.java deleted file mode 100644 index 1e9b1a71383..00000000000 --- a/plc4j/transports/socketcan/src/main/generated/org/apache/plc4x/java/socketcan/readwrite/SocketCANFrame.java +++ /dev/null @@ -1,211 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.plc4x.java.socketcan.readwrite; - -import org.apache.plc4x.java.socketcan.readwrite.utils.StaticHelper; -import org.apache.plc4x.java.spi.buffers.api.Message; -import org.apache.plc4x.java.spi.buffers.api.ReadBuffer; -import org.apache.plc4x.java.spi.buffers.api.WithOption; -import org.apache.plc4x.java.spi.buffers.api.WriteBuffer; -import org.apache.plc4x.java.spi.buffers.api.exceptions.BufferException; -import org.apache.plc4x.java.spi.buffers.bytebased.WithByteBasedOption; -import org.apache.plc4x.java.spi.fields.data.reader.DataReaderFactory; -import org.apache.plc4x.java.spi.fields.data.writer.DataWriterFactory; -import org.apache.plc4x.java.spi.fields.fields.reader.FieldReaderFactory; -import org.apache.plc4x.java.spi.fields.fields.writer.FieldWriterFactory; -import org.apache.plc4x.java.spi.fields.utils.ThreadLocalHelper; - -/** - * Code generated by code-generation. DO NOT EDIT. - */ -public class SocketCANFrame implements Message { - protected final int rawId; - - protected final byte[] data; - - public SocketCANFrame(Integer rawId, byte[] data) { - this.rawId = rawId; - this.data = data; - } - - /** - * Property field rawId - */ - public int getRawId() { - return rawId; - } - - /** - * Property field data - */ - public byte[] getData() { - return data; - } - - /** - * Virtual field identifier - */ - public int getIdentifier() { - return (int) (StaticHelper.readIdentifier(rawId)); - } - - /** - * Virtual field extended - */ - public boolean getExtended() { - return (boolean) (StaticHelper.isExtended(rawId)); - } - - /** - * Virtual field remote - */ - public boolean getRemote() { - return (boolean) (StaticHelper.isRemote(rawId)); - } - - /** - * Virtual field error - */ - public boolean getError() { - return (boolean) (StaticHelper.isError(rawId)); - } - - public static SocketCANFrame staticParse(ReadBuffer readBuffer) throws BufferException { - readBuffer.pushContext(WithOption.WithName("SocketCANFrame"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - int startPos = readBuffer.getPositionInBits(); - boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); - // Simple Field: rawId - int rawId = FieldReaderFactory.readSimpleField(DataReaderFactory.readSignedInt(readBuffer, 32), WithOption.WithName("rawId"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Virtual Field: identifier (doesn't parse anything, just makes the value available) - int identifier = FieldReaderFactory.readVirtualField(int.class, StaticHelper.readIdentifier(rawId), WithOption.WithName("identifier"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Virtual Field: extended (doesn't parse anything, just makes the value available) - boolean extended = FieldReaderFactory.readVirtualField(boolean.class, StaticHelper.isExtended(rawId), WithOption.WithName("extended"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Virtual Field: remote (doesn't parse anything, just makes the value available) - boolean remote = FieldReaderFactory.readVirtualField(boolean.class, StaticHelper.isRemote(rawId), WithOption.WithName("remote"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Virtual Field: error (doesn't parse anything, just makes the value available) - boolean error = FieldReaderFactory.readVirtualField(boolean.class, StaticHelper.isError(rawId), WithOption.WithName("error"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Implicit Field: size - short size = FieldReaderFactory.readImplicitField(DataReaderFactory.readUnsignedShort(readBuffer, 8), WithOption.WithName("size"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Reserved Field - FieldReaderFactory.readReservedField(DataReaderFactory.readUnsignedShort(readBuffer, 8), (short) 0x0, WithOption.WithName("SocketCANFrame.reserved6")); - - // Reserved Field - FieldReaderFactory.readReservedField(DataReaderFactory.readUnsignedShort(readBuffer, 8), (short) 0x0, WithOption.WithName("SocketCANFrame.reserved7")); - - // Reserved Field - FieldReaderFactory.readReservedField(DataReaderFactory.readUnsignedShort(readBuffer, 8), (short) 0x0, WithOption.WithName("SocketCANFrame.reserved8")); - - // Array Field: data - byte[] data = readBuffer.readBits(Math.toIntExact((size) * 8), WithOption.WithName("data"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Padding Field: padding10 - FieldReaderFactory.readPaddingField(DataReaderFactory.readUnsignedShort(readBuffer, 8), (int) (8) - ((org.apache.plc4x.java.spi.utils.StaticHelper.COUNT(data)))); - - readBuffer.popContext(); - return new SocketCANFrame(rawId, data); - } - - @Override - public void serialize(WriteBuffer writeBuffer) throws BufferException { - writeBuffer.pushContext(WithOption.WithName("SocketCANFrame"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - int startPos = writeBuffer.getPositionInBits(); - boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); - // Simple Field: rawId - FieldWriterFactory.writeSimpleField((int) rawId, DataWriterFactory.writeSignedInt(writeBuffer, 32), WithOption.WithName("rawId"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Virtual Field: identifier (doesn't serialize anything, just makes the value available) - int identifier = (int) getIdentifier(); - - // Virtual Field: extended (doesn't serialize anything, just makes the value available) - boolean extended = (boolean) getExtended(); - - // Virtual Field: remote (doesn't serialize anything, just makes the value available) - boolean remote = (boolean) getRemote(); - - // Virtual Field: error (doesn't serialize anything, just makes the value available) - boolean error = (boolean) getError(); - - // Implicit Field: size - short size = (short) (org.apache.plc4x.java.spi.utils.StaticHelper.COUNT(data)); - FieldWriterFactory.writeImplicitField((short) size, DataWriterFactory.writeUnsignedShort(writeBuffer, 8), WithOption.WithName("size"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Reserved Field - FieldWriterFactory.writeReservedField((short) 0x0, DataWriterFactory.writeUnsignedShort(writeBuffer, 8)); - - // Reserved Field - FieldWriterFactory.writeReservedField((short) 0x0, DataWriterFactory.writeUnsignedShort(writeBuffer, 8)); - - // Reserved Field - FieldWriterFactory.writeReservedField((short) 0x0, DataWriterFactory.writeUnsignedShort(writeBuffer, 8)); - - // Array Field: data - FieldWriterFactory.writeByteArrayField(data, DataWriterFactory.writeByteArray(writeBuffer, (int) ((data != null) ? data.length : 0)), WithOption.WithName("data"), WithOption.WithFloatEncoding("IEEE754"), WithOption.WithSignedIntegerEncoding("twos-complement"), WithOption.WithUnsignedIntegerEncoding("unsigned-binary"), WithByteBasedOption.WithByteOrder("LITTLE_ENDIAN"), WithOption.WithStringEncoding("UTF8")); - - // Padding Field: padding10 - FieldWriterFactory.writePaddingField((int) (8) - ((org.apache.plc4x.java.spi.utils.StaticHelper.COUNT(data))), (short) 0x00, DataWriterFactory.writeUnsignedShort(writeBuffer, 8)); - - writeBuffer.popContext(); - } - - @Override - public int getLengthInBytes() { - return (int) Math.ceil((float) getLengthInBits() / 8.0); - } - - @Override - public int getLengthInBits() { - int lengthInBits = 0; - SocketCANFrame _value = this; - boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get(); - // Simple Field: rawId - lengthInBits += 32; - - // Virtual Field: identifier (doesn't produce any output, just makes the value available) - - // Virtual Field: extended (doesn't produce any output, just makes the value available) - - // Virtual Field: remote (doesn't produce any output, just makes the value available) - - // Virtual Field: error (doesn't produce any output, just makes the value available) - - // Implicit Field: size - lengthInBits += 8; - - // Reserved Field - lengthInBits += 8; - - // Reserved Field - lengthInBits += 8; - - // Reserved Field - lengthInBits += 8; - - // Array Field: data - lengthInBits += 8 * ((data != null) ? data.length : 0); - - // Padding Field: padding10 - lengthInBits += 8 * ((int) (8) - ((org.apache.plc4x.java.spi.utils.StaticHelper.COUNT(data)))); - - return lengthInBits; - } -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java deleted file mode 100644 index 42a7d61ec08..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/socketcan/readwrite/utils/StaticHelper.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.socketcan.readwrite.utils; - -public class StaticHelper { - - public static final int EFF_FLAG = 0b10000000_00000000_00000000_00000000; - public static final int RTR_FLAG = 0b01000000_00000000_00000000_00000000; - public static final int ERR_FLAG = 0b00100000_00000000_00000000_00000000; - public static final int SFF_MASK = 0b00000000_00000000_00000111_11111111; - public static final int EFF_MASK = 0b00011111_11111111_11111111_11111111; - public static final int ERR_MASK = EFF_MASK; - - public static final int EXTENDED_FRAME_FORMAT_FLAG = 0x80000000; - - public static final int REMOTE_TRANSMISSION_FLAG = 0x40000000; - - public static final int ERROR_FRAME_FLAG = 0x20000000; - - public static final int STANDARD_FORMAT_IDENTIFIER_MASK = 0x7ff; - - public static final int EXTENDED_FORMAT_IDENTIFIER_MASK = 0x1fffffff; - - public static int readIdentifier(int identifier) { - if ((isExtended(identifier))) { - return identifier & EXTENDED_FORMAT_IDENTIFIER_MASK; - } - return identifier & STANDARD_FORMAT_IDENTIFIER_MASK; - } - - public static boolean isExtended(int identifier) { - return (identifier & EXTENDED_FRAME_FORMAT_FLAG) != 0; - } - - public static boolean isRemote(int identifier) { - return (identifier & REMOTE_TRANSMISSION_FLAG) != 0; - } - - public static boolean isError(int identifier) { - return (identifier & ERROR_FRAME_FLAG) != 0; - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANChannelFactory.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANChannelFactory.java deleted file mode 100644 index eb18abf6406..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANChannelFactory.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan; - -import io.netty.bootstrap.Bootstrap; -import io.netty.channel.Channel; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.ThreadPerChannelEventLoop; -import io.netty.channel.oio.OioEventLoopGroup; -import org.apache.plc4x.java.spi.configuration.HasConfiguration; -import org.apache.plc4x.java.spi.connection.NettyChannelFactory; -import org.apache.plc4x.java.transport.can.CANTransportConfiguration; -import org.apache.plc4x.java.transport.socketcan.netty.SocketCANChannel; -import org.apache.plc4x.java.transport.socketcan.netty.address.SocketCANAddress; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SocketCANChannelFactory extends NettyChannelFactory implements HasConfiguration { - - private static final Logger logger = LoggerFactory.getLogger(SocketCANChannelFactory.class); - - private CANTransportConfiguration configuration; - - public SocketCANChannelFactory(SocketCANAddress address) { - super(address); - } - - @Override - public void setConfiguration(CANTransportConfiguration configuration) { - this.configuration = configuration; - } - - @Override - public Class getChannel() { - return SocketCANChannel.class; - } - - @Override - public boolean isPassive() { - return true; - } - - @Override - public EventLoopGroup getEventLoopGroup() { - return new ThreadPerChannelEventLoop(new OioEventLoopGroup()); - } - - @Override - public void configureBootstrap(Bootstrap bootstrap) { - if(configuration != null) { - logger.info("Configuring Bootstrap with {}", configuration); - } - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANFrameBuilder.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANFrameBuilder.java deleted file mode 100644 index f2445b072f0..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANFrameBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan; - -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.socketcan.readwrite.SocketCANFrame; -import org.apache.plc4x.java.transport.can.CANFrameBuilder; - -public class SocketCANFrameBuilder implements CANFrameBuilder { - - private int nodeId; - private byte[] data; - - @Override - public CANFrameBuilder withId(int nodeId) { - this.nodeId = nodeId; - return this; - } - - @Override - public CANFrameBuilder withData(byte[] data) { - this.data = data; - return this; - } - - @Override - public SocketCANFrame create() throws PlcRuntimeException { - return new SocketCANFrame(nodeId, data); - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANTransport.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANTransport.java deleted file mode 100644 index 382bcfad2ad..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/SocketCANTransport.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan; - -import io.netty.buffer.ByteBuf; - -import java.util.function.Function; -import java.util.function.ToIntFunction; - -import org.apache.plc4x.java.spi.configuration.PlcConnectionConfiguration; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.socketcan.readwrite.SocketCANFrame; -import org.apache.plc4x.java.spi.configuration.PlcTransportConfiguration; -import org.apache.plc4x.java.spi.connection.ChannelFactory; -import org.apache.plc4x.java.spi.generation.*; -import org.apache.plc4x.java.transport.can.CANFrameBuilder; -import org.apache.plc4x.java.transport.can.CANTransport; -import org.apache.plc4x.java.transport.can.FrameData; -import org.apache.plc4x.java.transport.socketcan.netty.address.SocketCANAddress; - -/** - * CAN specific transport which rely on JavaCAN library. - */ -public class SocketCANTransport implements CANTransport { - - @Override - public String getTransportCode() { - return "socketcan"; - } - - @Override - public String getTransportName() { - return "SocketCAN Transport (based on JavaCAN)"; - } - - @Override - public ChannelFactory createChannelFactory(String transportConfig) { - SocketCANAddress address = new SocketCANAddress(transportConfig); - return new SocketCANChannelFactory(address); - } - - @Override - public ToIntFunction getEstimator() { - return (buff) -> 16; - } - - public static class EmptyConfiguration implements PlcTransportConfiguration {} - - @Override - public Class getTransportConfigType() { - return EmptyConfiguration.class; - } - - - @Override - public MessageInput getMessageInput(PlcConnectionConfiguration cfg) { - return SocketCANFrame::staticParse; - } - - @Override - public Class getMessageType() { - return SocketCANFrame.class; - } - - @Override - public CANFrameBuilder getTransportFrameBuilder() { - return new SocketCANFrameBuilder(); - } - - @Override - public Function adapter() { - return frame -> new FrameData() { - @Override - public int getNodeId() { - return frame.getIdentifier(); - } - - @Override - public int getDataLength() { - return frame.getData().length; - } - - @Override - public byte[] getData() { - return frame.getData(); - } - - @Override - public T read(MessageInput input) { - try { - return input.parse(new ReadBufferByteBased(frame.getData(), ByteOrder.LITTLE_ENDIAN)); - } catch (ParseException e) { - throw new PlcRuntimeException(e); - } - } - }; - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannel.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannel.java deleted file mode 100644 index 9633f322c46..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannel.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan.netty; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelPromise; -import io.netty.channel.EventLoop; -import io.netty.channel.oio.OioByteStreamChannel; -import org.apache.plc4x.java.transport.socketcan.netty.address.SocketCANAddress; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import tel.schich.javacan.CanChannels; -import tel.schich.javacan.NetworkDevice; -import tel.schich.javacan.RawCanChannel; -import tel.schich.javacan.platform.linux.LinuxNetworkDevice; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.SocketAddress; -import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; - -/** - * A naive copy of pcap channel implementation which allows to pass over data to PLC4X as well as drop it back to JavaCAN. - * Sadly all this involves double parsing. - */ -public class SocketCANChannel extends OioByteStreamChannel { - - private final Logger logger = LoggerFactory.getLogger(SocketCANChannel.class); - - private final SocketCANChannelConfig config; - - private SocketCANAddress remoteRawSocketAddress; - private SocketAddress localAddress; - private RawCanChannel handle; - private Thread loopThread; - - public SocketCANChannel() { - super(null); - config = new SocketCANChannelConfig(this); - } - - @Override - protected boolean isInputShutdown() { - return false; - } - - @Override - protected ChannelFuture shutdownInput() { - throw new UnsupportedOperationException(""); - } - - @Override - protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { - if (!(remoteAddress instanceof SocketCANAddress)) { - logger.error("Expecting remote address of type SocketCANAddress"); - pipeline().fireExceptionCaught(new IllegalArgumentException("Expecting remote address of type SocketCANAddress")); - return; - } - this.localAddress = localAddress; - remoteRawSocketAddress = (SocketCANAddress) remoteAddress; - - // Try to get the device name of the network interface that we want to open. - String interfaceName = getInterfaceName(remoteRawSocketAddress); - if(interfaceName == null) { - logger.error("Interface name is not specified and couldn't detect it automatically"); - pipeline().fireExceptionCaught(new IllegalArgumentException("Interface name is not specified and couldn't detect it automatically")); - return; - } - - NetworkDevice device = LinuxNetworkDevice.lookup(interfaceName); - // Get a handle to the network-device and open it. - handle = CanChannels.newRawChannel(device); - - if(logger.isDebugEnabled()) { - logger.debug(String.format("Listening on device %s", interfaceName)); - } - - // TODO If the address allows fine tuning which packets to process, set a filter to reduce the load. -// String filter = -// if(filter.length() > 0) { -// handle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE); -// } - - // Create a buffer where the raw socket worker can send data to. - ByteBuf buffer = Unpooled.buffer(); - - // Start a thread that processes the callbacks from the raw socket and simply - // forwards the bytes read to the buffer. - loopThread = new Thread(() -> { - try { - ByteBuffer byteBuffer = ByteBuffer.allocateDirect(16); - while (!isInputShutdown()) { - handle.readUnsafe(byteBuffer); - buffer.writeBytes(byteBuffer); - byteBuffer.rewind(); - } - } catch (Exception e) { - logger.warn("Could not read data", e); - pipeline().fireExceptionCaught(e); - } catch (Throwable e) { - logger.warn("Fatal error while handling CAN communication", e); - pipeline().fireExceptionCaught(e); - } - }, "javacan-reader"); - loopThread.start(); - - activate(new CANInputStream(buffer), new CANOutputStream(handle)); - } - - @Override - protected SocketAddress localAddress0() { - return localAddress; - } - - @Override - protected SocketAddress remoteAddress0() { - return remoteRawSocketAddress; - } - - @Override - protected void doBind(SocketAddress localAddress) { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - protected void doDisconnect() { - this.loopThread.interrupt(); - if (this.handle != null) { - try { - this.handle.close(); - } catch (IOException e) { - logger.error("Failed to close CAN socket!"); - } - } - } - - @Override - protected int doReadBytes(ByteBuf buf) throws Exception { - if (handle == null || !handle.isOpen()) { - return -1; - } - try { - return super.doReadBytes(buf); - } catch (SocketTimeoutException ignored) { - return 0; - } - } - - @Override - protected boolean isCompatible(EventLoop loop) { - return super.isCompatible(loop); - } - - @Override - public ChannelConfig config() { - return this.config; - } - - @Override - public boolean isOpen() { - return true; - } - - @Override - protected AbstractUnsafe newUnsafe() { - return new RawSocketUnsafe(); - } - - private String getInterfaceName(SocketCANAddress address) { - // If the device name is provided, simply use this. - if(address.getInterfaceName() != null) { - return address.getInterfaceName(); - } - - // TODO: Implement this ... - return null; - } - - /** - * InputStream that fulfills the contract of Netty for read operations to timeout. - * Without this the InputStream would simply block indefinitely which would block - * the entire IO module. - */ - private static class CANInputStream extends InputStream { - final ByteBuf buf; - - private CANInputStream(ByteBuf buf) { - this.buf = buf; - } - - @Override - public int available() { - return buf.readableBytes(); - } - - @Override - public int read() throws IOException { - // Timeout 10 ms - final long timeout = System.nanoTime() + 10_000; - // Yes, this could make the thread go nuts in case of no data, - // but the Netty guys are doing it the same way and there probably - // is a reason for it ;-) - while (System.nanoTime() < timeout) { - if (buf.readableBytes() > 0) { - return buf.readByte() & 0xFF; - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - throw new IOException(e); - } - } - throw new SocketTimeoutException(); - } - - } - - - private static class CANOutputStream extends OutputStream { - - private final RawCanChannel rawCanChannel; - private final ByteBuffer buffer = ByteBuffer.allocateDirect(16); - - public CANOutputStream(RawCanChannel rawCanChannel) { - this.rawCanChannel = rawCanChannel; - } - - @Override - public void write(int b) throws IOException { - throw new IOException("Appending single bytes is not permitted. Use write(byte[], int, int)"); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - buffer.put(b, off, len); - buffer.flip(); - rawCanChannel.writeUnsafe(buffer); - // the NIO clear call does clear positions and limits, but does not erase contents of buffer. - // since we write a complete frame with length any remaining data at the end of memory block - // should be ignored. When we get payload of full length it will eventually override earlier data - // which was not used - buffer.clear(); - } - } - - /** - * Internal helper to wrap access to unsafe operations (Only used internally by netty) - */ - private class RawSocketUnsafe extends AbstractUnsafe { - @Override - public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - try { - doConnect(remoteAddress, localAddress); - pipeline().fireChannelActive(); - promise.setSuccess(); - } catch (Exception e) { - promise.setFailure(e); - } - } - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannelConfig.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannelConfig.java deleted file mode 100644 index 04301167998..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/SocketCANChannelConfig.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan.netty; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelConfig; -import io.netty.channel.DefaultChannelConfig; - -public class SocketCANChannelConfig extends DefaultChannelConfig implements ChannelConfig { - - public SocketCANChannelConfig(Channel channel) { - super(channel); - } - -} diff --git a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/address/SocketCANAddress.java b/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/address/SocketCANAddress.java deleted file mode 100644 index 7d3cf45f55d..00000000000 --- a/plc4j/transports/socketcan/src/main/java/org/apache/plc4x/java/transport/socketcan/netty/address/SocketCANAddress.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.socketcan.netty.address; - -import java.net.SocketAddress; - -/** - * Simple address implementation which covers only interface name. - */ -public class SocketCANAddress extends SocketAddress { - - private static final long serialVersionUID = 1L; - - private final String interfaceName; - - public SocketCANAddress(String interfaceName) { - this.interfaceName = interfaceName; - } - - public String getInterfaceName() { - return interfaceName; - } - -} diff --git a/plc4j/transports/socketcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport b/plc4j/transports/socketcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport deleted file mode 100644 index 41e97c1060b..00000000000 --- a/plc4j/transports/socketcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -org.apache.plc4x.java.transport.socketcan.SocketCANTransport \ No newline at end of file diff --git a/plc4j/transports/virtualcan/pom.xml b/plc4j/transports/virtualcan/pom.xml deleted file mode 100644 index daf1f9dcee1..00000000000 --- a/plc4j/transports/virtualcan/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - 4.1.0 - - - org.apache.plc4x - plc4j-transports - 1.0.0-SNAPSHOT - - - plc4j-transports-virtualcan - PLC4J: Transports: VirtualCAN - Virtual CAN transport which does work without any real CAN interface. - - - 2025-08-02T13:55:11Z - - - - - org.apache.plc4x - plc4j-api - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-spi - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-transports-can - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-transports-test - 1.0.0-SNAPSHOT - - - - commons-codec - commons-codec - - - io.netty - netty-buffer - - - - - - - org.apache.felix - maven-bundle-plugin - true - - - ${project.groupId}.${project.artifactId} - org.apache.plc4x.java.osgi.TransportActivator - org.apache.plc4x.java.spi.transport.Transport,org.apache.plc4x.java.transport.virtualcan.VirtualCANTransport - - - - - - - \ No newline at end of file diff --git a/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANFrame.java b/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANFrame.java deleted file mode 100644 index f1992fba205..00000000000 --- a/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANFrame.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.virtualcan; - -import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*; -import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*; -import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*; - -import org.apache.commons.codec.binary.Hex; -import org.apache.plc4x.java.spi.codegen.WithOption; -import org.apache.plc4x.java.spi.generation.ByteOrder; -import org.apache.plc4x.java.spi.generation.Message; -import org.apache.plc4x.java.spi.generation.MessageInput; -import org.apache.plc4x.java.spi.generation.ParseException; -import org.apache.plc4x.java.spi.generation.ReadBuffer; -import org.apache.plc4x.java.spi.generation.SerializationException; -import org.apache.plc4x.java.spi.generation.WriteBuffer; - -public class VirtualCANFrame implements Message { - - public final static MessageInput PARSER = new MessageInput() { - - @Override - public VirtualCANFrame parse(ReadBuffer io) throws ParseException { - WithOption withOption = WithOption.WithByteOrder(ByteOrder.LITTLE_ENDIAN); - - short length = io.readUnsignedShort("length", 8, withOption); - int nodeId = io.readInt("nodeId", 32, withOption); - byte[] data = io.readByteArray("data", length, withOption); - - return new VirtualCANFrame(nodeId, data); - } - }; - - private final int nodeId; - private final byte[] data; - - public VirtualCANFrame(int nodeId, byte[] data) { - this.nodeId = nodeId; - this.data = data; - } - - public int getNodeId() { - return nodeId; - } - - public byte[] getData() { - return data; - } - - @Override - public void serialize(WriteBuffer writeBuffer) throws SerializationException { - WithOption withOption = WithOption.WithByteOrder(ByteOrder.LITTLE_ENDIAN); - - writeSimpleField("length", (short) data.length, writeUnsignedShort(writeBuffer, 8), withOption); - writeSimpleField("nodeId", nodeId, writeSignedInt(writeBuffer, 32), withOption); - writeByteArrayField("data", data, writeByteArray(writeBuffer, 8), withOption); - } - - - @Override - public int getLengthInBytes() { - return 1 + 4 + data.length; - } - - @Override - public int getLengthInBits() { - return getLengthInBytes() * 8; - } - - public String toString() { - return "VirtualCANFrame " + nodeId + "[" + data.length + "]" + Hex.encodeHexString(data); - } -} diff --git a/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANTransport.java b/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANTransport.java deleted file mode 100644 index 18322c98a2d..00000000000 --- a/plc4j/transports/virtualcan/src/main/java/org/apache/plc4x/java/transport/virtualcan/VirtualCANTransport.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.transport.virtualcan; - -import io.netty.buffer.ByteBuf; -import org.apache.plc4x.java.spi.configuration.PlcConnectionConfiguration; -import org.apache.plc4x.java.api.exceptions.PlcRuntimeException; -import org.apache.plc4x.java.spi.configuration.PlcTransportConfiguration; -import org.apache.plc4x.java.spi.generation.*; -import org.apache.plc4x.java.transport.can.CANFrameBuilder; -import org.apache.plc4x.java.transport.can.CANTransport; -import org.apache.plc4x.java.transport.can.FrameData; -import org.apache.plc4x.java.transport.test.TestTransport; - -import java.util.function.Function; -import java.util.function.ToIntFunction; - -public class VirtualCANTransport extends TestTransport implements CANTransport { - - @Override - public String getTransportCode() { - return "virtualcan"; // vcan is used by socketcan, using virtualcan to avoid mismatches - } - - @Override - public String getTransportName() { - return "Virtual CAN"; - } - - @Override - public ToIntFunction getEstimator() { - return ByteBuf::readableBytes; - } - - @Override - public Class getMessageType() { - return VirtualCANFrame.class; - } - - public static class EmptyConfiguration implements PlcTransportConfiguration {} - - @Override - public Class getTransportConfigType() { - return EmptyConfiguration.class; - } - - @Override - public CANFrameBuilder getTransportFrameBuilder() { - return new CANFrameBuilder<>() { - - private byte[] data; - private int nodeId; - - @Override - public CANFrameBuilder withId(int nodeId) { - this.nodeId = nodeId; - return this; - } - - @Override - public CANFrameBuilder withData(byte[] data) { - this.data = data; - return this; - } - - @Override - public VirtualCANFrame create() { - return new VirtualCANFrame(nodeId, data); - } - }; - } - - @Override - public Function adapter() { - return frame -> new FrameData() { - @Override - public int getNodeId() { - return frame.getNodeId(); - } - - @Override - public T read(MessageInput input) { - try { - return input.parse(new ReadBufferByteBased(getData(), ByteOrder.LITTLE_ENDIAN)); - } catch (ParseException e) { - throw new PlcRuntimeException(e); - } - } - - @Override - public int getDataLength() { - return frame.getData().length; - } - - @Override - public byte[] getData() { - return frame.getData(); - } - }; - } - - @Override - public MessageInput getMessageInput(PlcConnectionConfiguration configuration) { - return VirtualCANFrame.PARSER; - } - -} diff --git a/plc4j/transports/virtualcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport b/plc4j/transports/virtualcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport deleted file mode 100644 index 93b1f846ec9..00000000000 --- a/plc4j/transports/virtualcan/src/main/resources/META-INF/services/org.apache.plc4x.java.spi.transports.api.Transport +++ /dev/null @@ -1,20 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -org.apache.plc4x.java.transport.virtualcan.VirtualCANTransport \ No newline at end of file diff --git a/plc4j/utils/pcap-replay/pom.xml b/plc4j/utils/pcap-replay/pom.xml deleted file mode 100644 index 587ef841041..00000000000 --- a/plc4j/utils/pcap-replay/pom.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - org.apache.plc4x - plc4j-utils - 1.0.0-SNAPSHOT - - - plc4j-utils-pcap-replay - - PLC4J: Utils: Pcap-Replay - An implementation of a Netty Channel that uses a PCAP packet dump as input and simulates a raw socket - device by replaying the recorded traffic. - - - - 2025-08-02T13:55:11Z - - - - - org.apache.plc4x - plc4j-utils-pcap-shared - 1.0.0-SNAPSHOT - - - - io.netty - netty-buffer - - - io.netty - netty-transport - - - - org.pcap4j - pcap4j-core - - - - org.pcap4j - pcap4j-packetfactory-static - runtime - - - - org.apache.commons - commons-lang3 - - - - org.slf4j - slf4j-api - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - org.pcap4j:pcap4j-packetfactory-static - - - - - - - org.sonarsource.scanner.maven - sonar-maven-plugin - - true - - - - - - \ No newline at end of file diff --git a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/PcapReplayChannel.java b/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/PcapReplayChannel.java deleted file mode 100644 index ec0be02d1eb..00000000000 --- a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/PcapReplayChannel.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcapreplay.netty; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelPromise; -import io.netty.channel.oio.OioByteStreamChannel; -import org.apache.commons.lang3.NotImplementedException; -import org.apache.plc4x.java.utils.pcap.netty.exception.PcapException; -import org.apache.plc4x.java.utils.pcapreplay.netty.address.PcapReplayAddress; -import org.apache.plc4x.java.utils.pcapreplay.netty.config.PcapReplayChannelConfig; -import org.pcap4j.core.*; -import org.pcap4j.packet.Packet; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.SocketAddress; -import java.net.SocketTimeoutException; -import java.sql.Timestamp; -import java.util.concurrent.TimeUnit; - -public class PcapReplayChannel extends OioByteStreamChannel { - - private static final Logger logger = LoggerFactory.getLogger(PcapReplayChannel.class); - - private final PcapReplayChannelConfig config; - - private PcapReplayAddress remoteRawSocketAddress; - private SocketAddress localAddress; - private PcapHandle handle; - private Thread loopThread; - - public PcapReplayChannel() { - super(null); - config = new PcapReplayChannelConfig(this); - } - - @Override - protected boolean isInputShutdown() { - return false; - } - - @Override - protected ChannelFuture shutdownInput() { - throw new NotImplementedException(""); - } - - @Override - protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { - this.localAddress = localAddress; - - if (!(remoteAddress instanceof PcapReplayAddress)) { - logger.error("Expecting remote address of type PcapSocketAddress"); - pipeline().fireExceptionCaught(new PcapException("Expecting remote address of type PcapSocketAddress")); - return; - } - remoteRawSocketAddress = (PcapReplayAddress) remoteAddress; - - // Get a handle to the network-device and open it. - File pcapFile = remoteRawSocketAddress.getPcapFile(); - if (!pcapFile.exists()) { - logger.error("Couldn't find PCAP capture file at: {}", pcapFile.getAbsolutePath()); - PcapException exception = new PcapException(String.format("Couldn't find PCAP capture file at: %s", pcapFile.getAbsolutePath())); - pipeline().fireExceptionCaught(exception); - return; - } - logger.debug("Opening PCAP capture file at: {}", pcapFile.getAbsolutePath()); - - handle = Pcaps.openOffline(remoteRawSocketAddress.getPcapFile().getAbsolutePath(), - PcapHandle.TimestampPrecision.NANO); - - // If the address allows fine tuning which packets to process, set a filter to reduce the load. - String filter = config.getFilter(); - if (filter.length() > 0) { - handle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE); - } - - // Create a buffer where the raw socket worker can send data to. - ByteBuf buffer = Unpooled.buffer(); - - // Start a thread that processes the callbacks from the raw socket and simply - // forwards the bytes read to the buffer. - loopThread = new Thread(() -> { - try { - handle.loop(-1, new PacketListener() { - private Timestamp lastPacketTime = null; - - @Override - public void gotPacket(Packet packet) { - Timestamp curPacketTime = handle.getTimestamp(); - - // Only enable the throttling if it is not disabled. - if (config.getSpeedFactor() != PcapReplayChannelConfig.SPEED_FAST_FULL) { - // If last-time is not null, wait for the given number of nano-seconds. - if (lastPacketTime != null) { - int numMicrosecondsSleep = (int) - ((curPacketTime.getNanos() - lastPacketTime.getNanos()) / config.getSpeedFactor()); - nanoSecondSleep(numMicrosecondsSleep); - } - } - - // Send the bytes to the netty pipeline. - byte[] data = config.getPacketHandler().getData(packet); - if (data != null) { - buffer.writeBytes(data); - } - - // Remember the timestamp of the current packet. - lastPacketTime = curPacketTime; - } - }); - } catch (PcapNativeException | NotOpenException e) { - logger.error("PCAP loop thread died!", e); - pipeline().fireExceptionCaught(e); - } catch (InterruptedException e) { - logger.warn("PCAP loop thread was interrupted (hopefully intentionally)", e); - Thread.currentThread().interrupt(); - } - }); - loopThread.start(); - - // Right now we're using an output stream that simply discards everything. - // This is ok while implementing passive drivers for protocols, however as - // soon as we start implementing ethernet layer protocols, we'll have to also - // be able to actually send data. The PcapInputStream simply acts as a - // breaking point if no packets are coming in and the read operation would - // simply block indefinitely. - activate(new PcapInputStream(buffer), new DiscardingOutputStream()); - } - - @Override - protected SocketAddress localAddress0() { - return localAddress; - } - - @Override - protected SocketAddress remoteAddress0() { - return remoteRawSocketAddress; - } - - @Override - protected void doBind(SocketAddress localAddress) { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - protected void doDisconnect() { - this.loopThread.interrupt(); - if (this.handle != null) { - this.handle.close(); - } - } - - @Override - protected int doReadBytes(ByteBuf buf) throws Exception { - if (handle == null || !handle.isOpen()) { - return -1; - } - try { - return super.doReadBytes(buf); - } catch (SocketTimeoutException ignored) { - return 0; - } - } - - @Override - public ChannelConfig config() { - return this.config; - } - - @Override - public boolean isOpen() { - return true; - } - - @Override - protected AbstractUnsafe newUnsafe() { - return new RawSocketUnsafe(); - } - - private void nanoSecondSleep(long numNanos) { - try { - TimeUnit.NANOSECONDS.sleep(numNanos); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - - /** - * This output stream simply discards anything it should send. - */ - private static class DiscardingOutputStream extends OutputStream { - @Override - public void write(int b) throws IOException { - // discard - logger.debug("Discarding {}", b); - } - - @Override - public void write(byte[] b, int off, int len) { - logger.debug("Discarding {}", b); - } - } - - /** - * InputStream that fulfills the contract of Netty for read operations to timeout. - * Without this the InputStream would simply block indefinitely which would block - * the entire IO module. - */ - private static class PcapInputStream extends InputStream { - final ByteBuf buf; - - private PcapInputStream(ByteBuf buf) { - this.buf = buf; - } - - @Override - public int available() { - return buf.readableBytes(); - } - - @Override - public int read() throws IOException { - // Timeout 10 ms - final long timeout = System.nanoTime() + 10_000; - // Yes, this could make the thread go nuts in case of no data, - // but the Netty guys are doing it the same way and there probably - // is a reason for it ;-) - while (System.nanoTime() < timeout) { - if (buf.readableBytes() > 0) { - return buf.readByte() & 0xFF; - } - } - throw new SocketTimeoutException(); - } - } - - /** - * Internal helper to wrap access to unsafe operations (Only used internally by netty) - */ - private class RawSocketUnsafe extends AbstractUnsafe { - @Override - public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - try { - doConnect(remoteAddress, localAddress); - pipeline().fireChannelActive(); - promise.setSuccess(); - } catch (Exception e) { - promise.setFailure(e); - } - } - } - -} diff --git a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/address/PcapReplayAddress.java b/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/address/PcapReplayAddress.java deleted file mode 100644 index 28bcd1edd84..00000000000 --- a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/address/PcapReplayAddress.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcapreplay.netty.address; - -import org.apache.plc4x.java.utils.pcap.netty.address.PcapSocketAddress; - -import java.io.File; - -public class PcapReplayAddress extends PcapSocketAddress { - - private static final long serialVersionUID = 1L; - - private final File pcapFile; - - public PcapReplayAddress(File pcapFile) { - this.pcapFile = pcapFile; - } - - public File getPcapFile() { - return pcapFile; - } - -} diff --git a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelConfig.java b/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelConfig.java deleted file mode 100644 index 08ec928ba6c..00000000000 --- a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcapreplay.netty.config; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelOption; -import org.apache.plc4x.java.utils.pcap.netty.config.PcapChannelConfig; - -import java.util.Map; - -public class PcapReplayChannelConfig extends PcapChannelConfig { - - public static final float SPEED_SLOW_HALF = 0.5f; - public static final float SPEED_REALTIME = 1f; - public static final float SPEED_FAST_DOUBLE = 2f; - public static final float SPEED_FAST_FULL = 0f; - - private float speedFactor = SPEED_REALTIME; - private boolean loop = false; - private String filter = ""; - - public PcapReplayChannelConfig(Channel channel) { - super(channel); - } - - @Override - public Map, Object> getOptions() { - return getOptions(super.getOptions(), PcapReplayChannelOption.SPEED_FACTOR); - } - - @Override - public boolean setOption(ChannelOption option, T value) { - if (option == PcapReplayChannelOption.SPEED_FACTOR) { - if (value instanceof Float) { - speedFactor = (Float) value; - return speedFactor >= 0; - } - return false; - } else if (option == PcapReplayChannelOption.LOOP) { - if (value instanceof Boolean) { - loop = (Boolean) value; - return true; - } - return false; - } else if (option == PcapReplayChannelOption.FILTER) { - if (value instanceof String) { - filter = (String) value; - return true; - } - return false; - } else { - return super.setOption(option, value); - } - } - - public float getSpeedFactor() { - return speedFactor; - } - - public void setSpeedFactor(float speedFactor) { - this.speedFactor = speedFactor; - } - - public boolean isLoop() { - return loop; - } - - public void setLoop(boolean loop) { - this.loop = loop; - } - - public String getFilter() { - return filter; - } - - public void setFilter(String filter) { - this.filter = filter; - } -} diff --git a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelOption.java b/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelOption.java deleted file mode 100644 index fefe74bc9e5..00000000000 --- a/plc4j/utils/pcap-replay/src/main/java/org/apache/plc4x/java/utils/pcapreplay/netty/config/PcapReplayChannelOption.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcapreplay.netty.config; - -import io.netty.channel.ChannelOption; -import org.apache.plc4x.java.utils.pcap.netty.config.PcapChannelOption; - -public class PcapReplayChannelOption extends PcapChannelOption { - - /** - * Option to increase/decrease the replay speed of the recording. - * 1.0 being real-time. - */ - public static final ChannelOption SPEED_FACTOR = - ChannelOption.valueOf(Float.class, "SPEED_FACTOR"); - - /** - * Option to tell the playback to automatically restart at the - * beginning as soon as the end of the playback is reached. - */ - public static final ChannelOption LOOP = - ChannelOption.valueOf(Boolean.class, "LOOP"); - - /** - * set a BPF filter - */ - public static final ChannelOption FILTER = - ChannelOption.valueOf(String.class, "FILTER"); - -} diff --git a/plc4j/utils/pcap-shared/pom.xml b/plc4j/utils/pcap-shared/pom.xml deleted file mode 100644 index b861df98f7f..00000000000 --- a/plc4j/utils/pcap-shared/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - org.apache.plc4x - plc4j-utils - 1.0.0-SNAPSHOT - - - plc4j-utils-pcap-shared - - PLC4J: Utils: Pcap (Shared) - Classes shared between all PCAP related channels. - - - 2025-08-02T13:55:11Z - - - - - io.netty - netty-transport - - - - org.pcap4j - pcap4j-core - - - - org.pcap4j - pcap4j-packetfactory-static - runtime - - - - org.slf4j - slf4j-api - - - ch.qos.logback - logback-classic - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - org.pcap4j:pcap4j-packetfactory-static - - - - - - - org.sonarsource.scanner.maven - sonar-maven-plugin - - true - - - - - - \ No newline at end of file diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/address/PcapSocketAddress.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/address/PcapSocketAddress.java deleted file mode 100644 index e5d3a132184..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/address/PcapSocketAddress.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.address; - -import java.net.SocketAddress; - -public class PcapSocketAddress extends SocketAddress { - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelConfig.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelConfig.java deleted file mode 100644 index b1b0ab40965..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelConfig.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.config; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelConfig; -import io.netty.channel.ChannelOption; -import io.netty.channel.DefaultChannelConfig; -import org.apache.plc4x.java.utils.pcap.netty.handlers.PacketHandler; -import org.pcap4j.core.Pcaps; -import org.pcap4j.packet.Packet; -import org.pcap4j.util.MacAddress; - -import java.net.SocketAddress; -import java.util.Map; - -public class PcapChannelConfig extends DefaultChannelConfig implements ChannelConfig { - - public static final int ALL_PROTOCOLS = -1; - public static final int ALL_PORTS = -1; - - private boolean supportVlans = false; - private int protocolId = ALL_PROTOCOLS; - private int port = ALL_PORTS; - private PacketHandler packetHandler = Packet::getRawData; - private boolean resolveMacAddress = false; - - public PcapChannelConfig(Channel channel) { - super(channel); - } - - public PcapChannelConfig clone() { - PcapChannelConfig clone = new PcapChannelConfig(channel); - clone.supportVlans = this.supportVlans; - clone.protocolId = this.protocolId; - clone.port = this.port; - clone.packetHandler = this.packetHandler; - clone.resolveMacAddress = this.resolveMacAddress; - return clone; - } - - @Override - public Map, Object> getOptions() { - return getOptions(super.getOptions(), - PcapChannelOption.SUPPORT_VLANS, PcapChannelOption.PORT, PcapChannelOption.PROTOCOL_ID, - PcapChannelOption.PACKET_HANDLER, PcapChannelOption.RESOLVE_MAC_ADDRESS); - } - - @Override - public boolean setOption(ChannelOption option, T value) { - if (option == PcapChannelOption.SUPPORT_VLANS) { - if (value instanceof Boolean) { - supportVlans = (Boolean) value; - return true; - } - return false; - } else if (option == PcapChannelOption.PORT) { - if (value instanceof Integer) { - port = (Integer) value; - return true; - } - return false; - } else if (option == PcapChannelOption.PROTOCOL_ID) { - if (value instanceof Integer) { - protocolId = (Integer) value; - return true; - } - return false; - } else if (option == PcapChannelOption.PACKET_HANDLER) { - if (value instanceof PacketHandler) { - packetHandler = (PacketHandler) value; - return true; - } - return false; - } else if (option == PcapChannelOption.RESOLVE_MAC_ADDRESS) { - if (value instanceof Boolean) { - resolveMacAddress = (Boolean) value; - return true; - } - return false; - } else { - return super.setOption(option, value); - } - } - - public boolean isSupportVlans() { - return supportVlans; - } - - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - - public int getProtocolId() { - return protocolId; - } - - public void setProtocolId(int protocolId) { - this.protocolId = protocolId; - } - - public void setPacketHandler(PacketHandler packetHandler) { - this.packetHandler = packetHandler; - } - - public PacketHandler getPacketHandler() { - return packetHandler; - } - - public boolean isResolveMacAddress() { - return resolveMacAddress; - } - - public String getMacBasedFilterString(MacAddress localMacAddress, MacAddress remoteMacAddress) { - StringBuilder sb = new StringBuilder(); - if (getProtocolId() != ALL_PROTOCOLS) { - sb.append(" and (ether proto ").append(getProtocolId()).append(")"); - } - // Add a filter for TCP or UDP port. - if (getPort() != ALL_PORTS) { - sb.append(" and (port ").append(getPort()).append(")"); - } - // Add a filter for source or target address. - if(localMacAddress != null) { - sb.append(" and (ether dst ").append(Pcaps.toBpfString(localMacAddress)).append(")"); - } - // Add a filter for source or target address. - if(remoteMacAddress != null) { - sb.append(" and (ether src ").append(Pcaps.toBpfString(remoteMacAddress)).append(")"); - } - return (sb.length() > 0) ? sb.substring(" and ".length()) : ""; - } - - public String getMacBasedFilterString(SocketAddress localAddress, SocketAddress remoteAddress) { - StringBuilder sb = new StringBuilder(); - if (isSupportVlans()) { - final PcapChannelConfig clone = this.clone(); - clone.supportVlans = false; - String subFilterString = clone.getMacBasedFilterString(localAddress, remoteAddress); - if (subFilterString.isEmpty()) { - sb.append(" and (vlan)"); - } else { - sb.append(" and ((vlan and ").append(subFilterString).append(") or (").append(subFilterString).append("))"); - } - } else { - if (getProtocolId() != ALL_PROTOCOLS) { - sb.append(" and (ether proto ").append(getProtocolId()).append(")"); - } - // Add a filter for TCP or UDP port. - if (getPort() != ALL_PORTS) { - sb.append(" and (port ").append(getPort()).append(")"); - } - // Add a filter for source or target address. - /*if(localAddress != null) { - sb.append(" and (host ").append(localAddress.getHostAddress()).append(")"); - } - // Add a filter for source or target address. - if(remoteAddress != null) { - sb.append(" and (host ").append(localAddress.getHostAddress()).append(")"); - }*/ - } - return (sb.length() > 0) ? sb.substring(" and ".length()) : ""; - } - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelOption.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelOption.java deleted file mode 100644 index c792ea32bf4..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelOption.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.config; - -import io.netty.channel.ChannelOption; -import org.apache.plc4x.java.utils.pcap.netty.handlers.PacketHandler; - -public class PcapChannelOption { - - /** - * Option to restrict the captures based on packet port. - */ - public static final ChannelOption SUPPORT_VLANS = - ChannelOption.valueOf(Boolean.class, "SUPPORT_VLANS"); - - /** - * Option to restrict the captures based on packet port. - */ - public static final ChannelOption PORT = - ChannelOption.valueOf(Integer.class, "PORT"); - - /** - * Option to restrict the captures based on TCP protocol ids. - */ - public static final ChannelOption PROTOCOL_ID = - ChannelOption.valueOf(Integer.class, "PROTOCOL_ID"); - - /** - * Option for providing a PacketHandler, that intercepts the captured packets - * before passing the data into the channel. - */ - public static final ChannelOption PACKET_HANDLER = - ChannelOption.valueOf(PacketHandler.class, "PACKET_HANDLER"); - - /** - * Option for automatically resolving the remote ips MAC address with an - * ARP request. - */ - public static final ChannelOption RESOLVE_MAC_ADDRESS = - ChannelOption.valueOf("RESOLVE_MAC_ADDRESS"); - - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/exception/PcapException.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/exception/PcapException.java deleted file mode 100644 index bb275189071..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/exception/PcapException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.exception; - -public class PcapException extends Exception { - - public PcapException() { - super(); - } - - public PcapException(String message) { - super(message); - } - - public PcapException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/PacketHandler.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/PacketHandler.java deleted file mode 100644 index 8b2c8f2a776..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/PacketHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.handlers; - -import org.pcap4j.packet.Packet; - -public interface PacketHandler { - - byte[] getData(Packet packet); - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/TcpIpPacketHandler.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/TcpIpPacketHandler.java deleted file mode 100644 index f0d76333829..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/TcpIpPacketHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.handlers; - -import org.pcap4j.packet.*; - -/** - * Little helper to automatically unwrap TCP packets to only - * pass along the payload and not the raw Ethernet packet. - */ -public class TcpIpPacketHandler implements PacketHandler { - - @Override - public byte[] getData(Packet packet) { - EthernetPacket ethernetPacket = (EthernetPacket) packet; - IpV4Packet ipv4Packet = (IpV4Packet) ethernetPacket.getPayload(); - TcpPacket tcpPacket = (TcpPacket) ipv4Packet.getPayload(); - if(tcpPacket.getPayload() instanceof UnknownPacket) { - UnknownPacket unknownPacket = (UnknownPacket) tcpPacket.getPayload(); - return unknownPacket.getRawData(); - } - return new byte[0]; - } - -} diff --git a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/UdpIpPacketHandler.java b/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/UdpIpPacketHandler.java deleted file mode 100644 index 7c0efe14c72..00000000000 --- a/plc4j/utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/handlers/UdpIpPacketHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.pcap.netty.handlers; - -import org.pcap4j.packet.*; - -/** - * Little helper to automatically unwrap UDP packets to only - * pass along the payload and not the raw Ethernet packet. - */ -public class UdpIpPacketHandler implements PacketHandler { - - @Override - public byte[] getData(Packet packet) { - EthernetPacket ethernetPacket = (EthernetPacket) packet; - IpV4Packet ipv4Packet = (IpV4Packet) ethernetPacket.getPayload(); - UdpPacket udpPacket = (UdpPacket) ipv4Packet.getPayload(); - if(udpPacket.getPayload() instanceof UnknownPacket) { - UnknownPacket unknownPacket = (UnknownPacket) udpPacket.getPayload(); - return unknownPacket.getRawData(); - } - return new byte[0]; - } - -} diff --git a/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/LICENSE b/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/LICENSE deleted file mode 100644 index 3122c985ac6..00000000000 --- a/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/LICENSE +++ /dev/null @@ -1,6 +0,0 @@ - ----------------------------------------------- - -The Files: -src/main/java/org/apache/plc4x/java/utils/pcap/netty/exception/PcapException.java -Are copyrighted by the The Netty Project which is distributed under the Apache 2.0 license. diff --git a/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/NOTICE b/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/NOTICE deleted file mode 100644 index ccad4c46b77..00000000000 --- a/plc4j/utils/pcap-shared/src/main/remote-resources/META-INF/NOTICE +++ /dev/null @@ -1,4 +0,0 @@ ----------------------------------------------- - -This product includes software developed at -The Netty project (https://netty.io/). diff --git a/plc4j/utils/plc-simulator/pom.xml b/plc4j/utils/plc-simulator/pom.xml deleted file mode 100644 index 4a5fed7e1e4..00000000000 --- a/plc4j/utils/plc-simulator/pom.xml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - 4.1.0 - - - org.apache.plc4x - plc4j-utils - 1.0.0-SNAPSHOT - - - plc4j-utils-plc-simulator - - PLC4J: Utils: PLC-Simulator - - - 2025-08-02T13:55:11Z - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - generate-uber-jar - package - - shade - - - - - org.apache.plc4x.simulator.PlcSimulator - - - - - - - - - - - - - org.apache.plc4x - plc4j-driver-bacnet - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-driver-c-bus - 1.0.0-SNAPSHOT - - - org.apache.plc4x - plc4j-driver-s7 - 1.0.0-SNAPSHOT - - - - org.apache.plc4x - plc4j-api - 1.0.0-SNAPSHOT - - - - org.apache.commons - commons-lang3 - - - org.apache.commons - commons-collections4 - - - commons-cli - commons-cli - - - - io.netty - netty-transport - - - io.netty - netty-common - - - io.netty - netty-codec - - - io.netty - netty-buffer - - - - - org.slf4j - slf4j-api - - - - ch.qos.logback - logback-classic - compile - - - - diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java deleted file mode 100644 index c8d6bea263e..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/java/s7/utils/StaticHelper.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.s7.utils; - -import org.apache.commons.lang3.NotImplementedException; -import org.apache.plc4x.java.api.value.PlcValue; -import org.apache.plc4x.java.spi.buffers.api.ReadBuffer; -import org.apache.plc4x.java.spi.buffers.api.WithOption; -import org.apache.plc4x.java.spi.buffers.api.WriteBuffer; -import org.apache.plc4x.java.spi.buffers.api.exceptions.BufferException; - -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.temporal.ChronoUnit; - -public class StaticHelper { - - public static LocalTime parseTiaTime(ReadBuffer io) { - try { - int millisSinceMidnight = io.readSignedInt(32); - return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus( - millisSinceMidnight, ChronoUnit.MILLIS); - } catch (BufferException e) { - return null; - } - } - - public static void serializeTiaTime(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing TIME not implemented"); - } - - public static LocalTime parseS5Time(ReadBuffer io) { - try { - int stuff = io.readSignedInt(16); - // TODO: Implement this correctly. - throw new NotImplementedException("S5TIME not implemented"); - } catch (BufferException e) { - return null; - } - } - - public static void serializeS5Time(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing S5TIME not implemented"); - - } - - public static LocalTime parseTiaLTime(ReadBuffer io) { - throw new NotImplementedException("LTIME not implemented"); - } - - public static void serializeTiaLTime(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing LTIME not implemented"); - } - - public static LocalTime parseTiaTimeOfDay(ReadBuffer io) { - try { - long millisSinceMidnight = io.readUnsignedLong(32); - return LocalTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0).plus( - millisSinceMidnight, ChronoUnit.MILLIS); - } catch (BufferException e) { - return null; - } - } - - public static void serializeTiaTimeOfDay(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing TIME_OF_DAY not implemented"); - } - - public static LocalDate parseTiaDate(ReadBuffer io) { - try { - int daysSince1990 = io.readUnsignedInt(16); - return LocalDate.now().withYear(1990).withDayOfMonth(1).withMonth(1).plus(daysSince1990, ChronoUnit.DAYS); - } catch (BufferException e) { - return null; - } - } - - public static void serializeTiaDate(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing DATE not implemented"); - } - - public static LocalDateTime parseTiaDateTime(ReadBuffer io) { - try { - int year = io.readUnsignedInt(16); - int month = io.readUnsignedInt(8); - int day = io.readUnsignedInt(8); - // Skip day-of-week - io.readSignedByte(8); - int hour = io.readSignedByte(8); - int minute = io.readSignedByte(8); - int second = io.readSignedByte(8); - int nanosecond = io.readUnsignedInt(24); - - return LocalDateTime.of(year, month, day, hour, minute, second, nanosecond); - } catch (Exception e) { - return null; - } - } - - public static void serializeTiaDateTime(WriteBuffer io, PlcValue value) { - throw new NotImplementedException("Serializing DATE_AND_TIME not implemented"); - } - - public static String parseS7String(ReadBuffer io, int stringLength, Object encoding) { - try { - // This is the maximum number of bytes a string can be long. - short maxLength = io.readUnsignedShort(8); - // This is the total length of the string on the PLC (Not necessarily the number of characters read) - short totalStringLength = io.readSignedShort(8); - // Read the full size of the string. - String str = io.readString(stringLength * 8, WithOption.WithEncoding((String) encoding)); - // Cut off the parts that don't belong to it. - return str.substring(0, totalStringLength); - } catch (BufferException e) { - return null; - } - } - - public static void serializeS7String(WriteBuffer io, PlcValue value, int stringLength, Object encoding) { - // TODO: Need to implement the serialization or we can't write strings - throw new NotImplementedException("Serializing STRING not implemented"); - } - - public static String parseS7Char(ReadBuffer io, Object encoding) throws BufferException { - // Read the full size of the string. - return io.readString(8, WithOption.WithEncoding((String) encoding)); - } - - public static void serializeS7Char(WriteBuffer io, PlcValue value, Object encoding) { - // TODO: Need to implement the serialization or we can't write strings - throw new NotImplementedException("Serializing STRING not implemented"); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java deleted file mode 100644 index 14e3868da5e..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulator.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator; - -import org.apache.commons.cli.*; -import org.apache.plc4x.simulator.model.Context; -import org.apache.plc4x.simulator.server.ServerModule; -import org.apache.plc4x.simulator.simulation.SimulationModule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; -import java.util.ServiceLoader; -import java.util.TreeMap; -import java.util.concurrent.TimeUnit; - -public class PlcSimulator { - - private static final Logger LOGGER = LoggerFactory.getLogger(PlcSimulator.class); - - private boolean running; - private final Map serverModules; - private final SimulationModule simulationModule; - - private PlcSimulator(String simulationName, PlcSimulatorConfig config) { - this(simulationName, config, Thread.currentThread().getContextClassLoader()); - } - - private PlcSimulator(String simulationName, PlcSimulatorConfig config, ClassLoader classLoader) { - Context context = null; - // Initialize all the simulation modules. - LOGGER.info("Initializing Simulation Modules:"); - SimulationModule foundSimulationModule = null; - ServiceLoader simulationModuleLoader = ServiceLoader.load(SimulationModule.class, classLoader); - for (SimulationModule curSimulationModule : simulationModuleLoader) { - if (!curSimulationModule.getName().equals(simulationName)) { - continue; - } - LOGGER.info("Initializing simulation module: {} ...", simulationName); - foundSimulationModule = curSimulationModule; - context = curSimulationModule.getContext(); - LOGGER.info("Initialized"); - } - // If we couldn't find the simulation module provided, report an error and exit. - if (foundSimulationModule == null) { - LOGGER.info("Couldn't find simulation module {}", simulationName); - System.exit(1); - } - simulationModule = foundSimulationModule; - LOGGER.info("Finished Initializing Simulation Modules\n"); - - // Initialize all the server modules. - LOGGER.info("Initializing Server Modules:"); - serverModules = new TreeMap<>(); - ServiceLoader serverModuleLoader = ServiceLoader.load(ServerModule.class, classLoader); - for (ServerModule serverModule : serverModuleLoader) { - LOGGER.info("Initializing server module: {} ...", serverModule.getName()); - serverModules.put(serverModule.getName(), serverModule); - // Inject the contexts. - serverModule.setContext(context); - serverModule.setConfig(config); - LOGGER.info("Initialized"); - } - LOGGER.info("Finished Initializing Server Modules\n"); - - running = true; - } - - private void stop() { - running = false; - } - - private void run() { - // Start all server modules. - LOGGER.info("Starting Server Modules:"); - for (ServerModule serverModule : serverModules.values()) { - LOGGER.info("Starting server module: {}...", serverModule.getName()); - try { - serverModule.start(); - LOGGER.info("Started"); - } catch (Exception e) { - LOGGER.warn("Error starting server module: {}...", serverModule.getName(), e); - } - } - LOGGER.info("Finished Starting Server Modules\n"); - - try { - LOGGER.info("Starting simulations ..."); - while (running) { - try { - simulationModule.loop(); - } catch (Exception e) { - LOGGER.error("Caught error while executing loop() method of {} simulation.", simulationModule.getName(), e); - } - // Sleep 100 ms to not run the simulation too eagerly. - try { - TimeUnit.MILLISECONDS.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException(e); - } - } - } finally { - LOGGER.info("Simulations ended"); - // Start all server modules. - for (ServerModule serverModule : serverModules.values()) { - LOGGER.info("Stopping server module {} ...", serverModule.getName()); - try { - serverModule.stop(); - LOGGER.info("Stopped"); - } catch (Exception e) { - LOGGER.warn("Error stopping server module {} ...", serverModule.getName()); - } - - } - } - } - - public static void main(String... args) throws Exception { - final PlcSimulator simulator = new PlcSimulator("Water Tank", plcSimulatorConfigFromArgs(args)); - // Make sure we stop everything correctly. - Runtime.getRuntime().addShutdownHook(new Thread(simulator::stop)); - // Start the simulator. - simulator.run(); - } - - public static PlcSimulatorConfig plcSimulatorConfigFromArgs(String... args) throws Exception { - PlcSimulatorConfig config = new PlcSimulatorConfig(); - - // Build options - Options options = new Options(); - - options.addOption("public", false, "listen on all interfaces (overrides host option)"); - options.addOption("host", true, "the host interface"); - options.addOption("s7Port", true, "changes the s7 port"); - options.addOption("cBusPort", true, "changes the C-Bus port"); - options.addOption("bacnetPort", true, "changes the Bacnet port"); - - // Parse args - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(options, args); - - // Map options - config.host = cmd.getOptionValue("host", "localhost"); - if (cmd.hasOption("public")) { - LOGGER.info("Listening on all interfaces. (omitting {})", config.host); - config.host = null; - } - config.s7Port = cmd.getOptionValue("s7port"); - config.cBusPort = cmd.getOptionValue("cBusPort"); - config.bacnetPort = cmd.getOptionValue("bacnetPort"); - - return config; - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulatorConfig.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulatorConfig.java deleted file mode 100644 index 99a0fc30be4..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/PlcSimulatorConfig.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator; - -public class PlcSimulatorConfig { - String host; - - String s7Port; - String cBusPort; - - String bacnetPort; - - public String getHost() { - return host; - } - - public String getS7Port() { - return s7Port; - } - - public String getCBusPort() { - return cBusPort; - } - - public String getBacnetPort() { - return bacnetPort; - } -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/exceptions/SimulatorException.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/exceptions/SimulatorException.java deleted file mode 100644 index 7c2fe63f06c..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/exceptions/SimulatorException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.exceptions; - -public class SimulatorException extends Exception { - - public SimulatorException(String message) { - super(message); - } - - public SimulatorException(String message, Throwable cause) { - super(message, cause); - } - - public SimulatorException(Throwable cause) { - super(cause); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/model/Context.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/model/Context.java deleted file mode 100644 index 2f66197d64b..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/model/Context.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.model; - -import org.apache.commons.collections4.list.FixedSizeList; -import org.apache.commons.collections4.map.FixedSizeMap; - -import java.util.*; - -public class Context { - - private final FixedSizeMap memory; - private final FixedSizeList digitalInputs; - private final FixedSizeList analogInputs; - private final FixedSizeList digitalOutputs; - private final FixedSizeList analogOutputs; - - public Context(FixedSizeMap memory, - FixedSizeList digitalInputs, FixedSizeList analogInputs, - FixedSizeList digitalOutputs, FixedSizeList analogOutputs) { - this.memory = memory; - this.digitalInputs = digitalInputs; - this.analogInputs = analogInputs; - this.digitalOutputs = digitalOutputs; - this.analogOutputs = analogOutputs; - } - - public Map getMemory() { - return memory; - } - - public List getDigitalInputs() { - return digitalInputs; - } - - public List getAnalogInputs() { - return analogInputs; - } - - public List getDigitalOutputs() { - return digitalOutputs; - } - - public List getAnalogOutputs() { - return analogOutputs; - } - - public static class ContextBuilder { - private final Map memory; - private final List digitalInputs; - private final List analogInputs; - private final List digitalOutputs; - private final List analogOutputs; - - public ContextBuilder() { - memory = new TreeMap<>(); - digitalInputs = new LinkedList<>(); - analogInputs = new LinkedList<>(); - digitalOutputs = new LinkedList<>(); - analogOutputs = new LinkedList<>(); - } - - public ContextBuilder addMemoryVariable(String name, Object defaultValue) { - memory.put(name, defaultValue); - return this; - } - - public ContextBuilder addDigitalInput(Boolean defaultValue) { - digitalInputs.add(defaultValue); - return this; - } - - public ContextBuilder addAnalogInput(Long defaultValue) { - analogInputs.add(defaultValue); - return this; - } - - public ContextBuilder addDigitalOutput(Boolean defaultValue) { - digitalOutputs.add(defaultValue); - return this; - } - - public ContextBuilder addAnalogOutput(Long defaultValue) { - analogOutputs.add(defaultValue); - return this; - } - - public Context build() { - return new Context(FixedSizeMap.fixedSizeMap(memory), - FixedSizeList.fixedSizeList(digitalInputs), FixedSizeList.fixedSizeList(analogInputs), - FixedSizeList.fixedSizeList(digitalOutputs), FixedSizeList.fixedSizeList(analogOutputs)); - } - - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java deleted file mode 100644 index eed2e42b0ab..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/ServerModule.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server; - -import org.apache.plc4x.simulator.PlcSimulatorConfig; -import org.apache.plc4x.simulator.exceptions.SimulatorException; -import org.apache.plc4x.simulator.model.Context; - -public interface ServerModule { - - /** - * @return the name of the server module - */ - String getName(); - - void setConfig(PlcSimulatorConfig config); - - void setContext(Context contexts); - - void start() throws SimulatorException; - - void stop() throws SimulatorException; -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java deleted file mode 100644 index a907a0fb742..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.bacnet; - -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.DatagramPacket; -import io.netty.channel.socket.nio.NioDatagramChannel; -import io.netty.handler.codec.MessageToMessageDecoder; -import io.netty.handler.codec.MessageToMessageEncoder; -import io.netty.util.concurrent.FastThreadLocal; -import org.apache.plc4x.java.bacnetip.BacNetIpDriver; -import org.apache.plc4x.java.bacnetip.readwrite.BVLC; -import org.apache.plc4x.java.bacnetip.readwrite.Constants; -import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec; -import org.apache.plc4x.java.spi.generation.ByteOrder; -import org.apache.plc4x.simulator.PlcSimulatorConfig; -import org.apache.plc4x.simulator.exceptions.SimulatorException; -import org.apache.plc4x.simulator.model.Context; -import org.apache.plc4x.simulator.server.ServerModule; -import org.apache.plc4x.simulator.server.bacnet.protocol.BacnetServerAdapter; - -import java.net.InetSocketAddress; -import java.util.List; - -public class BacnetServerModule implements ServerModule { - - private EventLoopGroup loopGroup; - private EventLoopGroup workerGroup; - private Context context; - private PlcSimulatorConfig config; - - private final FastThreadLocal returnToSender = new FastThreadLocal<>(); - - @Override - public String getName() { - return "Bacnet"; - } - - @Override - public void setConfig(PlcSimulatorConfig config) { - this.config = config; - } - - @Override - public void setContext(Context context) { - this.context = context; - } - - @Override - public void start() throws SimulatorException { - if (loopGroup != null) { - return; - } - - try { - loopGroup = new NioEventLoopGroup(); - - Bootstrap bootstrap = new Bootstrap(); - bootstrap.group(loopGroup) - .channel(NioDatagramChannel.class) - .option(ChannelOption.SO_BROADCAST, true) - .handler(new ChannelInitializer() { - @Override - public void initChannel(NioDatagramChannel channel) { - channel.pipeline() - .addLast(new MessageToMessageDecoder() { - @Override - protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List out) throws Exception { - final ByteBuf content = msg.content(); - out.add(content.retain()); - String value = msg.sender().getHostString(); - returnToSender.set(value); - } - }) - .addLast(new MessageToMessageEncoder() { - @Override - protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List out) throws Exception { - msg.retain(); - out.add(new DatagramPacket(msg, new InetSocketAddress(returnToSender.get(), 47808))); - } - }) - .addLast(new GeneratedProtocolMessageCodec<>(BVLC.class, - BVLC::staticParse, ByteOrder.BIG_ENDIAN, - new BacNetIpDriver.ByteLengthEstimator(), - new BacNetIpDriver.CorruptPackageCleaner())) - .addLast(new BacnetServerAdapter(context)); - } - }); - - int port = Constants.BACNETUDPDEFAULTPORT; - if (config.getCBusPort() != null) { - port = Integer.parseInt(config.getCBusPort()); - } - String host = config.getHost(); - if (host != null) { - bootstrap.bind(host, port).sync(); - } else { - bootstrap.bind(port).sync(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new SimulatorException(e); - } - } - - @Override - public void stop() { - if (workerGroup == null) { - return; - } - - workerGroup.shutdownGracefully(); - loopGroup.shutdownGracefully(); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java deleted file mode 100644 index 2ee7c5d3d9d..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.bacnet.protocol; - -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.apache.plc4x.java.bacnetip.readwrite.Error; -import org.apache.plc4x.java.bacnetip.readwrite.*; -import org.apache.plc4x.java.bacnetip.readwrite.utils.StaticHelper; -import org.apache.plc4x.simulator.model.Context; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class BacnetServerAdapter extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(BacnetServerAdapter.class); - - private Context context; - - // TODO: make configurable - private static final int DEVICE_INSTANCE = 4711; - - // TODO: make configurable - private static final int DEVICE_ID = 815; - - public BacnetServerAdapter(Context context) { - LOGGER.info("Creating adapter with context {}", context); - } - - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - super.channelInactive(ctx); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - System.out.println("Got request"); - System.out.println(msg); - if (!(msg instanceof BVLC)) { - return; - } - BVLC bvlc = (BVLC) msg; - if (!(bvlc instanceof BVLCOriginalUnicastNPDU)) { - // TODO: write useful error - ctx.writeAndFlush(new BVLCOriginalUnicastNPDU( - new NPDU( - (short) 1, - new NPDUControl(true, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE), - 0, - (short) 0, - null, - 0, - (short) 0, - null, - (short) 0, - null, - new APDUError( - (short) 0, - BACnetConfirmedServiceChoice.READ_PROPERTY, - new BACnetErrorGeneral(new Error( - new ErrorClassTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorClass.COMMUNICATION, 0L), - new ErrorCodeTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorCode.VENDOR_PROPRIETARY_VALUE, 0L) - )) - ) - ) - )).addListener((ChannelFutureListener) f -> { - if (!f.isSuccess()) { - f.cause().printStackTrace(); - } - }); - return; - } - BVLCOriginalUnicastNPDU bvlcOriginalUnicastNPDU = (BVLCOriginalUnicastNPDU) bvlc; - // TODO: get messageTypeTag - APDU apdu = bvlcOriginalUnicastNPDU.getNpdu().getApdu(); - if (apdu instanceof APDUUnconfirmedRequest) { - APDUUnconfirmedRequest apduUnconfirmedRequest = (APDUUnconfirmedRequest) apdu; - BACnetUnconfirmedServiceRequest serviceRequest = apduUnconfirmedRequest.getServiceRequest(); - if (serviceRequest instanceof BACnetUnconfirmedServiceRequestWhoIs) { - BACnetUnconfirmedServiceRequestWhoIs baCnetUnconfirmedServiceRequestWhoIs = (BACnetUnconfirmedServiceRequestWhoIs) serviceRequest; - if (baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeLowLimit() != null) { - if (DEVICE_INSTANCE < baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeLowLimit().getActualValue().longValue()) { - // Ignoring because we out if limit - return; - } - } - if (baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeHighLimit() != null) { - if (DEVICE_INSTANCE > baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeHighLimit().getActualValue().longValue()) { - // Ignoring because we out if limit - return; - } - } - BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU( - new NPDU( - (short) 1, - new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE), - null, - null, - null, - null, - null, - null, - null, - null, - new APDUUnconfirmedRequest( - new BACnetUnconfirmedServiceRequestIAm( - StaticHelper.createBACnetApplicationTagObjectIdentifier(BACnetObjectType.DEVICE.getValue(), DEVICE_INSTANCE), - StaticHelper.createBACnetApplicationTagUnsignedInteger(1024), - StaticHelper.creatBACnetSegmentationTagged(BACnetSegmentation.NO_SEGMENTATION), - StaticHelper.createBACnetVendorIdApplicationTagged(BACnetVendorId.MAPPED.getVendorId()) - ) - ) - ) - ); - System.out.println("Writing response"); - System.out.println(response); - ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { - if (!f.isSuccess()) { - f.cause().printStackTrace(); - } - }); - } else { - throw new Exception(apdu.getClass() + " not set supported"); - } - } else if (apdu instanceof APDUConfirmedRequest) { - APDUConfirmedRequest apduConfirmedRequest = (APDUConfirmedRequest) apdu; - // TODO: just handle read for now - BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU( - new NPDU( - (short) 1, - new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE), - null, - null, - null, - null, - null, - null, - null, - null, - new APDUComplexAck( - false, - false, - apduConfirmedRequest.getInvokeId(), - null, - null, - new BACnetServiceAckReadProperty( - 0L, - StaticHelper.createBACnetContextTagObjectIdentifier((byte) 0, (short) 2, 1), - StaticHelper.createBACnetPropertyIdentifierTagged((byte) 1, 85), - null, - new BACnetConstructedDataAnalogValuePresentValue( - StaticHelper.createBACnetOpeningTag((short) 3), - StaticHelper.createBACnetTagHeaderBalanced(true, (short) 3, 3L), - StaticHelper.createBACnetClosingTag((short) 3), - StaticHelper.createBACnetApplicationTagReal(101L) - ) - ), - null, - null - ) - ) - ); - System.out.println("Writing response"); - System.out.println(response); - ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> { - if (!f.isSuccess()) { - f.cause().printStackTrace(); - } - }); - } - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/CBusServerModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/CBusServerModule.java deleted file mode 100644 index fdb7576ee3a..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/CBusServerModule.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.cbus; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import org.apache.plc4x.java.cbus.CBusDriver; -import org.apache.plc4x.java.cbus.readwrite.CBusMessage; -import org.apache.plc4x.java.cbus.readwrite.CBusOptions; -import org.apache.plc4x.java.cbus.readwrite.Constants; -import org.apache.plc4x.java.cbus.readwrite.RequestContext; -import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec; -import org.apache.plc4x.java.spi.generation.ByteOrder; -import org.apache.plc4x.java.spi.generation.MessageInput; -import org.apache.plc4x.simulator.PlcSimulatorConfig; -import org.apache.plc4x.simulator.exceptions.SimulatorException; -import org.apache.plc4x.simulator.model.Context; -import org.apache.plc4x.simulator.server.ServerModule; -import org.apache.plc4x.simulator.server.cbus.protocol.CBusServerAdapter; - -public class CBusServerModule implements ServerModule { - - public static final MessageInput MESSAGE_INPUT = io -> - CBusMessage.staticParse(io, false, new RequestContext(false), - new CBusOptions(false, false, false, false, false, false, false, false, false)); - - private EventLoopGroup loopGroup; - private EventLoopGroup workerGroup; - private Context context; - private PlcSimulatorConfig config; - - @Override - public String getName() { - return "C-BUS"; - } - - @Override - public void setConfig(PlcSimulatorConfig config) { - this.config = config; - } - - @Override - public void setContext(Context context) { - this.context = context; - } - - @Override - public void start() throws SimulatorException { - if (loopGroup != null) { - return; - } - - try { - loopGroup = new NioEventLoopGroup(); - workerGroup = new NioEventLoopGroup(); - - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(loopGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel channel) { - ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast(new GeneratedProtocolMessageCodec<>(CBusMessage.class, - MESSAGE_INPUT, ByteOrder.BIG_ENDIAN, - new CBusDriver.ByteLengthEstimator(), - new CBusDriver.CorruptPackageCleaner())); - pipeline.addLast(new CBusServerAdapter(context)); - } - }) - .option(ChannelOption.SO_BACKLOG, 128) - .childOption(ChannelOption.SO_KEEPALIVE, true); - - int port = Constants.CBUSTCPDEFAULTPORT; - if (config.getCBusPort() != null) { - port = Integer.parseInt(config.getCBusPort()); - } - String host = config.getHost(); - if (host != null) { - bootstrap.bind(host, port).sync(); - } else { - bootstrap.bind(port).sync(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new SimulatorException(e); - } - } - - @Override - public void stop() { - if (workerGroup == null) { - return; - } - - workerGroup.shutdownGracefully(); - loopGroup.shutdownGracefully(); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java deleted file mode 100644 index d745f2823cf..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/cbus/protocol/CBusServerAdapter.java +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.cbus.protocol; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.apache.plc4x.java.cbus.readwrite.*; -import org.apache.plc4x.simulator.model.Context; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -public class CBusServerAdapter extends ChannelInboundHandlerAdapter { - - private static final List AVAILABLE_UNITS = Arrays.asList((byte) 3, (byte) 23, (byte) 48); - - private static final Logger LOGGER = LoggerFactory.getLogger(CBusServerAdapter.class); - - private final Context context; - - private static final RequestContext requestContext = new RequestContext(false); - - private static boolean connect; - private static boolean smart; - private static boolean idmon; - private static boolean exstat; - private static boolean monitor; - private static boolean monall; - private static boolean pun; - private static boolean pcn; - private static boolean srchk; - - private static byte monitorApplicationAddress1; - - private static byte monitorApplicationAddress2; - private static CBusOptions cBusOptions; - - private final Lock outputLock = new ReentrantLock(); - - private ScheduledFuture salMonitorFuture; - - private ScheduledFuture mmiMonitorFuture; - - public CBusServerAdapter(Context context) { - LOGGER.info("Creating adapter with context {}", context); - this.context = context; - cBusOptions = new CBusOptions(connect, smart, idmon, exstat, monitor, monall, pun, pcn, srchk); - } - - private static void buildCBusOptions() { - LOGGER.info("Updating options {}", cBusOptions); - cBusOptions = new CBusOptions(connect, smart, idmon, exstat, monitor, monall, pun, pcn, srchk); - LOGGER.info("Updated options {}", cBusOptions); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (salMonitorFuture != null) - salMonitorFuture.cancel(false); - if (mmiMonitorFuture != null) - mmiMonitorFuture.cancel(false); - super.channelInactive(ctx); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (!(msg instanceof CBusMessage)) { - return; - } - try { - outputLock.lock(); - syncChannelRead(ctx, msg); - } finally { - ctx.flush(); - outputLock.unlock(); - } - } - - private void syncChannelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - LOGGER.debug("Working with cBusOptions\n{}", cBusOptions); - // Serial is slow - TimeUnit.MILLISECONDS.sleep(100); - if (!smart && !connect) { - // In this mode every message will be echoed - LOGGER.info("Sending echo"); - ctx.write(msg); - } - CBusMessage packet = (CBusMessage) msg; - if (packet instanceof CBusMessageToClient) { - LOGGER.info("Message to client not supported\n{}", packet); - return; - } - CBusMessageToServer cBusMessageToServer = (CBusMessageToServer) packet; - Request request = cBusMessageToServer.getRequest(); - if (request instanceof RequestEmpty || request instanceof RequestNull) { - LOGGER.debug("Ignoring\n{}", request); - } else if (request instanceof RequestDirectCommandAccess) { - handleDirectCommandAccess(ctx, (RequestDirectCommandAccess) request); - } else if (request instanceof RequestCommand) { - handleRequestCommand(ctx, (RequestCommand) request); - } else if (request instanceof RequestObsolete) { - RequestObsolete requestObsolete = (RequestObsolete) request; - LOGGER.info("Handling RequestObsolete\n{}", requestObsolete); - // TODO: handle this - } else if (request instanceof RequestReset) { - if (smart || connect) { - // On reset, we need to send the echo if we had not sent it above - LOGGER.info("Sending echo"); - ctx.write(msg); - } - LOGGER.info("Handling RequestReset\n{}", request); - handleReset(); - } else if (request instanceof RequestSmartConnectShortcut) { - handleSmartConnect((RequestSmartConnectShortcut) request); - } - } - - private void handleDirectCommandAccess(ChannelHandlerContext ctx, RequestDirectCommandAccess requestDirectCommandAccess) { - CALData calData = requestDirectCommandAccess.getCalData(); - LOGGER.info("Handling RequestDirectCommandAccess\n{}", requestDirectCommandAccess); - handleCalData(ctx, calData, requestDirectCommandAccess.getAlpha()); - } - - private void handleRequestCommand(ChannelHandlerContext ctx, RequestCommand requestCommand) { - LOGGER.info("Handling RequestCommand\n{}", requestCommand); - CBusCommand cbusCommand = requestCommand.getCbusCommand(); - LOGGER.info("Handling CBusCommand\n{}", cbusCommand); - if (cbusCommand instanceof CBusCommandPointToPoint) { - CBusCommandPointToPoint cBusCommandPointToPoint = (CBusCommandPointToPoint) cbusCommand; - CBusPointToPointCommand command = cBusCommandPointToPoint.getCommand(); - UnitAddress unitAddress = null; - if (command instanceof CBusPointToPointCommandIndirect) { - CBusPointToPointCommandIndirect cBusPointToPointCommandIndirect = (CBusPointToPointCommandIndirect) command; - // TODO: handle bridgeAddress - // TODO: handle networkRoute - unitAddress = cBusPointToPointCommandIndirect.getUnitAddress(); - } - if (command instanceof CBusPointToPointCommandDirect) { - CBusPointToPointCommandDirect cBusPointToPointCommandDirect = (CBusPointToPointCommandDirect) command; - unitAddress = cBusPointToPointCommandDirect.getUnitAddress(); - } - if (unitAddress == null) { - throw new IllegalStateException("Unit address should be set at this point"); - } - boolean knownUnit = AVAILABLE_UNITS.contains(unitAddress.getAddress()); - if (!knownUnit) { - LOGGER.warn("{} not a known unit", unitAddress); - ReplyOrConfirmation replyOrConfirmation = new ServerErrorReply((byte) 0x0); - CBusMessageToClient cBusMessageToClient = new CBusMessageToClient(replyOrConfirmation); - ctx.writeAndFlush(cBusMessageToClient); - return; - } - CALData calData = command.getCalData(); - handleCalData(ctx, calData, requestCommand.getAlpha()); - return; - } else if (cbusCommand instanceof CBusCommandPointToMultiPoint) { - CBusCommandPointToMultiPoint cBusCommandPointToMultiPoint = (CBusCommandPointToMultiPoint) cbusCommand; - CBusPointToMultiPointCommand command = cBusCommandPointToMultiPoint.getCommand(); - if (command instanceof CBusPointToMultiPointCommandStatus) { - CBusPointToMultiPointCommandStatus cBusPointToMultiPointCommandStatus = (CBusPointToMultiPointCommandStatus) command; - StatusRequest statusRequest = cBusPointToMultiPointCommandStatus.getStatusRequest(); - if (statusRequest instanceof StatusRequestBinaryState) { - StatusRequestBinaryState statusRequestBinaryState = (StatusRequestBinaryState) statusRequest; - LOGGER.info("Handling StatusRequestBinaryState\n{}", statusRequestBinaryState); - handleStatusRequestBinary(ctx, requestCommand, statusRequestBinaryState.getApplication()); - } - if (statusRequest instanceof StatusRequestBinaryStateDeprecated) { - StatusRequestBinaryStateDeprecated statusRequestBinaryStateDeprecated = (StatusRequestBinaryStateDeprecated) statusRequest; - LOGGER.info("Handling StatusRequestBinaryStateDeprecated\n{}", statusRequestBinaryStateDeprecated); - handleStatusRequestBinary(ctx, requestCommand, statusRequestBinaryStateDeprecated.getApplication()); - return; - } - if (statusRequest instanceof StatusRequestLevel) { - StatusRequestLevel statusRequestLevel = (StatusRequestLevel) statusRequest; - handleStatusRequestLevel(ctx, requestCommand, statusRequestLevel); - return; - } - throw new IllegalStateException(); - } - if (command instanceof CBusPointToMultiPointCommandNormal) { - CBusPointToMultiPointCommandNormal cBusPointToMultiPointCommandNormal = (CBusPointToMultiPointCommandNormal) command; - LOGGER.info("Handling CBusPointToMultiPointCommandNormal\n{}", cBusPointToMultiPointCommandNormal); - // TODO: handle this - return; - } - // TODO: handle this - return; - } else if (cbusCommand instanceof CBusCommandPointToPointToMultiPoint) { - CBusCommandPointToPointToMultiPoint cBusCommandPointToPointToMultiPoint = (CBusCommandPointToPointToMultiPoint) cbusCommand; - LOGGER.info("Handling CBusCommandPointToPointToMultiPoint\n{}", cBusCommandPointToPointToMultiPoint); - // TODO: handle this - return; - } else if (cbusCommand instanceof CBusCommandDeviceManagement) { - CBusCommandDeviceManagement cBusCommandDeviceManagement = (CBusCommandDeviceManagement) cbusCommand; - LOGGER.info("Handling CBusCommandDeviceManagement\n{}", cBusCommandDeviceManagement); - // TODO: handle this - return; - } - - Alpha alpha = requestCommand.getAlpha(); - if (alpha != null) { - Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.NOT_TRANSMITTED_CORRUPTION); - ReplyOrConfirmationConfirmation replyOrConfirmationConfirmation = new ReplyOrConfirmationConfirmation(alpha.getCharacter(), confirmation, null); - CBusMessage response = new CBusMessageToClient(replyOrConfirmationConfirmation); - LOGGER.info("Send response\n{}", response); - ctx.writeAndFlush(response); - } - } - - private static void handleStatusRequestLevel(ChannelHandlerContext ctx, RequestCommand requestCommand, StatusRequestLevel statusRequestLevel) { - StatusCoding coding = StatusCoding.LEVEL_BY_THIS_SERIAL_INTERFACE; - // TODO: map actual values from simulator - byte blockStart = statusRequestLevel.getStartingGroupAddressLabel(); - List levelInformations = Collections.singletonList(new LevelInformationNormal(0x5555, LevelInformationNibblePair.Value_F, LevelInformationNibblePair.Value_F)); - CALData calData = new CALDataStatusExtended(requestContext, CALCommandTypeContainer.CALCommandReply_4Bytes, null, coding, statusRequestLevel.getApplication(), blockStart, null, levelInformations); - CALReply calReply; - if (exstat) { - calReply = new CALReplyLong((byte) 0x0, calData, (byte) 0x0, new UnitAddress((byte) 0x04), null, new SerialInterfaceAddress((byte) 0x02), (byte) 0x0, null); - } else { - calReply = new CALReplyShort((byte) 0x0, calData); - } - CBusMessage response = createCBusMessageForReply(requestCommand.getAlpha(), calReply, cBusOptions); - LOGGER.info("Send level status response\n{}", response); - ctx.writeAndFlush(response); - } - - private void handleStatusRequestBinary(ChannelHandlerContext ctx, RequestCommand requestCommand, ApplicationIdContainer application) { - if (application == ApplicationIdContainer.NETWORK_CONTROL) { - LOGGER.info("Handling installation MMI Request"); - sendInstallationMMIResponse(ctx, requestCommand.getAlpha()); - return; - } - List statusBytes = new LinkedList<>(); - // TODO: map actual values from simulator - for (int i = 0; i < 22; i++) { - statusBytes.add(new StatusByte(GAVState.ON, GAVState.ERROR, GAVState.OFF, GAVState.DOES_NOT_EXIST)); - } - - LOGGER.info("Send binary status response"); - sendStatusBytes(ctx, "First parts {}", application, (byte) 0x0, statusBytes, requestCommand.getAlpha(), cBusOptions); - } - - private void handleCalData(ChannelHandlerContext ctx, CALData calData, Alpha alpha) { - if (calData instanceof CALDataGetStatus) { - // TODO: implement me - } else if (calData instanceof CALDataIdentify) { - handleCalDataIdentify(ctx, (CALDataIdentify) calData, alpha); - } else if (calData instanceof CALDataRecall) { - // TODO: implement me - } else if (calData instanceof CALDataReset) { - CALDataReset calDataReset = (CALDataReset) calData; - if (smart || connect) { - // On reset, we need to send the echo if we had not sent it above - LOGGER.info("Sending echo"); - ctx.write(calDataReset); - } - LOGGER.info("Handling CALDataReset\n{}", calDataReset); - handleReset(); - } else if (calData instanceof CALDataWrite) { - CALDataWrite calDataWrite = (CALDataWrite) calData; - Runnable acknowledger = () -> { - CALDataAcknowledge calDataAcknowledge = new CALDataAcknowledge(requestContext, CALCommandTypeContainer.CALCommandAcknowledge, null, calDataWrite.getParamNo(), (short) 0x0); - CALReplyShort calReply = new CALReplyShort((byte) 0x0, calDataAcknowledge); - EncodedReplyCALReply encodedReply = new EncodedReplyCALReply(requestContext, (byte) 0x0, calReply); - ReplyEncodedReply replyEncodedReply = new ReplyEncodedReply((byte) 0x0, cBusOptions, encodedReply, null); - ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0x0, replyEncodedReply, new ResponseTermination()); - if (alpha != null) { - replyOrConfirmation = new ReplyOrConfirmationConfirmation((byte) 0x0, new Confirmation(alpha, null, ConfirmationType.CONFIRMATION_SUCCESSFUL), replyOrConfirmation); - } - CBusMessageToClient cBusMessageToClient = new CBusMessageToClient(replyOrConfirmation); - LOGGER.info("Sending ack\n{}", cBusMessageToClient); - ctx.writeAndFlush(cBusMessageToClient); - }; - switch (calDataWrite.getParamNo().getParameterType()) { - case APPLICATION_ADDRESS_1: - ApplicationAddress1 applicationAddress1 = ((ParameterValueApplicationAddress1) calDataWrite.getParameterValue()).getValue(); - monitorApplicationAddress1 = applicationAddress1.getAddress(); - acknowledger.run(); - return; - case APPLICATION_ADDRESS_2: - ApplicationAddress2 applicationAddress2 = ((ParameterValueApplicationAddress2) calDataWrite.getParameterValue()).getValue(); - monitorApplicationAddress2 = applicationAddress2.getAddress(); - acknowledger.run(); - return; - case INTERFACE_OPTIONS_1: - InterfaceOptions1 interfaceOptions1 = ((ParameterValueInterfaceOptions1) calDataWrite.getParameterValue()).getValue(); - idmon = interfaceOptions1.getIdmon(); - monitor = interfaceOptions1.getMonitor(); - if (monitor) startMMIMonitor(ctx); - else stopMMIMonitor(); - smart = interfaceOptions1.getSmart(); - srchk = interfaceOptions1.getSrchk(); - // TODO: add support for xonxoff - // xonxoff = interfaceOptions1.getXonXoff(); - connect = interfaceOptions1.getConnect(); - if (connect) startSALMonitor(ctx); - else stopSALMonitor(); - buildCBusOptions(); - acknowledger.run(); - return; - case INTERFACE_OPTIONS_2: - InterfaceOptions2 interfaceOptions2 = ((ParameterValueInterfaceOptions2) calDataWrite.getParameterValue()).getValue(); - // TODO: add support for burden - // burden = interfaceOptions2.getBurden(); - // TODO: add support for clockgen - // clockgen = interfaceOptions2.getClockGen(); - buildCBusOptions(); - acknowledger.run(); - return; - case INTERFACE_OPTIONS_3: - InterfaceOptions3 interfaceOptions3Value = ((ParameterValueInterfaceOptions3) calDataWrite.getParameterValue()).getValue(); - boolean oldExstat = exstat; - exstat = interfaceOptions3Value.getExstat(); - if (oldExstat != exstat) { - LOGGER.info("Restarting monitors"); - stopMMIMonitor(); - startMMIMonitor(ctx); - stopSALMonitor(); - startSALMonitor(ctx); - } - pun = interfaceOptions3Value.getPun(); - // TODO: add support for localsal - // localsal = interfaceOptions3Value.getLocalSal(); - pcn = interfaceOptions3Value.getPcn(); - buildCBusOptions(); - acknowledger.run(); - return; - case BAUD_RATE_SELECTOR: - BaudRateSelector baudRateSelector = ((ParameterValueBaudRateSelector) calDataWrite.getParameterValue()).getValue(); - // TODO: add support for baudrate - // baudrate = baudRateSelector.getValue(); - buildCBusOptions(); - acknowledger.run(); - return; - case INTERFACE_OPTIONS_1_POWER_UP_SETTINGS: - InterfaceOptions1 interfaceOptions1PowerUpSettings = ((ParameterValueInterfaceOptions1PowerUpSettings) calDataWrite.getParameterValue()).getValue().getInterfaceOptions1(); - idmon = interfaceOptions1PowerUpSettings.getIdmon(); - monitor = interfaceOptions1PowerUpSettings.getMonitor(); - if (monitor) startMMIMonitor(ctx); - else stopMMIMonitor(); - smart = interfaceOptions1PowerUpSettings.getSmart(); - srchk = interfaceOptions1PowerUpSettings.getSrchk(); - // TODO: add support for xonxoff - // xonxoff = interfaceOptions1PowerUpSettings.getXonXoff(); - connect = interfaceOptions1PowerUpSettings.getConnect(); - if (connect) startSALMonitor(ctx); - else stopSALMonitor(); - buildCBusOptions(); - acknowledger.run(); - return; - case CUSTOM_MANUFACTURER: - // TODO: handle other param typed - acknowledger.run(); - return; - case SERIAL_NUMBER: - // TODO: handle other param typed - acknowledger.run(); - return; - case CUSTOM_TYPE: - // TODO: handle other param typed - acknowledger.run(); - return; - default: - throw new IllegalStateException("Unmapped type"); - } - } else { - throw new IllegalStateException("Unmapped type: " + calData.getClass()); - } - } - - private static CBusMessage createCBusMessageForReply(Alpha alpha, CALReply calReply, CBusOptions cBusOptions) { - EncodedReply encodedReply = new EncodedReplyCALReply(CBusServerAdapter.requestContext, (byte) 0x0, calReply); - ReplyEncodedReply replyEncodedReply = new ReplyEncodedReply((byte) 0xC0, CBusServerAdapter.cBusOptions, encodedReply, null); - ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0xFF, replyEncodedReply, new ResponseTermination()); - if (alpha != null) { - Confirmation confirmation = new Confirmation(alpha, null, ConfirmationType.CONFIRMATION_SUCCESSFUL); - replyOrConfirmation = new ReplyOrConfirmationConfirmation(alpha.getCharacter(), confirmation, replyOrConfirmation); - } - return new CBusMessageToClient(replyOrConfirmation); - } - - private static void sendInstallationMMIResponse(ChannelHandlerContext ctx, Alpha alpha) { - LOGGER.info("Send installation MMIs"); - sendMMIs(ctx, ApplicationIdContainer.NETWORK_CONTROL, alpha, cBusOptions); - } - - private static void sendMonitoredMMIs(ChannelHandlerContext ctx) { - LOGGER.info("Send installation MMIs"); - // TODO: for whatever reason those are not send with a crc - CBusOptions cBusOptions = new CBusOptions(connect, smart, idmon, exstat, monitor, monall, pun, pcn, false); - sendMMIs(ctx, ApplicationIdContainer.LIGHTING_38, null, cBusOptions); - } - - private static void sendMMIs(ChannelHandlerContext ctx, ApplicationIdContainer application, Alpha alpha, CBusOptions cBusOptions) { - { - byte blockStart = 0x0; - List unitStatusBytes = new LinkedList<>(); - for (int i = blockStart; i <= 88 - 4; i = i + 4) { - LOGGER.debug("Handling units 0-88 {},{},{},{}", i, (i + 1), (i + 2), (i + 3)); - addStatusBytesAtOffset(unitStatusBytes, i); - } - LOGGER.debug("Produced {}, status bytes which equates to {} status", unitStatusBytes.size(), unitStatusBytes.size() * 4); - sendStatusBytes(ctx, "Sending second part {}", application, blockStart, unitStatusBytes, alpha, cBusOptions); - } - { - byte blockStart = 88; - List unitStatusBytes = new LinkedList<>(); - for (int i = 88; i <= 88 + 88 - 4; i = i + 4) { - LOGGER.debug("Handling units 88-176 {},{},{},{}", i, (i + 1), (i + 2), (i + 3)); - addStatusBytesAtOffset(unitStatusBytes, i); - } - LOGGER.debug("Produced {}, status bytes which equates to {} status", unitStatusBytes.size(), unitStatusBytes.size() * 4); - sendStatusBytes(ctx, "Sending second part {}", application, blockStart, unitStatusBytes, null, cBusOptions); - } - { - byte blockStart = (byte) 176; - List unitStatusBytes = new LinkedList<>(); - for (int i = 176; i <= 176 + 80 - 4; i = i + 4) { - LOGGER.debug("Handling units 176-256 {},{},{},{}", i, (i + 1), (i + 2), (i + 3)); - addStatusBytesAtOffset(unitStatusBytes, i); - } - LOGGER.debug("Produced {}, status bytes which equates to {} status", unitStatusBytes.size(), unitStatusBytes.size() * 4); - sendStatusBytes(ctx, "Sending third part {}", application, blockStart, unitStatusBytes, null, cBusOptions); - } - } - - private static void addStatusBytesAtOffset(List unitStatusBytes, int i) { - unitStatusBytes.add( - new StatusByte( - AVAILABLE_UNITS.contains((byte) (i + 3)) ? GAVState.ON : GAVState.DOES_NOT_EXIST, - AVAILABLE_UNITS.contains((byte) (i + 2)) ? GAVState.ON : GAVState.DOES_NOT_EXIST, - AVAILABLE_UNITS.contains((byte) (i + 1)) ? GAVState.ON : GAVState.DOES_NOT_EXIST, - AVAILABLE_UNITS.contains((byte) (i)) ? GAVState.ON : GAVState.DOES_NOT_EXIST - ) - ); - } - - private static void sendStatusBytes(ChannelHandlerContext ctx, String logMessage, ApplicationIdContainer application, byte blockStart, List unitStatusBytes, Alpha alpha, CBusOptions cBusOptions) { - int numberOfStatusBytes = unitStatusBytes.size(); - CALReply calReply; - CALCommandTypeContainer commandTypeContainer = null; - if (cBusOptions.getExstat()) { - for (CALCommandTypeContainer calCommandTypeContainerElement : CALCommandTypeContainer.values()) { - if (calCommandTypeContainerElement.getCommandType() != CALCommandType.STATUS_EXTENDED) { - continue; - } - if (calCommandTypeContainerElement.getNumBytes() + 3 == numberOfStatusBytes) { - commandTypeContainer = calCommandTypeContainerElement; - break; - } - } - CALData calData = new CALDataStatusExtended(requestContext, commandTypeContainer, null, StatusCoding.BINARY_BY_THIS_SERIAL_INTERFACE, application, blockStart, unitStatusBytes, null); - // TODO: do we use a random unit or a fixed or do we need it as parameter - int randomElementIndex = ThreadLocalRandom.current().nextInt(AVAILABLE_UNITS.size()) % AVAILABLE_UNITS.size(); - byte randomUnit = AVAILABLE_UNITS.get(randomElementIndex); - calReply = new CALReplyLong((byte) 0x86, calData, 0x00, new UnitAddress(randomUnit), null, new SerialInterfaceAddress((byte) 0x02), (byte) 0x00, null); - } else { - for (CALCommandTypeContainer calCommandTypeContainerElement : CALCommandTypeContainer.values()) { - if (calCommandTypeContainerElement.getCommandType() != CALCommandType.STATUS) { - continue; - } - if (calCommandTypeContainerElement.getNumBytes() + 3 == numberOfStatusBytes) { - commandTypeContainer = calCommandTypeContainerElement; - break; - } - } - CALData calData = new CALDataStatus(requestContext, commandTypeContainer, null, application, (byte) 0x00, unitStatusBytes); - calReply = new CALReplyShort((byte) 0x0, calData); - } - CBusMessage response = createCBusMessageForReply(alpha, calReply, cBusOptions); - LOGGER.debug(logMessage, response); - ctx.writeAndFlush(response); - } - - private void handleCalDataIdentify(ChannelHandlerContext ctx, CALDataIdentify calDataIdentify, Alpha alpha) { - byte numBytes; - IdentifyReplyCommand identifyReplyCommand; - switch (calDataIdentify.getAttribute()) { - case Manufacturer: - numBytes = 0x08; - identifyReplyCommand = new IdentifyReplyCommandManufacturer("Apache "); - break; - case Type: - numBytes = 0x08; - identifyReplyCommand = new IdentifyReplyCommandType("plc4x-si"); - break; - case FirmwareVersion: - numBytes = 0x08; - identifyReplyCommand = new IdentifyReplyCommandFirmwareVersion(" 0.09 "); - break; - case Summary: - numBytes = 0x09; - identifyReplyCommand = new IdentifyReplyCommandSummary("NOIDEA", (byte) 0xAF, "0900"); - break; - case ExtendedDiagnosticSummary: - numBytes = 0x0C; - identifyReplyCommand = new IdentifyReplyCommandExtendedDiagnosticSummary(ApplicationIdContainer.FREE_USAGE_01, ApplicationIdContainer.FREE_USAGE_0F, (byte) 0x0, 0x0, 4711L, (byte) 0x13, false, false, false, true, false, false, false, false, false, false, false, false, false); - break; - case NetworkTerminalLevels: - numBytes = 0x0C; - identifyReplyCommand = new IdentifyReplyCommandNetworkTerminalLevels(new byte[]{0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13}); - break; - case TerminalLevel: - numBytes = 0x0C; - identifyReplyCommand = new IdentifyReplyCommandTerminalLevels(new byte[]{0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13}); - break; - case NetworkVoltage: - numBytes = 0x05; - identifyReplyCommand = new IdentifyReplyCommandNetworkVoltage("48", "7"); - break; - case GAVValuesCurrent: - numBytes = 0x10; - identifyReplyCommand = new IdentifyReplyCommandGAVValuesCurrent(new byte[]{ - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - }); - break; - case GAVValuesStored: - numBytes = 0x10; - identifyReplyCommand = new IdentifyReplyCommandGAVValuesStored(new byte[]{ - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - }); - break; - case GAVPhysicalAddresses: - numBytes = 0x10; - identifyReplyCommand = new IdentifyReplyCommandGAVPhysicalAddresses(new byte[]{ - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - }); - break; - case LogicalAssignment: - numBytes = 0x0E; - identifyReplyCommand = new IdentifyReplyCommandLogicalAssignment(Collections.singletonList(new LogicAssignment(false, true, true, true, true, true))); - break; - case Delays: - numBytes = 0x0F; - identifyReplyCommand = new IdentifyReplyCommandDelays(new byte[]{0x3}, (byte) 0x13); - break; - case MinimumLevels: - numBytes = 0x0E; - identifyReplyCommand = new IdentifyReplyCommandMinimumLevels(new byte[]{0x3}); - break; - case MaximumLevels: - numBytes = 0x0F; - identifyReplyCommand = new IdentifyReplyCommandMaximumLevels(new byte[]{0xF}); - break; - case CurrentSenseLevels: - numBytes = 0x10; - identifyReplyCommand = new IdentifyReplyCommandCurrentSenseLevels(new byte[]{0xF}); - break; - case OutputUnitSummary: - numBytes = 0x12; - identifyReplyCommand = new IdentifyReplyCommandOutputUnitSummary(new IdentifyReplyCommandUnitSummary(false, false, false, false, false, false, false, false), (byte) 0x4, (byte) 0x4, (short) 45); - break; - case DSIStatus: - numBytes = 0x12; - identifyReplyCommand = new IdentifyReplyCommandDSIStatus(ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, ChannelStatus.OK, UnitStatus.OK, (byte) 0x34); - break; - default: - throw new IllegalStateException("unmapped type " + calDataIdentify.getAttribute()); - } - - CALData calData = new CALDataIdentifyReply(requestContext, getReplyCommandType(numBytes + 1), null, calDataIdentify.getAttribute(), identifyReplyCommand); - CALReply calReply; - if (exstat) { - calReply = new CALReplyLong((byte) 0x0, calData, (byte) 0x0, new UnitAddress((byte) 0x0), null, new SerialInterfaceAddress((byte) 0x02), (byte) 0x0, null); - } else { - calReply = new CALReplyShort((byte) 0x0, calData); - } - CBusMessage response = createCBusMessageForReply(alpha, calReply, cBusOptions); - LOGGER.info("Send identify response\n{}", response); - ctx.writeAndFlush(response); - } - - private static void handleSmartConnect(RequestSmartConnectShortcut requestSmartConnectShortcut) { - LOGGER.info("Handling RequestSmartConnectShortcut\n{}", requestSmartConnectShortcut); - smart = true; - connect = true; - buildCBusOptions(); - } - - private void handleReset() { - connect = false; - smart = false; - idmon = false; - exstat = false; - monitor = false; - monall = false; - pun = false; - pcn = false; - srchk = false; - stopSALMonitor(); - stopMMIMonitor(); - } - - private void startSALMonitor(ChannelHandlerContext ctx) { - if (salMonitorFuture != null) { - LOGGER.debug("SAL Monitor already running"); - return; - } - LOGGER.info("Starting monitor"); - salMonitorFuture = ctx.executor().scheduleAtFixedRate(() -> { - if (monitorApplicationAddress1 != 0x38 && monitorApplicationAddress2 != 0x38 && monitorApplicationAddress1 != (byte) 0xFF && monitorApplicationAddress2 != (byte) 0xFF) { - LOGGER.debug("Filtered because monitor application address 1 {} monitor application address 1 {}", monitorApplicationAddress1, monitorApplicationAddress2); - return; - } - try { - int randomElementIndex = ThreadLocalRandom.current().nextInt(AVAILABLE_UNITS.size()) % AVAILABLE_UNITS.size(); - byte randomUnit = AVAILABLE_UNITS.get(randomElementIndex); - outputLock.lock(); - MonitoredSAL monitoredSAL; - SALData salData = createLightingData(); - if (cBusOptions.getExstat()) { - monitoredSAL = new MonitoredSALLongFormSmartMode((byte) 0x05, (byte) 0x00, new UnitAddress(randomUnit), null, ApplicationIdContainer.LIGHTING_38, (byte) 0x00, null, salData); - } else { - monitoredSAL = new MonitoredSALShortFormBasicMode((byte) 0x0, (byte) 0x0, (short) 0x0, (short) 0x0, (byte) 0x0, ApplicationIdContainer.LIGHTING_38, salData); - } - EncodedReply encodedReply = new MonitoredSALReply(requestContext, (byte) 0x0, monitoredSAL); - Reply reply = new ReplyEncodedReply((byte) 0x0, cBusOptions, encodedReply, null); - ReplyOrConfirmation replyOrConfirmation = new ReplyOrConfirmationReply((byte) 0x00, reply, new ResponseTermination()); - CBusMessage message = new CBusMessageToClient(replyOrConfirmation); - LOGGER.info("[SAL Monitor] Sending out\n{}", message); - ctx.writeAndFlush(message); - } finally { - outputLock.unlock(); - } - }, 5, 5, TimeUnit.SECONDS); - } - - private static SALData createLightingData() { - LightingData lightingData; - double random = Math.random(); - if (random < 0.25) { - lightingData = new LightingDataOn(LightingCommandTypeContainer.LightingCommandOn, (byte) 0xAF); - } else if (random > 0.25 && random < 0.5) { - lightingData = new LightingDataOff(LightingCommandTypeContainer.LightingCommandOff, (byte) 0xAF); - } else if (random > 0.5 && random < 0.75) { - lightingData = new LightingDataRampToLevel(LightingCommandTypeContainer.LightingCommandRampToLevel_20Second, (byte) 0xAF, (byte) 0xE0); - } else { - lightingData = new LightingDataTerminateRamp(LightingCommandTypeContainer.LightingCommandTerminateRamp, (byte) 0xAF); - } - return new SALDataLighting(null, lightingData); - } - - private void stopSALMonitor() { - if (salMonitorFuture == null) { - return; - } - LOGGER.info("Stopping SAL monitor"); - salMonitorFuture.cancel(false); - salMonitorFuture = null; - } - - private void startMMIMonitor(ChannelHandlerContext ctx) { - if (mmiMonitorFuture != null) { - LOGGER.debug("MMI Monitor already running"); - return; - } - LOGGER.info("Starting MMI monitor"); - mmiMonitorFuture = ctx.executor().scheduleAtFixedRate(() -> { - try { - outputLock.lock(); - LOGGER.info("[MMI Monitor] Sending out infos"); - sendMonitoredMMIs(ctx); - } finally { - outputLock.unlock(); - } - }, 5, 5, TimeUnit.SECONDS); - } - - private void stopMMIMonitor() { - if (mmiMonitorFuture == null) { - return; - } - LOGGER.info("Stopping monitor"); - mmiMonitorFuture.cancel(false); - mmiMonitorFuture = null; - } - - private CALCommandTypeContainer getReplyCommandType(int numBytes) { - for (CALCommandTypeContainer value : CALCommandTypeContainer.values()) { - if (value.getCommandType() == CALCommandType.REPLY && value.getNumBytes() == numBytes) { - return value; - } - } - throw new IllegalArgumentException("No reply type for " + numBytes); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java deleted file mode 100644 index 4bcbce0d47c..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/S7ServerModule.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.s7; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.ChannelPipeline; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import org.apache.plc4x.simulator.PlcSimulatorConfig; -import org.apache.plc4x.java.s7.S7Driver; -import org.apache.plc4x.java.s7.readwrite.TPKTPacket; -import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec; -import org.apache.plc4x.java.spi.generation.ByteOrder; -import org.apache.plc4x.simulator.exceptions.SimulatorException; -import org.apache.plc4x.simulator.model.Context; -import org.apache.plc4x.simulator.server.ServerModule; -import org.apache.plc4x.simulator.server.s7.protocol.S7Step7ServerAdapter; - -public class S7ServerModule implements ServerModule { - - private static final int ISO_ON_TCP_PORT = 102; - - private EventLoopGroup loopGroup; - private EventLoopGroup workerGroup; - private Context context; - private PlcSimulatorConfig config; - - @Override - public String getName() { - return "S7-STEP7"; - } - - @Override - public void setConfig(PlcSimulatorConfig config) { - this.config = config; - } - - @Override - public void setContext(Context context) { - this.context = context; - } - - - @Override - public void start() throws SimulatorException { - if (loopGroup != null) { - return; - } - - try { - loopGroup = new NioEventLoopGroup(); - workerGroup = new NioEventLoopGroup(); - - ServerBootstrap bootstrap = new ServerBootstrap(); - bootstrap.group(loopGroup, workerGroup) - .channel(NioServerSocketChannel.class) - .childHandler(new ChannelInitializer() { - @Override - public void initChannel(SocketChannel channel) { - ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast(new GeneratedProtocolMessageCodec<>(TPKTPacket.class, - TPKTPacket::staticParse, ByteOrder.BIG_ENDIAN, - new S7Driver.ByteLengthEstimator(), - new S7Driver.CorruptPackageCleaner())); - pipeline.addLast(new S7Step7ServerAdapter(context)); - } - }).option(ChannelOption.SO_BACKLOG, 128) - .childOption(ChannelOption.SO_KEEPALIVE, true); - - int port = ISO_ON_TCP_PORT; - if (config.getS7Port() != null) { - port = Integer.parseInt(config.getS7Port()); - } - String host = config.getHost(); - if (host != null) { - bootstrap.bind(host, port).sync(); - } else { - bootstrap.bind(port).sync(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new SimulatorException(e); - } - } - - @Override - public void stop() { - if (workerGroup == null) { - return; - } - - workerGroup.shutdownGracefully(); - loopGroup.shutdownGracefully(); - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java deleted file mode 100644 index 795e0d1d894..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/s7/protocol/S7Step7ServerAdapter.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.server.s7.protocol; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.apache.plc4x.java.s7.readwrite.*; -import org.apache.plc4x.java.spi.generation.ReadBuffer; -import org.apache.plc4x.java.spi.generation.ReadBufferByteBased; -import org.apache.plc4x.java.spi.generation.WriteBuffer; -import org.apache.plc4x.java.spi.generation.WriteBufferByteBased; -import org.apache.plc4x.simulator.model.Context; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.List; - -public class S7Step7ServerAdapter extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(S7Step7ServerAdapter.class); - - private final Context context; - - private State state; - - // COTP parameters - private static final int localReference = 42; - private int remoteReference = -1; - private COTPProtocolClass protocolClass; - private static final int localTsapId = 1; - private int remoteTsapId = -1; - private static final COTPTpduSize maxTpduSize = COTPTpduSize.SIZE_256; - private COTPTpduSize tpduSize; - // S7 parameters - // Set this to 1 as we don't want to handle stuff in parallel - private static final int maxAmqCaller = 1; - private int amqCaller; - // Set this to 1 as we don't want to handle stuff in parallel - private static final int maxAmqCallee = 1; - private int amqCallee; - private static final int maxPduLength = 240; - private int pduLength; - - public S7Step7ServerAdapter(Context context) { - this.context = context; - state = State.INITIAL; - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof TPKTPacket) { - TPKTPacket packet = (TPKTPacket) msg; - final COTPPacket cotpPacket = packet.getPayload(); - switch (state) { - case INITIAL: { - if (!(cotpPacket instanceof COTPPacketConnectionRequest)) { - LOGGER.error("Expecting COTP Connection-Request"); - return; - } - - COTPTpduSize proposedTpduSize = null; - COTPPacketConnectionRequest cotpConnectionRequest = (COTPPacketConnectionRequest) cotpPacket; - for (COTPParameter parameter : cotpConnectionRequest.getParameters()) { - if (parameter instanceof COTPParameterCalledTsap) { - // this is actually ignored as it doesn't contain any information. - } else if (parameter instanceof COTPParameterCallingTsap) { - COTPParameterCallingTsap callingTsapParameter = (COTPParameterCallingTsap) parameter; - remoteTsapId = callingTsapParameter.getTsapId(); - } else if (parameter instanceof COTPParameterTpduSize) { - COTPParameterTpduSize tpduSizeParameter = (COTPParameterTpduSize) parameter; - proposedTpduSize = tpduSizeParameter.getTpduSize(); - } else { - LOGGER.error(String.format("Unexpected COTP Connection-Request Parameter %s", - parameter.getClass().getName())); - return; - } - } - if (proposedTpduSize == null) { - LOGGER.error("Missing COTP Connection-Request Parameter Tpdu Size"); - return; - } - - remoteReference = cotpConnectionRequest.getSourceReference(); - protocolClass = cotpConnectionRequest.getProtocolClass(); - tpduSize = (proposedTpduSize.getSizeInBytes() > maxTpduSize.getSizeInBytes()) ? maxTpduSize : proposedTpduSize; - - // Prepare a response and send it back to the remote. - List parameters = new ArrayList<>(); - parameters.add(new COTPParameterCalledTsap(remoteTsapId)); - parameters.add(new COTPParameterCallingTsap(localTsapId)); - parameters.add(new COTPParameterTpduSize(tpduSize)); - COTPPacketConnectionResponse response = new COTPPacketConnectionResponse( - parameters, null, remoteReference, localReference, protocolClass - ); - ctx.writeAndFlush(new TPKTPacket(response)); - - state = State.COTP_CONNECTED; - break; - } - case COTP_CONNECTED: { - if (!(cotpPacket instanceof COTPPacketData)) { - LOGGER.error("Expecting COTP Data packet"); - return; - } - - COTPPacketData packetData = (COTPPacketData) cotpPacket; - final byte cotpTpduRef = packetData.getTpduRef(); - final S7Message payload = packetData.getPayload(); - if (!(payload instanceof S7MessageRequest)) { - LOGGER.error("Expecting S7 Message Request"); - return; - } - S7MessageRequest s7MessageRequest = (S7MessageRequest) payload; - final int s7TpduReference = s7MessageRequest.getTpduReference(); - final S7Parameter s7Parameter = s7MessageRequest.getParameter(); - if (!(s7Parameter instanceof S7ParameterSetupCommunication)) { - LOGGER.error("Expecting S7 Message Request containing a S7 Setup Communication Parameter"); - return; - } - S7ParameterSetupCommunication s7ParameterSetupCommunication = - (S7ParameterSetupCommunication) s7Parameter; - - amqCaller = Math.min(s7ParameterSetupCommunication.getMaxAmqCaller(), maxAmqCaller); - amqCallee = Math.min(s7ParameterSetupCommunication.getMaxAmqCallee(), maxAmqCallee); - pduLength = Math.min(s7ParameterSetupCommunication.getPduLength(), maxPduLength); - - S7ParameterSetupCommunication s7ParameterSetupCommunicationResponse = - new S7ParameterSetupCommunication(amqCaller, amqCallee, pduLength); - // TODO should send S7MessageResponseData - S7MessageResponseData s7MessageResponse = new S7MessageResponseData( - s7TpduReference, s7ParameterSetupCommunicationResponse, null, (short) 0, (short) 0); - ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, s7MessageResponse, true, cotpTpduRef))); - - state = State.S7_CONNECTED; - break; - } - case S7_CONNECTED: { - if (!(cotpPacket instanceof COTPPacketData)) { - LOGGER.error("Expecting COTP Data packet"); - return; - } - - COTPPacketData packetData = (COTPPacketData) cotpPacket; - final byte cotpTpduRef = packetData.getTpduRef(); - final S7Message payload = packetData.getPayload(); - if (payload instanceof S7MessageUserData) { - S7MessageUserData s7MessageUserData = (S7MessageUserData) payload; - final int s7TpduReference = s7MessageUserData.getTpduReference(); - final S7Parameter s7Parameter = s7MessageUserData.getParameter(); - if (s7Parameter instanceof S7ParameterUserData) { - S7ParameterUserData userDataParameter = (S7ParameterUserData) s7Parameter; - for (S7ParameterUserDataItem item : userDataParameter.getItems()) { - if (item instanceof S7ParameterUserDataItemCPUFunctions) { - S7ParameterUserDataItemCPUFunctions function = - (S7ParameterUserDataItemCPUFunctions) item; - final S7PayloadUserData userDataPayload = - (S7PayloadUserData) s7MessageUserData.getPayload(); - - for (S7PayloadUserDataItem userDataPayloadItem : userDataPayload.getItems()) { - if (userDataPayloadItem instanceof S7PayloadUserDataItemCpuFunctionReadSzlRequest) { - S7PayloadUserDataItemCpuFunctionReadSzlRequest readSzlRequestPayload = - (S7PayloadUserDataItemCpuFunctionReadSzlRequest) userDataPayloadItem; - - final SzlId szlId = readSzlRequestPayload.getSzlId(); - // This is a request to list the type of device - if ((szlId.getTypeClass() == SzlModuleTypeClass.CPU) && - (szlId.getSublistList() == SzlSublist.MODULE_IDENTIFICATION)) { - - S7ParameterUserDataItemCPUFunctions readSzlResponseParameter = - new S7ParameterUserDataItemCPUFunctions((short) 0x12, - (byte) 0x08, function.getCpuFunctionGroup(), - function.getCpuSubfunction(), (short) 1, - (short) 0, (short) 0, 0); - - // This is the product number of a S7-1200 - List items = new ArrayList<>(); - items.add(new SzlDataTreeItem((short) 0x0001, - "6ES7 212-1BD30-0XB0 ".getBytes(), 0x2020, 0x0001, 0x2020)); - - WriteBuffer writeBuffer = new WriteBufferByteBased(items.get(0).getLengthInBytes()); - ReadBuffer readBuffer = new ReadBufferByteBased(new byte[items.get(0).getLengthInBytes()]); - items.get(0).serialize(writeBuffer); - - //TODO: Fix this section. Fail!!! - S7PayloadUserDataItemCpuFunctionReadSzlResponse readSzlResponsePayload = -// new S7PayloadUserDataItemCpuFunctionReadSzlResponse( -// DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, szlId, -// readSzlRequestPayload.getSzlIndex(), items); - new S7PayloadUserDataItemCpuFunctionReadSzlResponse( - DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, items.get(0).getLengthInBytes(), readBuffer.readByteArray(items.get(0).getLengthInBytes())); - - List responseParameterItems = new ArrayList<>(); - responseParameterItems.add(readSzlResponseParameter); - S7ParameterUserData responseParameterUserData = - new S7ParameterUserData(responseParameterItems); - - List responsePayloadItems = new ArrayList<>(); - responsePayloadItems.add(readSzlResponsePayload); - S7PayloadUserData responsePayloadUserData = - new S7PayloadUserData(responsePayloadItems); - - S7Message s7ResponseMessage = new S7MessageUserData(s7TpduReference, - responseParameterUserData, responsePayloadUserData); - ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, s7ResponseMessage, true, cotpTpduRef))); - } else { - LOGGER.error("Not able to respond to the given request Read SZL with SZL type class " + - szlId.getTypeClass().name() + " and SZL sublist " + szlId.getSublistList().name()); - } - - } - } - } - } - } else { - LOGGER.error("Unsupported type of S7MessageUserData parameter " + - s7Parameter.getClass().getName()); - } - } else { - if (cotpPacket.getPayload() instanceof S7MessageRequest) { - S7MessageRequest request = (S7MessageRequest) cotpPacket.getPayload(); - if (request.getParameter() instanceof S7ParameterReadVarRequest) { - S7ParameterReadVarRequest readVarRequestParameter = - (S7ParameterReadVarRequest) request.getParameter(); - List items = readVarRequestParameter.getItems(); - List payloadItems = new ArrayList<>(); - for (S7VarRequestParameterItem item : items) { - if (item instanceof S7VarRequestParameterItemAddress) { - S7VarRequestParameterItemAddress address = - (S7VarRequestParameterItemAddress) item; - final S7Address address1 = address.getAddress(); - if (address1 instanceof S7AddressAny) { - S7AddressAny addressAny = (S7AddressAny) address1; - switch (addressAny.getArea()) { - case DATA_BLOCKS: { - final int dataBlockNumber = addressAny.getDbNumber(); - if (dataBlockNumber != 1) { - // TODO: Return unknown object. - } - final int numberOfElements = addressAny.getNumberOfElements(); - if (numberOfElements != 1) { - // TODO: Return invalid address. - } - final int byteAddress = addressAny.getByteAddress(); - if (byteAddress != 0) { - // TODO: Return invalid address. - } - final byte bitAddress = addressAny.getBitAddress(); - switch (addressAny.getTransportSize()) { - case BOOL: - payloadItems.add(new S7VarPayloadDataItem(DataTransportErrorCode.OK, DataTransportSize.BIT, new byte[]{1})); - break; - case INT: - case UINT: { - String firstKey = context.getMemory().keySet().iterator().next(); - Object value = context.getMemory().get(firstKey); - short shortValue = ((Number) value).shortValue(); - byte[] data = new byte[2]; - data[1] = (byte) (shortValue & 0xff); - data[0] = (byte) ((shortValue >> 8) & 0xff); - payloadItems.add(new S7VarPayloadDataItem(DataTransportErrorCode.OK, DataTransportSize.BYTE_WORD_DWORD, data)); - break; - } - default: { - // TODO: Return invalid address. - } - } - break; - } - case INPUTS: - case OUTPUTS: { - final int ioNumber = (addressAny.getByteAddress() * 8) + addressAny.getBitAddress(); - final int numElements = (addressAny.getTransportSize() == TransportSize.BOOL) ? - addressAny.getNumberOfElements() : addressAny.getTransportSize().getSizeInBytes() * 8; - final BitSet bitSet = toBitSet(context.getDigitalInputs(), ioNumber, numElements); - final byte[] data = Arrays.copyOf(bitSet.toByteArray(), (numElements + 7) / 8); - payloadItems.add(new S7VarPayloadDataItem(DataTransportErrorCode.OK, DataTransportSize.BYTE_WORD_DWORD, data)); - break; - } - } - } - } - } - S7ParameterReadVarResponse readVarResponseParameter = new S7ParameterReadVarResponse((short) items.size()); - S7PayloadReadVarResponse readVarResponsePayload = new S7PayloadReadVarResponse(payloadItems); - S7MessageResponseData response = new S7MessageResponseData(request.getTpduReference(), - readVarResponseParameter, readVarResponsePayload, (short) 0x00, (short) 0x00); - ctx.writeAndFlush(new TPKTPacket(new COTPPacketData(null, response, true, cotpTpduRef))); - } else if (request.getParameter() instanceof S7ParameterWriteVarRequest) { - S7ParameterWriteVarRequest writeVarRequestParameter = - (S7ParameterWriteVarRequest) request.getParameter(); - - } else { - LOGGER.error("Unsupported type of S7MessageRequest parameter " + - request.getParameter().getClass().getName()); - } - } else { - LOGGER.error("Unsupported type of message " + payload.getClass().getName()); - } - } - break; - } - default: - throw new IllegalStateException("Unexpected value: " + state); - } - } - } - - private enum State { - INITIAL, - COTP_CONNECTED, - S7_CONNECTED - } - - private BitSet toBitSet(List booleans, int startIndex, int numElements) { - BitSet bitSet = new BitSet(booleans.size()); - for (int i = 0; i < Math.min(booleans.size() - startIndex, numElements); i++) { - bitSet.set(i, booleans.get(i + startIndex)); - } - return bitSet; - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java deleted file mode 100644 index 7bc77c8a2fe..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/SimulationModule.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.simulation; - -import org.apache.plc4x.simulator.model.Context; - -public interface SimulationModule { - - /** - * @return the name of the simulation module - */ - String getName(); - - /** - * Gives access to the internal simulations context. - * @return reference to the simulations context - */ - Context getContext(); - - /** - * Method for doing the actual processing inside the simulation. - * In this method the simulation can do calculations and update it's context variables. - */ - void loop(); - -} diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java deleted file mode 100644 index 5b4dd6116ea..00000000000 --- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/simulation/watertank/WaterTankSimulationModule.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.simulator.simulation.watertank; - -import org.apache.plc4x.simulator.model.Context; -import org.apache.plc4x.simulator.simulation.SimulationModule; - -import java.util.concurrent.TimeUnit; - -/** - * This is a little simulation that simulates a Water tank. - * This tank has a capacity who's "waterLevel" is represented as a Long value. - * Water can flow into the tank if the input valve is opened, and it can flow - * out of the tank if the output valve is open. - *

- * The capacity of the output is slightly smaller than that of the input, so - * opening both valves will result in the tank filling. - *

- * To prevent the tank from bursting, there's an emergency valve which is opened - * as soon as the water-level reaches a critical maximum. - */ -public class WaterTankSimulationModule implements SimulationModule { - - private static final long MAX_WATER_LEVEL = 27648L; - private static final long EMERGENCY_VALVE_WATER_LEVEL = 27500L; - - private static final int NUM_INPUT_VALVE_INPUT = 0; - private static final int NUM_OUTPUT_VALVE_INPUT = 1; - - private static final int EMERGENCY_VALVE_OUTPUT = 0; - - private static final String PROP_WATER_LEVEL = "waterLevel"; - - private final Context context; - - public WaterTankSimulationModule() { - context = new Context.ContextBuilder() - // The input valve - .addDigitalInput(false) - // The output valve - .addDigitalInput(true) - // The emergency valve - .addDigitalOutput(false) - // The water level - .addMemoryVariable(PROP_WATER_LEVEL, 0L).build(); - } - - @Override - public String getName() { - return "Water Tank"; - } - - @Override - public Context getContext() { - return context; - } - - @Override - public void loop() { - // TODO: Do something sensible ;-) - // Just a POC for now ... to be replaced by a "real" simulation ... - try { - // Get the current value for the water tank level. - Long value = (Long) context.getMemory().get(PROP_WATER_LEVEL); - - // If the input valve is open, add 10. - if (context.getDigitalInputs().get(NUM_INPUT_VALVE_INPUT)) { - value += 10; - value = Math.min(MAX_WATER_LEVEL, value); - } - - // If the output valve is open, subtract 8 (It's slightly less throughput than the input) - if (context.getDigitalInputs().get(NUM_OUTPUT_VALVE_INPUT)) { - value -= 8; - value = Math.max(0, value); - } - - // Calculate if the emergency valve should be open - boolean emergencyValveOpen = value > EMERGENCY_VALVE_WATER_LEVEL; - - // Update the memory. - context.getMemory().put(PROP_WATER_LEVEL, value); - // Update the state of the emergency valve. - context.getDigitalOutputs().set(EMERGENCY_VALVE_OUTPUT, emergencyValveOpen); - - // Should probably be handled by the simulator - TimeUnit.MILLISECONDS.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - -} diff --git a/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule b/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule deleted file mode 100644 index d859c974557..00000000000 --- a/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.server.ServerModule +++ /dev/null @@ -1,21 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -org.apache.plc4x.simulator.server.s7.S7ServerModule -org.apache.plc4x.simulator.server.cbus.CBusServerModule -org.apache.plc4x.simulator.server.bacnet.BacnetServerModule \ No newline at end of file diff --git a/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule b/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule deleted file mode 100644 index 941372c8800..00000000000 --- a/plc4j/utils/plc-simulator/src/main/resources/META-INF/services/org.apache.plc4x.simulator.simulation.SimulationModule +++ /dev/null @@ -1,19 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -org.apache.plc4x.simulator.simulation.watertank.WaterTankSimulationModule \ No newline at end of file diff --git a/plc4j/utils/plc-simulator/src/main/resources/logback.xml b/plc4j/utils/plc-simulator/src/main/resources/logback.xml deleted file mode 100644 index 264277d573f..00000000000 --- a/plc4j/utils/plc-simulator/src/main/resources/logback.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/plc4j/utils/pom.xml b/plc4j/utils/pom.xml index db392fa0003..fdd7a43f54a 100644 --- a/plc4j/utils/pom.xml +++ b/plc4j/utils/pom.xml @@ -38,18 +38,11 @@ audit-log subscription-emulation - - pcap-replay - pcap-shared raw-sockets test-generator test-utils - - - - \ No newline at end of file diff --git a/plc4j/utils/raw-sockets/pom.xml b/plc4j/utils/raw-sockets/pom.xml index 99ab11631db..599fbf94b5c 100644 --- a/plc4j/utils/raw-sockets/pom.xml +++ b/plc4j/utils/raw-sockets/pom.xml @@ -44,13 +44,6 @@ org.pcap4j:pcap4j-packetfactory-static - - - io.netty:netty-common - @@ -75,25 +68,6 @@ - - org.apache.plc4x - plc4j-utils-pcap-shared - 1.0.0-SNAPSHOT - - - - io.netty - netty-buffer - - - io.netty - netty-common - - - io.netty - netty-transport - - org.pcap4j pcap4j-core @@ -122,13 +96,6 @@ ch.qos.logback logback-classic - - - org.apache.plc4x - plc4j-utils-test-utils - 1.0.0-SNAPSHOT - test - \ No newline at end of file diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java deleted file mode 100644 index a51000b3d61..00000000000 --- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannel.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.rawsockets.netty; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.*; -import io.netty.channel.oio.OioByteStreamChannel; -import org.apache.commons.lang3.NotImplementedException; -import org.apache.commons.net.util.SubnetUtils; -import org.apache.plc4x.java.utils.pcap.netty.exception.PcapException; -import org.apache.plc4x.java.utils.rawsockets.netty.address.RawSocketAddress; -import org.apache.plc4x.java.utils.rawsockets.netty.address.RawSocketPassiveAddress; -import org.apache.plc4x.java.utils.rawsockets.netty.config.RawSocketChannelConfig; -import org.apache.plc4x.java.utils.rawsockets.netty.utils.ArpUtils; -import org.pcap4j.core.*; -import org.pcap4j.packet.EthernetPacket; -import org.pcap4j.packet.IllegalRawDataException; -import org.pcap4j.packet.Packet; -import org.pcap4j.util.MacAddress; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.*; - -/** - * Channel based on a Pcap4J raw-socket, allowing to actively communicate based on ethernet frames. - */ -public class RawSocketChannel extends OioByteStreamChannel { - - private static final Logger logger = LoggerFactory.getLogger(RawSocketChannel.class); - - private final RawSocketChannelConfig config; - - private MacAddress remoteMacAddress; - private SocketAddress remoteAddress; - private MacAddress localMacAddress; - private SocketAddress localAddress; - private PcapHandle receiveHandle; - private Thread loopThread; - - public RawSocketChannel() { - super(null); - config = new RawSocketChannelConfig(this); - } - - public void setRemoteMacAddress(MacAddress remoteMacAddress) { - this.remoteMacAddress = remoteMacAddress; - - // Update the filter expression, if the handle is already open. - if((receiveHandle != null) && (receiveHandle.isOpen())){ - MacAddress tempRemoteMacAddress = remoteMacAddress != null ? remoteMacAddress : MacAddress.getByAddress(new byte[]{0,0,0,0,0,0}); - String filter = config.getMacBasedFilterString(localMacAddress, tempRemoteMacAddress); - if(!filter.isEmpty()) { - try { - receiveHandle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE); - } catch (NotOpenException | PcapNativeException e) { - throw new RuntimeException("Error updating filter expression"); - } - } - } - } - - @Override - protected boolean isInputShutdown() { - return false; - } - - @Override - protected ChannelFuture shutdownInput() { - throw new NotImplementedException(""); - } - - @Override - protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { - if(!((remoteAddress instanceof RawSocketPassiveAddress) || (remoteAddress instanceof InetSocketAddress) || (remoteAddress instanceof RawSocketAddress))) { - logger.error("Expecting remote address of type RawSocketPassiveAddress or InetSocketAddress"); - pipeline().fireExceptionCaught( - new PcapException("Expecting remote address of type RawSocketPassiveAddress or InetSocketAddress")); - return; - } - this.localAddress = localAddress; - this.remoteAddress = remoteAddress; - - PcapNetworkInterface nif = null; - // Try to get the device name of the network interface that we want to open. - if(remoteAddress instanceof RawSocketPassiveAddress) { - RawSocketPassiveAddress rawSocketPassiveAddress = (RawSocketPassiveAddress) remoteAddress; - String deviceName = getDeviceName(rawSocketPassiveAddress); - if (deviceName == null) { - logger.error("Network device not specified and couldn't detect it automatically"); - pipeline().fireExceptionCaught( - new PcapException("Network device not specified and couldn't detect it automatically")); - return; - } - - // Get a handle to the network-device and open it. - nif = Pcaps.getDevByName(deviceName); - } else if (remoteAddress instanceof InetSocketAddress) { - InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress; - InetAddress address = inetSocketAddress.getAddress(); - deviceLoop: - for (PcapNetworkInterface dev : Pcaps.findAllDevs()) { - // We're only interested in real running network interfaces, skip the rest. - if (dev.isLoopBack()) { - continue; - } - - // Go through all configured addresses and subnets and if we find a matching - // device, use that as nif. - for (PcapAddress curAddress : dev.getAddresses()) { - if((curAddress.getAddress() == null) || (curAddress.getNetmask() == null)) { - continue; - } - if((address instanceof Inet4Address) && !(curAddress instanceof PcapIpV4Address)) { - continue; - } - if((address instanceof Inet6Address) && !(curAddress instanceof PcapIpV6Address)) { - continue; - } - final SubnetUtils.SubnetInfo subnetInfo = new SubnetUtils(curAddress.getAddress().getHostAddress(), curAddress.getNetmask().getHostAddress()).getInfo(); - if(subnetInfo.isInRange(address.getHostAddress())) { - nif = dev; - // Update the local address - this.localAddress = new InetSocketAddress(curAddress.getAddress(), 0); - this.localMacAddress = dev.getLinkLayerAddresses().stream() - .filter(linkLayerAddress -> linkLayerAddress instanceof MacAddress).map(linkLayerAddress -> (MacAddress) linkLayerAddress) - .findFirst().orElse(null); - break deviceLoop; - } - } - } - } - // This would be generally to use a remote MAC address as target. - else { - // Here we would need to do a reverse ARP lookup to find the - throw new RuntimeException("Not Implemented yet "); - // TODO: Implement finding out which device is used for communicating with a given MAC address. - } - - if (nif == null) { - logger.error(String.format("Couldn't find network device for %s", remoteAddress)); - pipeline().fireExceptionCaught( - new PcapException(String.format("Couldn't find network device for %s", remoteAddress))); - return; - } - - // If desired: Try to get the mac address of the remote station by sending an ARP request. - if(config.isResolveMacAddress()) { - if ((this.remoteMacAddress == null) && (this.remoteAddress instanceof InetSocketAddress)) { - this.remoteMacAddress = ArpUtils.resolveMacAddress(nif, (InetSocketAddress) this.remoteAddress, - (InetSocketAddress) this.localAddress, localMacAddress).orElse(null); - } - } - - receiveHandle = nif.openLive(65535, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10); - if(logger.isDebugEnabled()) { - logger.debug(String.format("Listening on device %s", nif.getName())); - } - - // If the address allows fine-tuning which packets to process, set a filter to reduce the load. - // If no remote mac address is set, we'll set it to 00:00:00:00:00, which is an invalid address - // and therefore no traffic will be incoming. - // TODO: Make configurable, if we should accept from any source or not. - MacAddress tempRemoteMacAddress = remoteMacAddress != null ? remoteMacAddress : MacAddress.getByAddress(new byte[]{0,0,0,0,0,0}); - String filter = config.getMacBasedFilterString(localMacAddress, tempRemoteMacAddress); - if(!filter.isEmpty()) { - receiveHandle.setFilter(filter, BpfProgram.BpfCompileMode.OPTIMIZE); - } - - // Create a buffer where the raw socket worker can send data to. - ByteBuf buffer = Unpooled.buffer(); - - // Start a thread that processes the callbacks from the raw socket and simply - // forwards the bytes read to the buffer. - loopThread = new Thread(() -> { - try { - receiveHandle.loop(-1, - (PacketListener) packet -> buffer.writeBytes(config.getPacketHandler().getData(packet))); - } catch (PcapNativeException | NotOpenException e) { - // TODO this should close everything automatically - logger.error("Pcap4j loop thread died!", e); - pipeline().fireExceptionCaught(e); - } catch (InterruptedException e) { - // This usually happens when the raw socket transport is closed. - } - }); - loopThread.start(); - - if(remoteAddress instanceof RawSocketPassiveAddress) { - // Right now we're using an output stream that simply discards everything. - // This is ok while implementing passive drivers for protocols, however as - // soon as we start implementing ethernet layer protocols, we'll have to also - // be able to actually send data. The PcapInputStream simply acts as a - // breaking point if no packets are coming in and the read operation would - // simply block indefinitely. - activate(new PcapInputStream(buffer), new DiscardingOutputStream()); - } else { - PcapHandle sendHandle = nif.openLive(65535, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, 10); - activate(new PcapInputStream(buffer), new PcapOutputStream(sendHandle)); - } - } - - @Override - protected SocketAddress localAddress0() { - return localAddress; - } - - @Override - protected SocketAddress remoteAddress0() { - return remoteAddress; - } - - @Override - protected void doBind(SocketAddress localAddress) { - throw new UnsupportedOperationException("Not implemented"); - } - - @Override - protected void doDisconnect() throws NotOpenException { - this.loopThread.interrupt(); - if (this.receiveHandle != null) { - // Interrupt the receiving loop. - receiveHandle.breakLoop(); - // Close the channel. - receiveHandle.close(); - // Shutdown the loop-thread. - // (Doing it the graceful way, didn't work) - eventLoop().shutdownNow(); - } - } - - @Override - protected int doReadBytes(ByteBuf buf) throws Exception { - if (receiveHandle == null || !receiveHandle.isOpen()) { - return -1; - } - try { - return super.doReadBytes(buf); - } catch (SocketTimeoutException ignored) { - return 0; - } - } - - @Override - public ChannelConfig config() { - return this.config; - } - - @Override - public boolean isOpen() { - return true; - } - - @Override - protected AbstractUnsafe newUnsafe() { - return new RawSocketUnsafe(); - } - - public SocketAddress getRemoteAddress() { - return remoteAddress; - } - - public MacAddress getRemoteMacAddress() { - return remoteMacAddress; - } - - public SocketAddress getLocalAddress() { - return localAddress; - } - - public MacAddress getLocalMacAddress() { - return localMacAddress; - } - - private String getDeviceName(RawSocketPassiveAddress rawSocketAddress) { - // If the device name is provided, simply use this. - if(rawSocketAddress.getDeviceName() != null) { - return rawSocketAddress.getDeviceName(); - } - - // TODO: Implement this ... - return null; - } - - /** - * This output stream simply discards anything it should send. - */ - private static class DiscardingOutputStream extends OutputStream { - @Override - public void write(int b) { - // discard - logger.debug("Discarding {}", b); - } - - @Override - public void write(byte[] b, int off, int len) { - logger.debug("Discarding {}", b); - } - } - - private static class PcapOutputStream extends OutputStream { - - private final PcapHandle sendHandle; - - public PcapOutputStream(PcapHandle sendHandle) { - this.sendHandle = sendHandle; - } - - @Override - public void write(int b) { - // This should actually not be called, as in contrast to TCP, Raw sockets are not a stream - // messages which should be sent should be processed in total by the write(byte[]) method. - throw new RuntimeException("write(byte) should never be called in a RawSocketChannel"); - } - - @Override - public void write(byte[] packetBytes, int offset, int len) throws IOException { - if((offset < 0) || (len < 0) || (offset + len > packetBytes.length)) { - throw new IndexOutOfBoundsException(); - } - try { - // Create a new EthernetPacket with the raw content of the packet bytes. - Packet rawPacket = EthernetPacket.newPacket(packetBytes, offset, len); - // Send the packet. - sendHandle.sendPacket(rawPacket); - } catch (IllegalRawDataException | NotOpenException | PcapNativeException e) { - throw new IOException("Error sending packet", e); - } - } - } - - /** - * InputStream that fulfills the contract of Netty for read operations to timeout. - * Without this the InputStream would simply block indefinitely which would block - * the entire IO module. - */ - private static class PcapInputStream extends InputStream { - final ByteBuf buf; - - private PcapInputStream(ByteBuf buf) { - this.buf = buf; - } - - @Override - public int available() { - return buf.readableBytes(); - } - - @Override - public int read() throws IOException { - // Timeout 10 ms - final long timeout = System.nanoTime() + 10_000; - // Yes, this could make the thread go nuts in case of no data, - // but the Netty guys are doing it the same way and there probably - // is a reason for it ;-) - while (System.nanoTime() < timeout) { - if (buf.readableBytes() > 0) { - return buf.readByte() & 0xFF; - } - } - throw new SocketTimeoutException(); - } - } - - /** - * Internal helper to wrap access to unsafe operations (Only used internally by netty) - */ - private class RawSocketUnsafe extends AbstractUnsafe { - @Override - public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { - try { - doConnect(remoteAddress, localAddress); - pipeline().fireChannelActive(); - promise.setSuccess(); - } catch (Exception e) { - promise.setFailure(e); - } - } - - @Override - public void close(ChannelPromise promise) { - try { - doDisconnect(); - promise.setSuccess(); - } catch (Exception e) { - promise.setFailure(e); - } - } - } - -} diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketAddress.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketAddress.java deleted file mode 100644 index b2e45c9f9a0..00000000000 --- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketAddress.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.plc4x.java.utils.rawsockets.netty.address; - -import java.net.SocketAddress; - -public class RawSocketAddress extends SocketAddress { - - private final byte[] macAddress; - - public RawSocketAddress(byte[] macAddress) { - this.macAddress = macAddress; - } - - public byte[] getMacAddress() { - return macAddress; - } - -} diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketPassiveAddress.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketPassiveAddress.java deleted file mode 100644 index 852796c76b5..00000000000 --- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/address/RawSocketPassiveAddress.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.rawsockets.netty.address; - -import org.apache.plc4x.java.utils.pcap.netty.address.PcapSocketAddress; - -public class RawSocketPassiveAddress extends PcapSocketAddress { - - private static final long serialVersionUID = 1L; - - private final String deviceName; - - public RawSocketPassiveAddress(String deviceName) { - this.deviceName = deviceName; - } - - public String getDeviceName() { - return deviceName; - } - -} diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/config/RawSocketChannelConfig.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/config/RawSocketChannelConfig.java deleted file mode 100644 index fdcdae64a2a..00000000000 --- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/config/RawSocketChannelConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.rawsockets.netty.config; - -import io.netty.channel.*; -import org.apache.plc4x.java.utils.pcap.netty.config.PcapChannelConfig; - -public class RawSocketChannelConfig extends PcapChannelConfig { - - public RawSocketChannelConfig(Channel channel) { - super(channel); - } - -} diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/utils/ArpUtils.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/utils/ArpUtils.java index c19d56e0a87..ac6ea9f7071 100644 --- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/utils/ArpUtils.java +++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/netty/utils/ArpUtils.java @@ -37,7 +37,6 @@ import java.net.UnknownHostException; import java.util.*; import java.util.concurrent.*; -import java.util.stream.Collectors; public class ArpUtils { @@ -78,8 +77,7 @@ public static Set scanNetworkDevice(PcapNetworkInterface nif) { // Calculate all ip addresses, this device can reach. Map> addresses = new HashMap<>(); for (PcapAddress address : nif.getAddresses()) { - if (address instanceof PcapIpV4Address) { - final PcapIpV4Address ipV4Address = (PcapIpV4Address) address; + if (address instanceof PcapIpV4Address ipV4Address) { SubnetUtils su = new SubnetUtils(ipV4Address.getAddress().getHostAddress(), ipV4Address.getNetmask().getHostAddress()); final String currentAddress = ipV4Address.getAddress().getHostAddress(); final List reachableAddresses = new ArrayList<>(Arrays.asList(su.getInfo().getAllAddresses())); diff --git a/plc4j/utils/raw-sockets/src/remote-resources/META-INF/LICENSE b/plc4j/utils/raw-sockets/src/remote-resources/META-INF/LICENSE deleted file mode 100644 index fcab6f339bb..00000000000 --- a/plc4j/utils/raw-sockets/src/remote-resources/META-INF/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ - ----------------------------------------------- - -The Files: -src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawEthernetSocket.java -src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawIpSocket.java -src/main/java/org/apache/plc4x/java/utils/rawsockets/attic/RawSocketListener.java -src/test/java/org/apache/plc4x/java/utils/rawsockets/attic/RawIpSocketTest.java -Are copyrighted by the The Netty Project which is distributed under the Apache 2.0 license. diff --git a/plc4j/utils/raw-sockets/src/remote-resources/META-INF/NOTICE b/plc4j/utils/raw-sockets/src/remote-resources/META-INF/NOTICE deleted file mode 100644 index ccad4c46b77..00000000000 --- a/plc4j/utils/raw-sockets/src/remote-resources/META-INF/NOTICE +++ /dev/null @@ -1,4 +0,0 @@ ----------------------------------------------- - -This product includes software developed at -The Netty project (https://netty.io/). diff --git a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/ManualArpTest.java b/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/ManualArpTest.java deleted file mode 100644 index 7f8dda1841e..00000000000 --- a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/ManualArpTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.plc4x.java.utils.rawsockets.netty; - -import org.apache.plc4x.java.utils.rawsockets.netty.utils.ArpUtils; -import org.pcap4j.core.PcapNetworkInterface; -import org.pcap4j.core.Pcaps; - -import java.net.InetAddress; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -public class ManualArpTest { - - public static void main(String[] args) throws Exception { - for (PcapNetworkInterface dev : Pcaps.findAllDevs()) { - final Set inetAddresses = ArpUtils.scanNetworkDevice(dev); - final List inetAddresses1 = inetAddresses.stream().map(address -> (short) address.getAddress()[3] & 0xFF).sorted().collect(Collectors.toList()); - System.out.printf("Found %d ip addresses with device %s:\n %s%n", inetAddresses.size(), dev, inetAddresses1); - } - } - -} diff --git a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelTest.java b/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelTest.java deleted file mode 100644 index 85e5fe28767..00000000000 --- a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/netty/RawSocketChannelTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.plc4x.java.utils.rawsockets.netty; - -import io.netty.bootstrap.Bootstrap; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.buffer.Unpooled; -import io.netty.channel.*; -import io.netty.channel.oio.OioEventLoopGroup; -import org.apache.plc4x.java.utils.rawsockets.netty.address.RawSocketPassiveAddress; -import org.apache.plc4x.java.utils.testutils.RequirePcap; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.pcap4j.core.PcapNetworkInterface; -import org.pcap4j.core.Pcaps; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class RawSocketChannelTest { - - private static final Logger logger = LoggerFactory.getLogger(RawSocketChannelTest.class); - - @Test - @RequirePcap - @Disabled("Disabled as currently we can't seem to be able to get it working on Jenkins") - public void doConnect() throws Exception { - Channel channel = null; - final EventLoopGroup workerGroup = new OioEventLoopGroup(); - try { - Bootstrap bootstrap = new Bootstrap(); - bootstrap.group(workerGroup); - bootstrap.channel(RawSocketChannel.class); - // TODO we should use an explicit (configurable?) timeout here - // bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000); - bootstrap.handler(new ChannelInitializer() { - @Override - protected void initChannel(RawSocketChannel ch) throws Exception { - logger.info("Initialize Buffer!"); - ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - System.out.println(ByteBufUtil.prettyHexDump(((ByteBuf) msg))); - } - }); - ch.pipeline().addLast(new ChannelHandlerAdapter() { - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - logger.warn("Exception caught", cause); - } - }); - } - }); - // Start the client. - PcapNetworkInterface loopbackDevice = Pcaps.findAllDevs().stream().filter( - PcapNetworkInterface::isLoopBack).findFirst().orElse(null); - assertNotNull(loopbackDevice); - final ChannelFuture f = bootstrap.connect(new RawSocketPassiveAddress(loopbackDevice.getName())); - // Wait for sync - f.sync(); - // Wait till the session is finished initializing. - channel = f.channel(); - - logger.info("Channel is connected and ready to use..."); - - - channel.writeAndFlush(Unpooled.wrappedBuffer("Hallo".getBytes())); - - // Prepare something to read - Thread.sleep(10_000); - - } finally { - if (channel != null) { - channel.close().sync(); - } - workerGroup.shutdownGracefully().sync(); - } - } -} \ No newline at end of file diff --git a/plc4j/utils/raw-sockets/src/test/resources/logback-test.xml b/plc4j/utils/raw-sockets/src/test/resources/logback-test.xml deleted file mode 100644 index 2b9cea25dc8..00000000000 --- a/plc4j/utils/raw-sockets/src/test/resources/logback-test.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/plc4j/utils/test-generator/pom.xml b/plc4j/utils/test-generator/pom.xml index fc91d1460db..2339bbc7b14 100644 --- a/plc4j/utils/test-generator/pom.xml +++ b/plc4j/utils/test-generator/pom.xml @@ -77,7 +77,6 @@ org.apache.plc4x:plc4j-driver-s7 org.apache.plc4x:plc4j-driver-eip org.apache.plc4x:plc4j-driver-iec-60870 - org.apache.plc4x:plc4j-utils-pcap-shared @@ -103,12 +102,6 @@ plc4j-spi-buffers-xml 1.0.0-SNAPSHOT - - org.apache.plc4x - plc4j-utils-pcap-shared - 1.0.0-SNAPSHOT - - org.apache.groovy groovy-xml diff --git a/pom.xml b/pom.xml index f7ec40dbfc2..59c27a5dfe7 100644 --- a/pom.xml +++ b/pom.xml @@ -103,21 +103,17 @@ 1.1.2 3.27.7 4.3.0 - - 1.4.3 1.85 1.18.11 3.31.5-b1 1.9.4 1.11.0 1.22.1 - 4.6.0 1.28.0 2.15.1 2.22.0 3.20.0 1.3.5 - 3.6.1 3.13.0 1.15.0 1.14.1 @@ -141,13 +137,9 @@ 1.8.2 1.6.1 3.2.0 - 0.6.16 5.23.0 - - 4.1.123.Final 1.8.2 2.0.18 - 1.0.1 2.13.0 @@ -203,14 +195,6 @@ ${freemarker.version} - - io.netty - netty-bom - ${netty.version} - pom - import - - commons-cli commons-cli @@ -221,11 +205,6 @@ commons-codec ${commons-codec.version} - - org.apache.commons - commons-collections4 - ${commons-collections4.version} - org.apache.commons commons-compress @@ -246,11 +225,6 @@ commons-lang3 ${commons-lang3.version} - - org.apache.commons - commons-math3 - ${commons-math3.version} - commons-net commons-net @@ -267,31 +241,12 @@ ${commons-csv.version} - - com.google.googlejavaformat - google-java-format - 1.36.1 - - org.awaitility awaitility ${awaitility.version} - - - io.vavr - vavr - ${vavr.version} - - - - com.github.jinahya - bit-io - ${bit-io.version} - - org.apache.httpcomponents httpclient @@ -307,8 +262,6 @@ org.pcap4j pcap4j-core ${pcap4j.version} - - org.pcap4j @@ -334,17 +287,6 @@ 0.4.8 - - com.github.purejavacomm - purejavacomm - 1.0.2.RELEASE - - - - com.fasterxml.woodstox - woodstox-core - ${woodstox-core.version} - com.fasterxml.jackson.core jackson-annotations @@ -408,11 +350,6 @@ slf4j-api ${slf4j.version} - - org.slf4j - log4j-over-slf4j - ${slf4j.version} - ch.qos.logback logback-classic @@ -436,28 +373,12 @@ bcprov-jdk18on ${bouncycastle.version} - - org.bouncycastle - bcutil-jdk18on - ${bouncycastle.version} - org.bouncycastle bctls-jdk18on ${bouncycastle.version} - - org.eclipse.milo - stack-core - ${milo.version} - - - org.eclipse.milo - stack-client - ${milo.version} - - org.hamcrest hamcrest @@ -498,6 +419,7 @@ + org.assertj assertj-core @@ -509,6 +431,7 @@ ${equalsverifier.version} + org.apache.groovy groovy-test-junit5 @@ -593,6 +516,20 @@ jna ${jna.version} + + + + com.fasterxml.woodstox + woodstox-core + ${woodstox-core.version} + + + + + org.bouncycastle + bcutil-jdk18on + ${bouncycastle.version} + diff --git a/protocols/bacnetip/pom.xml b/protocols/bacnetip/pom.xml index debf46d11a8..f007148be55 100644 --- a/protocols/bacnetip/pom.xml +++ b/protocols/bacnetip/pom.xml @@ -57,6 +57,15 @@ logback-classic test + + org.slf4j + slf4j-api + + + org.opentest4j + opentest4j + test + diff --git a/protocols/bacnetip/src/main/generated/protocols/bacnetip/bacnet-vendorids.mspec b/protocols/bacnetip/src/main/generated/protocols/bacnetip/bacnet-vendorids.mspec index c17f6e3a7b6..2f4cf9ee22b 100644 --- a/protocols/bacnetip/src/main/generated/protocols/bacnetip/bacnet-vendorids.mspec +++ b/protocols/bacnetip/src/main/generated/protocols/bacnetip/bacnet-vendorids.mspec @@ -1651,6 +1651,12 @@ ['1638' SPEC_PROM_DIZAJNOOO ['1638', '"SpecPromDizajn OOO"']] ['1639' FACTS_ENGINEERINGLLC ['1639', '"FACTS Engineering, LLC"']] ['1640' G_ASERV_GMBH ['1640', '"GAserv GmbH"']] + ['1641' LEEDS_ELECTRONICS_ENGINEERING_LIMITED ['1641', '"Leeds Electronics Engineering Limited"']] + ['1642' MITO_CONTRACTING_GROUP_INC ['1642', '"MITO Contracting Group Inc."']] + ['1643' CALECTROAB ['1643', '"Calectro AB"']] + ['1644' BMSOS_TECHNOLOGY_INC ['1644', '"bmsOS Technology Inc."']] + ['1645' VOSSLOH_SCHWABE_DEUTSCHAND_GMBH ['1645', '"Vossloh-Schwabe Deutschand GmbH"']] + ['1646' IVIVA_PTE_LTD ['1646', '"Iviva Pte Ltd"']] ['0xFFFF' UNKNOWN_VENDOR ['0xFFFF', '"Unknown"']] ] diff --git a/protocols/c-bus/pom.xml b/protocols/c-bus/pom.xml index c913bb4ef47..26ad4d6e40f 100644 --- a/protocols/c-bus/pom.xml +++ b/protocols/c-bus/pom.xml @@ -46,6 +46,10 @@ logback-classic test + + org.slf4j + slf4j-api + \ No newline at end of file diff --git a/protocols/cotp/pom.xml b/protocols/cotp/pom.xml index 116a4058108..e8f427b377a 100644 --- a/protocols/cotp/pom.xml +++ b/protocols/cotp/pom.xml @@ -43,22 +43,11 @@ - - org.opentest4j - opentest4j - test - ch.qos.logback logback-classic test - - - org.junit.jupiter - junit-jupiter-api - test - \ No newline at end of file diff --git a/protocols/knxnetip/pom.xml b/protocols/knxnetip/pom.xml index 31a1f962952..b74401173be 100644 --- a/protocols/knxnetip/pom.xml +++ b/protocols/knxnetip/pom.xml @@ -81,6 +81,16 @@ commons-compress test + + org.apache.httpcomponents + httpcore + test + + + commons-io + commons-io + test + diff --git a/protocols/opcua/pom.xml b/protocols/opcua/pom.xml index c528d6bf84f..e254a30e612 100644 --- a/protocols/opcua/pom.xml +++ b/protocols/opcua/pom.xml @@ -57,6 +57,10 @@ logback-classic test + + org.slf4j + slf4j-api + diff --git a/protocols/plc4x-api/pom.xml b/protocols/plc4x-api/pom.xml index 6a905469a28..6245dc23cc0 100644 --- a/protocols/plc4x-api/pom.xml +++ b/protocols/plc4x-api/pom.xml @@ -46,6 +46,10 @@ logback-classic test + + org.slf4j + slf4j-api + \ No newline at end of file diff --git a/protocols/plc4x/pom.xml b/protocols/plc4x/pom.xml index 14572294b96..15431e88f57 100644 --- a/protocols/plc4x/pom.xml +++ b/protocols/plc4x/pom.xml @@ -46,6 +46,10 @@ logback-classic test + + org.slf4j + slf4j-api + \ No newline at end of file diff --git a/protocols/pom.xml b/protocols/pom.xml index 492d193cd0a..e1afa62935f 100644 --- a/protocols/pom.xml +++ b/protocols/pom.xml @@ -37,6 +37,39 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + + check-dependencies + verify + + analyze-only + + + true + true + + org.junit.jupiter:junit-jupiter + org.junit.jupiter:junit-jupiter-api + org.opentest4j:opentest4j + ch.qos.logback:logback-classic + + + + + + + + org.apache.plc4x.plugins + plc4x-code-generation-types-base + + + org.apache.plc4x.plugins + plc4x-code-generation-protocol-base + + org.junit.jupiter diff --git a/protocols/profinet/pom.xml b/protocols/profinet/pom.xml index c74d79c3ec6..f23398f132f 100644 --- a/protocols/profinet/pom.xml +++ b/protocols/profinet/pom.xml @@ -46,6 +46,10 @@ logback-classic test + + org.slf4j + slf4j-api + \ No newline at end of file