sync from Azure to LF
Change-Id: I9daba071938fd021b277d8d17d3c0822d23ac100
Signed-off-by: ss412g <shuky.har-noy@intl.att.com>
diff --git a/tools/xapp_mock/Dockerfile b/tools/xapp_mock/Dockerfile
new file mode 100644
index 0000000..48c07ae
--- /dev/null
+++ b/tools/xapp_mock/Dockerfile
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2019 AT&T Intellectual Property.
+#
+# Licensed 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.
+#
+##############################################################################
+
+FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:1-u16.04-nng1.1.1 as ubuntu
+
+WORKDIR /opt/xapp_mock
+COPY . .
+ENV PATH=$PATH:/usr/local/go/bin:/usr/lib/go-1.12/bin
+# Install RMr library and dev files
+RUN wget --content-disposition https://packagecloud.io/o-ran-sc/master/packages/debian/stretch/rmr_1.3.0_amd64.deb/download.deb
+RUN dpkg -i rmr_1.3.0_amd64.deb
+RUN wget --content-disposition https://packagecloud.io/o-ran-sc/master/packages/debian/stretch/rmr-dev_1.3.0_amd64.deb/download.deb
+RUN dpkg -i rmr-dev_1.3.0_amd64.deb
+
+RUN go get github.com/pkg/errors
+RUN go build main/xapp_mock.go
+
+
+
+FROM ubuntu:16.04
+COPY --from=ubuntu /opt/xapp_mock/xapp_mock /opt/xapp_mock/xapp_mock
+COPY --from=ubuntu /opt/xapp_mock/resources /opt/xapp_mock/resources
+COPY --from=ubuntu /usr/local/lib/librmr_nng.so.1 /usr/local/lib/librmr_nng.so.1
+COPY --from=ubuntu /usr/local/lib/libnng.so.1 /usr/local/lib/libnng.so.1
+WORKDIR /opt/xapp_mock
+ENV LD_LIBRARY_PATH=/usr/local/lib
+ENV RMR_SEED_RT=resources/router.txt
+ENV RMR_PORT=5001
+#CMD mkdir -p resources/conf exec ./xapp_mock
+CMD mkdir -p resources/conf && exec /bin/bash
diff --git a/tools/xapp_mock/configuration.json b/tools/xapp_mock/configuration.json
new file mode 100644
index 0000000..9df43a1
--- /dev/null
+++ b/tools/xapp_mock/configuration.json
@@ -0,0 +1,4 @@
+[
+ {“id”: “RIC_X2_SETUP_REQ” , “rmrMessageType”: 10060, “transactionId”: “e2e$”, “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”, “packedPayload”: "3137322e31372e302e357c353537377c74657374327c34367c0006002a000002001500080013302300fffff000140017000001f700133023fffff0000000133023000000000001" },
+ {“id”: “RIC_ENB_CONF_UPDATE_ACK_positive” , “rmrMessageType”: 10081, “transactionId”: “e2e$”, “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”, “packedPayload”: "2025000a00000100f70003000000" }
+]
diff --git a/tools/xapp_mock/frontend/configfile.go b/tools/xapp_mock/frontend/configfile.go
new file mode 100644
index 0000000..f332a0c
--- /dev/null
+++ b/tools/xapp_mock/frontend/configfile.go
@@ -0,0 +1,56 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 frontend
+
+import (
+ "github.com/pkg/errors"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func ProcessConfigurationFile(resourcesFolder, inputFolder, suffix string, processor func(data []byte) error) error {
+ cwd, err := os.Getwd()
+ if err != nil {
+ return errors.New(err.Error())
+ }
+ inputDir := filepath.Join(cwd, resourcesFolder, inputFolder)
+
+ files, err := ioutil.ReadDir(inputDir)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+
+ for _, file := range files {
+ if file.Mode().IsRegular() && strings.HasSuffix(strings.ToLower(file.Name()), suffix) {
+ filespec := filepath.Join(inputDir, file.Name())
+
+ data, err := ioutil.ReadFile(filespec)
+ if err != nil {
+ return errors.New(err.Error())
+ }
+
+ err = processor(data)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/tools/xapp_mock/frontend/jsonDecoder.go b/tools/xapp_mock/frontend/jsonDecoder.go
new file mode 100644
index 0000000..0609db2
--- /dev/null
+++ b/tools/xapp_mock/frontend/jsonDecoder.go
@@ -0,0 +1,80 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 frontend
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "github.com/pkg/errors"
+ "io"
+)
+
+const (
+ SendRmrMessage = "send"
+ ReceiveRmrMessage = "receive"
+)
+
+
+type JsonCommand struct {
+ Id string
+ RmrMessageType string
+ TransactionId string
+ RanName string
+ RanIp string
+ RanPort int
+ PayloadHeader string
+ PackedPayload string
+ Payload string
+ Action string
+ WaitForRmrMessageType string
+}
+
+// Id -> Command
+var Configuration = make(map[string]*JsonCommand)
+// Rmr Message Id -> Command
+var WaitedForRmrMessageType = make(map[int]*JsonCommand)
+
+func JsonCommandDecoder(data []byte, processor func (*JsonCommand) error ) error {
+ dec := json.NewDecoder(bytes.NewReader(data))
+ var cmd JsonCommand
+ if err := dec.Decode(&cmd); err != nil && err != io.EOF {
+ return errors.New(err.Error())
+ }
+ if err := processor (&cmd); err != nil {
+ return err
+ }
+ return nil
+}
+
+func JsonCommandsDecoder(data []byte, processor func (*JsonCommand) error ) error {
+ dec := json.NewDecoder(bytes.NewReader(data))
+ for {
+ var commands []JsonCommand
+ if err := dec.Decode(&commands); err == io.EOF {
+ break
+ } else if err != nil {
+ return errors.New(err.Error())
+ }
+ for i, cmd := range commands {
+ if err := processor(&cmd); err != nil {
+ return errors.New(fmt.Sprintf("processing error at #%d, %s",i,err))
+ }
+ }
+ }
+ return nil
+}
diff --git a/tools/xapp_mock/main/xapp_mock.go b/tools/xapp_mock/main/xapp_mock.go
new file mode 100644
index 0000000..ae2c601
--- /dev/null
+++ b/tools/xapp_mock/main/xapp_mock.go
@@ -0,0 +1,109 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 main
+
+import (
+ "../frontend"
+ "../rmr"
+ "../sender"
+ "flag"
+ "fmt"
+ "github.com/pkg/errors"
+ "log"
+ "os"
+ "strconv"
+)
+
+const (
+ ENV_RMR_PORT = "RMR_PORT"
+ RMR_PORT_DEFAULT = 5001
+)
+
+var rmrService *rmr.Service
+
+func main() {
+ var rmrContext *rmr.Context
+
+ var rmrConfig rmr.Config = rmr.Config{Port: RMR_PORT_DEFAULT, MaxMsgSize: rmr.RMR_MAX_MSG_SIZE, MaxRetries: 3, Flags: 0}
+ if port, err := strconv.ParseUint(os.Getenv(ENV_RMR_PORT), 10, 16); err == nil {
+ rmrConfig.Port = int(port)
+ } else {
+ log.Printf("%s: %s, using default (%d).", ENV_RMR_PORT, err,RMR_PORT_DEFAULT)
+ }
+ rmrService = rmr.NewService(rmrConfig, rmrContext)
+
+ /* Load configuration file*/
+ err := frontend.ProcessConfigurationFile("resources","conf", ".json",
+ func(data []byte) error {
+ return frontend.JsonCommandsDecoder(data,jsonCommandsDecoderCB)
+ })
+ if err != nil {
+ log.Fatalf("processing Error: %s", err)
+ }
+
+ log.Print("xapp_mock is up and running.")
+
+ cmd:= flag.Arg(0) /*first remaining argument after flags have been processed*/
+ if err := frontend.JsonCommandDecoder([]byte(cmd),jsonCommandDecoderCB); err != nil {
+ log.Printf("command processing Error: %s", err)
+ }
+
+ rmrService.CloseContext()
+
+ log.Print("xapp_mock is down.")
+}
+
+
+// TODO: move callbacks to Dispatcher.
+func jsonCommandsDecoderCB(command *frontend.JsonCommand) error {
+ if len(command.Id) == 0{
+ return errors.New(fmt.Sprintf("invalid command, no Id"))
+ }
+ frontend.Configuration[command.Id] = command
+ if rmrMsgId, err := rmr.MessageIdToUint(command.WaitForRmrMessageType); err != nil {
+ return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType))
+ } else {
+ frontend.WaitedForRmrMessageType[int(rmrMsgId)] = command
+ }
+ return nil
+}
+
+// TODO: merge command with configuration
+func jsonCommandDecoderCB(command *frontend.JsonCommand) error {
+ if len(command.Id) == 0{
+ return errors.New(fmt.Sprintf("invalid command, no Id"))
+ }
+ switch command.Action {
+ case frontend.SendRmrMessage:
+ if err := sender.SendJsonRmrMessage(*command, nil, rmrService); err != nil {
+ return err
+ }
+ if len(command.WaitForRmrMessageType) > 0 {
+ rmrService.ListenAndHandle() //TODO: handle error
+ }
+ case frontend.ReceiveRmrMessage:
+ if rmrMsgId, err := rmr.MessageIdToUint(command.RmrMessageType); err != nil {
+ return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType))
+ } else {
+ frontend.WaitedForRmrMessageType[int(rmrMsgId)] = command
+ }
+ rmrService.ListenAndHandle() //TODO: handle error
+ default:
+ return errors.New(fmt.Sprintf("invalid command action %s", command.Action))
+ }
+ return nil
+}
\ No newline at end of file
diff --git a/tools/xapp_mock/resources/router.txt b/tools/xapp_mock/resources/router.txt
new file mode 100644
index 0000000..1d3fea3
--- /dev/null
+++ b/tools/xapp_mock/resources/router.txt
@@ -0,0 +1,4 @@
+newrt|start
+rte|1001|10.0.2.15:38000
+rte|2002|10.0.2.15:3801
+newrt|end
diff --git a/tools/xapp_mock/resp b/tools/xapp_mock/resp
new file mode 100644
index 0000000..01f2657
--- /dev/null
+++ b/tools/xapp_mock/resp
@@ -0,0 +1 @@
+20060043000002001500080002f82900007a8000140030010000630002f8290007ab50102002f8290000010001330000640002f9290007ac50203202f82902f929000002000344
diff --git a/tools/xapp_mock/rmr/rmrCgoApi.go b/tools/xapp_mock/rmr/rmrCgoApi.go
new file mode 100644
index 0000000..7686ea8
--- /dev/null
+++ b/tools/xapp_mock/rmr/rmrCgoApi.go
@@ -0,0 +1,104 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 rmr
+
+// #cgo LDFLAGS: -L/usr/local/lib -lrmr_nng -lnng
+// #include <rmr/rmr.h>
+// #include <stdlib.h>
+import "C"
+import (
+ "fmt"
+ "github.com/pkg/errors"
+ "time"
+ "unsafe"
+)
+
+func (*Context) Init(port string, maxMsgSize int, maxRetries int, flags int) *Messenger {
+ pp := C.CString(port)
+ defer C.free(unsafe.Pointer(pp))
+ ctx := NewContext(maxMsgSize, maxRetries, flags, C.rmr_init(pp, C.int(maxMsgSize), C.int(flags)))
+ start := time.Now()
+ for !ctx.IsReady() {
+ time.Sleep(time.Second)
+ if time.Since(start) >= time.Minute {
+ start = time.Now()
+ }
+ }
+ // Configure the rmr to make rounds of attempts to send a message before notifying the application that it should retry.
+ // Each round is about 1000 attempts with a short sleep between each round.
+ C.rmr_set_stimeout(ctx.RmrCtx, C.int(0))
+ r := Messenger(ctx)
+ return &r
+}
+
+func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) {
+
+ allocatedCMBuf, err := ctx.getAllocatedCRmrMBuf(msg, ctx.MaxMsgSize)
+ if err != nil{
+ return nil, err
+ }
+ if state := allocatedCMBuf.state; state != RMR_OK {
+ errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to get allocated message. state: %v - %s", state, states[int(state)])
+ return nil, errors.New(errorMessage)
+ }
+ defer C.rmr_free_msg(allocatedCMBuf)
+
+ for i:=0; i < ctx.MaxRetries; i++ {
+ currCMBuf := C.rmr_send_msg(ctx.RmrCtx, allocatedCMBuf)
+ if state := currCMBuf.state; state != RMR_OK {
+ if state != RMR_ERR_RETRY {
+ errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to send message. state: %v - %s", state, states[int(state)])
+ return nil, errors.New(errorMessage)
+ }
+ time.Sleep(100*time.Millisecond)
+ continue
+ }
+ return convertToMBuf(currCMBuf)
+ }
+
+ return nil, errors.New(fmt.Sprintf("#rmrCgoApi.SendMsg - Too many retries"))
+}
+
+func (ctx *Context) RecvMsg() (*MBuf, error) {
+ allocatedCMBuf, err :=C.rmr_alloc_msg(ctx.RmrCtx, C.int(ctx.MaxMsgSize))
+ if err != nil{
+ return nil, err
+ }
+ if state := allocatedCMBuf.state;state != RMR_OK {
+ errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to get allocated message. state: %v - %s", state, states[int(state)])
+ return nil, errors.New(errorMessage)
+ }
+ defer C.rmr_free_msg(allocatedCMBuf)
+
+ currCMBuf := C.rmr_rcv_msg(ctx.RmrCtx, allocatedCMBuf)
+ if state := currCMBuf.state; state != RMR_OK {
+ errorMessage := fmt.Sprintf("#rmrCgoApi.RecvMsg - Failed to receive message. state: %v - %s", state, states[int(state)])
+ return nil, errors.New(errorMessage)
+ }
+
+ return convertToMBuf(currCMBuf)
+}
+
+
+func (ctx *Context) IsReady() bool {
+ return int(C.rmr_ready(ctx.RmrCtx)) != 0
+}
+
+func (ctx *Context) Close() {
+ C.rmr_close(ctx.RmrCtx)
+}
diff --git a/tools/xapp_mock/rmr/rmrCgoTypes.go b/tools/xapp_mock/rmr/rmrCgoTypes.go
new file mode 100644
index 0000000..54d4f8f
--- /dev/null
+++ b/tools/xapp_mock/rmr/rmrCgoTypes.go
@@ -0,0 +1,123 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 rmr
+
+// #cgo LDFLAGS: -L/usr/local/lib -lrmr_nng -lnng
+// #include <rmr/rmr.h>
+// #include <stdlib.h>
+import "C"
+import (
+ "fmt"
+ "unsafe"
+)
+
+func NewMBuf(mType int, len int, payload []byte, xAction []byte) *MBuf {
+ return &MBuf{
+ MType: mType,
+ Len: len,
+ Payload: payload,
+ XAction: xAction,
+ }
+}
+
+func NewContext(maxMsgSize int, maxRetries, flags int, ctx unsafe.Pointer) *Context {
+ return &Context{
+ MaxMsgSize: maxMsgSize,
+ MaxRetries: maxRetries,
+ Flags: flags,
+ RmrCtx: ctx,
+ }
+}
+
+const (
+ RMR_MAX_XACTION_LEN = int(C.RMR_MAX_XID)
+ RMR_MAX_MSG_SIZE = int(C.RMR_MAX_RCV_BYTES)
+ RMR_MAX_MEID_LEN = int(C.RMR_MAX_MEID)
+
+ //states
+ RMR_OK = C.RMR_OK
+ RMR_ERR_BADARG = C.RMR_ERR_BADARG
+ RMR_ERR_NOENDPT = C.RMR_ERR_NOENDPT
+ RMR_ERR_EMPTY = C.RMR_ERR_EMPTY
+ RMR_ERR_NOHDR = C.RMR_ERR_NOHDR
+ RMR_ERR_SENDFAILED = C.RMR_ERR_SENDFAILED
+ RMR_ERR_CALLFAILED = C.RMR_ERR_CALLFAILED
+ RMR_ERR_NOWHOPEN = C.RMR_ERR_NOWHOPEN
+ RMR_ERR_WHID = C.RMR_ERR_WHID
+ RMR_ERR_OVERFLOW = C.RMR_ERR_OVERFLOW
+ RMR_ERR_RETRY = C.RMR_ERR_RETRY
+ RMR_ERR_RCVFAILED = C.RMR_ERR_RCVFAILED
+ RMR_ERR_TIMEOUT = C.RMR_ERR_TIMEOUT
+ RMR_ERR_UNSET = C.RMR_ERR_UNSET
+ RMR_ERR_TRUNC = C.RMR_ERR_TRUNC
+ RMR_ERR_INITFAILED = C.RMR_ERR_INITFAILED
+)
+
+var states = map[int]string{
+ RMR_OK: "state is good",
+ RMR_ERR_BADARG: "argument passd to function was unusable",
+ RMR_ERR_NOENDPT: "send/call could not find an endpoint based on msg type",
+ RMR_ERR_EMPTY: "msg received had no payload; attempt to send an empty message",
+ RMR_ERR_NOHDR: "message didn't contain a valid header",
+ RMR_ERR_SENDFAILED: "send failed; errno has nano reason",
+ RMR_ERR_CALLFAILED: "unable to send call() message",
+ RMR_ERR_NOWHOPEN: "no wormholes are open",
+ RMR_ERR_WHID: "wormhole id was invalid",
+ RMR_ERR_OVERFLOW: "operation would have busted through a buffer/field size",
+ RMR_ERR_RETRY: "request (send/call/rts) failed, but caller should retry (EAGAIN for wrappers)",
+ RMR_ERR_RCVFAILED: "receive failed (hard error)",
+ RMR_ERR_TIMEOUT: "message processing call timed out",
+ RMR_ERR_UNSET: "the message hasn't been populated with a transport buffer",
+ RMR_ERR_TRUNC: "received message likely truncated",
+ RMR_ERR_INITFAILED: "initialisation of something (probably message) failed",
+}
+
+type MBuf struct {
+ MType int
+ Len int
+ Meid string //Managed entity id (RAN name)*/
+ Payload []byte
+ XAction []byte
+}
+
+
+func (m MBuf) String() string {
+ return fmt.Sprintf("{ MType: %d, Len: %d, Meid: %q, Xaction: %q, Payload: [%x] }", m.MType, m.Len, m.Meid, m.XAction, m.Payload)
+}
+
+
+type Context struct {
+ MaxMsgSize int
+ MaxRetries int
+ Flags int
+ RmrCtx unsafe.Pointer
+}
+
+type Messenger interface {
+ Init(port string, maxMsgSize int, maxRetries int, flags int) *Messenger
+ SendMsg(msg *MBuf) (*MBuf, error)
+ RecvMsg() (*MBuf, error)
+ IsReady() bool
+ Close()
+}
+type Config struct {
+ Port int
+ MaxMsgSize int
+ MaxRetries int
+ Flags int
+}
diff --git a/tools/xapp_mock/rmr/rmrCgoUtils.go b/tools/xapp_mock/rmr/rmrCgoUtils.go
new file mode 100644
index 0000000..9b56785
--- /dev/null
+++ b/tools/xapp_mock/rmr/rmrCgoUtils.go
@@ -0,0 +1,116 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 rmr
+
+// #cgo LDFLAGS: -L/usr/local/lib -lrmr_nng -lnng
+// #include <rmr/rmr.h>
+// #include <stdlib.h>
+import "C"
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "github.com/pkg/errors"
+ "strconv"
+ "strings"
+ "unsafe"
+)
+
+/*
+Allocates an mBuf and initialize it with the content of C.rmr_mbuf_t.
+The xAction field is assigned a a value without trailing spaces.
+*/
+func convertToMBuf( m *C.rmr_mbuf_t) (*MBuf, error) {
+ payloadArr := C.GoBytes(unsafe.Pointer(m.payload),C.int(m.len))
+ xActionArr := C.GoBytes(unsafe.Pointer(m.xaction),C.int(RMR_MAX_XACTION_LEN))
+
+ // Trim padding (space and 0)
+ xActionStr := strings.TrimRight(string(xActionArr), "\040\000")
+ xActionArr = []byte(xActionStr)
+
+ mbuf := &MBuf{
+ MType: int(m.mtype),
+ Len: int(m.len),
+ //Payload: (*[]byte)(unsafe.Pointer(m.payload)),
+ Payload: payloadArr,
+ //XAction: (*[]byte)(unsafe.Pointer(m.xaction)),
+ XAction: xActionArr,
+ }
+
+ meidBuf := make([]byte, RMR_MAX_MEID_LEN)
+ if meidCstr := C.rmr_get_meid(m, (*C.uchar)(unsafe.Pointer(&meidBuf[0]))); meidCstr != nil {
+ mbuf.Meid = strings.TrimRight(string(meidBuf), "\000")
+ }
+
+ return mbuf, nil
+}
+
+/*
+Allocates an C.rmr_mbuf_t and initialize it with the content of mBuf.
+The xAction field is padded with trailing spaces upto capacity
+*/
+func (ctx *Context) getAllocatedCRmrMBuf( mBuf *MBuf, maxMsgSize int) (cMBuf *C.rmr_mbuf_t, rc error) {
+ var xActionBuf [RMR_MAX_XACTION_LEN]byte
+ var meidBuf[RMR_MAX_MEID_LEN]byte
+
+ cMBuf = C.rmr_alloc_msg(ctx.RmrCtx, C.int(maxMsgSize))
+ cMBuf.mtype = C.int(mBuf.MType)
+ cMBuf.len = C.int(mBuf.Len)
+
+ payloadLen := len(mBuf.Payload)
+ xActionLen := len(mBuf.XAction)
+
+ copy(xActionBuf[:], mBuf.XAction)
+ for i:= xActionLen; i < RMR_MAX_XACTION_LEN; i++{
+ xActionBuf[i] = '\040' //space
+ }
+
+ // Add padding
+ copy(meidBuf[:], mBuf.Meid)
+ for i:= len(mBuf.Meid); i < RMR_MAX_MEID_LEN; i++{
+ meidBuf[i] = 0
+ }
+
+ payloadArr := (*[1 << 30]byte)(unsafe.Pointer(cMBuf.payload))[:payloadLen:payloadLen]
+ xActionArr := (*[1 << 30]byte)(unsafe.Pointer(cMBuf.xaction))[:RMR_MAX_XACTION_LEN:RMR_MAX_XACTION_LEN]
+
+ err := binary.Read(bytes.NewReader(mBuf.Payload), binary.LittleEndian, payloadArr)
+ if err != nil {
+ return nil, errors.New(fmt.Sprintf("#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to read payload to allocated RMR message buffer, %s", err))
+ }
+ err = binary.Read(bytes.NewReader(xActionBuf[:]), binary.LittleEndian, xActionArr)
+ if err != nil {
+ return nil, errors.New(fmt.Sprintf("#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to read xAction data to allocated RMR message buffer, %s", err))
+ }
+
+ len := C.rmr_bytes2meid(cMBuf, (*C.uchar)(unsafe.Pointer(&meidBuf[0])), C.int(RMR_MAX_XACTION_LEN))
+ if int(len) != RMR_MAX_MEID_LEN {
+ return nil, errors.New(
+ "#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to copy meid data to allocated RMR message buffer")
+ }
+ return cMBuf,nil
+}
+
+func MessageIdToUint(id string) (msgId uint64, err error) {
+ if len(id) == 0 {
+ msgId, err = 0, nil
+ } else{
+ msgId, err = strconv.ParseUint(id, 10, 16)
+ }
+ return
+}
\ No newline at end of file
diff --git a/tools/xapp_mock/rmr/rmrEndPoint.go b/tools/xapp_mock/rmr/rmrEndPoint.go
new file mode 100644
index 0000000..fc599a5
--- /dev/null
+++ b/tools/xapp_mock/rmr/rmrEndPoint.go
@@ -0,0 +1,68 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 rmr
+
+import (
+ "../frontend"
+ "log"
+ "strconv"
+)
+// RmrService holds an instance of RMR messenger as well as its configuration
+type Service struct {
+ messenger *Messenger
+}
+
+// NewRmrService instantiates a new Rmr service instance
+func NewService(rmrConfig Config, messenger Messenger) *Service {
+ return &Service{
+ messenger: messenger.Init("tcp:"+strconv.Itoa(rmrConfig.Port), rmrConfig.MaxMsgSize, rmrConfig.MaxRetries, rmrConfig.Flags),
+ }
+}
+
+func (r *Service) SendMessage(messageType int, msg []byte, transactionId []byte) (*MBuf, error){
+ log.Printf( "SendMessage (type: %d, tid: %s, msg: %v", messageType, transactionId, msg)
+ mbuf := NewMBuf(messageType, len(msg), msg, transactionId)
+ return (*r.messenger).SendMsg(mbuf)
+}
+
+// ListenAndHandle waits for messages coming from rmr_rcv_msg and sends it to a designated message handler
+func (r *Service) ListenAndHandle() error {
+ for {
+ mbuf, err := (*r.messenger).RecvMsg()
+
+ if err != nil {
+ return err
+ }
+
+ if _, ok := frontend.WaitedForRmrMessageType[mbuf.MType]; ok {
+ log.Printf( "ListenAndHandle Expected msg: %s", mbuf)
+ break
+ } else {
+ log.Printf( "ListenAndHandle Unexpected msg: %s", mbuf)
+ }
+ }
+ return nil
+}
+
+
+func (r *Service) CloseContext() {
+ (*r.messenger).Close()
+
+}
+
+
+
diff --git a/tools/xapp_mock/sender/jsonSender.go b/tools/xapp_mock/sender/jsonSender.go
new file mode 100644
index 0000000..b68ee9d
--- /dev/null
+++ b/tools/xapp_mock/sender/jsonSender.go
@@ -0,0 +1,146 @@
+//
+// Copyright 2019 AT&T Intellectual Property
+// Copyright 2019 Nokia
+//
+// Licensed 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 sender
+
+import (
+ "../frontend"
+ "../rmr"
+ "fmt"
+ "github.com/pkg/errors"
+ "log"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync/atomic"
+ "time"
+ "unicode"
+)
+
+var counter uint64
+
+func SendJsonRmrMessage(command frontend.JsonCommand /*the copy is modified locally*/, xAction *[]byte, r *rmr.Service) error {
+ var payload []byte
+ _, err := fmt.Sscanf(command.PackedPayload, "%x", &payload)
+ if err != nil {
+ return errors.New(fmt.Sprintf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err))
+ }
+ command.PackedPayload = string(payload)
+ command.TransactionId = expandTransactionId(command.TransactionId)
+ if len(command.TransactionId) == 0 {
+ command.TransactionId = string(*xAction)
+ }
+ command.PayloadHeader = expandPayloadHeader(command.PayloadHeader, &command)
+ rmrMsgId, err := rmr.MessageIdToUint(command.RmrMessageType)
+ if err != nil {
+ return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType))
+ }
+ _, err = r.SendMessage(int(rmrMsgId), append([]byte(command.PayloadHeader), payload...), []byte(command.TransactionId))
+ return err
+}
+
+/*
+ * transactionId (xAction): The value may have a fixed value or $ or <prefix>$.
+ * $ is replaced by a value generated at runtime (possibly unique per message sent).
+ * If the tag does not exist, then the mock shall use the value taken from the incoming message.
+ */
+func expandTransactionId(id string) string {
+ if len(id) == 1 && id[0] == '$' {
+ return fmt.Sprintf("%d", incAndGetCounter())
+ }
+ if len(id) > 1 && id[len(id)-1] == '$' {
+ return fmt.Sprintf("%s%d", id[:len(id)-1], incAndGetCounter())
+ }
+ return id
+}
+
+/*
+ * payloadHeader: A prefix to combine with the payload that will be the message’s payload. The value may include variables of the format $<name> or #<name> where:
+ * $<name> expands to the value of <name> if it exists or the empty string if not.
+ * #<name> expands to the length of the value of <name> if it exists or omitted if not.
+ * The intention is to allow the Mock to construct the payload header required by the setup messages (ranIp|ranPort|ranName|payload len|<payload>).
+ * Example: “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”
+ */
+
+func expandPayloadHeader(header string, command *frontend.JsonCommand) string {
+ var name strings.Builder
+ var expandedHeader strings.Builder
+
+ r := strings.NewReader(header)
+ ch, err := r.ReadByte()
+ for {
+ if err != nil {
+ break
+ }
+ switch ch {
+ case '$':
+ for {
+ ch, err = r.ReadByte() //on error ch == 0
+ if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) {
+ name.WriteByte(ch)
+ } else {
+ if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() {
+ switch fieldValue.Kind() {
+ case reflect.String:
+ expandedHeader.WriteString(fieldValue.String())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ expandedHeader.WriteString(strconv.FormatInt(fieldValue.Int(), 10))
+ case reflect.Bool:
+ expandedHeader.WriteString(strconv.FormatBool(fieldValue.Bool()))
+ case reflect.Float64, reflect.Float32:
+ expandedHeader.WriteString(fmt.Sprintf("%g", fieldValue.Float()))
+ default:
+ log.Fatalf("invalid type for $%s, value must be a string, an int, a bool or a float", name.String())
+ }
+ }
+ name.Reset()
+ break
+ }
+ }
+ case '#':
+ for {
+ ch, err = r.ReadByte() //on error ch == 0
+ if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) {
+ name.WriteByte(ch)
+ } else {
+ if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() {
+ if fieldValue.Kind() == reflect.String {
+ expandedHeader.WriteString(strconv.FormatInt(int64(len(fieldValue.String())), 10))
+ } else {
+ log.Fatalf("invalid type for #%s, value must be a string", name.String())
+ }
+ }
+ name.Reset()
+ break
+ }
+ }
+ default:
+ if unicode.IsPrint(rune(ch)) {
+ expandedHeader.WriteByte(ch)
+ }
+ ch, err = r.ReadByte()
+ }
+ }
+ return expandedHeader.String()
+}
+
+func incAndGetCounter() uint64 {
+ return atomic.AddUint64(&counter, 1)
+}
+
+func init() {
+ counter = uint64(time.Now().Second())
+}