From 754974c66f18446289ab1ef77f92254cd7048af1 Mon Sep 17 00:00:00 2001 From: ZhangJian He Date: Mon, 16 Sep 2024 22:54:47 +0800 Subject: [PATCH] feat: add some message type Signed-off-by: ZhangJian He --- go.sum | 2 - opcua/const.go | 3 +- opcua/message_acknowledge.go | 16 ++++---- opcua/message_browse_req.go | 30 ++++++++++++++ opcua/message_browse_req_test.go | 19 +++++++++ opcua/message_browse_resp.go | 30 ++++++++++++++ opcua/message_browse_resp_test.go | 19 +++++++++ opcua/message_close_secure_channel.go | 34 ++++++++++++++++ opcua/message_close_secure_channel_test.go | 19 +++++++++ opcua/message_close_session_req.go | 30 ++++++++++++++ opcua/message_close_session_req_test.go | 19 +++++++++ opcua/message_close_session_resp.go | 30 ++++++++++++++ opcua/message_close_session_resp_test.go | 19 +++++++++ opcua/message_create_session_req.go | 30 ++++++++++++++ opcua/message_create_session_req_test.go | 19 +++++++++ opcua/message_get_endpoints_req.go | 30 ++++++++++++++ opcua/message_get_endpoints_req_test.go | 19 +++++++++ opcua/message_get_endpoints_resp.go | 30 ++++++++++++++ opcua/message_get_endpoints_resp_test.go | 19 +++++++++ opcua/message_hello.go | 24 +++++------ opcua/message_open_secure_channel.go | 46 ++++++++++++++++++++++ opcua/message_open_secure_channel_test.go | 19 +++++++++ opcua/message_read_req.go | 30 ++++++++++++++ opcua/message_read_req_test.go | 19 +++++++++ opcua/message_read_resp.go | 30 ++++++++++++++ opcua/message_read_resp_test.go | 19 +++++++++ opcua/util.go | 5 +++ 27 files changed, 584 insertions(+), 25 deletions(-) create mode 100644 opcua/message_browse_req.go create mode 100644 opcua/message_browse_req_test.go create mode 100644 opcua/message_browse_resp.go create mode 100644 opcua/message_browse_resp_test.go create mode 100644 opcua/message_close_secure_channel.go create mode 100644 opcua/message_close_secure_channel_test.go create mode 100644 opcua/message_close_session_req.go create mode 100644 opcua/message_close_session_req_test.go create mode 100644 opcua/message_close_session_resp.go create mode 100644 opcua/message_close_session_resp_test.go create mode 100644 opcua/message_create_session_req.go create mode 100644 opcua/message_create_session_req_test.go create mode 100644 opcua/message_get_endpoints_req.go create mode 100644 opcua/message_get_endpoints_req_test.go create mode 100644 opcua/message_get_endpoints_resp.go create mode 100644 opcua/message_get_endpoints_resp_test.go create mode 100644 opcua/message_open_secure_channel.go create mode 100644 opcua/message_open_secure_channel_test.go create mode 100644 opcua/message_read_req.go create mode 100644 opcua/message_read_req_test.go create mode 100644 opcua/message_read_resp.go create mode 100644 opcua/message_read_resp_test.go create mode 100644 opcua/util.go diff --git a/go.sum b/go.sum index 222d718..0ef0f52 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/shoothzj/gox v0.0.4-0.20240916070027-2e4a2098d749 h1:yytTUCM7e17ADriGwcEaWdQ63ocmsdDGH+Qj979gNF8= -github.com/shoothzj/gox v0.0.4-0.20240916070027-2e4a2098d749/go.mod h1:JrD7u6Tem/9Ut4o0kQNK+aZkMWCba/d9VeabBZSEDT4= github.com/shoothzj/gox v0.0.4-0.20240916105254-02a0a7039d5d h1:oUVTx1ezGfBFkfRb192K+FFRAjjBX5u58qkbXEHfTdo= github.com/shoothzj/gox v0.0.4-0.20240916105254-02a0a7039d5d/go.mod h1:JrD7u6Tem/9Ut4o0kQNK+aZkMWCba/d9VeabBZSEDT4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= diff --git a/opcua/const.go b/opcua/const.go index c48c4e1..71723cc 100644 --- a/opcua/const.go +++ b/opcua/const.go @@ -7,7 +7,8 @@ const ( LenMessageSize = 4 LenMessageType = 3 LenReceiveBufferSize = 4 + LenRequestId = 4 LenSendBufferSize = 4 - LenStringLen = 4 + LenSequenceNumber = 4 LenVersion = 4 ) diff --git a/opcua/message_acknowledge.go b/opcua/message_acknowledge.go index 3fb4b08..007199a 100644 --- a/opcua/message_acknowledge.go +++ b/opcua/message_acknowledge.go @@ -10,29 +10,29 @@ type MessageAcknowledge struct { MaxChunkCount uint32 } -func DecodeMessageAcknowledge(buf *buffer.Buffer) (resp *MessageAcknowledge, err error) { - resp = &MessageAcknowledge{} - resp.Version, err = buf.ReadUInt32Le() +func DecodeMessageAcknowledge(buf *buffer.Buffer) (msg *MessageAcknowledge, err error) { + msg = &MessageAcknowledge{} + msg.Version, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.ReceiveBufferSize, err = buf.ReadUInt32Le() + msg.ReceiveBufferSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.SendBufferSize, err = buf.ReadUInt32Le() + msg.SendBufferSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.MaxMessageSize, err = buf.ReadUInt32Le() + msg.MaxMessageSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.MaxChunkCount, err = buf.ReadUInt32Le() + msg.MaxChunkCount, err = buf.ReadUInt32Le() if err != nil { return nil, err } - return resp, nil + return msg, nil } func (m *MessageAcknowledge) Length() int { diff --git a/opcua/message_browse_req.go b/opcua/message_browse_req.go new file mode 100644 index 0000000..672bf12 --- /dev/null +++ b/opcua/message_browse_req.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageBrowseReq struct { +} + +func DecodeMessageBrowseReq(buf *buffer.Buffer) (msg *MessageBrowseReq, err error) { + msg = &MessageBrowseReq{} + return msg, nil +} + +func (m *MessageBrowseReq) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageBrowseReq) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_browse_req_test.go b/opcua/message_browse_req_test.go new file mode 100644 index 0000000..45fa2d2 --- /dev/null +++ b/opcua/message_browse_req_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageBrowseReq(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d534746870000000200000001000000c8000000c800000001000f020500002000000048cce1823313199f88bb583a480954a576d4fae160deef9bf25daa6e50bfbc39f6c9be3815fcda01c800000000000000ffffffffa00f00000000000000000000000000000000000000000000000100000001000f3d00000000002d01000000003f000000") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageBrowseReq(t *testing.T) { + msg := &MessageBrowseReq{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_browse_resp.go b/opcua/message_browse_resp.go new file mode 100644 index 0000000..e7d8cba --- /dev/null +++ b/opcua/message_browse_resp.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageBrowseResp struct { +} + +func DecodeMessageBrowseResp(buf *buffer.Buffer) (msg *MessageBrowseResp, err error) { + msg = &MessageBrowseResp{} + return msg, nil +} + +func (m *MessageBrowseResp) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageBrowseResp) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_browse_resp_test.go b/opcua/message_browse_resp_test.go new file mode 100644 index 0000000..82ce2d1 --- /dev/null +++ b/opcua/message_browse_resp_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageBrowseResp(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d534746480000000200000001000000fb030000c500000001001202b0c4be3815fcda01c50000000000000000ffffffff0000000100000000000000ffffffff00000000ffffffff") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageBrowseResp(t *testing.T) { + msg := &MessageBrowseResp{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_close_secure_channel.go b/opcua/message_close_secure_channel.go new file mode 100644 index 0000000..8d0a21a --- /dev/null +++ b/opcua/message_close_secure_channel.go @@ -0,0 +1,34 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageCloseSecureChannel struct { + SecureChannelId uint32 +} + +func DecodeMessageCloseSecureChannel(buf *buffer.Buffer) (msg *MessageCloseSecureChannel, err error) { + msg = &MessageCloseSecureChannel{} + return msg, nil +} + +func (m *MessageCloseSecureChannel) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageCloseSecureChannel) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'C', 'L', 'O'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + if err := buf.PutUInt32Le(uint32(m.Length())); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_close_secure_channel_test.go b/opcua/message_close_secure_channel_test.go new file mode 100644 index 0000000..b07ab98 --- /dev/null +++ b/opcua/message_close_secure_channel_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageCloseSecureChannel(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d5347465f0000000200000001000000e6000000e60000000100d9010500002000000048cce1823313199f88bb583a480954a576d4fae160deef9bf25daa6e50bfbc396ee1343d15fcda01e600000000000000ffffffffa00f000000000001") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageCloseSecureChannel(t *testing.T) { + msg := &MessageCloseSecureChannel{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_close_session_req.go b/opcua/message_close_session_req.go new file mode 100644 index 0000000..b13323b --- /dev/null +++ b/opcua/message_close_session_req.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageCloseSessionReq struct { +} + +func DecodeMessageCloseSessionReq(buf *buffer.Buffer) (msg *MessageCloseSessionReq, err error) { + msg = &MessageCloseSessionReq{} + return msg, nil +} + +func (m *MessageCloseSessionReq) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageCloseSessionReq) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_close_session_req_test.go b/opcua/message_close_session_req_test.go new file mode 100644 index 0000000..b2c22fb --- /dev/null +++ b/opcua/message_close_session_req_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageCloseSessionReq(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d5347465f0000000200000001000000e6000000e60000000100d9010500002000000048cce1823313199f88bb583a480954a576d4fae160deef9bf25daa6e50bfbc396ee1343d15fcda01e600000000000000ffffffffa00f000000000001") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageCloseSessionReq(t *testing.T) { + msg := &MessageCloseSessionReq{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_close_session_resp.go b/opcua/message_close_session_resp.go new file mode 100644 index 0000000..f9f2940 --- /dev/null +++ b/opcua/message_close_session_resp.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageCloseSessionResp struct { +} + +func DecodeMessageCloseSessionResp(buf *buffer.Buffer) (msg *MessageCloseSessionResp, err error) { + msg = &MessageCloseSessionResp{} + return msg, nil +} + +func (m *MessageCloseSessionResp) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageCloseSessionResp) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_close_session_resp_test.go b/opcua/message_close_session_resp_test.go new file mode 100644 index 0000000..1a21ced --- /dev/null +++ b/opcua/message_close_session_resp_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageCloseSessionResp(t *testing.T) { + buffer := testx.Hex2Buffer(t, "1e00000060090900005406400000000000000000000000000000000100000000000000000000000000000001d11afd7da59b38d0e146c88b801816eb005c00000101080a1f86fec7f584f6454d5347463400000002000000010000001c040000e60000000100dc01c07f353d15fcda01e60000000000000000ffffffff000000") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageCloseSessionResp(t *testing.T) { + msg := &MessageCloseSessionResp{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_create_session_req.go b/opcua/message_create_session_req.go new file mode 100644 index 0000000..a0c3107 --- /dev/null +++ b/opcua/message_create_session_req.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageCreateSessionReq struct { +} + +func DecodeMessageCreateSessionReq(buf *buffer.Buffer) (msg *MessageCreateSessionReq, err error) { + msg = &MessageCreateSessionReq{} + return msg, nil +} + +func (m *MessageCreateSessionReq) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageCreateSessionReq) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_create_session_req_test.go b/opcua/message_create_session_req_test.go new file mode 100644 index 0000000..1716162 --- /dev/null +++ b/opcua/message_create_session_req_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageCreateSessionReq(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d5347464c010000020000000100000002000000020000000100cd010000700fb43815fcda010200000000000000ffffffffa00f00000000001800000075726e3a667265656f706375613a636c69656e742d6775691e00000075726e3a667265656f706375612e6769746875622e696f3a636c69656e7402190000005075726520507974686f6e204173796e632e20436c69656e7401000000ffffffffffffffff00000000ffffffff450000006f70632e7463703a2f2f68657a68616e676a69616e64654d6163426f6f6b2d50726f2e6c6f63616c3a35333533302f4f504355412f53696d756c6174696f6e536572766572220000005075726520507974686f6e204173796e632e20436c69656e742053657373696f6e3120000000a06ee593955cb82598cb5e9950a3f7634642941823761b762323ef23f9cc805effffffff0000000040774b4100000000") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageCreateSessionReq(t *testing.T) { + msg := &MessageCreateSessionReq{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_get_endpoints_req.go b/opcua/message_get_endpoints_req.go new file mode 100644 index 0000000..5e4ebd5 --- /dev/null +++ b/opcua/message_get_endpoints_req.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageGetEndpointsReq struct { +} + +func DecodeMessageGetEndpointsReq(buf *buffer.Buffer) (msg *MessageGetEndpointsReq, err error) { + msg = &MessageGetEndpointsReq{} + return msg, nil +} + +func (m *MessageGetEndpointsReq) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageGetEndpointsReq) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_get_endpoints_req_test.go b/opcua/message_get_endpoints_req_test.go new file mode 100644 index 0000000..eb515de --- /dev/null +++ b/opcua/message_get_endpoints_req_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageGetEndpointsReq(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d534746a8000000010000000100000002000000020000000100ac010000a018aacbf780d9010000000000000000ffffffff60ea00000000001e0000006f70632e7463703a2f2f6c6f63616c686f73743a31323638362f6d696c6f000000000100000041000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412d50726f66696c652f5472616e73706f72742f75617463702d756173632d756162696e617279") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageGetEndpointsReq(t *testing.T) { + msg := &MessageGetEndpointsReq{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_get_endpoints_resp.go b/opcua/message_get_endpoints_resp.go new file mode 100644 index 0000000..67683d2 --- /dev/null +++ b/opcua/message_get_endpoints_resp.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageGetEndpointsResp struct { +} + +func DecodeMessageGetEndpointsResp(buf *buffer.Buffer) (msg *MessageGetEndpointsResp, err error) { + msg = &MessageGetEndpointsResp{} + return msg, nil +} + +func (m *MessageGetEndpointsResp) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageGetEndpointsResp) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_get_endpoints_resp_test.go b/opcua/message_get_endpoints_resp_test.go new file mode 100644 index 0000000..ced9699 --- /dev/null +++ b/opcua/message_get_endpoints_resp_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageGetEndpointsResp(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d534746a60d0000010000000100000002000000020000000100af0160edabcbf780d901000000000000000000ffffffff000000020000001e0000006f70632e7463703a2f2f6c6f63616c686f73743a31323638362f6d696c6f4500000075726e3a65636c697073653a6d696c6f3a6578616d706c65733a7365727665723a30633064313738622d356261632d343032302d386138352d6435636361353361306333311f00000075726e3a65636c697073653a6d696c6f3a6578616d706c652d7365727665720302000000656e2200000045636c69707365204d696c6f204f5043205541204578616d706c652053657276657200000000ffffffffffffffff02000000280000006f70632e7463703a2f2f6c6f63616c686f73743a31323638362f6d696c6f2f646973636f766572792500000068747470733a2f2f6c6f63616c686f73743a383434332f6d696c6f2f646973636f766572794f0400003082044b30820333a00302010202060187f6bf2986300d06092a864886f70d01010b050030763124302206035504030c1b45636c69707365204d696c6f204578616d706c652053657276657231153013060355040a0c0c6469676974616c7065747269310c300a060355040b0c03646576310f300d06035504070c06466f6c736f6d310b300906035504080c024341310b3009060355040613025553301e170d3233303530363136303030305a170d3236303530363136303030305a30763124302206035504030c1b45636c69707365204d696c6f204578616d706c652053657276657231153013060355040a0c0c6469676974616c7065747269310c300a060355040b0c03646576310f300d06035504070c06466f6c736f6d310b300906035504080c024341310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100eea7a45b5864943a777fb68a00fb390d6434f13c7486d82e5ec488d8a29290fe91c9404dd4af6bccbd318591d0b75117b54b60f3ce4e661b3e7592a903c312195cf5a9df944bc6cf79701c4d7b2d19987b561352ae8b5365cdf6146746faf274db3c3d8217ba3902ed879603e95dfa9b92a8b459b6b265afe5e63cbe015f835ea5fb2690e009c30234bf0d9c461526b4475ab46415b7c78f04499dd87b619b31d8e0dd4cc8532ad5aca684fdae506094e6fde45acf17a3ef4cd9c7927836741df9e68819a6b68a7ef0c8b4b88bb63ca16cabeb5e2f691aeef7ecfc9978b1fad483ef1db861d0512ccb334a8e5d333b3dc231aea59ada7c1ee883439c60d1f4350203010001a381de3081db301f0603551d23041830168014c572a46d2932cacb1113347277bbbee305e868f6300f0603551d13040830060101ff020100300b0603551d0f0404030202fc301d0603551d250416301406082b0601050507030206082b06010505070301305c0603551d1104553053864575726e3a65636c697073653a6d696c6f3a6578616d706c65733a7365727665723a30633064313738622d356261632d343032302d386138352d6435636361353361306333318704c0a800658704c0a84001301d0603551d0e04160414c572a46d2932cacb1113347277bbbee305e868f6300d06092a864886f70d01010b050003820101003c2979bcb26fff82fe9e0732766ca290904a00835196b552189cf9e8e9409c1d48ca1a58e5c4c898a5fddc791fad0aee7e71c760b87aecd4f2e32b25f48069c80cc10fc79a21f390df0faedd724b1fe80259ef3c88edc28b917f62c442ed552c9b566fd58268dc73a161784b2d0173e15ea562cd1597d8f0059c631506a752a7628d02e5048706be9f1ded55441334fd39bc1d45edf666333d8fd5591ae97184c26fa507eb2709142ef5eb828c7a18a0455cd4255efd5e98f7f7425ed6bf1785dc9bef2ecd8e82d9d7049ac33ff518cbb2c76d630bbdd87eed159714a5db1384b6468640bccf56e9d233689f0ed7675a3c8ae4931bc54f1896512dcedafaac07010000002f000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c696379234e6f6e650300000009000000616e6f6e796d6f757300000000ffffffffffffffffffffffff08000000757365726e616d6501000000ffffffffffffffff33000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c6963792342617369633235360b000000636572746966696361746502000000ffffffffffffffff33000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c69637923426173696332353641000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412d50726f66696c652f5472616e73706f72742f75617463702d756173632d756162696e617279201e0000006f70632e7463703a2f2f6c6f63616c686f73743a31323638362f6d696c6f4500000075726e3a65636c697073653a6d696c6f3a6578616d706c65733a7365727665723a30633064313738622d356261632d343032302d386138352d6435636361353361306333311f00000075726e3a65636c697073653a6d696c6f3a6578616d706c652d7365727665720302000000656e2200000045636c69707365204d696c6f204f5043205541204578616d706c652053657276657200000000ffffffffffffffff02000000280000006f70632e7463703a2f2f6c6f63616c686f73743a31323638362f6d696c6f2f646973636f766572792500000068747470733a2f2f6c6f63616c686f73743a383434332f6d696c6f2f646973636f766572794f0400003082044b30820333a00302010202060187f6bf2986300d06092a864886f70d01010b050030763124302206035504030c1b45636c69707365204d696c6f204578616d706c652053657276657231153013060355040a0c0c6469676974616c7065747269310c300a060355040b0c03646576310f300d06035504070c06466f6c736f6d310b300906035504080c024341310b3009060355040613025553301e170d3233303530363136303030305a170d3236303530363136303030305a30763124302206035504030c1b45636c69707365204d696c6f204578616d706c652053657276657231153013060355040a0c0c6469676974616c7065747269310c300a060355040b0c03646576310f300d06035504070c06466f6c736f6d310b300906035504080c024341310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100eea7a45b5864943a777fb68a00fb390d6434f13c7486d82e5ec488d8a29290fe91c9404dd4af6bccbd318591d0b75117b54b60f3ce4e661b3e7592a903c312195cf5a9df944bc6cf79701c4d7b2d19987b561352ae8b5365cdf6146746faf274db3c3d8217ba3902ed879603e95dfa9b92a8b459b6b265afe5e63cbe015f835ea5fb2690e009c30234bf0d9c461526b4475ab46415b7c78f04499dd87b619b31d8e0dd4cc8532ad5aca684fdae506094e6fde45acf17a3ef4cd9c7927836741df9e68819a6b68a7ef0c8b4b88bb63ca16cabeb5e2f691aeef7ecfc9978b1fad483ef1db861d0512ccb334a8e5d333b3dc231aea59ada7c1ee883439c60d1f4350203010001a381de3081db301f0603551d23041830168014c572a46d2932cacb1113347277bbbee305e868f6300f0603551d13040830060101ff020100300b0603551d0f0404030202fc301d0603551d250416301406082b0601050507030206082b06010505070301305c0603551d1104553053864575726e3a65636c697073653a6d696c6f3a6578616d706c65733a7365727665723a30633064313738622d356261632d343032302d386138352d6435636361353361306333318704c0a800658704c0a84001301d0603551d0e04160414c572a46d2932cacb1113347277bbbee305e868f6300d06092a864886f70d01010b050003820101003c2979bcb26fff82fe9e0732766ca290904a00835196b552189cf9e8e9409c1d48ca1a58e5c4c898a5fddc791fad0aee7e71c760b87aecd4f2e32b25f48069c80cc10fc79a21f390df0faedd724b1fe80259ef3c88edc28b917f62c442ed552c9b566fd58268dc73a161784b2d0173e15ea562cd1597d8f0059c631506a752a7628d02e5048706be9f1ded55441334fd39bc1d45edf666333d8fd5591ae97184c26fa507eb2709142ef5eb828c7a18a0455cd4255efd5e98f7f7425ed6bf1785dc9bef2ecd8e82d9d7049ac33ff518cbb2c76d630bbdd87eed159714a5db1384b6468640bccf56e9d233689f0ed7675a3c8ae4931bc54f1896512dcedafaac070300000039000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c6963792342617369633235365368613235360300000009000000616e6f6e796d6f757300000000ffffffffffffffffffffffff08000000757365726e616d6501000000ffffffffffffffff33000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c6963792342617369633235360b000000636572746966696361746502000000ffffffffffffffff33000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c69637923426173696332353641000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412d50726f66696c652f5472616e73706f72742f75617463702d756173632d756162696e61727988") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageGetEndpointsResp(t *testing.T) { + msg := &MessageGetEndpointsResp{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_hello.go b/opcua/message_hello.go index b6b8855..5536f6d 100644 --- a/opcua/message_hello.go +++ b/opcua/message_hello.go @@ -11,34 +11,34 @@ type MessageHello struct { EndpointUrl string } -func DecodeMessageHello(buf *buffer.Buffer) (resp *MessageHello, err error) { - resp = &MessageHello{} - resp.Version, err = buf.ReadUInt32Le() +func DecodeMessageHello(buf *buffer.Buffer) (msg *MessageHello, err error) { + msg = &MessageHello{} + msg.Version, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.ReceiveBufferSize, err = buf.ReadUInt32Le() + msg.ReceiveBufferSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.SendBufferSize, err = buf.ReadUInt32Le() + msg.SendBufferSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.MaxMessageSize, err = buf.ReadUInt32Le() + msg.MaxMessageSize, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.MaxChunkCount, err = buf.ReadUInt32Le() + msg.MaxChunkCount, err = buf.ReadUInt32Le() if err != nil { return nil, err } - resp.EndpointUrl, err = buf.ReadString() + msg.EndpointUrl, err = buf.ReadStringLe() if err != nil { return nil, err } - return resp, nil + return msg, nil } func (m *MessageHello) Length() int { @@ -51,8 +51,7 @@ func (m *MessageHello) Length() int { length += LenSendBufferSize length += LenMaxMessageSize length += LenMaxChunkCount - length += LenStringLen - length += len(m.EndpointUrl) + length += StrLen(m.EndpointUrl) return length } @@ -82,9 +81,6 @@ func (m *MessageHello) Buffer() (*buffer.Buffer, error) { if err := buf.PutUInt32Le(m.MaxChunkCount); err != nil { return nil, err } - if err := buf.PutUInt32Le(uint32(len(m.EndpointUrl))); err != nil { - return nil, err - } if err := buf.PutStringLe(m.EndpointUrl); err != nil { return nil, err } diff --git a/opcua/message_open_secure_channel.go b/opcua/message_open_secure_channel.go new file mode 100644 index 0000000..61e3617 --- /dev/null +++ b/opcua/message_open_secure_channel.go @@ -0,0 +1,46 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageOpenSecureChannel struct { + SecureChannelId uint32 + SecurityPolicyUri string + SenderCertificate []byte + ReceiverCertificateThumbprint string + SequenceNumber uint32 + RequestId uint32 +} + +func DecodeMessageOpenSecureChannel(buf *buffer.Buffer) (msg *MessageOpenSecureChannel, err error) { + msg = &MessageOpenSecureChannel{} + return msg, nil +} + +func (m *MessageOpenSecureChannel) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + length += StrLen(m.SecurityPolicyUri) + // todo senderCertificate + length += 4 + // todo receiverCertificateThumbprint + length += 4 + length += LenSequenceNumber + length += LenRequestId + return length +} + +func (m *MessageOpenSecureChannel) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'O', 'P', 'N'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + if err := buf.PutUInt32Le(uint32(m.Length())); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_open_secure_channel_test.go b/opcua/message_open_secure_channel_test.go new file mode 100644 index 0000000..f750f20 --- /dev/null +++ b/opcua/message_open_secure_channel_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageOpenSecureChannel(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4f504e4684000000000000002f000000687474703a2f2f6f7063666f756e646174696f6e2e6f72672f55412f5365637572697479506f6c696379234e6f6e65ffffffffffffffff01000000010000000100be0100000092a8cbf780d9010000000000000000ffffffff60ea0000000000000000000000000001000000ffffffff80ee3600") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageOpenSecureChannel(t *testing.T) { + msg := &MessageOpenSecureChannel{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_read_req.go b/opcua/message_read_req.go new file mode 100644 index 0000000..ea58dbb --- /dev/null +++ b/opcua/message_read_req.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageReadReq struct { +} + +func DecodeMessageReadReq(buf *buffer.Buffer) (msg *MessageReadReq, err error) { + msg = &MessageReadReq{} + return msg, nil +} + +func (m *MessageReadReq) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageReadReq) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_read_req_test.go b/opcua/message_read_req_test.go new file mode 100644 index 0000000..d50e94e --- /dev/null +++ b/opcua/message_read_req_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageReadReq(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d534746800000000200000001000000e4000000e4000000010077020500002000000048cce1823313199f88bb583a480954a576d4fae160deef9bf25daa6e50bfbc39fa284e3c15fcda01e400000000000000ffffffffa00f0000000000000000000000000000000000010000000100d3080d000000ffffffff0000ffffffff") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageReadReq(t *testing.T) { + msg := &MessageReadReq{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/message_read_resp.go b/opcua/message_read_resp.go new file mode 100644 index 0000000..db31338 --- /dev/null +++ b/opcua/message_read_resp.go @@ -0,0 +1,30 @@ +package opcua + +import "github.com/shoothzj/gox/buffer" + +type MessageReadResp struct { +} + +func DecodeMessageReadResp(buf *buffer.Buffer) (msg *MessageReadResp, err error) { + msg = &MessageReadResp{} + return msg, nil +} + +func (m *MessageReadResp) Length() int { + length := 0 + length += LenMessageType + length += LenChunkType + length += LenMessageSize + return length +} + +func (m *MessageReadResp) Buffer() (*buffer.Buffer, error) { + buf := buffer.NewBuffer(m.Length()) + if _, err := buf.Write([]byte{'M', 'S', 'G'}); err != nil { + return nil, err + } + if _, err := buf.Write([]byte{'F'}); err != nil { + return nil, err + } + return buf, nil +} diff --git a/opcua/message_read_resp_test.go b/opcua/message_read_resp_test.go new file mode 100644 index 0000000..c7db845 --- /dev/null +++ b/opcua/message_read_resp_test.go @@ -0,0 +1,19 @@ +package opcua + +import ( + "github.com/shoothzj/gox/testx" + "github.com/stretchr/testify/require" + "testing" +) + +func TestDecodeMessageReadResp(t *testing.T) { + buffer := testx.Hex2Buffer(t, "4d5347464a00000002000000010000001a040000e400000001007a02207b4e3c15fcda01e40000000000000000ffffffff00000001000000050600000000206b273c15fcda01ffffffff") + err := buffer.Skip(8) + require.Nil(t, err) +} + +func TestEncodeMessageReadResp(t *testing.T) { + msg := &MessageReadResp{} + _, err := msg.Buffer() + require.Nil(t, err) +} diff --git a/opcua/util.go b/opcua/util.go new file mode 100644 index 0000000..e0af088 --- /dev/null +++ b/opcua/util.go @@ -0,0 +1,5 @@ +package opcua + +func StrLen(str string) int { + return 4 + len([]byte(str)) +}