diff --git a/code-generation/language/java/src/main/resources/templates/java/complex-type-template.java.ftlh b/code-generation/language/java/src/main/resources/templates/java/complex-type-template.java.ftlh
index efd4444ae0..37d461a178 100644
--- a/code-generation/language/java/src/main/resources/templates/java/complex-type-template.java.ftlh
+++ b/code-generation/language/java/src/main/resources/templates/java/complex-type-template.java.ftlh
@@ -60,6 +60,7 @@ import org.apache.plc4x.java.api.exceptions.*;
import org.apache.plc4x.java.spi.generation.*;
import org.apache.plc4x.java.api.value.*;
+import java.io.*;
import java.time.*;
import java.util.*;
import java.math.BigInteger;
@@ -623,8 +624,15 @@ ${helper.getExternalTypeImports()}
<#assign arrayElementTypeReference = arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
<#if arrayElementTypeReference.isByteBased()>
- <#if !field.isCountArrayField() && !field.isLengthArrayField()>${helper.fail("array fields of type byte only support 'count' and 'length' loop-types.")}#if>
- byte[] ${namedField.name} = readBuffer.readByteArray("${namedField.name}", Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+ <#if field.isCountArrayField() || field.isLengthArrayField()>
+ byte[] ${namedField.name} = readBuffer.readByteArray("${namedField.name}", Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+ <#else>
+ ByteArrayOutputStream ${namedField.name}Buffer = new ByteArrayOutputStream();
+ while (${helper.toParseExpression(arrayField, helper.boolTypeReference, arrayField.loopExpression, parserArguments)}) {
+ ${namedField.name}Buffer.write(readBuffer.readByte("${namedField.name}"${helper.getFieldOptions(typedField, parserArguments)}));
+ }
+ byte[] ${namedField.name} = ${namedField.name}Buffer.toByteArray();
+ #if>
<#else>
<#-- If this is a count array, we can directly initialize an array with the given size -->
<#if field.isCountArrayField()>
diff --git a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
index 3427650db8..f490096c31 100644
--- a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
+++ b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4
@@ -395,8 +395,13 @@ BOOLEAN_LITERAL
STRING_LITERAL
: '"' STRING_CHARACTERS? '"'
+ | SINGLE_LINE_STRING
+ | MULTI_LINE_STRING
;
+SINGLE_LINE_STRING : '"' ( ESCAPE | '\\"' | ~[\\"])* '"';
+MULTI_LINE_STRING : '"""' .*? '"""';
+
// As we're generating property names and class names from these,
// we have to put more restrictions on them.
@@ -404,6 +409,8 @@ IDENTIFIER_LITERAL
: [A-Za-z0-9_-]+
;
+fragment ESCAPE: '\\' ( [\\abdefnrstv0] | 'x' HEX_LITERAL HEX_LITERAL | 'u' HEX_LITERAL HEX_LITERAL HEX_LITERAL HEX_LITERAL | 'u{' HEX_LITERAL+ '}');
+
fragment
STRING_CHARACTERS
: STRING_CHARACTER+
diff --git a/plc4j/drivers/pom.xml b/plc4j/drivers/pom.xml
index deb6a14ca0..6774b493f6 100644
--- a/plc4j/drivers/pom.xml
+++ b/plc4j/drivers/pom.xml
@@ -57,6 +57,7 @@
profinet
profinet-ng
s7
+ sip
simulated
all
diff --git a/plc4j/drivers/sip/pom.xml b/plc4j/drivers/sip/pom.xml
new file mode 100644
index 0000000000..2e51565c54
--- /dev/null
+++ b/plc4j/drivers/sip/pom.xml
@@ -0,0 +1,238 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.plc4x
+ plc4j-drivers
+ 0.14.0-SNAPSHOT
+
+
+ plc4j-driver-sip
+
+ PLC4J: Driver: SIP
+ Implementation of a PLC4X driver for the SIP protocol.
+
+
+ 2025-08-02T13:55:11Z
+
+
+
+
+
+ org.apache.karaf.tooling
+ karaf-maven-plugin
+
+
+ generate-feature-xml
+ compile
+
+
+ features-generate-descriptor
+
+ verify
+
+
+ true
+ true
+
+
+
+ build-kar
+ package
+
+
+ kar
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+ ${project.groupId}.${project.artifactId}
+ org.apache.plc4x.java.osgi.DriverActivator
+ org.apache.plc4x.java.api.PlcDriver,org.apache.plc4x.java.sip.readwrite.sipDriver
+
+
+ *
+
+ *
+
+
+
+
+
+
+
+
+ org.apache.plc4x
+ plc4j-api
+ 0.14.0-SNAPSHOT
+
+
+ org.apache.plc4x
+ plc4j-spi
+ 0.14.0-SNAPSHOT
+
+
+
+ org.apache.plc4x
+ plc4j-transport-udp
+ 0.14.0-SNAPSHOT
+
+
+
+ org.pcap4j
+ pcap4j-core
+
+ compile
+
+
+ org.pcap4j
+ pcap4j-packetfactory-static
+ runtime
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ commons-codec
+ commons-codec
+
+
+ io.netty
+ netty-buffer
+
+
+ io.netty
+ netty-transport
+
+
+ io.netty
+ netty-handler
+
+
+ io.netty
+ netty-codec
+
+
+ io.netty
+ netty-common
+
+
+ org.json
+ json
+
+
+
+ org.apache.plc4x
+ plc4j-utils-test-utils
+ 0.14.0-SNAPSHOT
+ test
+
+
+ org.skyscreamer
+ jsonassert
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ test
+
+
+
+ org.apache.plc4x
+ plc4x-protocols-sip
+ 0.14.0-SNAPSHOT
+ tests
+ test-jar
+ test
+
+
+
+
+
+ update-generated-code
+
+
+
+ org.apache.plc4x.plugins
+ plc4x-maven-plugin
+
+
+ generate-driver
+ generate-sources
+
+ generate-driver
+
+
+ sip
+ java
+ read-write
+ src/main/generated
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ org.apache.plc4x:plc4x-code-generation-language-java
+ org.apache.plc4x:plc4x-protocols-sip
+
+
+
+
+
+
+
+
+ org.apache.plc4x
+ plc4x-code-generation-language-java
+ 0.14.0-SNAPSHOT
+
+ provided
+
+
+
+ org.apache.plc4x
+ plc4x-protocols-sip
+ 0.14.0-SNAPSHOT
+
+ provided
+
+
+
+
+
+
diff --git a/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/Constants.java b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/Constants.java
new file mode 100644
index 0000000000..a8e74b7992
--- /dev/null
+++ b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/Constants.java
@@ -0,0 +1,173 @@
+/*
+ * 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.sip.readwrite;
+
+import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import java.io.*;
+import java.time.*;
+import java.util.*;
+import org.apache.plc4x.java.api.exceptions.*;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.codegen.*;
+import org.apache.plc4x.java.spi.codegen.fields.*;
+import org.apache.plc4x.java.spi.codegen.io.*;
+import org.apache.plc4x.java.spi.generation.*;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+public class Constants implements Message {
+
+ // Constant values.
+ public static final Byte SPACE = 0x20;
+ public static final Byte COLON = 0x3a;
+ public static final Byte SLASH = 0x2f;
+ public static final Byte R = 0x0d;
+ public static final Byte N = 0x0a;
+
+ public Constants() {
+ super();
+ }
+
+ public byte getSPACE() {
+ return SPACE;
+ }
+
+ public byte getCOLON() {
+ return COLON;
+ }
+
+ public byte getSLASH() {
+ return SLASH;
+ }
+
+ public byte getR() {
+ return R;
+ }
+
+ public byte getN() {
+ return N;
+ }
+
+ public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+ PositionAware positionAware = writeBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ writeBuffer.pushContext("Constants");
+
+ // Const Field (SPACE)
+ writeConstField("SPACE", SPACE, writeByte(writeBuffer, 8));
+
+ // Const Field (COLON)
+ writeConstField("COLON", COLON, writeByte(writeBuffer, 8));
+
+ // Const Field (SLASH)
+ writeConstField("SLASH", SLASH, writeByte(writeBuffer, 8));
+
+ // Const Field (R)
+ writeConstField("R", R, writeByte(writeBuffer, 8));
+
+ // Const Field (N)
+ writeConstField("N", N, writeByte(writeBuffer, 8));
+
+ writeBuffer.popContext("Constants");
+ }
+
+ @Override
+ public int getLengthInBytes() {
+ return (int) Math.ceil((float) getLengthInBits() / 8.0);
+ }
+
+ @Override
+ public int getLengthInBits() {
+ int lengthInBits = 0;
+ Constants _value = this;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ // Const Field (SPACE)
+ lengthInBits += 8;
+
+ // Const Field (COLON)
+ lengthInBits += 8;
+
+ // Const Field (SLASH)
+ lengthInBits += 8;
+
+ // Const Field (R)
+ lengthInBits += 8;
+
+ // Const Field (N)
+ lengthInBits += 8;
+
+ return lengthInBits;
+ }
+
+ public static Constants staticParse(ReadBuffer readBuffer) throws ParseException {
+ readBuffer.pullContext("Constants");
+ PositionAware positionAware = readBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ byte SPACE = readConstField("SPACE", readByte(readBuffer, 8), Constants.SPACE);
+
+ byte COLON = readConstField("COLON", readByte(readBuffer, 8), Constants.COLON);
+
+ byte SLASH = readConstField("SLASH", readByte(readBuffer, 8), Constants.SLASH);
+
+ byte R = readConstField("R", readByte(readBuffer, 8), Constants.R);
+
+ byte N = readConstField("N", readByte(readBuffer, 8), Constants.N);
+
+ readBuffer.closeContext("Constants");
+ // Create the instance
+ Constants _constants;
+ _constants = new Constants();
+ return _constants;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Constants)) {
+ return false;
+ }
+ Constants that = (Constants) o;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash();
+ }
+
+ @Override
+ public String toString() {
+ WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true);
+ try {
+ writeBufferBoxBased.writeSerializable(this);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ }
+ return "\n" + writeBufferBoxBased.getBox().toString() + "\n";
+ }
+}
diff --git a/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipPDU.java b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipPDU.java
new file mode 100644
index 0000000000..2ae9375f63
--- /dev/null
+++ b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipPDU.java
@@ -0,0 +1,218 @@
+/*
+ * 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.sip.readwrite;
+
+import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import java.io.*;
+import java.time.*;
+import java.util.*;
+import org.apache.plc4x.java.api.exceptions.*;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.codegen.*;
+import org.apache.plc4x.java.spi.codegen.fields.*;
+import org.apache.plc4x.java.spi.codegen.io.*;
+import org.apache.plc4x.java.spi.generation.*;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+public class SipPDU implements Message {
+
+ // Properties.
+ protected final SipRequestLine requestLine;
+ protected final List headers;
+ protected final byte[] payload;
+
+ public SipPDU(SipRequestLine requestLine, List headers, byte[] payload) {
+ super();
+ this.requestLine = requestLine;
+ this.headers = headers;
+ this.payload = payload;
+ }
+
+ public SipRequestLine getRequestLine() {
+ return requestLine;
+ }
+
+ public List getHeaders() {
+ return headers;
+ }
+
+ public byte[] getPayload() {
+ return payload;
+ }
+
+ public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+ PositionAware positionAware = writeBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ writeBuffer.pushContext("SipPDU");
+
+ // Simple Field (requestLine)
+ writeSimpleField(
+ "requestLine",
+ requestLine,
+ writeComplex(writeBuffer),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ // Array Field (headers)
+ writeComplexTypeArrayField(
+ "headers", headers, writeBuffer, WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ // Array Field (payload)
+ writeByteArrayField(
+ "payload",
+ payload,
+ writeByteArray(writeBuffer, 8),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ // Reserved Field (reserved)
+ writeReservedField(
+ "reserved",
+ (byte) Constants.R,
+ writeByte(writeBuffer, 8),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ // Reserved Field (reserved)
+ writeReservedField(
+ "reserved",
+ (byte) Constants.N,
+ writeByte(writeBuffer, 8),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ writeBuffer.popContext("SipPDU");
+ }
+
+ @Override
+ public int getLengthInBytes() {
+ return (int) Math.ceil((float) getLengthInBits() / 8.0);
+ }
+
+ @Override
+ public int getLengthInBits() {
+ int lengthInBits = 0;
+ SipPDU _value = this;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ // Simple field (requestLine)
+ lengthInBits += requestLine.getLengthInBits();
+
+ // Array field
+ if (headers != null) {
+ for (Message element : headers) {
+ lengthInBits += element.getLengthInBits();
+ }
+ }
+
+ // Array field
+ if (payload != null) {
+ lengthInBits += 8 * payload.length;
+ }
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ return lengthInBits;
+ }
+
+ public static SipPDU staticParse(ReadBuffer readBuffer, Integer len) throws ParseException {
+ readBuffer.pullContext("SipPDU");
+ PositionAware positionAware = readBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ SipRequestLine requestLine =
+ readSimpleField(
+ "requestLine",
+ readComplex(() -> SipRequestLine.staticParse(readBuffer), readBuffer),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ List headers =
+ readLengthArrayField(
+ "headers",
+ readComplex(() -> Header.staticParse(readBuffer), readBuffer),
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.untilToken(
+ readBuffer, "\r\n\r\n", 2),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ byte[] payload =
+ readBuffer.readByteArray(
+ "payload",
+ Math.toIntExact(
+ (((len) - (requestLine.getLengthInBytes())) - (ARRAY_SIZE_IN_BYTES(headers)))
+ - (2)),
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ Byte reservedField0 =
+ readReservedField(
+ "reserved",
+ readByte(readBuffer, 8),
+ (byte) Constants.R,
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ Byte reservedField1 =
+ readReservedField(
+ "reserved",
+ readByte(readBuffer, 8),
+ (byte) Constants.N,
+ WithOption.WithByteOrder(ByteOrder.BIG_ENDIAN));
+
+ readBuffer.closeContext("SipPDU");
+ // Create the instance
+ SipPDU _sipPDU;
+ _sipPDU = new SipPDU(requestLine, headers, payload);
+ return _sipPDU;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SipPDU)) {
+ return false;
+ }
+ SipPDU that = (SipPDU) o;
+ return (getRequestLine() == that.getRequestLine())
+ && (getHeaders() == that.getHeaders())
+ && (getPayload() == that.getPayload())
+ && true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getRequestLine(), getHeaders(), getPayload());
+ }
+
+ @Override
+ public String toString() {
+ WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true);
+ try {
+ writeBufferBoxBased.writeSerializable(this);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ }
+ return "\n" + writeBufferBoxBased.getBox().toString() + "\n";
+ }
+}
diff --git a/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipRequestLine.java b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipRequestLine.java
new file mode 100644
index 0000000000..622e6d97cd
--- /dev/null
+++ b/plc4j/drivers/sip/src/main/generated/org/apache/plc4x/java/sip/readwrite/SipRequestLine.java
@@ -0,0 +1,298 @@
+/*
+ * 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.sip.readwrite;
+
+import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
+import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
+import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
+
+import java.io.*;
+import java.time.*;
+import java.util.*;
+import org.apache.plc4x.java.api.exceptions.*;
+import org.apache.plc4x.java.api.value.*;
+import org.apache.plc4x.java.spi.codegen.*;
+import org.apache.plc4x.java.spi.codegen.fields.*;
+import org.apache.plc4x.java.spi.codegen.io.*;
+import org.apache.plc4x.java.spi.generation.*;
+
+// Code generated by code-generation. DO NOT EDIT.
+
+public class SipRequestLine implements Message {
+
+ // Properties.
+ protected final String method;
+ protected final String proto;
+ protected final String requestUri;
+ protected final String protocol;
+ protected final String version;
+
+ public SipRequestLine(
+ String method, String proto, String requestUri, String protocol, String version) {
+ super();
+ this.method = method;
+ this.proto = proto;
+ this.requestUri = requestUri;
+ this.protocol = protocol;
+ this.version = version;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public String getProto() {
+ return proto;
+ }
+
+ public String getRequestUri() {
+ return requestUri;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+ PositionAware positionAware = writeBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+ writeBuffer.pushContext("SipRequestLine");
+
+ // Manual Field (method)
+ writeManualField(
+ "method",
+ () ->
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.writeStringTill(
+ writeBuffer, method),
+ writeBuffer);
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.SPACE, writeByte(writeBuffer, 8));
+
+ // Manual Field (proto)
+ writeManualField(
+ "proto",
+ () ->
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.writeStringTill(
+ writeBuffer, proto),
+ writeBuffer);
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.COLON, writeByte(writeBuffer, 8));
+
+ // Manual Field (requestUri)
+ writeManualField(
+ "requestUri",
+ () ->
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.writeStringTill(
+ writeBuffer, requestUri),
+ writeBuffer);
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.SPACE, writeByte(writeBuffer, 8));
+
+ // Manual Field (protocol)
+ writeManualField(
+ "protocol",
+ () ->
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.writeStringTill(
+ writeBuffer, protocol),
+ writeBuffer);
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.SLASH, writeByte(writeBuffer, 8));
+
+ // Manual Field (version)
+ writeManualField(
+ "version",
+ () ->
+ org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.writeStringTill(
+ writeBuffer, version),
+ writeBuffer);
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.R, writeByte(writeBuffer, 8));
+
+ // Reserved Field (reserved)
+ writeReservedField("reserved", (byte) Constants.N, writeByte(writeBuffer, 8));
+
+ writeBuffer.popContext("SipRequestLine");
+ }
+
+ @Override
+ public int getLengthInBytes() {
+ return (int) Math.ceil((float) getLengthInBits() / 8.0);
+ }
+
+ @Override
+ public int getLengthInBits() {
+ int lengthInBits = 0;
+ SipRequestLine _value = this;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ // Manual Field (method)
+ lengthInBits += (8) * (STR_LEN(method));
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Manual Field (proto)
+ lengthInBits += (8) * (STR_LEN(proto));
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Manual Field (requestUri)
+ lengthInBits += (8) * (STR_LEN(requestUri));
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Manual Field (protocol)
+ lengthInBits += (8) * (STR_LEN(protocol));
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Manual Field (version)
+ lengthInBits += (8) * (STR_LEN(version));
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ // Reserved Field (reserved)
+ lengthInBits += 8;
+
+ return lengthInBits;
+ }
+
+ public static SipRequestLine staticParse(ReadBuffer readBuffer) throws ParseException {
+ readBuffer.pullContext("SipRequestLine");
+ PositionAware positionAware = readBuffer;
+ boolean _lastItem = ThreadLocalHelper.lastItemThreadLocal.get();
+
+ String method =
+ readManualField(
+ "method",
+ readBuffer,
+ () ->
+ (String)
+ (org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.readStringTill(
+ readBuffer, " ")));
+
+ Byte reservedField0 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.SPACE);
+
+ String proto =
+ readManualField(
+ "proto",
+ readBuffer,
+ () ->
+ (String)
+ (org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.readStringTill(
+ readBuffer, ":")));
+
+ Byte reservedField1 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.COLON);
+
+ String requestUri =
+ readManualField(
+ "requestUri",
+ readBuffer,
+ () ->
+ (String)
+ (org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.readStringTill(
+ readBuffer, " ")));
+
+ Byte reservedField2 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.SPACE);
+
+ String protocol =
+ readManualField(
+ "protocol",
+ readBuffer,
+ () ->
+ (String)
+ (org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.readStringTill(
+ readBuffer, "/")));
+
+ Byte reservedField3 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.SLASH);
+
+ String version =
+ readManualField(
+ "version",
+ readBuffer,
+ () ->
+ (String)
+ (org.apache.plc4x.java.sip.readwrite.utils.StaticHelper.readStringTill(
+ readBuffer, "\r\n")));
+
+ Byte reservedField4 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.R);
+
+ Byte reservedField5 =
+ readReservedField("reserved", readByte(readBuffer, 8), (byte) Constants.N);
+
+ readBuffer.closeContext("SipRequestLine");
+ // Create the instance
+ SipRequestLine _sipRequestLine;
+ _sipRequestLine = new SipRequestLine(method, proto, requestUri, protocol, version);
+ return _sipRequestLine;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SipRequestLine)) {
+ return false;
+ }
+ SipRequestLine that = (SipRequestLine) o;
+ return (getMethod() == that.getMethod())
+ && (getProto() == that.getProto())
+ && (getRequestUri() == that.getRequestUri())
+ && (getProtocol() == that.getProtocol())
+ && (getVersion() == that.getVersion())
+ && true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getMethod(), getProto(), getRequestUri(), getProtocol(), getVersion());
+ }
+
+ @Override
+ public String toString() {
+ WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true);
+ try {
+ writeBufferBoxBased.writeSerializable(this);
+ } catch (SerializationException e) {
+ throw new RuntimeException(e);
+ }
+ return "\n" + writeBufferBoxBased.getBox().toString() + "\n";
+ }
+}
diff --git a/plc4j/drivers/sip/src/main/java/org/apache/plc4x/java/sip/readwrite/utils/StaticHelper.java b/plc4j/drivers/sip/src/main/java/org/apache/plc4x/java/sip/readwrite/utils/StaticHelper.java
new file mode 100644
index 0000000000..409487a691
--- /dev/null
+++ b/plc4j/drivers/sip/src/main/java/org/apache/plc4x/java/sip/readwrite/utils/StaticHelper.java
@@ -0,0 +1,137 @@
+/*
+ * 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
+ *
+ * http://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.sip.readwrite.utils;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+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 StaticHelper {
+
+ public static String asString(byte[] bytes) {
+ return new String(bytes);
+ }
+
+ public static int untilToken(ReadBuffer readBuffer, String terminator, int keep) {
+ int start = readBuffer.getPos();
+ StringBuilder buffer = new StringBuilder();
+ int length = terminator.length();
+ int retrieved = 0;
+ boolean success = false;
+ while (readBuffer.hasMore(8) && retrieved < length) {
+ try {
+ buffer.append((char) readBuffer.readByte());
+ if (buffer.length() >= length) {
+ if (buffer.toString().endsWith(terminator)) {
+ success = true;
+ break;
+ }
+ }
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ if (!success) {
+ throw new PlcRuntimeException("Failed to reach termination sequence for array");
+ }
+
+ int end = readBuffer.getPos();
+ readBuffer.reset(start);
+ return end - start - keep;
+ }
+
+ public static boolean until(ReadBuffer readBuffer, String terminator) {
+ int start = readBuffer.getPos();
+ StringBuilder buffer = new StringBuilder();
+ int length = terminator.length();
+ int retrieved = 0;
+ while (readBuffer.hasMore(8) && retrieved < length) {
+ try {
+ buffer.append((char) readBuffer.readByte());
+ if (buffer.length() == length) {
+ if (buffer.toString().equals(terminator)) {
+ readBuffer.reset(start + length - 1);
+ return false;
+ }
+ break;
+ }
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ readBuffer.reset(start);
+ return true;
+ }
+
+ public static String readStringTill(ReadBuffer readBuffer, String terminator) throws ParseException {
+ int start = readBuffer.getPos();
+ StringBuilder buffer = new StringBuilder();
+ int length = terminator.length();
+ while (readBuffer.hasMore(8)) {
+ buffer.append((char) readBuffer.readByte());
+ if (buffer.length() >= length) {
+ if (buffer.subSequence(buffer.length() - length, buffer.length()).equals(terminator)) {
+ break;
+ }
+ }
+ }
+
+ int end = readBuffer.getPos();
+ readBuffer.reset(end - length);
+ if (start == end) {
+ return "";
+ }
+ return buffer.subSequence(0, buffer.length() - length).toString();
+ }
+
+ public static String readString(ReadBuffer readBuffer, String terminator) throws ParseException {
+ int start = readBuffer.getPos();
+ StringBuilder buffer = new StringBuilder();
+ int length = terminator.length();
+ while (readBuffer.hasMore(8)) {
+ buffer.append((char) readBuffer.readByte());
+ if (buffer.length() >= length) {
+ if (buffer.subSequence(buffer.length() - length, buffer.length()).equals(terminator)) {
+ break;
+ }
+ }
+ }
+
+ int end = readBuffer.getPos();
+ //readBuffer.reset(end - length);
+ if (start == end) {
+ return "";
+ }
+ //return buffer.subSequence(0, buffer.length() - length).toString();
+ return buffer.toString();
+ }
+
+ public static void writeString(WriteBuffer writeBuffer, String method/*, String terminator*/) throws SerializationException {
+ writeBuffer.writeString(8 * method.length()/* + (terminator.length() * 8)*/ , method/* + terminator*/);
+ }
+
+ public static void writeStringTill(WriteBuffer writeBuffer, String method) throws SerializationException {
+ writeBuffer.writeString(8 * method.length(), method);
+ }
+}
diff --git a/plc4j/drivers/sip/src/test/java/org/apache/plc4x/java/sip/readwrite/SipParserSerializerTest.java b/plc4j/drivers/sip/src/test/java/org/apache/plc4x/java/sip/readwrite/SipParserSerializerTest.java
new file mode 100644
index 0000000000..387a286cb0
--- /dev/null
+++ b/plc4j/drivers/sip/src/test/java/org/apache/plc4x/java/sip/readwrite/SipParserSerializerTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.sip.readwrite;
+
+import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
+
+public class SipParserSerializerTest extends ParserSerializerTestsuiteRunner {
+
+ public SipParserSerializerTest() {
+ super("/protocols/sip/ParserSerializerTestsuite.xml");
+ }
+
+}
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
index 47e3ab016c..84ec9aab06 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -204,8 +204,8 @@ public void writeBigDecimal(String logicalName, int bitLength, BigDecimal value,
@Override
public void writeString(String logicalName, int bitLength, String value, WithWriterArgs... writerArgs) throws SerializationException {
String encoding = extractEncoding(writerArgs).orElse("UTF-8");
- String cleanedUpString = StringUtils.trimToEmpty(value).replaceAll("[^\u0009\r\n\u0020-\uD7FF\uE000-\uFFFD\ud800\udc00-\udbff\udfff]", "");
- createAndAppend(logicalName, rwStringKey, bitLength, cleanedUpString, encoding, writerArgs);
+ //String cleanedUpString = StringUtils.trimToEmpty(value).replaceAll("[^\u0009\r\n\u0020-\uD7FF\uE000-\uFFFD\ud800\udc00-\udbff\udfff]", "");
+ createAndAppend(logicalName, rwStringKey, bitLength, value, encoding, writerArgs);
move(bitLength);
}
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 6baa7e1c28..6d802989e7 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -58,6 +58,7 @@
profinet
s7
simulated
+ sip
socketcan
umas
diff --git a/protocols/sip/pom.xml b/protocols/sip/pom.xml
new file mode 100644
index 0000000000..5fef82e40f
--- /dev/null
+++ b/protocols/sip/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.plc4x
+ plc4x-protocols
+ 0.14.0-SNAPSHOT
+
+
+ plc4x-protocols-sip
+
+ Protocols: SIP
+ Base protocol specifications for the SIP protocol
+
+
+ 2025-08-02T13:55:11Z
+
+
+
+
+ org.apache.plc4x
+ plc4x-code-generation-protocol-base-mspec
+ 0.14.0-SNAPSHOT
+
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+
+
\ No newline at end of file
diff --git a/protocols/sip/src/main/java/org/apache/plc4x/protocol/sip/SipProtocol.java b/protocols/sip/src/main/java/org/apache/plc4x/protocol/sip/SipProtocol.java
new file mode 100644
index 0000000000..40fc89e99f
--- /dev/null
+++ b/protocols/sip/src/main/java/org/apache/plc4x/protocol/sip/SipProtocol.java
@@ -0,0 +1,42 @@
+/*
+ * 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.protocol.sip;
+
+import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ProtocolHelpers;
+import org.apache.plc4x.plugins.codegenerator.language.mspec.protocol.ValidatableTypeContext;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.protocol.TypeContext;
+import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+public class SipProtocol implements Protocol, ProtocolHelpers {
+
+ @Override
+ public String getName() {
+ return "sip";
+ }
+
+ @Override
+ public TypeContext getTypeContext() throws GenerationException {
+ ValidatableTypeContext typeContext = new MessageFormatParser().parse(getMspecStream());
+ typeContext.validate();
+ return typeContext;
+ }
+
+}
diff --git a/protocols/sip/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol b/protocols/sip/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000000..3a2e7a3183
--- /dev/null
+++ b/protocols/sip/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
@@ -0,0 +1,19 @@
+#
+# 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.protocol.sip.SipProtocol
diff --git a/protocols/sip/src/main/resources/protocols/sip/sip.mspec b/protocols/sip/src/main/resources/protocols/sip/sip.mspec
new file mode 100644
index 0000000000..4945894fa5
--- /dev/null
+++ b/protocols/sip/src/main/resources/protocols/sip/sip.mspec
@@ -0,0 +1,40 @@
+[type Constants
+ [const byte SPACE 0x20]
+ [const byte COLON 0x3a]
+ [const byte SLASH 0x2f]
+ [const byte R 0x0d]
+ [const byte N 0x0a]
+]
+
+[type SipPDU (uint 16 len) byteOrder='BIG_ENDIAN'
+ [simple SipRequestLine requestLine]
+ [array Header headers length 'STATIC_CALL("untilToken", readBuffer, "\r\n\r\n", 2)']
+ [array byte payload length 'len - requestLine.lengthInBytes - ARRAY_SIZE_IN_BYTES(headers) - 2']
+ [reserved byte 8 'Constants.R']
+ [reserved byte 8 'Constants.N']
+
+]
+
+[type Header
+ [manual vstring header 'STATIC_CALL("readStringTill", readBuffer, ":")' 'STATIC_CALL("writeStringTill", writeBuffer, header)' '8 * STR_LEN(header)' ]
+ [reserved byte 8 'Constants.COLON']
+ [reserved byte 8 'Constants.SPACE']
+ [manual vstring value 'STATIC_CALL("readStringTill", readBuffer, "\r\n")' 'STATIC_CALL("writeStringTill", writeBuffer, value)' '8 * STR_LEN(value)' ]
+ [const byte R 0x0d]
+ [const byte N 0x0a]
+]
+
+[type SipRequestLine
+ [manual vstring method 'STATIC_CALL("readStringTill", readBuffer, " ")' 'STATIC_CALL("writeStringTill", writeBuffer, method)' '8 * STR_LEN(method)' ]
+ [reserved byte 8 'Constants.SPACE']
+ [manual vstring proto 'STATIC_CALL("readStringTill", readBuffer, ":")' 'STATIC_CALL("writeStringTill", writeBuffer, proto)' '8 * STR_LEN(proto)' ]
+ [reserved byte 8 'Constants.COLON']
+ [manual vstring requestUri 'STATIC_CALL("readStringTill", readBuffer, " ")' 'STATIC_CALL("writeStringTill", writeBuffer, requestUri)' '8 * STR_LEN(requestUri)' ]
+ [reserved byte 8 'Constants.SPACE']
+ [manual vstring protocol 'STATIC_CALL("readStringTill", readBuffer, "/")' 'STATIC_CALL("writeStringTill", writeBuffer, protocol)' '8 * STR_LEN(protocol)' ]
+ [reserved byte 8 'Constants.SLASH']
+ [manual vstring version 'STATIC_CALL("readStringTill", readBuffer, "\r\n")' 'STATIC_CALL("writeStringTill", writeBuffer, version)' '8 * STR_LEN(version)' ]
+ [reserved byte 8 'Constants.R']
+ [reserved byte 8 'Constants.N']
+]
+
diff --git a/protocols/sip/src/test/resources/protocols/sip/ParserSerializerTestsuite.xml b/protocols/sip/src/test/resources/protocols/sip/ParserSerializerTestsuite.xml
new file mode 100644
index 0000000000..bf6667a8cb
--- /dev/null
+++ b/protocols/sip/src/test/resources/protocols/sip/ParserSerializerTestsuite.xml
@@ -0,0 +1,294 @@
+
+
+
+
+ SIP
+
+ sip
+ read-write
+
+
+ SIP Register
+ 5245474953544552207369703a7369702e6379626572636974792e646b205349502f322e300d0a5669613a205349502f322e302f554450203139322e3136382e312e323b6272616e63683d7a39684734624b6e703135313234383733372d34366561373135653139322e3136382e312e323b72706f72740d0a46726f6d3a203c7369703a766f693138303633407369702e6379626572636974792e646b3e3b7461673d393033646630610d0a546f3a203c7369703a766f693138303633407369702e6379626572636974792e646b3e0d0a43616c6c2d49443a203537383232323732392d3436363564373735403537383232323733322d34363635643737320d0a436f6e746163743a20203c7369703a766f693138303633403139322e3136382e312e323a353036303b6c696e653d396337643264626438383232303133633e3b657870697265733d313230303b713d302e3530300d0a457870697265733a20313230300d0a435365713a2036382052454749535445520d0a436f6e74656e742d4c656e6774683a20300d0a4d61782d466f7277617264733a2037300d0a557365722d4167656e743a204e65726f2053495050532049502050686f6e652056657273696f6e20322e302e35312e31360d0a0d0a
+ SipPDU
+
+ 467
+
+
+
+
+
+ REGISTER
+ 0x20
+ sip
+ 0x3a
+ sip.cybercity.dk
+ 0x20
+ SIP
+ 0x2f
+ 2.0
+ 0x0d
+ 0x0a
+
+
+
+
+ Via
+ 0x3a
+ 0x20
+ SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp151248737-46ea715e192.168.1.2;rport
+ 0x0d
+ 0x0a
+
+
+ From
+ 0x3a
+ 0x20
+ <sip:voi18063@sip.cybercity.dk>;tag=903df0a
+ 0x0d
+ 0x0a
+
+
+ To
+ 0x3a
+ 0x20
+ <sip:voi18063@sip.cybercity.dk>
+ 0x0d
+ 0x0a
+
+
+ Call-ID
+ 0x3a
+ 0x20
+ 578222729-4665d775@578222732-4665d772
+ 0x0d
+ 0x0a
+
+
+ Contact
+ 0x3a
+ 0x20
+ <sip:voi18063@192.168.1.2:5060;line=9c7d2dbd8822013c>;expires=1200;q=0.500
+ 0x0d
+ 0x0a
+
+
+ Expires
+ 0x3a
+ 0x20
+ 1200
+ 0x0d
+ 0x0a
+
+
+ CSeq
+ 0x3a
+ 0x20
+ 68 REGISTER
+ 0x0d
+ 0x0a
+
+
+ Content-Length
+ 0x3a
+ 0x20
+ 0
+ 0x0d
+ 0x0a
+
+
+ Max-Forwards
+ 0x3a
+ 0x20
+ 70
+ 0x0d
+ 0x0a
+
+
+ User-Agent
+ 0x3a
+ 0x20
+ Nero SIPPS IP Phone Version 2.0.51.16
+ 0x0d
+ 0x0a
+
+
+ 0x
+ 0x0d
+ 0x0a
+
+
+
+
+
+ Invite
+ 494e56495445207369703a30303937323339323837303434407369702e6379626572636974792e646b205349502f322e300d0a5669613a205349502f322e302f554450203139322e3136382e312e323b6272616e63683d7a39684734624b6e7032303233383237352d34373839323762613139322e3136382e312e323b72706f72740d0a46726f6d3a20226172696b22203c7369703a3335313034373233407369702e6379626572636974792e646b3e3b7461673d313735613164640d0a546f3a203c7369703a30303937323339323837303434407369702e6379626572636974792e646b3e0d0a43616c6c2d49443a2032343438373339312d3434396266326130403139322e3136382e312e320d0a435365713a203220494e564954450d0a50726f78792d417574686f72697a6174696f6e3a2044696765737420757365726e616d653d22766f693138303632222c7265616c6d3d227369702e6379626572636974792e646b222c7572693d227369703a3139322e3136382e312e32222c6e6f6e63653d2231373031623937623465623663363664363464306232306635613062656638222c6f70617175653d22313730316131333531663730373935222c6e633d223030303030303031222c726573706f6e73653d223062373939306262323164353537326436353731653937623938633664373066220d0a436f6e74656e742d547970653a206170706c69636174696f6e2f7364700d0a436f6e74656e742d4c656e6774683a203237300d0a446174653a204d6f6e2c203034204a756c20323030352030393a35343a323520474d540d0a436f6e746163743a203c7369703a3335313034373233403139322e3136382e312e323e0d0a457870697265733a203132300d0a4163636570743a206170706c69636174696f6e2f7364700d0a4d61782d466f7277617264733a2037300d0a557365722d4167656e743a204e65726f2053495050532049502050686f6e652056657273696f6e20322e302e35312e31360d0a416c6c6f773a20494e564954452c2041434b2c2043414e43454c2c204259452c2052454645522c204f5054494f4e532c204e4f544946592c20494e464f0d0a0d0a763d300d0a6f3d534950505320323434363634323220323434363634313820494e20495034203139322e3136382e312e320d0a733d5349502063616c6c0d0a633d494e20495034203139322e3136382e312e320d0a743d3020300d0a6d3d617564696f203330303030205254502f41565020302038203937203220330d0a613d7274706d61703a302070636d752f383030300d0a613d7274706d61703a382070636d612f383030300d0a613d7274706d61703a393720694c42432f383030300d0a613d7274706d61703a3220473732362d33322f383030300d0a613d7274706d61703a332047534d2f383030300d0a613d666d74703a3937206d6f64653d32300d0a613d73656e64726563760d0a
+ SipPDU
+
+ 1076
+
+
+
+
+
+ INVITE
+ 0x20
+ sip
+ 0x3a
+ 0097239287044@sip.cybercity.dk
+ 0x20
+ SIP
+ 0x2f
+ 2.0
+ 0x0d
+ 0x0a
+
+
+
+
+ Via
+ 0x3a
+ 0x20
+ SIP/2.0/UDP 192.168.1.2;branch=z9hG4bKnp20238275-478927ba192.168.1.2;rport
+ 0x0d
+ 0x0a
+
+
+ From
+ 0x3a
+ 0x20
+ "arik" <sip:35104723@sip.cybercity.dk>;tag=175a1dd
+ 0x0d
+ 0x0a
+
+
+ To
+ 0x3a
+ 0x20
+ <sip:0097239287044@sip.cybercity.dk>
+ 0x0d
+ 0x0a
+
+
+ Call-ID
+ 0x3a
+ 0x20
+ 24487391-449bf2a0@192.168.1.2
+ 0x0d
+ 0x0a
+
+
+ CSeq
+ 0x3a
+ 0x20
+ 2 INVITE
+ 0x0d
+ 0x0a
+
+
+ Proxy-Authorization
+ 0x3a
+ 0x20
+ Digest username="voi18062",realm="sip.cybercity.dk",uri="sip:192.168.1.2",nonce="1701b97b4eb6c66d64d0b20f5a0bef8",opaque="1701a1351f70795",nc="00000001",response="0b7990bb21d5572d6571e97b98c6d70f"
+ 0x0d
+ 0x0a
+
+
+ Content-Type
+ 0x3a
+ 0x20
+ application/sdp
+ 0x0d
+ 0x0a
+
+
+ Content-Length
+ 0x3a
+ 0x20
+ 270
+ 0x0d
+ 0x0a
+
+
+ Date
+ 0x3a
+ 0x20
+ Mon, 04 Jul 2005 09:54:25 GMT
+ 0x0d
+ 0x0a
+
+
+ Contact
+ 0x3a
+ 0x20
+ <sip:35104723@192.168.1.2>
+ 0x0d
+ 0x0a
+
+
+ Expires
+ 0x3a
+ 0x20
+ 120
+ 0x0d
+ 0x0a
+
+
+ Accept
+ 0x3a
+ 0x20
+ application/sdp
+ 0x0d
+ 0x0a
+
+
+ Max-Forwards
+ 0x3a
+ 0x20
+ 70
+ 0x0d
+ 0x0a
+
+
+ User-Agent
+ 0x3a
+ 0x20
+ Nero SIPPS IP Phone Version 2.0.51.16
+ 0x0d
+ 0x0a
+
+
+ Allow
+ 0x3a
+ 0x20
+ INVITE, ACK, CANCEL, BYE, REFER, OPTIONS, NOTIFY, INFO
+ 0x0d
+ 0x0a
+
+
+ 0x0d0a763d300d0a6f3d534950505320323434363634323220323434363634313820494e20495034203139322e3136382e312e320d0a733d5349502063616c6c0d0a633d494e20495034203139322e3136382e312e320d0a743d3020300d0a6d3d617564696f203330303030205254502f41565020302038203937203220330d0a613d7274706d61703a302070636d752f383030300d0a613d7274706d61703a382070636d612f383030300d0a613d7274706d61703a393720694c42432f383030300d0a613d7274706d61703a3220473732362d33322f383030300d0a613d7274706d61703a332047534d2f383030300d0a613d666d74703a3937206d6f64653d32300d0a613d73656e6472656376
+ 0x0d
+ 0x0a
+
+
+
+
+
\ No newline at end of file