Initial commit of source directory 79/2879/6
authorsjana <sj492a@att.com>
Thu, 19 Mar 2020 16:06:12 +0000 (12:06 -0400)
committersjana <sj492a@att.com>
Thu, 19 Mar 2020 16:56:07 +0000 (12:56 -0400)
Issue-ID: RICAPP-63

Signed-off-by: sjana <sj492a@att.com>
Change-Id: I6a13d89aa00887369187928acd5b14d31c1d6368

39 files changed:
src/Makefile [new file with mode: 0755]
src/README [new file with mode: 0644]
src/hw_xapp_main.cc [new file with mode: 0644]
src/routes.txt [new file with mode: 0644]
src/run_xapp.sh [new file with mode: 0755]
src/xapp-asn/e2ap/e2ap_control.cc [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_control.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_control_helper.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_control_response.cc [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_control_response.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_indication.cc [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_indication.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/e2ap_indication_helper.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/generic_helpers.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/response_helper.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_delete_request.cc [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_delete_request.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_delete_response.cc [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_delete_response.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_helper.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_request.cc [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_request.hpp [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_response.cc [new file with mode: 0644]
src/xapp-asn/e2ap/subscription_response.hpp [new file with mode: 0644]
src/xapp-asn/e2sm/e2sm.cc [new file with mode: 0644]
src/xapp-asn/e2sm/e2sm.hpp [new file with mode: 0644]
src/xapp-asn/e2sm/e2sm_helpers.hpp [new file with mode: 0644]
src/xapp-mgmt/msgs_proc.cc [new file with mode: 0644]
src/xapp-mgmt/msgs_proc.hpp [new file with mode: 0644]
src/xapp-mgmt/subs_mgmt.cc [new file with mode: 0644]
src/xapp-mgmt/subs_mgmt.hpp [new file with mode: 0644]
src/xapp-utils/xapp_config.cc [new file with mode: 0644]
src/xapp-utils/xapp_config.hpp [new file with mode: 0644]
src/xapp-utils/xapp_rmr.cc [new file with mode: 0755]
src/xapp-utils/xapp_rmr.hpp [new file with mode: 0755]
src/xapp-utils/xapp_sdl.cc [new file with mode: 0644]
src/xapp-utils/xapp_sdl.hpp [new file with mode: 0644]
src/xapp.cc [new file with mode: 0644]
src/xapp.hpp [new file with mode: 0644]

diff --git a/src/Makefile b/src/Makefile
new file mode 100755 (executable)
index 0000000..700b0d5
--- /dev/null
@@ -0,0 +1,76 @@
+CXX:= g++ --std=c++14 -O2
+CC:= gcc -O2
+
+SRC:=./
+HWSRC:=./
+UTILSRC=./xapp-utils
+MSGSRC:=./xapp-mgmt
+
+ASNSRC:=../asn1c_defs
+E2APSRC:=./xapp-asn/e2ap
+E2SMSRC:=./xapp-asn/e2sm
+
+####### Logging library and flags
+CLOGFLAGS:= `pkg-config mdclog --cflags`
+LOG_LIBS:= `pkg-config mdclog --libs`
+CURL_LIBS:= `pkg-config libcurl --libs`
+
+######## Keep include dirs separate so we have transparency
+BASEFLAGS=  -Wall  -std=c++14 $(CLOGFLAGS) 
+C_BASEFLAGS= -Wall $(CLOGFLAGS) -DASN_DISABLE_OER_SUPPORT
+
+XAPPFLAGS= -I./
+HWFLAGS= -I./
+UTILFLAGS= -I$(UTILSRC)
+MSGFLAGS= -I$(MSGSRC)
+
+ASNFLAGS=-I$(ASNSRC) -DASN_DISABLE_OER_SUPPORT
+E2APFLAGS = -I$(E2APSRC)
+E2SMFLAGS = -I$(E2SMSRC)
+
+########libs
+LIBS= -lsdl -lrmr_nng  -lnng -lpthread -lm $(LOG_LIBS) $(CURL_LIBS) 
+COV_FLAGS= -fprofile-arcs -ftest-coverage
+
+#######
+HWXAPP_SRC= hw_xapp_main.cc
+XAPP_SRC= xapp.cc
+UTIL_SRC= $(wildcard $(UTILSRC)/*.cc)
+MSG_SRC= $(wildcard $(MSGSRC)/*.cc)
+
+E2AP_SRC= $(wildcard $(E2APSRC)/*.cc)
+E2SM_SRC= $(wildcard $(E2SMSRC)/*.cc)
+ASN1C_SRC= $(wildcard $(ASNSRC)/*.c)
+
+##############Objects
+UTIL_OBJ=${UTIL_SRC:.cc=.o}
+XAPP_OBJ=${XAPP_SRC:.cc=.o}
+HWXAPP_OBJ= ${HWXAPP_SRC:.cc=.o} 
+MSG_OBJ= ${MSG_SRC:.cc=.o}
+
+E2AP_OBJ = $(E2AP_SRC:.cc=.o)
+E2SM_OBJ = $(E2SM_SRC:.cc=.o)
+ASN1C_MODULES = $(ASN1C_SRC:.c=.o)
+
+$(ASN1C_MODULES): export CFLAGS = $(C_BASEFLAGS) $(ASNFLAGS)
+$(UTIL_OBJ):export CPPFLAGS=$(BASEFLAGS) $(UTILFLAGS) $(E2APFLAGS) $(E2SMFLAGS) $(ASNFLAGS) $(MSGFLAGS)
+
+$(MSG_OBJ):export CPPFLAGS=$(BASEFLAGS) $(MSGFLAGS) $(ASNFLAGS) $(E2APFLAGS) $(E2SMFLAGS)
+$(E2AP_OBJ): export CPPFLAGS = $(BASEFLAGS) $(ASNFLAGS) $(E2APFLAGS)
+$(E2SM_OBJ): export CPPFLAGS = $(BASEFLAGS) $(ASNFLAGS) $(E2SMFLAGS)
+$(XAPP_OBJ): export CPPFLAGS = $(BASEFLAGS) $(XAPPFLAGS) $(UTILFLAGS) $(MSGFLAGS) $(E2APFLAGS) $(E2SMFLAGS) $(ASNFLAGS)
+
+$(HWXAPP_OBJ):export CPPFLAGS=$(BASEFLAGS) $(HWFLAGS) $(XAPPFLAGS) $(UTILFLAGS) $(MSGFLAGS) $(E2APFLAGS) $(E2SMFLAGS) $(ASNFLAGS)
+
+OBJ= $(HWXAPP_OBJ) $(UTIL_OBJ) $(MSG_OBJ)  $(ASN1C_MODULES) $(E2AP_OBJ) $(E2SM_OBJ) $(XAPP_OBJ)
+
+print-%  : ; @echo $* = $($*)
+
+hw_xapp_main: $(OBJ)
+       $(CXX) -o $@  $(OBJ) $(LIBS) $(CPPFLAGS) $(CLOGFLAGS) 
+
+install: hw_xapp_main
+       install  -D hw_xapp_main  /usr/local/bin/hw_xapp_main
+
+clean:
+       -rm *.o $(ASNSRC)/*.o $(E2APSRC)/*.o $(UTILSRC)/*.o $(E2SMSRC)/*.o  $(MSGSRC)/*.o $(SRC)/*.o hw_xapp_main 
diff --git a/src/README b/src/README
new file mode 100644 (file)
index 0000000..2c70d42
--- /dev/null
@@ -0,0 +1,25 @@
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+
+This repository consists of HelloWorld Xapp developed in C++. Its envisioned to be the most simplest example Xapp. 
+It is required to have following features
+
+1) E2 Subscription Handling
+2) A1 Policy Handling
+3) SDL Access
+4) Health Check
+5)...
diff --git a/src/hw_xapp_main.cc b/src/hw_xapp_main.cc
new file mode 100644 (file)
index 0000000..3c45e6a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * hw_xapp_main.cc
+ * Created on: Dec, 2019
+ * Author: Shraboni Jana
+ */
+
+#include "xapp.hpp"
+#include "subscription_request.hpp"
+#include "xapp_sdl.hpp"
+
+void signalHandler( int signum ) {
+   cout << "Interrupt signal (" << signum << ") received.\n";
+   exit(signum);
+}
+
+int main(int argc, char *argv[]){
+
+       //get configuration
+       XappSettings config;
+       //change the priority depending upon application requirement
+       config.loadDefaultSettings();
+       config.loadEnvVarSettings();
+       config.loadCmdlineSettings(argc, argv);
+
+       //getting the listening port and xapp name info
+       std::string  port = config[XappSettings::SettingName::HW_PORTS];
+       std::string  name = config[XappSettings::SettingName::XAPP_NAME];
+
+
+       //initialize rmr
+       std::unique_ptr<XappRmr> rmr;
+       rmr = std::make_unique<XappRmr>(name,port);
+       rmr->xapp_rmr_init();
+
+       //Register signal handler to stop
+       signal(SIGINT, signalHandler);
+       signal(SIGTERM, signalHandler);
+
+       //Test SDL.
+       XappSDL sdl = XappSDL("hw-xapp");
+
+       //Initiate the Xapp functionality
+       std::unique_ptr<Xapp> hw_xapp = std::make_unique<Xapp>(std::ref(config), std::ref(*rmr),std::ref(sdl));
+
+
+       //define the startup mode.
+       hw_xapp->startup();
+
+       //Register Callback Handlers
+       //Register E2 Msg Handlers - Subscription/Indication.
+       //Register A1 Msg Handlers.
+       //Register Callback Handlers
+
+
+       //start the receiver thread listening at HW_PORT
+       //currently only one receiver thread. In total how many receiver threads depend on the xapp developer.
+       //Register all the handlers required and start the receiver
+
+       //register_msgproc(RIC_SUB_RESP, sub_handler);
+       //register_msgproc(RIC_SUB_DEL_RESP, sub_handler);
+       //register_msgproc(RIC_SUB_FAILURE, sub_handler);
+
+
+       hw_xapp->start_xapp_receiver();
+       sleep(5);
+
+
+       //Delete all subscriptions if any based on Xapp Mode.
+       //xapp->shutdown();
+
+        while(1){
+                               sleep(1);
+                        }
+
+       return 0;
+}
+
+
+
diff --git a/src/routes.txt b/src/routes.txt
new file mode 100644 (file)
index 0000000..3dd7cdd
--- /dev/null
@@ -0,0 +1,19 @@
+newrt|start
+rte|0|localhost:4560
+rte|2|localhost:38000
+rte|100|localhost:4560
+rte|10002|localhost:4560
+rte|10005|localhost:4560
+rte|10003|localhost:38000
+rte|12010|localhost:38000
+rte|12020|localhost:38000
+rte|12011|localhost:4560
+rte|12012|localhost:4560
+rte|12021|localhost:4560
+rte|12022|localhost:4560
+rte|20000|localhost:4560
+rte|12040|localhost:38000
+rte|20001|localhost:4566
+rte|20011|localhost:4560
+rte|20012|localhost:4560
+newrt|end
diff --git a/src/run_xapp.sh b/src/run_xapp.sh
new file mode 100755 (executable)
index 0000000..1eff6b1
--- /dev/null
@@ -0,0 +1,38 @@
+#! /bin/bash
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+export RMR_SEED_RT="routes.txt"
+export RMR_RTG_SVC="9999"
+export XAPP_NAME="HELLOWORLD_XAPP"
+export HW_PORTS="4560"
+export MSG_MAX_BUFFER="2048"
+export THREADS="1"
+export VERBOSE="0"
+export CONFIG_FILE="config/config-file.json"
+export GNODEB="NYC123"
+export XAPP_ID="3489-er492k-92389"
+export A1_SCHEMA_FILE="schemas/hwxapp-policy.json"
+export VES_SCHEMA_FILE="schemas/hwxapp-ves.json"
+export VES_COLLECTOR_URL="127.0.0.1:6350"
+export VES_MEASUREMENT_INTERVAL="10"
+export LOG_LEVEL="MDCLOG_ERR"
+export OPERATING_MODE="CONTROL"
+
+
+
diff --git a/src/xapp-asn/e2ap/e2ap_control.cc b/src/xapp-asn/e2ap/e2ap_control.cc
new file mode 100644 (file)
index 0000000..e66ddec
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_control_request.c
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#include "e2ap_control.hpp"
+
+// Set up memory allocations for each IE for encoding
+// We are responsible for memory management for each IE for encoding
+// Hence destructor should clear out memory
+// When decoding, we rely on asn1c macro (ASN_STRUCT_FREE to be called
+// for releasing memory by external calling function)
+ric_control_request::ric_control_request(void){
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t * )calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  initMsg = 0;
+  initMsg = (E2N_InitiatingMessage_t * )calloc(1, sizeof(E2N_InitiatingMessage_t));
+  assert(initMsg != 0);
+
+  IE_array = 0;
+  IE_array = (E2N_RICcontrolRequest_IEs_t *)calloc(NUM_CONTROL_REQUEST_IES, sizeof(E2N_RICcontrolRequest_IEs_t));
+  assert(IE_array != 0);
+
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_initiatingMessage;
+  e2ap_pdu_obj->choice.initiatingMessage = initMsg;
+
+  
+};
+
+
+// Clear assigned protocolIE list from RIC control_request IE container
+ric_control_request::~ric_control_request(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing E2AP Control Request object memory");
+  
+  E2N_RICcontrolRequest_t *ricControl_Request  = &(initMsg->value.choice.RICcontrolRequest);
+  for(int i = 0; i < ricControl_Request->protocolIEs.list.size; i++){
+    ricControl_Request->protocolIEs.list.array[i] = 0;
+  }
+  
+  if (ricControl_Request->protocolIEs.list.size > 0){
+    free(ricControl_Request->protocolIEs.list.array);
+    ricControl_Request->protocolIEs.list.size = 0;
+    ricControl_Request->protocolIEs.list.count = 0;
+  }
+  
+  free(IE_array);
+  free(initMsg);
+  e2ap_pdu_obj->choice.initiatingMessage = 0;
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed E2N_E2AP Control Request object mempory");
+  
+}
+
+
+bool ric_control_request::encode_e2ap_control_request(unsigned char *buf, size_t *size, ric_control_helper & dinput){
+
+  initMsg->procedureCode = E2N_ProcedureCode_id_ricControl;
+  initMsg->criticality = E2N_Criticality_ignore;
+  initMsg->value.present = E2N_InitiatingMessage__value_PR_RICcontrolRequest;
+
+  bool res;
+  
+  res = set_fields(initMsg, dinput);
+  if (!res){
+    return false;
+  }
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    error_string = "Constraints failed for encoding control . Reason = " + error_string;
+    return false;
+  }
+
+  //xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+  
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    return false;
+  }
+  else {
+    if(*size < retval.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding event trigger definition. Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      return false;
+    }
+  }
+
+  *size = retval.encoded;
+  return true;
+  
+}
+
+bool ric_control_request::set_fields(E2N_InitiatingMessage_t *initMsg, ric_control_helper &dinput){
+  unsigned int ie_index;
+
+  if (initMsg == 0){
+    error_string = "Invalid reference for E2AP Control_Request message in set_fields";
+    return false;
+  }
+
+  E2N_RICcontrolRequest_t * ric_control_request = &(initMsg->value.choice.RICcontrolRequest);
+  ric_control_request->protocolIEs.list.count = 0; // reset 
+  
+  // for(i = 0; i < NUM_CONTROL_REQUEST_IES;i++){
+  //   memset(&(IE_array[i]), 0, sizeof(RICcontrolRequest_IEs_t));
+  // }
+  // Mandatory IE
+  ie_index = 0;
+  E2N_RICcontrolRequest_IEs_t *ies_ricreq = &IE_array[ie_index];  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICcontrolRequest_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = dinput.req_id;
+  ricrequest_ie->ricRequestSequenceNumber = dinput.req_seq_no;
+  ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+
+  // Mandatory IE
+  ie_index = 1;
+  E2N_RICcontrolRequest_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICcontrolRequest_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = dinput.func_id;
+  ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+
+
+  // Mandatory IE
+  ie_index = 2;
+  E2N_RICcontrolRequest_IEs_t *ies_richead = &IE_array[ie_index];
+  ies_richead->criticality = E2N_Criticality_reject;
+  ies_richead->id = E2N_ProtocolIE_ID_id_RICcontrolHeader;
+  ies_richead->value.present = E2N_RICcontrolRequest_IEs__value_PR_RICcontrolHeader;
+  E2N_RICcontrolHeader_t *richeader_ie = &ies_richead->value.choice.RICcontrolHeader;
+  richeader_ie->buf = dinput.control_header;
+  richeader_ie->size = dinput.control_header_size;
+  ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+
+  // Mandatory IE
+  ie_index = 3;
+  E2N_RICcontrolRequest_IEs_t *ies_indmsg = &IE_array[ie_index];
+  ies_indmsg->criticality = E2N_Criticality_reject;
+  ies_indmsg->id = E2N_ProtocolIE_ID_id_RICcontrolMessage;
+  ies_indmsg->value.present = E2N_RICcontrolRequest_IEs__value_PR_RICcontrolMessage;
+  E2N_RICcontrolMessage_t *ricmsg_ie = &ies_indmsg->value.choice.RICcontrolMessage;
+  ricmsg_ie->buf = dinput.control_msg;
+  ricmsg_ie->size = dinput.control_msg_size;
+  ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+
+  // Optional IE
+  ie_index = 4;
+  if (dinput.control_ack >= 0){
+    E2N_RICcontrolRequest_IEs_t *ies_indtyp = &IE_array[ie_index];
+    ies_indtyp->criticality = E2N_Criticality_reject;
+    ies_indtyp->id = E2N_ProtocolIE_ID_id_RICcontrolAckRequest;
+    ies_indtyp->value.present = E2N_RICcontrolRequest_IEs__value_PR_RICcontrolAckRequest;
+    E2N_RICcontrolAckRequest_t *ricackreq_ie = &ies_indtyp->value.choice.RICcontrolAckRequest;
+    *ricackreq_ie = dinput.control_ack;
+    ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+  }
+
+  // Optional IE
+  ie_index = 5;
+  if(dinput.call_process_id_size > 0){
+    E2N_RICcontrolRequest_IEs_t *ies_callprocid = &IE_array[ie_index];
+    ies_callprocid->criticality = E2N_Criticality_reject;
+    ies_callprocid->id = E2N_ProtocolIE_ID_id_RICcallProcessID;
+    ies_callprocid->value.present = E2N_RICcontrolRequest_IEs__value_PR_RICcallProcessID;
+    E2N_RICcallProcessID_t *riccallprocessid_ie = &ies_callprocid->value.choice.RICcallProcessID;
+    riccallprocessid_ie->buf = dinput.call_process_id;
+    riccallprocessid_ie->size = dinput.call_process_id_size;
+    ASN_SEQUENCE_ADD(&(ric_control_request->protocolIEs), &(IE_array[ie_index]));
+
+  }
+  return true;
+
+};
+
+  
+
+
+bool ric_control_request:: get_fields(E2N_InitiatingMessage_t * init_msg,  ric_control_helper &dout)
+{
+  if (init_msg == 0){
+    error_string = "Invalid reference for E2AP Control_Request message in get_fields";
+    return false;
+  }
+  
+  for(int edx = 0; edx < init_msg->value.choice.RICcontrolRequest.protocolIEs.list.count; edx++) {
+    E2N_RICcontrolRequest_IEs_t *memb_ptr = init_msg->value.choice.RICcontrolRequest.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICcontrolHeader):
+       dout.control_header = memb_ptr->value.choice.RICcontrolHeader.buf;
+       dout.control_header_size = memb_ptr->value.choice.RICcontrolHeader.size;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICcontrolMessage):
+       dout.control_msg =  memb_ptr->value.choice.RICcontrolMessage.buf;
+       dout.control_msg_size = memb_ptr->value.choice.RICcontrolMessage.size;
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICcallProcessID):
+       dout.call_process_id =  memb_ptr->value.choice.RICcallProcessID.buf;
+       dout.call_process_id_size = memb_ptr->value.choice.RICcallProcessID.size;
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       dout.req_id = memb_ptr->value.choice.RICrequestID.ricRequestorID;
+       dout.req_seq_no = memb_ptr->value.choice.RICrequestID.ricRequestSequenceNumber;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       dout.func_id = memb_ptr->value.choice.RANfunctionID;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICcontrolAckRequest):
+       dout.control_ack = memb_ptr->value.choice.RICcontrolAckRequest;
+       break;
+       
+      default:
+       break;
+      }
+    
+  }
+  
+  return true;
+
+}
+
+E2N_InitiatingMessage_t * ric_control_request::get_message(void)  {
+    return initMsg;
+}
diff --git a/src/xapp-asn/e2ap/e2ap_control.hpp b/src/xapp-asn/e2ap/e2ap_control.hpp
new file mode 100644 (file)
index 0000000..57a2e2d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.h
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#ifndef E2AP_RIC_CONTROL_REQUEST_H_
+#define E2AP_RIC_CONTROL_REQUEST_H_
+
+  
+#include <iostream>
+#include <errno.h>
+#include <mdclog/mdclog.h>
+#include <sstream>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_InitiatingMessage.h>
+#include <E2N_RICcontrolRequest.h>
+#include <E2N_ProtocolIE-Field.h>
+#include "e2ap_control_helper.hpp"
+
+#define NUM_CONTROL_REQUEST_IES 6
+  
+  
+class ric_control_request{
+    
+public:
+  ric_control_request(void);
+  ~ric_control_request(void);
+    
+  bool encode_e2ap_control_request(unsigned char *, size_t *,  ric_control_helper &);
+  E2N_InitiatingMessage_t * get_message (void) ;
+  bool set_fields(E2N_InitiatingMessage_t *, ric_control_helper &);
+  bool get_fields(E2N_InitiatingMessage_t *, ric_control_helper &);
+  std::string get_error(void) const {return error_string ; };
+private:
+
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+  E2N_InitiatingMessage_t *initMsg;
+  E2N_RICcontrolRequest_IEs_t *IE_array;
+  std::string error_string;
+
+  char errbuf[128];
+  size_t errbuf_len = 128;
+};
+
+
+#endif /* E2AP_RIC_CONTROL_REQUEST_H_ */
diff --git a/src/xapp-asn/e2ap/e2ap_control_helper.hpp b/src/xapp-asn/e2ap/e2ap_control_helper.hpp
new file mode 100644 (file)
index 0000000..11f668c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.h
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#ifndef CONTROL_HELPER_H
+#define CONTROL_HELPER_H
+
+// control and indication helper objects are very similar and can be merged into one
+// currently leaving them as two distnict entities till final design becomes clear
+
+typedef struct ric_control_helper ric_control_helper;
+
+struct ric_control_helper{
+  ric_control_helper(void):req_id(1), req_seq_no(1), func_id(0), action_id(1), control_ack(-1), cause(0), sub_cause(0), control_status(1), control_msg(0), control_msg_size(0), control_header(0), control_header_size(0), call_process_id(0), call_process_id_size(0){};
+  
+  long int req_id, req_seq_no, func_id, action_id,  control_ack, cause, sub_cause, control_status;
+  
+  unsigned char* control_msg;
+  size_t control_msg_size;
+  
+  unsigned char* control_header;
+  size_t control_header_size;
+  
+  unsigned char *call_process_id;
+  size_t call_process_id_size;
+  
+};
+
+#endif
diff --git a/src/xapp-asn/e2ap/e2ap_control_response.cc b/src/xapp-asn/e2ap/e2ap_control_response.cc
new file mode 100644 (file)
index 0000000..23ef9ae
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_control_response.c
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#include "e2ap_control_response.hpp"
+
+// Set up the initiating message and also allocate protocolIEs in container
+// Note : this bypasses requirement to use ASN_SEQUENCE_ADD. We can directly
+// assign pointers to the array in ProtocolIE. However, this also leaves us on the
+// hook to manually clear the memory
+
+ric_control_response::ric_control_response(void){
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t * )calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  successMsg = 0;
+  successMsg = (E2N_SuccessfulOutcome_t * )calloc(1, sizeof(E2N_SuccessfulOutcome_t));
+  assert(successMsg != 0);
+
+  successMsg->procedureCode = E2N_ProcedureCode_id_ricControl;
+  successMsg->criticality = E2N_Criticality_reject;
+  successMsg->value.present = E2N_SuccessfulOutcome__value_PR_RICcontrolAcknowledge;
+  
+  unsuccessMsg = 0;
+  unsuccessMsg = (E2N_UnsuccessfulOutcome_t * )calloc(1, sizeof(E2N_UnsuccessfulOutcome_t));
+  assert(unsuccessMsg != 0);
+
+  
+  unsuccessMsg->procedureCode = E2N_ProcedureCode_id_ricControl;
+  unsuccessMsg->criticality = E2N_Criticality_reject;
+  unsuccessMsg->value.present = E2N_UnsuccessfulOutcome__value_PR_RICcontrolFailure;
+
+  IE_array = 0;
+  IE_array = (E2N_RICcontrolAcknowledge_IEs_t *)calloc(NUM_CONTROL_ACKNOWLEDGE_IES, sizeof(E2N_RICcontrolAcknowledge_IEs_t));
+  assert(IE_array != 0);
+
+  E2N_RICcontrolAcknowledge_t * ric_acknowledge = &(successMsg->value.choice.RICcontrolAcknowledge);
+  for(int i = 0; i < NUM_CONTROL_ACKNOWLEDGE_IES; i++){
+    ASN_SEQUENCE_ADD(&(ric_acknowledge->protocolIEs), &(IE_array[i]));
+  }
+  
+
+  IE_failure_array = 0;
+  IE_failure_array = (E2N_RICcontrolFailure_IEs_t *)calloc(NUM_CONTROL_FAILURE_IES, sizeof(E2N_RICcontrolFailure_IEs_t));
+  assert(IE_failure_array != 0);
+
+  E2N_RICcontrolFailure_t * ric_failure = &(unsuccessMsg->value.choice.RICcontrolFailure);
+  for(int i = 0; i < NUM_CONTROL_FAILURE_IES; i++){
+    ASN_SEQUENCE_ADD(&(ric_failure->protocolIEs), &(IE_failure_array[i]));
+  }
+  
+};
+
+
+// Clear assigned protocolIE list from RIC control_request IE container
+ric_control_response::~ric_control_response(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing E2AP Control Response object memory");
+  
+  E2N_RICcontrolAcknowledge_t * ric_acknowledge = &(successMsg->value.choice.RICcontrolAcknowledge);
+  for(int i  = 0; i < ric_acknowledge->protocolIEs.list.size; i++){
+    ric_acknowledge->protocolIEs.list.array[i] = 0;
+  }
+  if (ric_acknowledge->protocolIEs.list.size > 0){
+    free(ric_acknowledge->protocolIEs.list.array);
+    ric_acknowledge->protocolIEs.list.array = 0;
+    ric_acknowledge->protocolIEs.list.count = 0;
+  }
+
+  E2N_RICcontrolFailure_t * ric_failure = &(unsuccessMsg->value.choice.RICcontrolFailure);
+  for(int i  = 0; i < ric_failure->protocolIEs.list.size; i++){
+    ric_failure->protocolIEs.list.array[i] = 0;
+  }
+  if (ric_failure->protocolIEs.list.size > 0){
+    free(ric_failure->protocolIEs.list.array);
+    ric_failure->protocolIEs.list.array = 0;
+    ric_failure->protocolIEs.list.count = 0;
+  }
+  
+  free(IE_array);
+  free(IE_failure_array);
+  free(successMsg);
+  free(unsuccessMsg);
+
+  e2ap_pdu_obj->choice.initiatingMessage = 0;
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_initiatingMessage;
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed E2AP Control Response object mempory");
+}
+
+
+bool ric_control_response::encode_e2ap_control_response(unsigned char *buf, size_t *size, ric_control_helper & dinput, bool is_success){
+
+  bool res;
+  if (is_success){
+    res = set_fields(successMsg, dinput);
+  }
+  else{
+    res = set_fields(unsuccessMsg, dinput);
+  }
+  
+  if (!res){
+    return false;
+  }
+
+  
+  if (is_success){
+    e2ap_pdu_obj->choice.successfulOutcome = successMsg;
+    e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_successfulOutcome ;
+  }
+  else{
+    e2ap_pdu_obj->choice.unsuccessfulOutcome = unsuccessMsg;
+    e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_unsuccessfulOutcome ;
+
+  }
+
+  //xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    error_string = "Constraints failed for encoding control response. Reason = " + error_string;
+    return false;
+  }
+  
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+  
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    return false;
+  }
+  else {
+    if(*size < retval.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding E2AP Control response . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      return false;
+    }
+  }
+
+  *size = retval.encoded;
+  return true;
+  
+}
+
+bool ric_control_response::set_fields(E2N_SuccessfulOutcome_t *successMsg, ric_control_helper &dinput){
+  unsigned int ie_index;
+
+  if (successMsg == 0){
+    error_string = "Invalid reference for E2AP Control Acknowledge in set_fields";
+    return false;
+  }
+
+  // for(i = 0; i < NUM_CONTROL_ACKNOWLEDGE_IES;i++){
+  //   memset(&(IE_array[i]), 0, sizeof(RICcontrolAcknowledge_IEs_t));
+  // }
+
+  //E2N_RICcontrolAcknowledge_t * ric_acknowledge = &(successMsg->value.choice.RICcontrolAcknowledge);
+  //ric_acknowledge->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICcontrolAcknowledge_IEs_t *ies_ricreq = &IE_array[ie_index];  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICcontrolAcknowledge_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = dinput.req_id;
+  ricrequest_ie->ricRequestSequenceNumber = dinput.req_seq_no;
+  //ASN_SEQUENCE_ADD(&(ric_acknowledge->protocolIEs), ies_ricreq);
+  
+  ie_index = 1;
+  E2N_RICcontrolAcknowledge_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICcontrolAcknowledge_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = dinput.func_id;
+  //ASN_SEQUENCE_ADD(&(ric_acknowledge->protocolIEs), ies_ranfunc);
+
+  // ie_index = 2;
+  // E2N_RICcontrolAcknowledge_IEs_t *ies_riccallprocessid = &IE_array[ie_index];
+  // ies_riccallprocessid->criticality = E2N_Criticality_reject;
+  // ies_riccallprocessid->id = E2N_ProtocolIE_ID_id_RICcallProcessID;
+  // ies_riccallprocessid->value.present = E2N_RICcontrolAcknowledge_IEs__value_PR_RICcallProcessID;
+  // RICcallProcessID_t *riccallprocessid_ie = &ies_riccallprocessid->value.choice.RICcallProcessID;
+  // riccallprocessid_ie->buf = dinput.call_process_id;
+  // riccallprocessid_ie->size = dinput.call_process_id_size;
+  // ASN_SEQUENCE_ADD(&(ric_acknowledge->protocolIEs), ies_riccallprocessid);
+  
+  ie_index = 2;
+  E2N_RICcontrolAcknowledge_IEs_t *ies_ric_cause = &IE_array[ie_index];
+  ies_ric_cause->criticality = E2N_Criticality_reject;
+  ies_ric_cause->id = E2N_ProtocolIE_ID_id_RICcontrolStatus;
+  ies_ric_cause->value.present = E2N_RICcontrolAcknowledge_IEs__value_PR_RICcontrolStatus;
+  ies_ric_cause->value.choice.RICcontrolStatus = dinput.control_status;  
+  //ASN_SEQUENCE_ADD(&(ric_acknowledge->protocolIEs), ies_ric_cause);
+  
+  return true;
+
+};
+
+bool ric_control_response::set_fields(E2N_UnsuccessfulOutcome_t *unsuccessMsg, ric_control_helper &dinput){
+  unsigned int ie_index;
+
+  if (unsuccessMsg == 0){
+    error_string = "Invalid reference for E2AP Control Failure in set_fields";
+    return false;
+  }
+  
+  // for(i = 0; i < NUM_CONTROL_FAILURE_IES;i++){
+  //   memset(&(IE_failure_array[i]), 0, sizeof(RICcontrolFailure_IEs_t));
+  // }
+
+  //E2N_RICcontrolFailure_t * ric_failure = &(unsuccessMsg->value.choice.RICcontrolFailure);
+  //ric_failure->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICcontrolFailure_IEs_t *ies_ricreq = &IE_failure_array[ie_index];  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICcontrolFailure_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &(ies_ricreq->value.choice.RICrequestID);
+  ricrequest_ie->ricRequestorID = dinput.req_id;
+  ricrequest_ie->ricRequestSequenceNumber = dinput.req_seq_no;
+  //ASN_SEQUENCE_ADD(&(ric_failure->protocolIEs), ies_ricreq);
+  
+  ie_index = 1;
+  E2N_RICcontrolFailure_IEs_t *ies_ranfunc = &IE_failure_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICcontrolFailure_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &(ies_ranfunc->value.choice.RANfunctionID);
+  *ranfunction_ie = dinput.func_id;
+  //ASN_SEQUENCE_ADD(&(ric_failure->protocolIEs), ies_ranfunc);
+
+  // ie_index = 2;
+  // E2N_RICcontrolFailure_IEs_t *ies_riccallprocessid = &IE_failure_array[i];
+  // ies_riccallprocessid->criticality = E2N_Criticality_reject;
+  // ies_riccallprocessid->id = E2N_ProtocolIE_ID_id_RICcallProcessID;
+  // ies_riccallprocessid->value.present = E2N_RICcontrolFailure_IEs__value_PR_RICcallProcessID;
+  // RICcallProcessID_t *riccallprocessid_ie = &(ies_riccallprocessid->value.choice.RICcallProcessID);
+  // riccallprocessid_ie->buf = dinput.call_process_id;
+  // riccallprocessid_ie->size = dinput.call_process_id_size;
+  // ASN_SEQUENCE_ADD(&(ric_failure->protocolIEs), ies_riccallprocessid);
+  
+  ie_index = 2;
+  E2N_RICcontrolFailure_IEs_t *ies_ric_cause = &IE_failure_array[ie_index];
+  ies_ric_cause->criticality = E2N_Criticality_ignore;
+  ies_ric_cause->id = E2N_ProtocolIE_ID_id_RICcause;
+  ies_ric_cause->value.present = E2N_RICcontrolFailure_IEs__value_PR_RICcause;
+  E2N_RICcause_t * ric_cause = &(ies_ric_cause->value.choice.RICcause);
+  ric_cause->present = (E2N_RICcause_PR)dinput.cause;
+  
+  switch(dinput.cause){
+  case E2N_RICcause_PR_radioNetwork:
+    ric_cause->choice.radioNetwork = dinput.sub_cause;
+    break;
+  case E2N_RICcause_PR_transport:
+    ric_cause->choice.transport = dinput.sub_cause;
+    break;
+  case E2N_RICcause_PR_protocol:
+    ric_cause->choice.protocol= dinput.sub_cause;
+    break;
+  case E2N_RICcause_PR_misc:
+    ric_cause->choice.misc = dinput.sub_cause;
+    break;
+  case E2N_RICcause_PR_ric:
+    ric_cause->choice.ric = dinput.sub_cause;
+    break;
+  default:
+    std::cout <<"Error ! Illegal cause enum" << dinput.cause << std::endl;
+    return false;
+  }
+  
+  //ASN_SEQUENCE_ADD(&(ric_failure->protocolIEs), ies_ric_cause);
+  return true;
+
+};
+
+  
+
+
+bool ric_control_response:: get_fields(E2N_SuccessfulOutcome_t * success_msg,  ric_control_helper &dout)
+{
+  if (success_msg == 0){
+    error_string = "Invalid reference for E2AP Control Acknowledge message in get_fields";
+    return false;
+  }
+  
+  
+  for(int edx = 0; edx < success_msg->value.choice.RICcontrolAcknowledge.protocolIEs.list.count; edx++) {
+    E2N_RICcontrolAcknowledge_IEs_t *memb_ptr = success_msg->value.choice.RICcontrolAcknowledge.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+       
+      case (E2N_ProtocolIE_ID_id_RICcallProcessID):
+       dout.call_process_id =  memb_ptr->value.choice.RICcallProcessID.buf;
+       dout.call_process_id_size = memb_ptr->value.choice.RICcallProcessID.size;
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       dout.req_id = memb_ptr->value.choice.RICrequestID.ricRequestorID;
+       dout.req_seq_no = memb_ptr->value.choice.RICrequestID.ricRequestSequenceNumber;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       dout.func_id = memb_ptr->value.choice.RANfunctionID;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICcause):
+       dout.control_status = memb_ptr->value.choice.RICcontrolStatus;
+       break;
+       
+      }
+    
+  }
+  
+  return true;
+
+}
+
+
+bool ric_control_response:: get_fields(E2N_UnsuccessfulOutcome_t * unsuccess_msg,  ric_control_helper &dout)
+{
+  if (unsuccess_msg == 0){
+    error_string = "Invalid reference for E2AP Control Failure message in get_fields";
+    return false;
+  }
+  
+  
+  for(int edx = 0; edx < unsuccess_msg->value.choice.RICcontrolFailure.protocolIEs.list.count; edx++) {
+    E2N_RICcontrolFailure_IEs_t *memb_ptr = unsuccess_msg->value.choice.RICcontrolFailure.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+       
+      case (E2N_ProtocolIE_ID_id_RICcallProcessID):
+       dout.call_process_id =  memb_ptr->value.choice.RICcallProcessID.buf;
+       dout.call_process_id_size = memb_ptr->value.choice.RICcallProcessID.size;
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       dout.req_id = memb_ptr->value.choice.RICrequestID.ricRequestorID;
+       dout.req_seq_no = memb_ptr->value.choice.RICrequestID.ricRequestSequenceNumber;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       dout.func_id = memb_ptr->value.choice.RANfunctionID;
+       break;
+       
+       
+      case (E2N_ProtocolIE_ID_id_RICcause):
+       dout.cause = memb_ptr->value.choice.RICcause.present;
+       switch(dout.cause){
+         case  E2N_RICcause_PR_radioNetwork :
+           dout.sub_cause = memb_ptr->value.choice.RICcause.choice.radioNetwork;
+           break;
+             
+         case E2N_RICcause_PR_transport :
+           dout.sub_cause = memb_ptr->value.choice.RICcause.choice.transport;
+           break;
+             
+         case  E2N_RICcause_PR_protocol :
+           dout.sub_cause = memb_ptr->value.choice.RICcause.choice.protocol;
+           break;
+             
+         case E2N_RICcause_PR_misc :
+           dout.sub_cause = memb_ptr->value.choice.RICcause.choice.misc;
+           break;
+             
+         case E2N_RICcause_PR_ric :
+           dout.sub_cause = memb_ptr->value.choice.RICcause.choice.ric;
+           break;
+               
+       default:
+         dout.sub_cause = -1;
+         break;
+       }       
+
+      default:
+       break;
+      }
+    
+  }
+  
+  return true;
+  
+}
+
diff --git a/src/xapp-asn/e2ap/e2ap_control_response.hpp b/src/xapp-asn/e2ap/e2ap_control_response.hpp
new file mode 100644 (file)
index 0000000..6880e48
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.h
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#ifndef E2AP_RIC_CONTROL_RESPONSE_H_
+#define E2AP_RIC_CONTROL_RESPONSE_H_
+
+  
+#include <iostream>
+#include <errno.h>
+#include <mdclog/mdclog.h>
+#include <sstream>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_SuccessfulOutcome.h>
+#include <E2N_UnsuccessfulOutcome.h>
+#include <E2N_RICcontrolAcknowledge.h>
+#include <E2N_RICcontrolFailure.h>
+#include <E2N_ProtocolIE-Field.h>
+#include "e2ap_control_helper.hpp"
+
+#define NUM_CONTROL_ACKNOWLEDGE_IES 3
+#define NUM_CONTROL_FAILURE_IES 3
+
+  
+class ric_control_response{
+    
+public:
+  ric_control_response(void);
+  ~ric_control_response(void);
+  
+  bool encode_e2ap_control_response(unsigned char *, size_t *,  ric_control_helper &, bool);
+
+
+  bool set_fields(E2N_SuccessfulOutcome_t *, ric_control_helper &);
+  bool get_fields(E2N_SuccessfulOutcome_t *, ric_control_helper &);
+
+  bool set_fields(E2N_UnsuccessfulOutcome_t *, ric_control_helper &);
+  bool get_fields(E2N_UnsuccessfulOutcome_t *, ric_control_helper &);
+  
+  std::string get_error(void) const {return error_string ; };
+
+private:
+  
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+  E2N_SuccessfulOutcome_t * successMsg;
+  E2N_UnsuccessfulOutcome_t * unsuccessMsg;
+  
+  E2N_RICcontrolAcknowledge_IEs_t *IE_array;
+  E2N_RICcontrolFailure_IEs_t *IE_failure_array;
+  
+  std::string error_string;
+  
+  char errbuf[128];
+  size_t errbuf_len = 128;
+};
+
+
+#endif /* E2AP_RIC_CONTROL_RESPONSE_H_ */
diff --git a/src/xapp-asn/e2ap/e2ap_indication.cc b/src/xapp-asn/e2ap/e2ap_indication.cc
new file mode 100644 (file)
index 0000000..33b2095
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.c
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#include "e2ap_indication.hpp"
+
+// Set up memory allocations for each IE for encoding
+// We are responsible for memory management for each IE for encoding
+// Hence destructor should clear out memory
+// When decoding, we rely on asn1c macro (ASN_STRUCT_FREE to be called
+// for releasing memory by external calling function)
+ric_indication::ric_indication(void){
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t * )calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  initMsg = 0;
+  initMsg = (E2N_InitiatingMessage_t * )calloc(1, sizeof(E2N_InitiatingMessage_t));
+  assert(initMsg != 0);
+
+  IE_array = 0;
+  IE_array = (E2N_RICindication_IEs_t *)calloc(NUM_INDICATION_IES, sizeof(E2N_RICindication_IEs_t));
+  assert(IE_array != 0);
+
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_initiatingMessage;
+  e2ap_pdu_obj->choice.initiatingMessage = initMsg;
+
+                      
+  
+    
+};
+
+
+
+// Clear assigned protocolIE list from RIC indication IE container
+ric_indication::~ric_indication(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing E2AP Indication object memory");
+  E2N_RICindication_t *ricIndication  = &(initMsg->value.choice.RICindication);
+  for(int i = 0; i < ricIndication->protocolIEs.list.size; i++){
+    ricIndication->protocolIEs.list.array[i] = 0;
+  }
+  if (ricIndication->protocolIEs.list.size > 0){
+    free(ricIndication->protocolIEs.list.array);
+    ricIndication->protocolIEs.list.array = 0;
+    ricIndication->protocolIEs.list.count = 0;
+    ricIndication->protocolIEs.list.size = 0;
+  }
+  
+  free(IE_array);
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed E2AP Indication object mempory");
+}
+
+
+bool ric_indication::encode_e2ap_indication(unsigned char *buf, size_t *size, ric_indication_helper & dinput){
+
+  initMsg->procedureCode = E2N_ProcedureCode_id_ricIndication;
+  initMsg->criticality = E2N_Criticality_ignore;
+  initMsg->value.present = E2N_InitiatingMessage__value_PR_RICindication;
+
+  bool res;
+  asn_enc_rval_t retval;
+  
+  res = set_fields(initMsg, dinput);
+  if (!res){
+    return false;
+  }
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    error_string = "Error encoding E2AP Indication message. Reason = " + error_string;
+    return false;
+  }
+
+  // std::cout <<"Constraint check ok ...." << std::endl;
+  // xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_obj);
+  
+  retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    return false;
+  }
+
+  else {
+    if(*size < retval.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding E2AP Indication . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      return false;
+    }
+  }
+
+  *size = retval.encoded;
+  return true;
+  
+}
+
+bool ric_indication::set_fields(E2N_InitiatingMessage_t *initMsg, ric_indication_helper &dinput){
+  unsigned int ie_index;
+
+  if (initMsg == 0){
+    error_string = "Invalid reference for E2AP Indication message in set_fields";
+    return false;
+  }
+  
+  
+  E2N_RICindication_t * ric_indication = &(initMsg->value.choice.RICindication);
+  ric_indication->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  
+  E2N_RICindication_IEs_t *ies_ricreq = &IE_array[ie_index];  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICindication_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = dinput.req_id;
+  ricrequest_ie->ricRequestSequenceNumber = dinput.req_seq_no;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+  ie_index = 1;
+  E2N_RICindication_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICindication_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = dinput.func_id;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+
+  ie_index = 2;
+  E2N_RICindication_IEs_t *ies_actid = &IE_array[ie_index];
+  ies_actid->criticality = E2N_Criticality_reject;
+  ies_actid->id = E2N_ProtocolIE_ID_id_RICactionID;
+  ies_actid->value.present = E2N_RICindication_IEs__value_PR_RICactionID;
+  E2N_RICactionID_t *ricaction_ie = &ies_actid->value.choice.RICactionID;
+  *ricaction_ie = dinput.action_id;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+
+  ie_index = 3;
+  E2N_RICindication_IEs_t *ies_ricsn = &IE_array[ie_index];
+  ies_ricsn->criticality = E2N_Criticality_reject;
+  ies_ricsn->id = E2N_ProtocolIE_ID_id_RICindicationSN;
+  ies_ricsn->value.present = E2N_RICindication_IEs__value_PR_RICindicationSN;
+  E2N_RICindicationSN_t *ricsn_ie = &ies_ricsn->value.choice.RICindicationSN;
+  *ricsn_ie = dinput.indication_sn;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+
+
+  ie_index = 4;
+  E2N_RICindication_IEs_t *ies_indtyp = &IE_array[ie_index];
+  ies_indtyp->criticality = E2N_Criticality_reject;
+  ies_indtyp->id = E2N_ProtocolIE_ID_id_RICindicationType;
+  ies_indtyp->value.present = E2N_RICindication_IEs__value_PR_RICindicationType;
+  E2N_RICindicationType_t *rictype_ie = &ies_indtyp->value.choice.RICindicationType;
+  *rictype_ie = dinput.indication_type;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+
+  ie_index = 5;
+  E2N_RICindication_IEs_t *ies_richead = &IE_array[ie_index];
+  ies_richead->criticality = E2N_Criticality_reject;
+  ies_richead->id = E2N_ProtocolIE_ID_id_RICindicationHeader;
+  ies_richead->value.present = E2N_RICindication_IEs__value_PR_RICindicationHeader;
+  E2N_RICindicationHeader_t *richeader_ie = &ies_richead->value.choice.RICindicationHeader;
+  richeader_ie->buf = dinput.indication_header;
+  richeader_ie->size = dinput.indication_header_size;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+  
+  ie_index = 6;
+  E2N_RICindication_IEs_t *ies_indmsg = &IE_array[ie_index];
+  ies_indmsg->criticality = E2N_Criticality_reject;
+  ies_indmsg->id = E2N_ProtocolIE_ID_id_RICindicationMessage;
+  ies_indmsg->value.present = E2N_RICindication_IEs__value_PR_RICindicationMessage;
+  E2N_RICindicationMessage_t *ricmsg_ie = &ies_indmsg->value.choice.RICindicationMessage;
+  ricmsg_ie->buf = dinput.indication_msg;
+  ricmsg_ie->size = dinput.indication_msg_size;
+  ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+
+
+  // optional call process id ..
+  if (dinput.call_process_id_size > 0){
+    ie_index = 7;
+    E2N_RICindication_IEs_t *ies_ind_callprocessid = &IE_array[ie_index];
+    ies_ind_callprocessid->criticality = E2N_Criticality_reject;
+    ies_ind_callprocessid->id = E2N_ProtocolIE_ID_id_RICcallProcessID;
+    ies_ind_callprocessid->value.present = E2N_RICindication_IEs__value_PR_RICcallProcessID;
+    E2N_RICcallProcessID_t *riccallprocessid_ie = &ies_ind_callprocessid->value.choice.RICcallProcessID;
+    riccallprocessid_ie->buf = dinput.indication_msg;
+    riccallprocessid_ie->size = dinput.indication_msg_size;
+    ASN_SEQUENCE_ADD(&(ric_indication->protocolIEs), &(IE_array[ie_index]));
+  }
+  
+  return true;
+
+};
+
+  
+
+
+bool ric_indication:: get_fields(E2N_InitiatingMessage_t * init_msg,  ric_indication_helper &dout)
+{
+  if (init_msg == 0){
+    error_string = "Invalid reference for E2AP Indication message in get_fields";
+    return false;
+  }
+  
+  for(int edx = 0; edx < init_msg->value.choice.RICindication.protocolIEs.list.count; edx++) {
+    E2N_RICindication_IEs_t *memb_ptr = init_msg->value.choice.RICindication.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICindicationHeader):
+       dout.indication_header = memb_ptr->value.choice.RICindicationHeader.buf;
+       dout.indication_header_size = memb_ptr->value.choice.RICindicationHeader.size;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICindicationMessage):
+       dout.indication_msg =  memb_ptr->value.choice.RICindicationMessage.buf;
+       dout.indication_msg_size = memb_ptr->value.choice.RICindicationMessage.size;
+       break;
+           
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       dout.req_id = memb_ptr->value.choice.RICrequestID.ricRequestorID;
+       dout.req_seq_no = memb_ptr->value.choice.RICrequestID.ricRequestSequenceNumber;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       dout.func_id = memb_ptr->value.choice.RANfunctionID;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICindicationSN):
+       dout.indication_sn = memb_ptr->value.choice.RICindicationSN;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICindicationType):
+       dout.indication_type = memb_ptr->value.choice.RICindicationType;
+       break;
+       
+      case (E2N_ProtocolIE_ID_id_RICactionID):
+       dout.action_id = memb_ptr->value.choice.RICactionID;
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICcallProcessID):
+       dout.call_process_id = memb_ptr->value.choice.RICcallProcessID.buf;
+       dout.call_process_id_size = memb_ptr->value.choice.RICcallProcessID.size;
+       
+      default:
+       break;
+      }
+    
+  }
+  
+  return true;
+
+}
+
+E2N_InitiatingMessage_t * ric_indication::get_message(void)  {
+    return initMsg;
+}
diff --git a/src/xapp-asn/e2ap/e2ap_indication.hpp b/src/xapp-asn/e2ap/e2ap_indication.hpp
new file mode 100644 (file)
index 0000000..af43086
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.h
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+#ifndef E2AP_RIC_INDICATION_H_
+#define E2AP_RIC_INDICATION_H_
+
+  
+#include <iostream>
+#include <errno.h>
+#include <mdclog/mdclog.h>
+#include <sstream>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_InitiatingMessage.h>
+#include <E2N_RICindication.h>
+#include <E2N_ProtocolIE-Field.h>
+#include "e2ap_indication_helper.hpp"
+
+#define NUM_INDICATION_IES 8
+  
+
+
+class ric_indication{
+  
+public:
+  ric_indication(void);
+  ~ric_indication(void);
+  
+  bool encode_e2ap_indication(unsigned char *, size_t *,  ric_indication_helper &);
+  E2N_InitiatingMessage_t * get_message (void) ;
+  bool set_fields(E2N_InitiatingMessage_t *, ric_indication_helper &);
+  bool get_fields(E2N_InitiatingMessage_t *, ric_indication_helper &);
+  std::string get_error(void) const {return error_string ; };
+  
+private:
+  
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+  E2N_InitiatingMessage_t *initMsg;
+  E2N_RICindication_IEs_t *IE_array;
+  std::string error_string;
+  char errbuf[128];
+  size_t errbuf_len = 128;
+};
+
+
+#endif /* E2AP_RIC_INDICATION_H_ */
diff --git a/src/xapp-asn/e2ap/e2ap_indication_helper.hpp b/src/xapp-asn/e2ap/e2ap_indication_helper.hpp
new file mode 100644 (file)
index 0000000..276a2a7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * ric_indication.h
+ *
+ *  Created on: Jul 11, 2019
+ *      Author: sjana, Ashwin Sridharan
+ */
+
+
+#ifndef E2AP_INDICATION_HELPER_
+#define E2AP_INDICATION_HELPER_
+
+typedef struct ric_indication_helper ric_indication_helper;
+
+struct ric_indication_helper{
+  ric_indication_helper(void) : req_id(1), req_seq_no(1), func_id(0), action_id(1), indication_type(0), indication_sn(0), indication_msg(0), indication_msg_size(0), indication_header(0), indication_header_size(0), call_process_id(0), call_process_id_size(0) {};
+  long int req_id, req_seq_no, func_id, action_id, indication_type, indication_sn;
+  
+  unsigned char* indication_msg;
+  size_t indication_msg_size;
+  
+  unsigned char* indication_header;
+  size_t indication_header_size;
+  
+  unsigned char *call_process_id;
+  size_t call_process_id_size;
+  
+};
+
+#endif
diff --git a/src/xapp-asn/e2ap/generic_helpers.hpp b/src/xapp-asn/e2ap/generic_helpers.hpp
new file mode 100644 (file)
index 0000000..32c019a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#pragma once
+#ifndef GENERIC_HELPERS
+#define GENERIC_HELPERS
+
+#include <cstddef>
+
+/* Utilities */
+
+class octet_helper {
+
+public:
+  octet_helper(void):_ref(NULL), _size(0){};
+  octet_helper(const void *ref, int size):_ref(ref), _size(size){};
+  void set_ref(const void *ref){
+    _ref = ref;
+  }
+  
+  void set_size(size_t size){
+    _size = size;
+  }
+  
+  const void * get_ref(void){return _ref ; };
+  size_t get_size(void) const {return _size ; } ;
+
+private:
+  const void *_ref;
+  size_t _size;
+};
+    
+#endif
diff --git a/src/xapp-asn/e2ap/response_helper.hpp b/src/xapp-asn/e2ap/response_helper.hpp
new file mode 100644 (file)
index 0000000..b370ff2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#pragma once
+
+#ifndef S_RESPONSE_HELPER_
+#define S_RESPONSE_HELPER_
+
+#include <vector>
+#include <memory>
+
+/* Simple structure to store action for RICaction of the Subscription response based on E2 v0.31 */
+struct ActionResponse {
+public:
+  ActionResponse(int id): _is_admit(true), _id(id), _cause(-1), _sub_cause(-1){};
+  ActionResponse(int id, int cause, int sub_cause): _is_admit(false), _id(id), _cause(cause), _sub_cause(sub_cause){};
+  
+  int get_id() const{
+    return _id;
+  };
+
+  int get_cause() const{
+    return _cause;
+  };
+
+  int get_sub_cause() const{
+    return _sub_cause;
+  };
+
+  bool is_admitted(void){
+    return _is_admit;
+  };
+  
+private:
+
+  bool _is_admit;
+  int _id, _cause, _sub_cause;
+  
+};
+
+
+struct subscription_response_helper {
+  
+public:
+
+  using action_t = std::vector<ActionResponse>;
+  
+  subscription_response_helper(void){
+    _action_admitted_ref = std::make_unique<action_t>();
+    _action_not_admitted_ref = std::make_unique<action_t>();
+    
+  };
+  
+  // copy operator
+  subscription_response_helper(const subscription_response_helper &he ){
+    _action_admitted_ref = std::make_unique<action_t>();
+    _action_not_admitted_ref = std::make_unique<action_t>();
+    
+    _req_id = he.get_request_id();
+    _req_seq_no = he.get_req_seq();
+    _func_id = he.get_function_id();
+    
+    // Take care of the actions
+    for (auto const & e: *(he.get_admitted_list())){
+      add_action(e.get_id());
+    }
+    
+    for(auto const  & e: *(he.get_not_admitted_list())){
+      add_action(e.get_id(), e.get_cause(), e.get_sub_cause());
+    };
+  }
+  
+
+  // assignment operator
+  void operator=(const subscription_response_helper & he){
+    _action_admitted_ref = std::make_unique<action_t>();
+    _action_not_admitted_ref = std::make_unique<action_t>();
+    
+    _req_id = he.get_request_id();
+    _req_seq_no = he.get_req_seq();
+    _func_id = he.get_function_id();
+    
+    
+    // Take care of the actions
+    for (auto  const & e: *(he.get_admitted_list())){
+      add_action(e.get_id());
+    }
+  
+    for(auto const  & e: *(he.get_not_admitted_list())){
+      add_action(e.get_id(), e.get_cause(), e.get_sub_cause());
+    };
+    
+  }
+  
+  action_t * get_admitted_list (void ) const {return _action_admitted_ref.get();};
+  action_t * get_not_admitted_list (void ) const{return _action_not_admitted_ref.get();};
+  
+  void set_request(int id, int seq_no){
+    _req_id = id;
+    _req_seq_no = seq_no;
+    
+  };
+
+  void clear(void){
+    _action_admitted_ref.get()->clear();
+    _action_not_admitted_ref.get()->clear();
+  }
+
+  
+  void set_function_id(int id){
+    _func_id = id;
+  };
+
+  void add_action(int id){
+    ActionResponse a(id) ;
+    _action_admitted_ref.get()->push_back(a);
+  };
+
+  void add_action(int id, int cause, int sub_cause){
+    ActionResponse a (id, cause, sub_cause);
+    _action_not_admitted_ref.get()->push_back(a);
+  };
+
+
+  int  get_request_id(void) const{
+    return _req_id;
+  }
+  
+  int get_req_seq(void) const{
+    return _req_seq_no;
+  }
+
+  int  get_function_id(void) const{
+    return _func_id;
+  }
+  std::string  to_string(void){
+    std::string Info;
+    Info += "Request ID = " + std::to_string(_req_id) + "\n";
+    Info += "Request Sequence No = "  + std::to_string(_req_seq_no) + "\n";
+    Info += "RAN Function ID = " + std::to_string(_func_id) + "\n";
+    Info += "Actions Admitted =\n";
+    int i = 0;
+    for(auto & e: *(_action_admitted_ref)){
+        Info += std::to_string(i)  + ": ID=" + std::to_string(e.get_id()) + "\n";
+        i++;
+    }    
+    Info += "Actions Not Admitted =\n";
+    i = 0;
+    for(auto & e: *(_action_not_admitted_ref)){
+      Info += std::to_string(i)  + ": ID=" + std::to_string(e.get_id()) +  ": Cause =" + std::to_string(e.get_cause()) + ": Sub-Cause=" + std::to_string(e.get_sub_cause()) + "\n";
+      i++;
+    }    
+  
+    return Info;
+  } 
+
+private:
+  int _req_id, _req_seq_no, _func_id;
+  std::unique_ptr<action_t> _action_admitted_ref;
+  std::unique_ptr<action_t> _action_not_admitted_ref;
+  
+};
+  
+
+#endif
diff --git a/src/xapp-asn/e2ap/subscription_delete_request.cc b/src/xapp-asn/e2ap/subscription_delete_request.cc
new file mode 100644 (file)
index 0000000..d103d2e
--- /dev/null
@@ -0,0 +1,180 @@
+
+
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#include "subscription_delete_request.hpp"
+  
+subscription_delete::subscription_delete(void){
+
+  _name = "default";
+  
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t * )calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  initMsg = (E2N_InitiatingMessage_t * )calloc(1, sizeof(E2N_InitiatingMessage_t));
+  assert(initMsg != 0);
+  
+  IE_array = (E2N_RICsubscriptionDeleteRequest_IEs_t *)calloc(NUM_SUBSCRIPTION_DELETE_IES, sizeof(E2N_RICsubscriptionDeleteRequest_IEs_t));
+  assert(IE_array != 0);
+  
+  E2N_RICsubscriptionDeleteRequest_t * subscription_delete = &(initMsg->value.choice.RICsubscriptionDeleteRequest);
+  for(int i = 0; i < NUM_SUBSCRIPTION_DELETE_IES; i++){
+    ASN_SEQUENCE_ADD(&subscription_delete->protocolIEs, &(IE_array[i]));
+  }
+  
+};
+
+
+
+// Clear assigned protocolIE list from RIC indication IE container
+subscription_delete::~subscription_delete(void){
+    
+  mdclog_write(MDCLOG_DEBUG, "Freeing subscription delete request object memory");
+  E2N_RICsubscriptionDeleteRequest_t * subscription_delete = &(initMsg->value.choice.RICsubscriptionDeleteRequest);
+  
+  for(int i = 0; i < subscription_delete->protocolIEs.list.size; i++){
+    subscription_delete->protocolIEs.list.array[i] = 0;
+  }
+
+  if (subscription_delete->protocolIEs.list.size > 0){
+    free(subscription_delete->protocolIEs.list.array);
+    subscription_delete->protocolIEs.list.count = 0;
+    subscription_delete->protocolIEs.list.size = 0;
+    subscription_delete->protocolIEs.list.array = 0;
+  }
+  
+  free(IE_array);
+  free(initMsg);
+  e2ap_pdu_obj->choice.initiatingMessage = 0;
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed subscription delete request object memory");
+  
+
+};
+
+
+bool subscription_delete::encode_e2ap_subscription(unsigned char *buf, size_t *size,  subscription_helper &dinput){
+
+  e2ap_pdu_obj->choice.initiatingMessage = initMsg;
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_initiatingMessage;
+  set_fields( dinput);
+
+  initMsg->procedureCode = E2N_ProcedureCode_id_ricSubscriptionDelete;
+  initMsg->criticality = E2N_Criticality_reject;
+  initMsg->value.present = E2N_InitiatingMessage__value_PR_RICsubscriptionDeleteRequest;
+
+  //xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    error_string = "Constraints failed for encoding subscription delete request. Reason = " + error_string;
+    return false;
+  }
+  
+  asn_enc_rval_t res = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+    
+  if(res.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding Subscription Delete Request. Reason = " + error_string;
+    return false;
+  }
+  else {
+    if(*size < res.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding Subscription Delete Request . Reason =  encoded pdu size " << res.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      res.encoded = -1;
+      return false;
+    }
+  }
+    
+  *size = res.encoded;
+  return true;
+    
+}
+
+
+bool  subscription_delete::set_fields( subscription_helper &helper){
+  unsigned int ie_index;
+  
+  ie_index = 0;
+  E2N_RICsubscriptionDeleteRequest_IEs_t *ies_ricreq = &IE_array[ie_index];
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionDeleteRequest_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+
+
+  
+  ie_index = 1;
+  E2N_RICsubscriptionDeleteRequest_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionDeleteRequest_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+
+  
+  return true;
+};
+
+
+   
+
+bool  subscription_delete:: get_fields(E2N_InitiatingMessage_t * init_msg,  subscription_helper & dout)
+{
+
+  if (init_msg == 0){
+    error_string = "Invalid reference for initiating message for get string";
+    return false;
+  }
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+    
+  for(int edx = 0; edx < init_msg->value.choice.RICsubscriptionDeleteRequest.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionDeleteRequest_IEs_t *memb_ptr = init_msg->value.choice.RICsubscriptionDeleteRequest.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+       
+      }
+    
+  //asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+  }
+
+  return true;
+}
+
+
+
diff --git a/src/xapp-asn/e2ap/subscription_delete_request.hpp b/src/xapp-asn/e2ap/subscription_delete_request.hpp
new file mode 100644 (file)
index 0000000..e3c1d4e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#pragma once
+
+#ifndef S_DELETE_
+#define S_DELETE_
+
+#include <mdclog/mdclog.h>
+#include <vector>
+#include <sstream>
+#include <mdclog/mdclog.h>
+#include <asn_application.h>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_InitiatingMessage.h>
+#include <E2N_RICsubscriptionDeleteRequest.h>
+#include <E2N_ProtocolIE-Field.h>
+#include "subscription_helper.hpp"
+
+#define NUM_SUBSCRIPTION_DELETE_IES 2
+
+class subscription_delete{   
+public:
+
+  subscription_delete(void);
+  ~subscription_delete(void);
+  
+  bool encode_e2ap_subscription(unsigned char *, size_t *,  subscription_helper &);
+  bool set_fields(subscription_helper &);
+  bool get_fields(E2N_InitiatingMessage_t *, subscription_helper &);
+    
+  std::string get_error(void) const {
+    return error_string ;
+  }
+    
+private:
+    
+  E2N_InitiatingMessage_t *initMsg;
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+
+  E2N_RICsubscriptionDeleteRequest_IEs_t * IE_array;
+
+  
+  char errbuf[128];
+  size_t errbuf_len = 128;
+  std::string _name;
+  std::string error_string;
+};
+
+
+
+#endif
diff --git a/src/xapp-asn/e2ap/subscription_delete_response.cc b/src/xapp-asn/e2ap/subscription_delete_response.cc
new file mode 100644 (file)
index 0000000..c1c166c
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#include "subscription_delete_response.hpp"
+
+/* The xAPP need only worry about the get_fields from a response, since it does
+not generate a response. Generating response however is included to support testing. 
+*/
+
+
+// Primarly for generation
+subscription_delete_response::subscription_delete_response(void){
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t *)calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  successMsg = 0;
+  successMsg = (E2N_SuccessfulOutcome_t *)calloc(1, sizeof(E2N_SuccessfulOutcome_t));
+  assert(successMsg != 0);
+
+  unsuccessMsg = 0;
+  unsuccessMsg = (E2N_UnsuccessfulOutcome_t *)calloc(1, sizeof(E2N_UnsuccessfulOutcome_t));
+  assert(unsuccessMsg != 0);
+
+  IE_array = 0;
+  IE_array = (E2N_RICsubscriptionDeleteResponse_IEs_t *)calloc(NUM_SUBSCRIPTION_DELETE_RESPONSE_IES, sizeof(E2N_RICsubscriptionDeleteResponse_IEs_t));
+  assert(IE_array != 0);
+
+  IE_Failure_array = 0;
+  IE_Failure_array = (E2N_RICsubscriptionDeleteFailure_IEs_t *)calloc(NUM_SUBSCRIPTION_DELETE_FAILURE_IES, sizeof(E2N_RICsubscriptionDeleteFailure_IEs_t));
+  assert(IE_Failure_array != 0);
+
+  
+   
+};
+
+  
+
+// Clear assigned protocolIE list from E2N_RIC indication IE container
+subscription_delete_response::~subscription_delete_response(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing subscription delete response memory");
+  E2N_RICsubscriptionDeleteResponse_t * ric_subscription_delete_response = &(successMsg->value.choice.RICsubscriptionDeleteResponse);
+  
+  for(unsigned int i = 0; i < ric_subscription_delete_response->protocolIEs.list.size ; i++){
+    ric_subscription_delete_response->protocolIEs.list.array[i] = 0;
+  }
+
+  
+  E2N_RICsubscriptionDeleteFailure_t * ric_subscription_failure = &(unsuccessMsg->value.choice.RICsubscriptionDeleteFailure);
+  for(unsigned int i = 0; i < ric_subscription_failure->protocolIEs.list.size; i++){
+    ric_subscription_failure->protocolIEs.list.array[i] = 0;
+  }
+
+  free(IE_array);
+  free(IE_Failure_array);
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_SuccessfulOutcome, successMsg);
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_UnsuccessfulOutcome, unsuccessMsg);
+  
+  e2ap_pdu_obj->choice.successfulOutcome = NULL;
+  e2ap_pdu_obj->choice.unsuccessfulOutcome = NULL;
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed subscription delete response memory");
+
+};
+
+
+bool subscription_delete_response::encode_e2ap_subscription_delete_response(unsigned char *buf, size_t *size,  subscription_response_helper &dinput, bool is_success){
+
+  bool res;
+  if(is_success){
+    res = set_fields(successMsg, dinput);
+    if (!res){
+      return false;
+    }
+    e2ap_pdu_obj->present =  E2N_E2AP_PDU_PR_successfulOutcome;
+    e2ap_pdu_obj->choice.successfulOutcome = successMsg;
+  }
+  else{
+    res = set_fields(unsuccessMsg, dinput);
+    if(! res){
+      return false;
+    }
+    e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_unsuccessfulOutcome;
+    e2ap_pdu_obj->choice.unsuccessfulOutcome = unsuccessMsg;
+  }
+    
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    return false;
+  }
+
+  //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_obj);
+  
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+    
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding subcription delete response. Reason = " + error_string;
+    return false;
+  }
+  else {
+    if(*size < retval.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding Subscription Delete Response . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      retval.encoded = -1;
+      return false;
+    }
+  }
+    
+  *size = retval.encoded;
+  return true;
+    
+}
+  
+bool  subscription_delete_response::set_fields(E2N_SuccessfulOutcome_t *success, subscription_response_helper &helper){
+
+  if (success == 0){
+    error_string = "Invalid reference to success message in set fields  subscription delete response";
+    return false;
+  }
+  
+  unsigned int ie_index;
+
+  success->procedureCode = E2N_ProcedureCode_id_ricSubscriptionDelete;
+  success->criticality = E2N_Criticality_reject;
+  success->value.present = E2N_SuccessfulOutcome__value_PR_RICsubscriptionDeleteResponse;   
+  E2N_RICsubscriptionDeleteResponse_t * subscription_delete_response = &(success->value.choice.RICsubscriptionDeleteResponse);
+  subscription_delete_response->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICsubscriptionDeleteResponse_IEs_t *ies_ricreq = &IE_array[ie_index];
+  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionDeleteResponse_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+  ASN_SEQUENCE_ADD(&subscription_delete_response->protocolIEs, ies_ricreq);
+
+  
+  ie_index = 1;
+  E2N_RICsubscriptionDeleteResponse_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionDeleteResponse_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+  ASN_SEQUENCE_ADD(&subscription_delete_response->protocolIEs, ies_ranfunc);
+
+  return true;
+       
+}
+
+bool subscription_delete_response:: get_fields(E2N_SuccessfulOutcome_t * success_msg,  subscription_response_helper & dout)
+{
+
+  if (success_msg == 0){
+    error_string = "Invalid reference to success message inn get fields subscription delete response";
+    return false;
+  }
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+  
+  for(int edx = 0; edx < success_msg->value.choice.RICsubscriptionDeleteResponse.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionDeleteResponse_IEs_t *memb_ptr = success_msg->value.choice.RICsubscriptionDeleteResponse.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+      }
+    
+  }
+  
+  return true;
+  //asn_fprint(stdout, &asn_DEF_E2AP_PDU, e2pdu);
+}
+
+
+bool subscription_delete_response::set_fields(E2N_UnsuccessfulOutcome_t *unsuccess, subscription_response_helper &helper){
+
+  if (unsuccess == 0){
+    error_string = "Invalid reference to unsuccess message in set fields  subscription delete response";
+    return false;
+  }
+  
+  unsigned int ie_index;
+
+  unsuccess->procedureCode = E2N_ProcedureCode_id_ricSubscriptionDelete;
+  unsuccess->criticality = E2N_Criticality_reject;
+  unsuccess->value.present = E2N_UnsuccessfulOutcome__value_PR_RICsubscriptionDeleteFailure;
+
+  E2N_RICsubscriptionDeleteFailure_t * ric_subscription_failure = &(unsuccess->value.choice.RICsubscriptionDeleteFailure);
+  ric_subscription_failure->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICsubscriptionDeleteFailure_IEs_t *ies_ricreq = &IE_Failure_array[ie_index];
+    
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionDeleteFailure_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+  ASN_SEQUENCE_ADD(&ric_subscription_failure->protocolIEs, ies_ricreq);
+  
+  ie_index = 1;
+  E2N_RICsubscriptionDeleteFailure_IEs_t *ies_ranfunc = &IE_Failure_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionDeleteFailure_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+  ASN_SEQUENCE_ADD(&ric_subscription_failure->protocolIEs, ies_ranfunc);
+    
+
+  return true;
+    
+}
+
+bool  subscription_delete_response:: get_fields(E2N_UnsuccessfulOutcome_t * unsuccess_msg,  subscription_response_helper & dout)
+{
+
+  if (unsuccess_msg == 0){
+    error_string = "Invalid reference to unsuccess message in get fields  subscription delete response";
+    return false;
+  }
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+    
+  for(int edx = 0; edx < unsuccess_msg->value.choice.RICsubscriptionDeleteFailure.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionDeleteFailure_IEs_t *memb_ptr = unsuccess_msg->value.choice.RICsubscriptionDeleteFailure.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+       
+      }
+    
+  }
+
+  return true;
+  //asn_fprint(stdout, &asn_DEF_E2AP_PDU, e2pdu);
+}
+
+
+
diff --git a/src/xapp-asn/e2ap/subscription_delete_response.hpp b/src/xapp-asn/e2ap/subscription_delete_response.hpp
new file mode 100644 (file)
index 0000000..d9581e4
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#pragma once
+
+#ifndef S_DEL_RESPONSE_
+#define S_DEL_RESPONSE_
+
+#include <mdclog/mdclog.h>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <mdclog/mdclog.h>
+#include <asn_application.h>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_SuccessfulOutcome.h>
+#include <E2N_UnsuccessfulOutcome.h>
+#include <E2N_RICsubscriptionDeleteResponse.h>
+#include <E2N_RICsubscriptionDeleteFailure.h>
+#include <E2N_ProtocolIE-Field.h>
+#include <E2N_ProcedureCode.h>
+#include "response_helper.hpp"
+
+#define NUM_SUBSCRIPTION_DELETE_RESPONSE_IES 2
+#define NUM_SUBSCRIPTION_DELETE_FAILURE_IES 2
+  
+class subscription_delete_response {   
+public:
+    
+  subscription_delete_response(void);
+  ~subscription_delete_response(void);
+    
+  bool encode_e2ap_subscription_delete_response(unsigned char *, size_t *,  subscription_response_helper &, bool);
+  bool set_fields(E2N_SuccessfulOutcome_t *, subscription_response_helper &);
+  bool get_fields(E2N_SuccessfulOutcome_t *, subscription_response_helper &);
+    
+  bool set_fields(E2N_UnsuccessfulOutcome_t *, subscription_response_helper &);
+  bool get_fields(E2N_UnsuccessfulOutcome_t *, subscription_response_helper &);
+  
+  std::string get_error_string(void) const {
+    return error_string;
+  }
+    
+private:
+
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+  E2N_SuccessfulOutcome_t * successMsg;
+  E2N_UnsuccessfulOutcome_t * unsuccessMsg;
+    
+
+  E2N_RICsubscriptionDeleteResponse_IEs_t *IE_array;
+  E2N_RICsubscriptionDeleteFailure_IEs_t *IE_Failure_array;
+  
+  
+  char errbuf[128];
+  size_t errbuf_len = 128;
+  std::string error_string;
+  
+};
+
+
+
+
+#endif
diff --git a/src/xapp-asn/e2ap/subscription_helper.hpp b/src/xapp-asn/e2ap/subscription_helper.hpp
new file mode 100644 (file)
index 0000000..a9e0417
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#ifndef SUB_HELPER_
+#define SUB_HELPER_
+
+/* 
+   Simple structure to store action related information based on E2 v0.22
+   Used for subscription request, response etc
+   
+   ricActionID                                 RICactionID,
+   ricActionType                               RICactionType,
+   ricActionDefinition                 RICactionDefinition     OPTIONAL,
+   ricSubsequentAction                 RICsubsequentAction     OPTIONAL,
+   ricCause
+*/
+
+#include <iostream>
+#include <vector>
+#include <memory>
+#include "generic_helpers.hpp"
+
+
+// Note : if no action definition specified, octet length of action definition  is NULL
+// If no subsequent action specified, default is subsequent_action = 0, time to wait is 0
+struct Action {
+
+public:
+  
+  Action(int id, int type): _is_def(false), _is_subs_act(false), _id(id), _type(type), _next_action(0), _wait(0){};
+  Action(int id, int type, const void *def, size_t def_size, int next, int wait): _is_def(false), _is_subs_act(false), _id(id), _type(type){
+    
+    if (def_size > 0){
+      _is_def = true;
+      _action_definition.set_ref(def);
+      _action_definition.set_size(def_size);
+    }
+    
+    if(next >= 0 && wait >= 0){
+      _is_subs_act = true;
+      _next_action = next;
+      _wait = wait;
+    }
+  };
+
+  
+  int get_id() const{
+    return _id;
+  }
+
+  int get_type() const {
+    return _type;
+  }
+
+
+  const void * get_definition(void )  {
+    return _action_definition.get_ref();
+  }
+
+  int get_definition_size(void) const {
+    return _action_definition.get_size();
+  };
+  
+
+  int get_subsequent_action() const {
+    return _next_action;
+  };
+
+  int get_wait() const {
+    return _wait;
+  }
+
+  bool is_definition() const{
+
+    return _is_def;
+  }
+
+  bool is_subsequent_action() const{
+    return _is_subs_act;
+  }
+    
+private:
+
+  bool _is_def;
+  bool _is_subs_act;
+  int _id, _type, _next_action, _wait, _cause, _sub_cause;
+  bool _is_admit;
+  octet_helper _action_definition;
+
+};
+
+
+/*
+ Helper class that stores subscription data 
+*/
+
+
+struct subscription_helper {
+
+public:
+
+  using action_t = std::vector<Action>;
+  
+  subscription_helper(){
+    _action_ref = std::make_unique<action_t>();
+    curr_index = 0;    
+  };
+  
+  action_t * get_list() const {return _action_ref.get();};
+
+  void clear(void){
+    _action_ref.get()->clear();
+  }
+  
+  void set_request(int id, int seq_no){
+    _req_id = id;
+    _req_seq_no = seq_no;
+    
+  };
+
+  void set_function_id(int id){
+    _func_id = id;
+  };
+
+  void set_event_def(const void *ref, size_t size){
+    _event_def.set_ref(ref);
+    _event_def.set_size(size);
+   };
+
+  void add_action(int id, int type){
+    Action a(id, type) ;
+    _action_ref.get()->push_back(a);
+  };
+
+  void add_action(int id, int type, std::string action_def, int next_action, int wait_time){
+    Action a (id, type, action_def.c_str(), action_def.length(), next_action, wait_time);
+    _action_ref.get()->push_back(a);
+  };
+
+
+  int  get_request_id(void) const{
+    return _req_id;
+  }
+
+  int  get_req_seq(void) const {
+    return _req_seq_no;
+  }
+
+  int  get_function_id(void) const{
+    return _func_id;
+  }
+  
+  const void * get_event_def(void)  {
+    return _event_def.get_ref();
+  }
+
+  int get_event_def_size(void) const {
+    return _event_def.get_size();
+  }
+
+  void print_sub_info(void){
+    std::cout <<"Request ID = " << _req_id << std::endl;
+    std::cout <<"Request Sequence Number = " << _req_seq_no << std::endl;
+    std::cout <<"RAN Function ID = " << _func_id << std::endl;
+    for(auto const & e: *(_action_ref.get())){
+      std::cout <<"Action ID = " << e.get_id() << " Action Type = " << e.get_type() << std::endl;
+    }
+  };
+  
+private:
+  
+  std::unique_ptr<action_t> _action_ref;
+  int curr_index;
+  int _req_id, _req_seq_no, _func_id;
+  octet_helper _event_def;
+};
+
+#endif
diff --git a/src/xapp-asn/e2ap/subscription_request.cc b/src/xapp-asn/e2ap/subscription_request.cc
new file mode 100644 (file)
index 0000000..9b2f897
--- /dev/null
@@ -0,0 +1,308 @@
+
+
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#include "subscription_request.hpp"
+
+
+// Set up memory allocations for each IE for encoding
+// We are responsible for memory management for each IE for encoding
+// Hence destructor should clear out memory
+// When decoding, we rely on asn1c macro (ASN_STRUCT_FREE to be called
+// for releasing memory by external calling function)
+subscription_request::subscription_request(void){
+
+  _name = "default";
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t * )calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  initMsg = 0;
+  initMsg = (E2N_InitiatingMessage_t * )calloc(1, sizeof(E2N_InitiatingMessage_t));
+  assert(initMsg != 0);
+
+  IE_array = 0;
+  IE_array = (E2N_RICsubscriptionRequest_IEs_t *)calloc(NUM_SUBSCRIPTION_REQUEST_IES, sizeof(E2N_RICsubscriptionRequest_IEs_t));
+  assert(IE_array != 0);
+  
+  action_array = 0;
+  action_array = (E2N_RICaction_ToBeSetup_ItemIEs_t *)calloc(INITIAL_REQUEST_LIST_SIZE, sizeof(E2N_RICaction_ToBeSetup_ItemIEs_t));
+  assert(action_array != 0);
+  action_array_size = INITIAL_REQUEST_LIST_SIZE;
+  // also need to add subsequent action and time to wait ..
+  for (unsigned int i = 0; i < action_array_size; i++){
+    action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction = (struct E2N_RICsubsequentAction *)calloc(1, sizeof(struct E2N_RICsubsequentAction));
+    assert(action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction  != 0);
+  }
+  
+  e2ap_pdu_obj->choice.initiatingMessage = initMsg;
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_initiatingMessage;
+
+
+  
+};
+
+
+
+// Clear assigned protocolIE list from RIC indication IE container
+subscription_request::~subscription_request(void){
+    
+  mdclog_write(MDCLOG_DEBUG, "Freeing subscription request memory for");;
+  
+  // Sequence of actions to be admitted causes special heart-ache. Free ric subscription element manually and reset the ie pointer  
+  E2N_RICsubscription_t * ricsubscription_ie = &(IE_array[2].value.choice.RICsubscription);
+
+  for(int i = 0; i < ricsubscription_ie->ricAction_ToBeSetup_List.list.size; i++){
+    ricsubscription_ie->ricAction_ToBeSetup_List.list.array[i] = 0;
+  }
+
+  if (ricsubscription_ie->ricAction_ToBeSetup_List.list.size > 0){
+    free(ricsubscription_ie->ricAction_ToBeSetup_List.list.array);
+    ricsubscription_ie->ricAction_ToBeSetup_List.list.size = 0;
+    ricsubscription_ie->ricAction_ToBeSetup_List.list.count = 0;
+    ricsubscription_ie->ricAction_ToBeSetup_List.list.array = 0;
+  }
+
+  // clear subsequent action array
+  for (unsigned int i = 0; i < action_array_size; i++){
+    free(action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction );
+  }
+  
+  free(action_array);
+  E2N_RICsubscriptionRequest_t * subscription_request = &(initMsg->value.choice.RICsubscriptionRequest);
+  
+  for(int i = 0; i < subscription_request->protocolIEs.list.size; i++){
+    subscription_request->protocolIEs.list.array[i] = 0;
+  }
+  
+  if( subscription_request->protocolIEs.list.size > 0){
+    free( subscription_request->protocolIEs.list.array);
+    subscription_request->protocolIEs.list.array = 0;
+    subscription_request->protocolIEs.list.size = 0;
+    subscription_request->protocolIEs.list.count = 0;
+  }
+  
+  free(IE_array);
+  free(initMsg);
+  e2ap_pdu_obj->choice.initiatingMessage = 0;
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  mdclog_write(MDCLOG_DEBUG, "Freed subscription request memory ");
+};
+
+
+bool subscription_request::encode_e2ap_subscription(unsigned char *buf, size_t *size,  subscription_helper &dinput){
+
+  bool res;
+
+  initMsg->procedureCode = E2N_ProcedureCode_id_ricSubscription;
+  initMsg->criticality = E2N_Criticality_ignore;
+  initMsg->value.present = E2N_InitiatingMessage__value_PR_RICsubscriptionRequest;
+
+  res = set_fields(initMsg, dinput);
+  if (!res){
+    return false;
+  }
+  
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    error_string = "Constraints failed for encoding subscription request. Reason = " + error_string;
+    return false;
+  }
+
+  //xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+  
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+    
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding Subscription  Request. Reason = " + error_string;
+    return false;
+  }
+  else {
+    if(*size < retval.encoded){
+      std::stringstream ss;
+      ss  <<"Error encoding Subscription  Request . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+      error_string = ss.str();
+      retval.encoded = -1;
+      return false;
+    }
+  }
+    
+  *size = retval.encoded;
+  return true;
+    
+}
+
+
+bool subscription_request::set_fields( E2N_InitiatingMessage_t * init_msg, subscription_helper &helper){
+
+  
+  int ie_index;
+  int result = 0;
+
+  if (init_msg == 0){
+    error_string = "Error. Invalid reference when getting fields from subscription request";
+    return false;
+  }
+
+  E2N_RICsubscriptionRequest_t * ric_subscription = &(init_msg->value.choice.RICsubscriptionRequest);
+  ric_subscription->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICsubscriptionRequest_IEs_t *ies_ricreq = &IE_array[ie_index];
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionRequest_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+  result = ASN_SEQUENCE_ADD(&(ric_subscription->protocolIEs), &IE_array[ie_index]);
+  assert(result == 0);
+     
+  ie_index = 1;
+  E2N_RICsubscriptionRequest_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionRequest_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+  result = ASN_SEQUENCE_ADD(&(ric_subscription->protocolIEs), &IE_array[ie_index]);
+  assert(result == 0);
+
+
+  ie_index = 2;
+  E2N_RICsubscriptionRequest_IEs_t *ies_actid = &IE_array[ie_index];
+  ies_actid->criticality = E2N_Criticality_reject;
+  ies_actid->id = E2N_ProtocolIE_ID_id_RICsubscription;
+  ies_actid->value.present = E2N_RICsubscriptionRequest_IEs__value_PR_RICsubscription;
+  E2N_RICsubscription_t *ricsubscription_ie = &ies_actid->value.choice.RICsubscription;
+
+  ricsubscription_ie->ricEventTriggerDefinition.buf = (uint8_t *) helper.get_event_def();
+  ricsubscription_ie->ricEventTriggerDefinition.size = helper.get_event_def_size();
+   
+  std::vector<Action> * ref_action_array = helper.get_list();
+  // do we need to resize  ?
+  // we don't care about contents, so just do a free/calloc
+  if(action_array_size < ref_action_array->size()){
+    std::cout <<"re-allocating action array from " << action_array_size << " to " << 2 * ref_action_array->size() <<  std::endl;
+    // free subsequent allocation
+    for (unsigned int i = 0; i < action_array_size; i++){
+      free(action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction );
+    }
+    
+    action_array_size = 2 * ref_action_array->size();
+    free(action_array);
+    action_array = (E2N_RICaction_ToBeSetup_ItemIEs_t *)calloc(action_array_size, sizeof(E2N_RICaction_ToBeSetup_ItemIEs_t));
+    assert(action_array != 0);
+
+    // also need to add subsequent action and time to wait ..
+    for (unsigned int i = 0; i < action_array_size; i++){
+      action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction = (struct E2N_RICsubsequentAction *)calloc(1, sizeof(struct E2N_RICsubsequentAction));
+      assert(action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction  != 0);
+    }
+    
+  }
+  
+  // reset the list count on ricAction_ToBeSetup_List;
+  ricsubscription_ie->ricAction_ToBeSetup_List.list.count = 0;
+  
+  for(unsigned int i = 0; i < ref_action_array->size(); i ++){
+    action_array[i].criticality = E2N_Criticality_ignore;
+    action_array[i].id = E2N_ProtocolIE_ID_id_RICaction_ToBeSetup_Item ;
+    action_array[i].value.present = E2N_RICaction_ToBeSetup_ItemIEs__value_PR_RICaction_ToBeSetup_Item;
+    action_array[i].value.choice.RICaction_ToBeSetup_Item.ricActionID = (*ref_action_array)[i].get_id();
+    action_array[i].value.choice.RICaction_ToBeSetup_Item.ricActionType = (*ref_action_array)[i].get_type();
+    action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction->ricSubsequentActionType = (*ref_action_array)[i].get_subsequent_action();
+    action_array[i].value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction->ricTimeToWait = (*ref_action_array)[i].get_wait();
+    
+    result = ASN_SEQUENCE_ADD(&ricsubscription_ie->ricAction_ToBeSetup_List, &(action_array[i]));
+    if (result == -1){
+      error_string = "Erorr : Unable to assign memory to add Action item to set up list";
+      return false;
+    }
+    
+  }
+  
+  result = ASN_SEQUENCE_ADD(&(ric_subscription->protocolIEs), &IE_array[ie_index]);
+  assert(result == 0);
+
+
+    
+  return true;
+};
+
+
+
+bool subscription_request:: get_fields(E2N_InitiatingMessage_t * init_msg,  subscription_helper & dout)
+{
+
+  if (init_msg == 0){
+    error_string = "Error. Invalid reference when getting fields from subscription request";
+    return false;
+  }
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+  E2N_RICsubscription_t * ricsubscription;
+    
+  for(int edx = 0; edx < init_msg->value.choice.RICsubscriptionRequest.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionRequest_IEs_t *memb_ptr = init_msg->value.choice.RICsubscriptionRequest.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RICsubscription):
+       ricsubscription = &memb_ptr->value.choice.RICsubscription;
+       dout.set_event_def(ricsubscription->ricEventTriggerDefinition.buf, ricsubscription->ricEventTriggerDefinition.size);
+         
+       for(int index = 0; index < ricsubscription->ricAction_ToBeSetup_List.list.count; index ++){
+         E2N_RICaction_ToBeSetup_ItemIEs_t * item = (E2N_RICaction_ToBeSetup_ItemIEs_t *)ricsubscription->ricAction_ToBeSetup_List.list.array[index];
+         if (item->value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction == NULL){
+           dout.add_action(item->value.choice.RICaction_ToBeSetup_Item.ricActionID, item->value.choice.RICaction_ToBeSetup_Item.ricActionType);
+         }
+         else{
+           std::string action_def = ""; // for now we are ignoring action definition
+           dout.add_action(item->value.choice.RICaction_ToBeSetup_Item.ricActionID, item->value.choice.RICaction_ToBeSetup_Item.ricActionType, action_def, item->value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction->ricSubsequentActionType, item->value.choice.RICaction_ToBeSetup_Item.ricSubsequentAction->ricTimeToWait);
+         }   
+       };
+       
+       break;
+      }
+      
+  }
+    
+  //asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+  return true;
+};
+
+
+
diff --git a/src/xapp-asn/e2ap/subscription_request.hpp b/src/xapp-asn/e2ap/subscription_request.hpp
new file mode 100644 (file)
index 0000000..28f419a
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#pragma once
+
+#ifndef S_REQUEST_
+#define S_REQUEST_
+
+#include <mdclog/mdclog.h>
+#include <vector>
+#include <sstream>
+
+#include <asn_application.h>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_InitiatingMessage.h>
+#include <E2N_RICsubscriptionRequest.h>
+#include <E2N_RICsubscription.h>
+#include <E2N_ProtocolIE-Field.h>
+#include <E2N_ProtocolIE-Single-Container.h>
+#include <E2N_RICactions-ToBeSetup-List.h>
+#include <E2N_RICsubsequentAction.h>
+#include "subscription_helper.hpp"
+
+#define NUM_SUBSCRIPTION_REQUEST_IES 3
+#define INITIAL_REQUEST_LIST_SIZE 4
+  
+class subscription_request{   
+public:
+
+  subscription_request(std::string name);
+  subscription_request(void);
+  ~subscription_request(void);
+  
+  bool encode_e2ap_subscription(unsigned char *, size_t *,  subscription_helper &);
+  bool set_fields(E2N_InitiatingMessage_t *, subscription_helper &);
+  bool get_fields(E2N_InitiatingMessage_t *, subscription_helper &);
+    
+  std::string get_error(void) const{
+    return error_string;
+  }
+    
+private:
+    
+  E2N_InitiatingMessage_t *initMsg;
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+
+  E2N_RICsubscriptionRequest_IEs_t * IE_array;
+  E2N_RICaction_ToBeSetup_ItemIEs_t * action_array;
+  unsigned int action_array_size;  
+  char errbuf[128];
+  size_t errbuf_len = 128;
+  std::string _name;
+  std::string error_string;
+};
+
+
+
+#endif
diff --git a/src/xapp-asn/e2ap/subscription_response.cc b/src/xapp-asn/e2ap/subscription_response.cc
new file mode 100644 (file)
index 0000000..5308e81
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+
+#include "subscription_response.hpp"
+
+/* The xAPP need only worry about the get_fields from a response, since it does
+not generate a response. Generating response however is included to support testing. 
+*/
+
+
+// Primarly for generation
+subscription_response::subscription_response(void){
+
+  e2ap_pdu_obj = 0;
+  e2ap_pdu_obj = (E2N_E2AP_PDU_t *)calloc(1, sizeof(E2N_E2AP_PDU_t));
+  assert(e2ap_pdu_obj != 0);
+
+  successMsg = 0;
+  successMsg = (E2N_SuccessfulOutcome_t *)calloc(1, sizeof(E2N_SuccessfulOutcome_t));
+  assert(successMsg != 0);
+
+  unsuccessMsg = 0;
+  unsuccessMsg = (E2N_UnsuccessfulOutcome_t *)calloc(1, sizeof(E2N_UnsuccessfulOutcome_t));
+  assert(unsuccessMsg != 0);
+
+  IE_array = 0;
+  IE_array = (E2N_RICsubscriptionResponse_IEs_t *)calloc(NUM_SUBSCRIPTION_RESPONSE_IES, sizeof(E2N_RICsubscriptionResponse_IEs_t));
+  assert(IE_array != 0);
+
+  IE_Failure_array = 0;
+  IE_Failure_array = (E2N_RICsubscriptionFailure_IEs_t *)calloc(NUM_SUBSCRIPTION_FAILURE_IES, sizeof(E2N_RICsubscriptionFailure_IEs_t));
+  assert(IE_Failure_array != 0);
+
+  ie_admitted_list = 0;
+  ie_admitted_list = (E2N_RICaction_Admitted_ItemIEs_t *)calloc(INITIAL_RESPONSE_LIST_SIZE, sizeof(E2N_RICaction_Admitted_ItemIEs_t));
+  assert(ie_admitted_list != 0);
+  ie_admitted_list_size = INITIAL_RESPONSE_LIST_SIZE;
+  
+  ie_not_admitted_list = 0;
+  ie_not_admitted_list = (E2N_RICaction_NotAdmitted_ItemIEs_t *)calloc(INITIAL_RESPONSE_LIST_SIZE, sizeof(E2N_RICaction_NotAdmitted_ItemIEs_t));
+  assert(ie_not_admitted_list != 0);
+  ie_not_admitted_list_size = INITIAL_RESPONSE_LIST_SIZE;
+
+
+
+
+  
+};
+
+  
+
+// Clear assigned protocolIE list from RIC indication IE container
+subscription_response::~subscription_response(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing subscription response memory");
+  E2N_RICaction_Admitted_List_t * response_admitted_list = (E2N_RICaction_Admitted_List_t *) &(IE_array[2].value.choice.RICaction_Admitted_List);
+  
+  for(int i = 0; i < response_admitted_list->list.size; i++){
+    response_admitted_list->list.array[i] = 0;
+  }
+
+  
+  if (response_admitted_list->list.size > 0){
+    free(response_admitted_list->list.array);
+    response_admitted_list->list.array = 0;
+    response_admitted_list->list.size = 0;
+    response_admitted_list->list.count = 0;
+  }
+
+  
+  E2N_RICaction_NotAdmitted_List_t * response_not_admitted_list = &(IE_array[3].value.choice.RICaction_NotAdmitted_List);
+  for(int i = 0; i < response_not_admitted_list->list.size; i++){
+    response_not_admitted_list->list.array[i] = 0;
+  }
+  
+  if (response_not_admitted_list->list.size > 0){
+    free(response_not_admitted_list->list.array);
+    response_not_admitted_list->list.array = 0;
+    response_not_admitted_list->list.size = 0;
+    response_not_admitted_list->list.count = 0;
+  }
+     
+  E2N_RICsubscriptionResponse_t * ric_subscription_response = &(successMsg->value.choice.RICsubscriptionResponse);
+  for(int i = 0; i < ric_subscription_response->protocolIEs.list.size ; i++){
+    ric_subscription_response->protocolIEs.list.array[i] = 0;
+  }
+  
+  if (ric_subscription_response->protocolIEs.list.size > 0){
+    free(ric_subscription_response->protocolIEs.list.array);
+    ric_subscription_response->protocolIEs.list.array = 0;
+    ric_subscription_response->protocolIEs.list.size = 0;
+    ric_subscription_response->protocolIEs.list.count = 0;
+  }
+  
+  
+  E2N_RICaction_NotAdmitted_List_t * failure_not_admitted_list = &(IE_Failure_array[2].value.choice.RICaction_NotAdmitted_List);
+  for(int i = 0; i < failure_not_admitted_list->list.size; i++){
+    failure_not_admitted_list->list.array[i] = 0;
+  }
+
+  if ( failure_not_admitted_list->list.size > 0){
+    free( failure_not_admitted_list->list.array);
+    failure_not_admitted_list->list.array = 0;
+    failure_not_admitted_list->list.size = 0;
+    failure_not_admitted_list->list.count = 0;
+  }
+  
+     
+  E2N_RICsubscriptionFailure_t * ric_subscription_failure = &(unsuccessMsg->value.choice.RICsubscriptionFailure);
+  for(int i = 0; i < ric_subscription_failure->protocolIEs.list.size; i++){
+    ric_subscription_failure->protocolIEs.list.array[i] = 0;
+  }
+  
+  if (  ric_subscription_failure->protocolIEs.list.size > 0){
+    free(ric_subscription_failure->protocolIEs.list.array);
+    ric_subscription_failure->protocolIEs.list.array = 0;
+    ric_subscription_failure->protocolIEs.list.size = 0;
+    ric_subscription_failure->protocolIEs.list.count = 0;
+  }
+
+
+  free(ie_admitted_list);  
+  free(ie_not_admitted_list);
+  free(IE_Failure_array);
+  free(IE_array);
+
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_SuccessfulOutcome, successMsg);
+  ASN_STRUCT_FREE(asn_DEF_E2N_UnsuccessfulOutcome, unsuccessMsg);
+
+  
+  e2ap_pdu_obj->choice.initiatingMessage = NULL;
+  e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_NOTHING;
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj);
+
+  mdclog_write(MDCLOG_DEBUG, "Freed subscription response memory ");
+
+  
+};
+
+
+bool subscription_response::encode_e2ap_subscription_response(unsigned char *buf, size_t *size, subscription_response_helper &dinput, bool is_success){
+  
+
+  if(is_success){
+    set_fields_success(dinput);
+    e2ap_pdu_obj->present =  E2N_E2AP_PDU_PR_successfulOutcome;
+    e2ap_pdu_obj->choice.successfulOutcome = successMsg;
+
+    successMsg->procedureCode = E2N_ProcedureCode_id_ricSubscription;
+    successMsg->criticality = E2N_Criticality_reject;
+    successMsg->value.present = E2N_SuccessfulOutcome__value_PR_RICsubscriptionResponse;   
+  }
+  else{
+    set_fields_unsuccess(dinput);
+    e2ap_pdu_obj->present = E2N_E2AP_PDU_PR_unsuccessfulOutcome;
+    e2ap_pdu_obj->choice.unsuccessfulOutcome = unsuccessMsg;
+
+    unsuccessMsg->procedureCode = E2N_ProcedureCode_id_ricSubscription;
+    unsuccessMsg->criticality = E2N_Criticality_reject;
+    unsuccessMsg->value.present = E2N_UnsuccessfulOutcome__value_PR_RICsubscriptionFailure;
+
+  }
+    
+  //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_obj);
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2AP_PDU, (void *) e2ap_pdu_obj, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(errbuf, errbuf_len);
+    error_string = "Constraints failed for encoding subscription response. Reason = " + error_string;
+    return false;
+  }
+    
+  asn_enc_rval_t res = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_obj, buf, *size);
+    
+  if(res.encoded == -1){
+    std::cout <<"Error encoding PDU. Reason =" << strerror(errno) << std::endl;
+    return false;
+  }
+  else {
+    if(*size < res.encoded){
+      fprintf(stderr,  "Buffer assigned too small to encode: %s",(char *)(asn_DEF_E2N_E2AP_PDU.name));
+      res.encoded = -1;
+      return false;
+    }
+  }
+    
+  *size = res.encoded;
+  return true;
+    
+}
+  
+void subscription_response::set_fields_success(subscription_response_helper &helper){
+
+  int ie_index;
+
+  E2N_RICsubscriptionResponse_t * subscription_response = &(successMsg->value.choice.RICsubscriptionResponse);
+  //reset list count ..
+  subscription_response->protocolIEs.list.count = 0;
+    
+  ie_index = 0;
+  E2N_RICsubscriptionResponse_IEs_t *ies_ricreq = &IE_array[ie_index];
+  
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionResponse_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+  ASN_SEQUENCE_ADD(&subscription_response->protocolIEs, &(IE_array[ie_index]));  
+
+  
+  ie_index = 1;
+  E2N_RICsubscriptionResponse_IEs_t *ies_ranfunc = &IE_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionResponse_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+  ASN_SEQUENCE_ADD(&subscription_response->protocolIEs, &(IE_array[ie_index]));
+
+  
+  ie_index = 2;
+  E2N_RICsubscriptionResponse_IEs_t *ies_admitted_actid = &IE_array[ie_index];
+  ies_admitted_actid->criticality = E2N_Criticality_reject;
+  ies_admitted_actid->id = E2N_ProtocolIE_ID_id_RICactions_Admitted;
+  E2N_RICaction_Admitted_List_t *ric_admitted_actions_ie = &ies_admitted_actid->value.choice.RICaction_Admitted_List;
+  ric_admitted_actions_ie->list.count = 0;
+  std::vector<ActionResponse> * ref_admitted_action_array = helper.get_admitted_list();  
+
+  if(ref_admitted_action_array->size() ==  0){
+    ies_admitted_actid->value.present =  E2N_RICsubscriptionResponse_IEs__value_PR_NOTHING;
+  }
+  else{  
+    ies_admitted_actid->value.present =  E2N_RICsubscriptionResponse_IEs__value_PR_RICaction_Admitted_List;
+
+    // resize memory ?
+    if (ref_admitted_action_array->size() >= ie_admitted_list_size){
+      ie_admitted_list_size = 2 * ref_admitted_action_array->size();
+      free(ie_admitted_list);
+      ie_admitted_list = (E2N_RICaction_Admitted_ItemIEs_t *)calloc(ie_admitted_list_size, sizeof(E2N_RICaction_Admitted_ItemIEs_t));
+      assert(ie_admitted_list != 0);
+    };
+  
+
+    for(unsigned int i = 0; i < ref_admitted_action_array->size(); i ++){
+      ie_admitted_list[i].criticality = E2N_Criticality_ignore;
+      ie_admitted_list[i].id = E2N_ProtocolIE_ID_id_RICaction_Admitted_Item ;
+      ie_admitted_list[i].value.present = E2N_RICaction_Admitted_ItemIEs__value_PR_RICaction_Admitted_Item;
+      ie_admitted_list[i].value.choice.RICaction_Admitted_Item.ricActionID = (*ref_admitted_action_array)[i].get_id();
+      ASN_SEQUENCE_ADD(ric_admitted_actions_ie, &(ie_admitted_list[i]));
+    }
+  }  
+  ASN_SEQUENCE_ADD(&subscription_response->protocolIEs, &(IE_array[ie_index]));
+
+  // optional IE : add only if non-zero list 
+  ie_index = 3;
+  std::vector<ActionResponse> * ref_notadmitted_action_array = helper.get_not_admitted_list();
+  if (ref_notadmitted_action_array->size() > 0){
+    
+    E2N_RICsubscriptionResponse_IEs_t *ies_notadmitted_actid = &IE_array[ie_index];
+    ies_notadmitted_actid->criticality = E2N_Criticality_reject;
+    ies_notadmitted_actid->id = E2N_ProtocolIE_ID_id_RICactions_NotAdmitted;
+
+    E2N_RICaction_NotAdmitted_List_t *ric_not_admitted_actions_ie = &ies_notadmitted_actid->value.choice.RICaction_NotAdmitted_List;
+    ric_not_admitted_actions_ie->list.count = 0;
+  
+  
+    ies_notadmitted_actid->value.present =  E2N_RICsubscriptionResponse_IEs__value_PR_RICaction_NotAdmitted_List;
+  
+    // resize memory ?
+    if (ref_notadmitted_action_array->size() >= ie_not_admitted_list_size){
+      ie_not_admitted_list_size = 2 * ref_notadmitted_action_array->size();
+      free(ie_not_admitted_list);
+      ie_not_admitted_list = (E2N_RICaction_NotAdmitted_ItemIEs_t *)calloc(ie_not_admitted_list_size, sizeof(E2N_RICaction_NotAdmitted_ItemIEs_t));
+      assert(ie_not_admitted_list != 0);
+    
+    };
+  
+  
+    for(unsigned int i = 0; i < ref_notadmitted_action_array->size(); i ++){
+      ie_not_admitted_list[i].criticality = E2N_Criticality_ignore;
+      ie_not_admitted_list[i].id = E2N_ProtocolIE_ID_id_RICaction_NotAdmitted_Item ;
+      ie_not_admitted_list[i].value.present = E2N_RICaction_NotAdmitted_ItemIEs__value_PR_RICaction_NotAdmitted_Item;;
+      ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricActionID = (*ref_notadmitted_action_array)[i].get_id();
+
+      int cause = (*ref_notadmitted_action_array)[i].get_cause();
+      switch(cause){
+      case E2N_RICcause_PR_radioNetwork:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.radioNetwork = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_transport:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.transport = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_protocol:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.protocol= (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_misc:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.misc = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_ric:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.ric = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      default:
+       mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Unknown RIC cause %d\n", __FILE__, __LINE__, cause);
+       return;
+      }
+
+      ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.present = (E2N_RICcause_PR)cause;      
+      ASN_SEQUENCE_ADD(ric_not_admitted_actions_ie, &(ie_not_admitted_list[i]));
+    }
+
+    ASN_SEQUENCE_ADD(&subscription_response->protocolIEs, &(IE_array[ie_index]));
+  }
+  
+}
+
+void subscription_response:: get_fields(E2N_SuccessfulOutcome_t * success_msg,  subscription_response_helper & dout)
+{
+
+  assert(success_msg != NULL);
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+  E2N_RICaction_Admitted_List_t  * ric_admitted_action_list;
+  E2N_RICaction_NotAdmitted_List_t * ric_not_admitted_action_list;
+    
+  for(int edx = 0; edx < success_msg->value.choice.RICsubscriptionResponse.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionResponse_IEs_t *memb_ptr = success_msg->value.choice.RICsubscriptionResponse.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RICactions_Admitted):
+       ric_admitted_action_list = &memb_ptr->value.choice.RICaction_Admitted_List;
+         
+       // admitted actions
+       for(int index = 0; index < ric_admitted_action_list->list.count; index ++){
+         E2N_RICaction_Admitted_ItemIEs_t * item = (E2N_RICaction_Admitted_ItemIEs_t *)ric_admitted_action_list->list.array[index];
+         long int id = item->value.choice.RICaction_Admitted_Item.ricActionID;
+         dout.get_admitted_list()->push_back(ActionResponse(id));
+       };
+
+       break;
+
+      case (E2N_ProtocolIE_ID_id_RICactions_NotAdmitted):
+       ric_not_admitted_action_list = &memb_ptr->value.choice.RICaction_NotAdmitted_List;
+         
+       for(int index = 0; index < ric_not_admitted_action_list->list.count; index ++){
+         E2N_RICaction_NotAdmitted_ItemIEs_t * item = (E2N_RICaction_NotAdmitted_ItemIEs_t *)ric_not_admitted_action_list->list.array[index];
+         long int id = item->value.choice.RICaction_NotAdmitted_Item.ricActionID;
+         int cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.present;
+         int sub_cause;
+         switch(cause){
+             
+         case  E2N_RICcause_PR_radioNetwork :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.radioNetwork;
+           break;
+             
+         case E2N_RICcause_PR_transport :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.transport;
+           break;
+             
+         case  E2N_RICcause_PR_protocol :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.protocol;
+           break;
+             
+         case E2N_RICcause_PR_misc :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.misc;
+           break;
+             
+         case E2N_RICcause_PR_ric :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.ric;
+           break;
+             
+         default:
+           std::cout <<"Error ! Illegal cause enum" << cause << std::endl;
+           return;
+         }  
+         dout.get_not_admitted_list()->push_back(ActionResponse(id, cause, sub_cause));
+       }
+       break;
+      }
+      
+  }
+    
+  //asn_fprint(stdout, &asn_DEF_E2AP_PDU, e2pdu);
+}
+
+
+void subscription_response::set_fields_unsuccess( subscription_response_helper &helper){
+
+  int ie_index;
+  E2N_RICsubscriptionFailure_t * ric_subscription_failure = &(unsuccessMsg->value.choice.RICsubscriptionFailure);
+  // reset list count
+  ric_subscription_failure->protocolIEs.list.count = 0;
+  
+  ie_index = 0;
+  E2N_RICsubscriptionFailure_IEs_t *ies_ricreq = &IE_Failure_array[ie_index];
+  ies_ricreq->criticality = E2N_Criticality_reject;
+  ies_ricreq->id = E2N_ProtocolIE_ID_id_RICrequestID;
+  ies_ricreq->value.present = E2N_RICsubscriptionFailure_IEs__value_PR_RICrequestID;
+  E2N_RICrequestID_t *ricrequest_ie = &ies_ricreq->value.choice.RICrequestID;
+  ricrequest_ie->ricRequestorID = helper.get_request_id();
+  ricrequest_ie->ricRequestSequenceNumber = helper.get_req_seq();
+  ASN_SEQUENCE_ADD(&ric_subscription_failure->protocolIEs, &(IE_Failure_array[ie_index]));  
+  
+  ie_index = 1;
+  E2N_RICsubscriptionFailure_IEs_t *ies_ranfunc = &IE_Failure_array[ie_index];
+  ies_ranfunc->criticality = E2N_Criticality_reject;
+  ies_ranfunc->id = E2N_ProtocolIE_ID_id_RANfunctionID;
+  ies_ranfunc->value.present = E2N_RICsubscriptionFailure_IEs__value_PR_RANfunctionID;
+  E2N_RANfunctionID_t *ranfunction_ie = &ies_ranfunc->value.choice.RANfunctionID;
+  *ranfunction_ie = helper.get_function_id();
+  ASN_SEQUENCE_ADD(&ric_subscription_failure->protocolIEs, &(IE_Failure_array[ie_index]));  
+
+  ie_index = 2;
+  E2N_RICsubscriptionFailure_IEs_t *ies_notadmitted_actid = &IE_Failure_array[ie_index];
+  ies_notadmitted_actid->criticality = E2N_Criticality_reject;
+  ies_notadmitted_actid->id = E2N_ProtocolIE_ID_id_RICactions_NotAdmitted;
+  E2N_RICaction_NotAdmitted_List_t *ric_not_admitted_actions_ie = &ies_notadmitted_actid->value.choice.RICaction_NotAdmitted_List;
+  ric_not_admitted_actions_ie->list.count = 0;   
+  std::vector<ActionResponse> * ref_notadmitted_action_array = helper.get_not_admitted_list();  
+  if(ref_notadmitted_action_array->size() == 0){
+    ies_notadmitted_actid->value.present =  E2N_RICsubscriptionFailure_IEs__value_PR_NOTHING;
+  }
+  else{
+    ies_notadmitted_actid->value.present =  E2N_RICsubscriptionFailure_IEs__value_PR_RICaction_NotAdmitted_List;
+
+    // resize memory  ?
+    if (ref_notadmitted_action_array->size() >= ie_not_admitted_list_size){
+      ie_not_admitted_list_size = 2 * ref_notadmitted_action_array->size();
+      free(ie_not_admitted_list);
+      ie_not_admitted_list = (E2N_RICaction_NotAdmitted_ItemIEs_t *)calloc(ie_not_admitted_list_size, sizeof(E2N_RICaction_NotAdmitted_ItemIEs_t));
+      assert(ie_not_admitted_list != 0);
+    };
+      
+  
+    // reset the list count on ricAction_ToBeSetup_List;
+    for(unsigned int i = 0; i < ref_notadmitted_action_array->size(); i ++){
+      ie_not_admitted_list[i].criticality = E2N_Criticality_ignore;
+      ie_not_admitted_list[i].id = E2N_ProtocolIE_ID_id_RICaction_NotAdmitted_Item ;
+      ie_not_admitted_list[i].value.present = E2N_RICaction_NotAdmitted_ItemIEs__value_PR_RICaction_NotAdmitted_Item;;
+      ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricActionID = (*ref_notadmitted_action_array)[i].get_id();
+
+      int cause = (*ref_notadmitted_action_array)[i].get_cause();
+      switch(cause){
+      case E2N_RICcause_PR_radioNetwork:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.radioNetwork = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_transport:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.transport = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_protocol:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.protocol= (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_misc:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.misc = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      case E2N_RICcause_PR_ric:
+       ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.choice.ric = (*ref_notadmitted_action_array)[i].get_sub_cause();
+       break;
+      default:
+       mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Unknown RIC cause %d\n", __FILE__, __LINE__, cause);
+       return ;
+      }
+
+      ie_not_admitted_list[i].value.choice.RICaction_NotAdmitted_Item.ricCause.present = (E2N_RICcause_PR)cause;
+      
+      ASN_SEQUENCE_ADD(ric_not_admitted_actions_ie, &(ie_not_admitted_list[i]));
+    }
+
+  }
+  ASN_SEQUENCE_ADD(&ric_subscription_failure->protocolIEs, &(IE_Failure_array[ie_index]));  
+
+
+  // // criticality diagnostics is not generated/parsed currently since optional
+  // i = 3;
+  // E2N_RICsubscriptionFailure_IEs_t *ies_criticality_diagnostics= &IE_Failure_array[i];
+  // ies_criticality_diagnostics->criticality = E2N_Criticality_ignore;
+  // ies_criticality_diagnostics->id = E2N_ProtocolIE_ID_id_CriticalityDiagnostics ;
+  // ies_criticality_diagnostics->value.present = E2N_RICsubscriptionFailure_IEs__value_PR_NOTHING;
+
+    
+}
+
+void subscription_response:: get_fields(E2N_UnsuccessfulOutcome_t * unsuccess_msg,  subscription_response_helper & dout)
+{
+
+  assert(unsuccess_msg != NULL);
+  
+  E2N_RICrequestID_t *requestid;
+  E2N_RANfunctionID_t * ranfunctionid;
+  E2N_RICaction_NotAdmitted_List_t * ric_not_admitted_action_list;
+    
+  for(int edx = 0; edx < unsuccess_msg->value.choice.RICsubscriptionFailure.protocolIEs.list.count; edx++) {
+    E2N_RICsubscriptionFailure_IEs_t *memb_ptr = unsuccess_msg->value.choice.RICsubscriptionFailure.protocolIEs.list.array[edx];
+    
+    switch(memb_ptr->id)
+      {
+      case (E2N_ProtocolIE_ID_id_RICrequestID):
+       requestid = &memb_ptr->value.choice.RICrequestID;
+       dout.set_request(requestid->ricRequestorID, requestid->ricRequestSequenceNumber);
+       break;
+         
+      case (E2N_ProtocolIE_ID_id_RANfunctionID):
+       ranfunctionid = &memb_ptr->value.choice.RANfunctionID;
+       dout.set_function_id(*ranfunctionid);
+       break;
+         
+
+      case (E2N_ProtocolIE_ID_id_RICactions_NotAdmitted):
+       ric_not_admitted_action_list = &memb_ptr->value.choice.RICaction_NotAdmitted_List;
+         
+       for(int index = 0; index < ric_not_admitted_action_list->list.count; index ++){
+         E2N_RICaction_NotAdmitted_ItemIEs_t * item = (E2N_RICaction_NotAdmitted_ItemIEs_t *)ric_not_admitted_action_list->list.array[index];
+         long int id = item->value.choice.RICaction_NotAdmitted_Item.ricActionID;
+         int cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.present;
+         int sub_cause;
+         switch(cause){
+             
+         case  E2N_RICcause_PR_radioNetwork :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.radioNetwork;
+           break;
+             
+         case E2N_RICcause_PR_transport :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.transport;
+           break;
+             
+         case  E2N_RICcause_PR_protocol :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.protocol;
+           break;
+             
+         case E2N_RICcause_PR_misc :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.misc;
+           break;
+             
+         case E2N_RICcause_PR_ric :
+           sub_cause = item->value.choice.RICaction_NotAdmitted_Item.ricCause.choice.ric;
+           break;
+             
+         default:
+           mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Unknown RIC cause %d\n", __FILE__, __LINE__, cause);
+           return;
+         }  
+         dout.get_not_admitted_list()->push_back(ActionResponse(id, cause, sub_cause));
+       }
+       break;
+      }
+      
+  }
+    
+  //asn_fprint(stdout, &asn_DEF_E2AP_PDU, e2pdu);
+}
+
+
+
diff --git a/src/xapp-asn/e2ap/subscription_response.hpp b/src/xapp-asn/e2ap/subscription_response.hpp
new file mode 100644 (file)
index 0000000..28fad4e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#pragma once
+
+#ifndef S_RESPONSE_
+#define S_RESPONSE_
+
+#include <mdclog/mdclog.h>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <asn_application.h>
+#include <E2N_E2AP-PDU.h>
+#include <E2N_SuccessfulOutcome.h>
+#include <E2N_UnsuccessfulOutcome.h>
+#include <E2N_ProtocolIE-Field.h>
+#include <E2N_ProtocolIE-Single-Container.h>
+#include <E2N_ProcedureCode.h>
+#include "response_helper.hpp"
+
+#define NUM_SUBSCRIPTION_RESPONSE_IES 4
+#define NUM_SUBSCRIPTION_FAILURE_IES 3
+#define INITIAL_RESPONSE_LIST_SIZE 4
+  
+class subscription_response{   
+public:
+    
+  subscription_response(void);
+  ~subscription_response(void);
+    
+  bool encode_e2ap_subscription_response(unsigned char *, size_t *,  subscription_response_helper &, bool);
+  void get_fields(E2N_SuccessfulOutcome_t *, subscription_response_helper &);    
+  void get_fields(E2N_UnsuccessfulOutcome_t *, subscription_response_helper &);
+  
+  std::string get_error(void) const{
+    return error_string;
+  }
+    
+private:
+
+  void set_fields_success( subscription_response_helper &);
+  void set_fields_unsuccess( subscription_response_helper &);
+
+  E2N_E2AP_PDU_t * e2ap_pdu_obj;
+  E2N_SuccessfulOutcome_t * successMsg;
+  E2N_UnsuccessfulOutcome_t * unsuccessMsg;
+    
+
+  E2N_RICsubscriptionResponse_IEs_t *IE_array;
+  E2N_RICsubscriptionFailure_IEs_t *IE_Failure_array;
+  
+
+  E2N_RICaction_Admitted_ItemIEs_t * ie_admitted_list;
+  E2N_RICaction_NotAdmitted_ItemIEs_t * ie_not_admitted_list;
+  unsigned int ie_admitted_list_size, ie_not_admitted_list_size;
+  
+  char errbuf[128];
+  size_t errbuf_len = 128;
+  std::string error_string;
+};
+
+
+
+
+#endif
diff --git a/src/xapp-asn/e2sm/e2sm.cc b/src/xapp-asn/e2sm/e2sm.cc
new file mode 100644 (file)
index 0000000..c476c83
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+  ==================================================================================
+
+  Copyright (c) 2018-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, softwares
+  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.
+  ==================================================================================
+*/
+
+/* Classes to handle E2 service model based on e2sm-gNB-X2-release-1-v040.asn */
+
+#include "e2sm.hpp"
+
+
+
+  //initialize
+  e2sm_event_trigger::e2sm_event_trigger(void){
+
+    memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
+
+    event_trigger = 0;
+    event_trigger = ( E2N_E2SM_gNB_X2_eventTriggerDefinition_t *)calloc(1, sizeof( E2N_E2SM_gNB_X2_eventTriggerDefinition_t));
+    assert(event_trigger != 0);
+    
+    // allocate space for gNodeB id  (used for encoding)
+    gNodeB_ID.gNB_ID.choice.gNB_ID.buf = 0;
+    gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
+    assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
+    
+    // allocate space for plmn identity  (used for encoding)
+    gNodeB_ID.pLMN_Identity.buf = 0;
+    gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
+    assert(gNodeB_ID.pLMN_Identity.buf != 0);
+
+    ie_list = 0;
+    ie_list = ( struct E2N_InterfaceProtocolIE_Item *) calloc(INITIAL_LIST_SIZE, sizeof( struct E2N_InterfaceProtocolIE_Item));
+    assert(ie_list != 0);
+    ie_list_size = INITIAL_LIST_SIZE;
+
+    condition_list = 0;
+    condition_list = (E2N_E2SM_gNB_X2_eventTriggerDefinition::E2N_E2SM_gNB_X2_eventTriggerDefinition__interfaceProtocolIE_List *) calloc(1, sizeof(E2N_E2SM_gNB_X2_eventTriggerDefinition::E2N_E2SM_gNB_X2_eventTriggerDefinition__interfaceProtocolIE_List ));
+    assert(condition_list != 0);
+
+    
+  };
+  
+e2sm_event_trigger::~e2sm_event_trigger(void){
+
+  mdclog_write(MDCLOG_DEBUG, "Freeing event trigger object memory");
+  for(int i = 0; i < condition_list->list.size; i++){
+    condition_list->list.array[i] = 0;
+  }
+
+  if (condition_list->list.size > 0){
+    free(condition_list->list.array);
+    condition_list->list.array = 0;
+    condition_list->list.size = 0;
+    condition_list->list.count = 0;
+  }
+
+  free(condition_list);
+  condition_list = 0;
+  
+  free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
+  gNodeB_ID.gNB_ID.choice.gNB_ID.buf = 0;
+  
+  free(gNodeB_ID.pLMN_Identity.buf);
+  gNodeB_ID.pLMN_Identity.buf = 0;
+  
+  free(ie_list);
+  ie_list = 0;
+  
+  event_trigger->interface_ID.choice.global_gNB_ID = 0;
+  event_trigger->interfaceProtocolIE_List = 0;
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger);
+  mdclog_write(MDCLOG_DEBUG, "Freed event trigger object memory");
+
+};
+
+bool e2sm_event_trigger::encode_event_trigger(unsigned char *buf, size_t *size, e2sm_event_trigger_helper &helper){
+  
+  bool res;
+  res = set_fields(event_trigger, helper);
+  if (!res){
+    return false;
+  }
+  
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    return false;
+  }
+
+  //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger);
+  
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event_trigger, buf, *size);
+  
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    return false;
+  }
+  else if (retval.encoded > *size){
+    std::stringstream ss;
+    ss  <<"Error encoding event trigger definition. Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+    error_string = ss.str();
+    return false;
+  }
+  else{
+    *size = retval.encoded;
+  }
+  
+  return true;
+}
+
+
+bool e2sm_event_trigger::set_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t * ref_event_trigger, e2sm_event_trigger_helper & helper){
+  if(ref_event_trigger == 0){
+    error_string = "Invalid reference for Event Trigger Definition set fields";
+    return false;
+  }
+      
+  // set the message type
+  ref_event_trigger->interfaceMessageType.procedureCode = helper.procedure_code;
+  ref_event_trigger->interfaceMessageType.typeOfMessage = helper.message_type;
+  
+  ref_event_trigger->interfaceDirection = helper.interface_direction; 
+  ref_event_trigger->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
+  
+  ref_event_trigger->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
+
+  // to do : need to put correct code here for upding plmn id and gNodeB
+  // for now just place holders :
+  //================================================================
+  memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
+  gNodeB_ID.pLMN_Identity.size = 3;
+  
+  memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
+  gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
+  
+  // we only do global gNodeB id for now, not eNodeB
+  gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
+  //================================================================
+  
+  
+  // Add in any requested IE items
+  std::vector<Item> * ref_ie_array = helper.get_list();
+
+  if (ref_ie_array->size() == 0){
+    ref_event_trigger->interfaceProtocolIE_List = 0;
+    
+  }
+  else{
+    ref_event_trigger->interfaceProtocolIE_List = condition_list;
+    
+    //resize memory ? 
+    if(ref_ie_array->size() > ie_list_size){
+      ie_list_size = 2 * ref_ie_array->size();
+      free(ie_list);
+      ie_list = (struct E2N_InterfaceProtocolIE_Item *)calloc(ie_list_size, sizeof(struct E2N_InterfaceProtocolIE_Item));
+      assert(ie_list != 0);
+    }
+    
+    // reset the count so that adds start from the beginning
+    ref_event_trigger->interfaceProtocolIE_List->list.count = 0;
+    
+    for(unsigned int i = 0; i < ref_ie_array->size(); i++){
+
+      ie_list[i].interfaceProtocolIE_ID = (*ref_ie_array)[i].interface_id;
+      ie_list[i].interfaceProtocolIE_Test = (*ref_ie_array)[i].test;
+      
+      //switch(ie_list[i].interfaceProtocolIE_Value.present){
+      switch((*ref_ie_array)[i].val_type){
+       
+      case (E2N_InterfaceProtocolIE_Value_PR_valueInt):
+       ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueInt;
+       ie_list[i].interfaceProtocolIE_Value.choice.valueInt = (*ref_ie_array)[i].value_n;
+       break;
+       
+      case (E2N_InterfaceProtocolIE_Value_PR_valueEnum):
+       ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueEnum;
+       ie_list[i].interfaceProtocolIE_Value.choice.valueEnum = (*ref_ie_array)[i].value_n;
+       break;
+       
+      case (E2N_InterfaceProtocolIE_Value_PR_valueBool):
+       ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueBool;
+       ie_list[i].interfaceProtocolIE_Value.choice.valueBool = (*ref_ie_array)[i].value_n;
+       break;
+       
+      case (E2N_InterfaceProtocolIE_Value_PR_valueBitS):
+       ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueBitS;
+       ie_list[i].interfaceProtocolIE_Value.choice.valueBitS.buf = (uint8_t *)(*ref_ie_array)[i].value_s.c_str();
+       ie_list[i].interfaceProtocolIE_Value.choice.valueBitS.size = (*ref_ie_array)[i].value_s.length();
+       break;
+
+      case (E2N_InterfaceProtocolIE_Value_PR_valueOctS):
+       ie_list[i].interfaceProtocolIE_Value.present = E2N_InterfaceProtocolIE_Value_PR_valueOctS;
+       ie_list[i].interfaceProtocolIE_Value.choice.valueOctS.buf = (uint8_t *)(*ref_ie_array)[i].value_s.c_str();
+       ie_list[i].interfaceProtocolIE_Value.choice.valueOctS.size = (*ref_ie_array)[i].value_s.length();
+       break;
+
+      default:
+       {
+         std::stringstream ss;
+         ss <<"Error ! " << __FILE__ << "," << __LINE__ << " illegal enum " << (*ref_ie_array)[i].val_type << " for interface Protocol IE value" << std::endl;
+         std::string error_string = ss.str();
+         return false;
+       }
+      }
+      
+      ASN_SEQUENCE_ADD(ref_event_trigger->interfaceProtocolIE_List, &ie_list[i]);
+    }
+  }
+
+  return true;
+};
+  
+
+bool e2sm_event_trigger::get_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t * ref_event_trigger, e2sm_event_trigger_helper & helper){
+
+  if (ref_event_trigger == 0){
+    error_string = "Invalid reference for Event Trigger definition get fields";
+    return false;
+  }
+  
+  helper.procedure_code = ref_event_trigger->interfaceMessageType.procedureCode;
+  helper.message_type   = ref_event_trigger->interfaceMessageType.typeOfMessage;
+  helper.interface_direction = ref_event_trigger->interfaceDirection;
+  
+  helper.plmn_id.assign((const char *)ref_event_trigger->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, ref_event_trigger->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
+  helper.egNB_id.assign((const char *)ref_event_trigger->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, ref_event_trigger->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
+  for(int i = 0; i < ref_event_trigger->interfaceProtocolIE_List->list.count; i++){
+    struct E2N_InterfaceProtocolIE_Item * ie_item = ref_event_trigger->interfaceProtocolIE_List->list.array[i];
+    switch(ie_item->interfaceProtocolIE_Value.present){
+    case (E2N_InterfaceProtocolIE_Value_PR_valueInt):
+      helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueInt);
+      break;
+    case (E2N_InterfaceProtocolIE_Value_PR_valueEnum):
+      helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueEnum);
+      break;
+    case (E2N_InterfaceProtocolIE_Value_PR_valueBool):
+      helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, ie_item->interfaceProtocolIE_Value.choice.valueBool);            
+      break;
+    case (E2N_InterfaceProtocolIE_Value_PR_valueBitS):
+      helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, std::string((const char *)ie_item->interfaceProtocolIE_Value.choice.valueBitS.buf,ie_item->interfaceProtocolIE_Value.choice.valueBitS.size) );
+      break;
+    case (E2N_InterfaceProtocolIE_Value_PR_valueOctS):
+      helper.add_protocol_ie_item(ie_item->interfaceProtocolIE_ID, ie_item->interfaceProtocolIE_Test, ie_item->interfaceProtocolIE_Value.present, std::string((const char *)ie_item->interfaceProtocolIE_Value.choice.valueOctS.buf,ie_item->interfaceProtocolIE_Value.choice.valueOctS.size) );
+      break;
+    default:
+      mdclog_write(MDCLOG_ERR, "Error : %s, %d: Unkown interface protocol IE type %d in event trigger definition\n", __FILE__, __LINE__, ie_item->interfaceProtocolIE_Value.present);
+      return false;
+    }
+  }
+  
+  return true;
+};
+    
+
+  
+   
+// initialize
+e2sm_indication::e2sm_indication(void) {
+  
+  memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
+    
+  // allocate space for gNodeB id  (used for encoding)
+  gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
+  assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
+    
+  // allocate space for plmn identity  (used for encoding)
+  gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
+  assert(gNodeB_ID.pLMN_Identity.buf != 0);
+
+  header = 0;
+  header = (E2N_E2SM_gNB_X2_indicationHeader_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_indicationHeader_t));
+  assert(header != 0);
+
+  message = 0;
+  message = (E2N_E2SM_gNB_X2_indicationMessage_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_indicationMessage_t));
+  assert(message != 0);
+}
+  
+e2sm_indication::~e2sm_indication(void){
+  mdclog_write(MDCLOG_DEBUG, "Freeing E2N_E2SM Indication  object memory");
+
+  free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
+  free(gNodeB_ID.pLMN_Identity.buf);
+  
+  header->interface_ID.choice.global_gNB_ID = 0;
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header);
+
+  message->interfaceMessage.buf = 0;
+  message->interfaceMessage.size = 0;
+
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message);
+  mdclog_write(MDCLOG_DEBUG, "Freed E2SM Indication  object memory");
+    
+}
+  
+  
+
+bool e2sm_indication::encode_indication_header(unsigned char *buf, size_t *size, e2sm_header_helper &helper){
+    
+  bool res;
+  res = set_header_fields(header, helper);
+  if (!res){
+    return false;
+  }
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    error_string = "E2SM Indication Header Constraint failed : " + error_string;
+
+    return false;
+  }
+
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_indicationHeader, header, buf, *size);
+
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding E2N_E2SM Indication Header. Reason = " + error_string;
+    return false;
+  }
+  else if (retval.encoded > *size){
+    std::stringstream ss;
+    ss  <<"Error encoding E2SM Indication Header . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+    error_string = ss.str();
+    return false;
+  }
+  else{
+    *size = retval.encoded;
+  }
+    
+  return true;
+}
+
+
+bool e2sm_indication::encode_indication_message(unsigned char *buf, size_t *size, e2sm_message_helper &helper){
+
+  set_message_fields(message, helper); 
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    error_string = "E2SM Indication Message Constraint failed : " + error_string;
+    return false;
+  }
+
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_indicationMessage, message, buf, *size);
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding E2SM Indication Header. Reason = " + error_string;
+    return false;
+  }
+  else if (retval.encoded > *size){
+    std::stringstream ss;
+    ss  <<"Error encoding E2N_E2SM Indication Message . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+    error_string = ss.str();
+    
+    return false;
+  }
+  else{
+    *size = retval.encoded;
+  }
+  
+  return true;
+}
+
+
+
+// Used when generating an indication header 
+bool e2sm_indication::set_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *header,  e2sm_header_helper &helper){
+
+  if (header == 0){
+    error_string = "Invalid reference for E2SM Indication Header set fields";
+    return false;
+  }
+  
+  
+  header->interfaceDirection = helper.interface_direction;
+  header->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
+  header->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
+
+
+  // to do : need to put correct code here for upding plmn id and gNodeB
+  // for now just place holders :
+  memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
+  gNodeB_ID.pLMN_Identity.size = 3;
+  
+  memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
+  gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
+  
+  // we only do global gNodeB id for now, not eNodeB
+  gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
+
+  return true;
+  
+};
+
+
+// used when decoding an indication header
+bool e2sm_indication::get_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *header,  e2sm_header_helper &helper){
+
+  if (header == 0){
+    error_string = "Invalid reference for E2SM Indication header get fields";
+    return false;
+  }
+  
+  helper.interface_direction = header->interfaceDirection;
+  helper.plmn_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, header->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
+  helper.egNB_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
+  
+  // to do : add code to decipher plmn and global gnodeb from ints (since that is likely the convention for packing)
+
+  return true;
+}
+
+
+
+// Used when generating an indication message 
+bool   e2sm_indication::set_message_fields(E2N_E2SM_gNB_X2_indicationMessage_t *interface_message,  e2sm_message_helper &helper){
+
+  if(interface_message == 0){
+    error_string = "Invalid reference for E2SM Indication Message set fields";
+    return false;
+  }
+
+  // interface-message is an octet string. just point it to the buffer
+  interface_message->interfaceMessage.buf = &(helper.x2ap_pdu[0]);
+  interface_message->interfaceMessage.size = helper.x2ap_pdu_size;
+
+  return true;
+  
+};
+
+// used when decoding an indication message
+bool e2sm_indication::get_message_fields( E2N_E2SM_gNB_X2_indicationMessage_t *interface_message, e2sm_message_helper &helper){
+
+  
+  if(interface_message == 0){
+    error_string = "Invalid reference for E2SM Indication Message get fields";
+    return false;
+  }
+
+  // interface message is an octet string
+  helper.x2ap_pdu = interface_message->interfaceMessage.buf;;
+  helper.x2ap_pdu_size = interface_message->interfaceMessage.size;
+
+  return true;
+  
+}
+  
+
+   
+// initialize
+e2sm_control::e2sm_control(void) {
+  
+  memset(&gNodeB_ID, 0, sizeof(E2N_GlobalGNB_ID_t));
+    
+  // allocate space for gNodeB id  (used for encoding)
+  gNodeB_ID.gNB_ID.choice.gNB_ID.buf = (uint8_t *)calloc(4, sizeof(uint8_t));
+  assert(gNodeB_ID.gNB_ID.choice.gNB_ID.buf != 0);
+    
+  // allocate space for plmn identity  (used for encoding)
+  gNodeB_ID.pLMN_Identity.buf = (uint8_t *) calloc(4, sizeof(uint8_t));
+  assert(gNodeB_ID.pLMN_Identity.buf != 0);
+
+  header = 0;
+  header = (E2N_E2SM_gNB_X2_controlHeader_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_controlHeader_t));
+  assert(header != 0);
+
+  message = 0;
+  message = (E2N_E2SM_gNB_X2_controlMessage_t *)calloc(1, sizeof(E2N_E2SM_gNB_X2_controlMessage_t));
+  assert(message != 0);
+}
+  
+e2sm_control::~e2sm_control(void){
+  mdclog_write(MDCLOG_DEBUG, "Freeing E2SM Control  object memory");
+
+  free(gNodeB_ID.gNB_ID.choice.gNB_ID.buf);
+  free(gNodeB_ID.pLMN_Identity.buf);
+  header->interface_ID.choice.global_gNB_ID = 0;
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header);
+
+  message->interfaceMessage.buf = 0;
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message);
+
+  mdclog_write(MDCLOG_DEBUG, "Freed E2SM Control  object memory");
+    
+}
+  
+  
+
+bool e2sm_control::encode_control_header(unsigned char *buf, size_t *size, e2sm_header_helper &helper){
+    
+  bool res;
+  res = set_header_fields(header, helper);
+  if (!res){
+    return false;
+  }
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    error_string = "E2SM Control Header Constraint failed : " + error_string;
+
+    return false;
+  }
+
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_controlHeader, header, buf, *size);
+
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding E2SM Control Header. Reason = " + error_string;
+    return false;
+  }
+  else if (retval.encoded > *size){
+    std::stringstream ss;
+    ss  <<"Error encoding E2N_E2SM Control Header . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+    error_string = ss.str();
+    return false;
+  }
+  else{
+    *size = retval.encoded;
+  }
+    
+  return true;
+}
+
+
+bool e2sm_control::encode_control_message(unsigned char *buf, size_t *size, e2sm_message_helper &helper){
+
+  set_message_fields(message, helper); 
+
+  int ret_constr = asn_check_constraints(&asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message, errbuf, &errbuf_len);
+  if(ret_constr){
+    error_string.assign(&errbuf[0], errbuf_len);
+    error_string = "E2SM Control Message Constraint failed : " + error_string;
+    return false;
+  }
+
+  asn_enc_rval_t retval = asn_encode_to_buffer(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_controlMessage, message, buf, *size);
+  if(retval.encoded == -1){
+    error_string.assign(strerror(errno));
+    error_string = "Error encoding E2SM Control Message. Reason = " + error_string;
+    return false;
+  }
+  else if (retval.encoded > *size){
+    std::stringstream ss;
+    ss  <<"Error encoding E2SM Control Message . Reason =  encoded pdu size " << retval.encoded << " exceeds buffer size " << *size << std::endl;
+    error_string = ss.str();
+    
+    return false;
+  }
+  else{
+    *size = retval.encoded;
+  }
+  
+  return true;
+}
+
+
+
+// Used when generating an indication header 
+bool e2sm_control::set_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *header,  e2sm_header_helper &helper){
+
+  if (header == 0){
+    error_string = "Invalid reference for E2SM Control Header set fields";
+    return false;
+  }
+  
+  
+  header->interfaceDirection = helper.interface_direction;
+  header->interface_ID.present = E2N_Interface_ID_PR_global_gNB_ID;
+  header->interface_ID.choice.global_gNB_ID = &gNodeB_ID;
+
+
+  // to do : need to put correct code here for upding plmn id and gNodeB
+  // for now just place holders :
+  memcpy(gNodeB_ID.pLMN_Identity.buf, helper.plmn_id.c_str(), 3);
+  gNodeB_ID.pLMN_Identity.size = 3;
+  
+  memcpy(gNodeB_ID.gNB_ID.choice.gNB_ID.buf, helper.egNB_id.c_str(), 3);
+  gNodeB_ID.gNB_ID.choice.gNB_ID.size = 3;
+  
+  // we only do global gNodeB id for now, not eNodeB
+  gNodeB_ID.gNB_ID.present = E2N_GNB_ID_PR_gNB_ID;
+
+  return true;
+  
+};
+
+
+// used when decoding an indication header
+bool e2sm_control::get_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *header,  e2sm_header_helper &helper){
+
+  if (header == 0){
+    error_string = "Invalid reference for E2SM Control header get fields";
+    return false;
+  }
+  
+  helper.interface_direction = header->interfaceDirection;
+  helper.plmn_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->pLMN_Identity.buf, header->interface_ID.choice.global_gNB_ID->pLMN_Identity.size);
+  helper.egNB_id.assign((const char *)header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.buf, header->interface_ID.choice.global_gNB_ID->gNB_ID.choice.gNB_ID.size);
+  
+  // to do : add code to decipher plmn and global gnodeb from ints (since that is likely the convention for packing)
+
+  return true;
+}
+
+
+
+// Used when generating an indication message 
+bool   e2sm_control::set_message_fields(E2N_E2SM_gNB_X2_controlMessage_t *interface_message,  e2sm_message_helper &helper){
+
+  if(interface_message == 0){
+    error_string = "Invalid reference for E2SM Control Message set fields";
+    return false;
+  }
+
+  // interface-message is an octet string. just point it to the buffer
+  interface_message->interfaceMessage.buf = &(helper.x2ap_pdu[0]);
+  interface_message->interfaceMessage.size = helper.x2ap_pdu_size;
+
+  return true;
+  
+};
+
+// used when decoding an indication message
+bool e2sm_control::get_message_fields( E2N_E2SM_gNB_X2_controlMessage_t *interface_message, e2sm_message_helper &helper){
+
+  
+  if(interface_message == 0){
+    error_string = "Invalid reference for E2SM Control Message get fields";
+    return false;
+  }
+
+  // interface message is an octet string
+  helper.x2ap_pdu = interface_message->interfaceMessage.buf;;
+  helper.x2ap_pdu_size = interface_message->interfaceMessage.size;
+
+  return true;
+  
+}
+  
diff --git a/src/xapp-asn/e2sm/e2sm.hpp b/src/xapp-asn/e2sm/e2sm.hpp
new file mode 100644 (file)
index 0000000..c0877b4
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+/* Classes to handle E2 service model based on e2sm-gNB-X2-release-1-v040.asn */
+
+#ifndef E2SM_
+#define E2SM_
+
+
+#include <sstream>
+#include <e2sm_helpers.hpp>
+#include <mdclog/mdclog.h>
+#include <E2N_E2SM-gNB-X2-indicationHeader.h>
+#include <E2N_E2SM-gNB-X2-indicationMessage.h>
+#include <E2N_E2SM-gNB-X2-controlHeader.h>
+#include <E2N_E2SM-gNB-X2-controlMessage.h>
+#include <E2N_E2SM-gNB-X2-eventTriggerDefinition.h>
+
+#include <E2N_GlobalGNB-ID.h>
+#include <E2N_TypeOfMessage.h>
+#include <E2N_InterfaceProtocolIE-Item.h>
+
+#include<E2N_InterfaceProtocolIE-ID.h>
+#include<E2N_InterfaceProtocolIE-Value.h>
+#include<E2N_InterfaceProtocolIE-Test.h>
+
+#define INITIAL_LIST_SIZE 4
+
+  
+
+  
+/* builder class for E2SM event trigger definition */
+
+class e2sm_event_trigger {
+public:
+  e2sm_event_trigger(void);
+  ~e2sm_event_trigger(void);
+    
+  bool set_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t *, e2sm_event_trigger_helper &);
+  bool get_fields(E2N_E2SM_gNB_X2_eventTriggerDefinition_t *, e2sm_event_trigger_helper &);
+  bool encode_event_trigger(unsigned char *, size_t *, e2sm_event_trigger_helper &);
+
+  std::string  get_error (void) const {return error_string ;};
+  
+private:
+
+  E2N_E2SM_gNB_X2_eventTriggerDefinition_t * event_trigger; // used for encoding
+  E2N_GlobalGNB_ID_t gNodeB_ID;
+  struct E2N_InterfaceProtocolIE_Item * ie_list;
+  unsigned int ie_list_size;
+    
+  //std::vector<struct InterfaceProtocolIE_Item> ie_list;
+  E2N_E2SM_gNB_X2_eventTriggerDefinition::E2N_E2SM_gNB_X2_eventTriggerDefinition__interfaceProtocolIE_List *condition_list;
+    
+  char errbuf[128];
+  size_t errbuf_len;
+  std::string error_string;
+};
+  
+    
+/* builder class for E2SM indication  using ASN1c */
+  
+class e2sm_indication {
+public:
+    
+  e2sm_indication(void);
+  ~e2sm_indication(void);
+    
+  E2N_E2SM_gNB_X2_indicationHeader_t * get_header(void);
+  E2N_E2SM_gNB_X2_indicationMessage_t * get_message(void);
+
+  bool set_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *, e2sm_header_helper &);
+  bool get_header_fields(E2N_E2SM_gNB_X2_indicationHeader_t *, e2sm_header_helper &);
+    
+  bool set_message_fields(E2N_E2SM_gNB_X2_indicationMessage_t *, e2sm_message_helper &);
+  bool get_message_fields(E2N_E2SM_gNB_X2_indicationMessage_t *, e2sm_message_helper &);
+
+  bool encode_indication_header(unsigned char * , size_t * , e2sm_header_helper &); 
+  bool encode_indication_message(unsigned char *, size_t *, e2sm_message_helper &);
+  std::string  get_error (void) const {return error_string ; };
+    
+private:
+  
+  E2N_E2SM_gNB_X2_indicationHeader_t *header; // used for encoding
+  E2N_E2SM_gNB_X2_indicationMessage_t *message; // used for encoding
+    
+  char errbuf[128];
+  size_t errbuf_len;
+  E2N_GlobalGNB_ID_t gNodeB_ID;
+  std::string error_string;
+
+  
+};
+
+/* builder class for E2SM control  using ASN1c */
+  
+class e2sm_control {
+public:
+    
+  e2sm_control(void);
+  ~e2sm_control(void);
+    
+  E2N_E2SM_gNB_X2_controlHeader_t * get_header(void);
+  E2N_E2SM_gNB_X2_controlMessage_t * get_message(void);
+
+  bool set_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *, e2sm_header_helper &);
+  bool get_header_fields(E2N_E2SM_gNB_X2_controlHeader_t *, e2sm_header_helper &);
+    
+  bool set_message_fields(E2N_E2SM_gNB_X2_controlMessage_t *, e2sm_message_helper &);
+  bool get_message_fields(E2N_E2SM_gNB_X2_controlMessage_t *, e2sm_message_helper &);
+
+  bool encode_control_header(unsigned char * , size_t * , e2sm_header_helper &); 
+  bool encode_control_message(unsigned char *, size_t *, e2sm_message_helper &);
+  std::string  get_error (void) const {return error_string ; };
+    
+private:
+  
+  E2N_E2SM_gNB_X2_controlHeader_t *header; // used for encoding
+  E2N_E2SM_gNB_X2_controlMessage_t *message; // used for encoding
+    
+  char errbuf[128];
+  size_t errbuf_len;
+  E2N_GlobalGNB_ID_t gNodeB_ID;
+  std::string error_string;
+
+  
+};
+
+#endif
diff --git a/src/xapp-asn/e2sm/e2sm_helpers.hpp b/src/xapp-asn/e2sm/e2sm_helpers.hpp
new file mode 100644 (file)
index 0000000..ae7a481
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+
+#ifndef E2SM_HELPER_
+#define E2SM_HELPER_
+
+#include <errno.h>
+#include <iostream>
+#include <vector>
+#include <sstream>
+
+ /* information holder for E2SM indication header */
+typedef struct e2sm_header_helper e2sm_header_helper;
+struct e2sm_header_helper {
+  int egNB_id_type;
+  
+  std::string egNB_id;
+  std::string plmn_id;
+  
+  long int interface_direction;
+  unsigned char* timestamp;
+};
+
+/* information holder for E2SM indication message */
+typedef struct e2sm_message_helper e2sm_message_helper;
+struct e2sm_message_helper {
+  unsigned char * x2ap_pdu;
+  size_t x2ap_pdu_size;
+};
+
+  
+/* information holder for E2SM Action Trigger Definition */
+struct Item
+{
+  Item(long int id, long int test, long int val_type, int value):interface_id(id), test(test), val_type(val_type), value_n(value){};
+  Item(long int id, long int test, long int val_type, std::string value):interface_id(id), test(test), val_type(val_type), value_s(value){};
+    
+  long int interface_id;
+  long int test;
+  long int  val_type;
+  long int value_n;
+  std::string value_s;
+    
+};
+  
+typedef struct e2sm_event_trigger_helper e2sm_event_trigger_helper;
+struct e2sm_event_trigger_helper {
+    
+  int egNB_id_type;
+  std::string egNB_id;
+  std::string plmn_id;
+    
+  long int interface_direction;
+  long int procedure_code;
+    
+  long int message_type;
+
+    
+  std::vector<struct Item> * get_list(void){ return &protocol_ie_list; };
+  void add_protocol_ie_item(long int id, long int test , unsigned int val_type, long int value ){
+    // into list 
+    protocol_ie_list.emplace_back(id, test, val_type, value);
+  };
+  
+  void add_protocol_ie_item(long int id, long int  test, unsigned  int val_type, std::string  value){
+    //  into list 
+    protocol_ie_list.emplace_back(id, test, val_type, value);    
+  };
+   
+  void clear(void){
+    protocol_ie_list.clear();
+  }
+
+  std::string get_string(void) const {
+    std::stringstream ss;
+    ss << "egNB_ID_type = " << egNB_id_type << std::endl;
+    ss << "PLMN Id = " << plmn_id << std::endl;
+    ss << "Procedure Code = " << procedure_code << std::endl;
+    ss << "Message Type = " << message_type << std::endl;
+
+    std::string info;
+    info = ss.str();
+    return info;
+  }
+  
+    
+    
+private:
+    
+  std::vector<struct Item> protocol_ie_list;
+    
+};
+
+  
+
+
+#endif
diff --git a/src/xapp-mgmt/msgs_proc.cc b/src/xapp-mgmt/msgs_proc.cc
new file mode 100644 (file)
index 0000000..d20ef76
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * msgs_proc.cc
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+
+
+#include "msgs_proc.hpp"
+
+//sending messages are encoded.
+bool XappMsgHandler::encode_subscription_request(unsigned char* buffer, size_t *buf_len)
+{
+       int request_id = 2; // will be over-written by subscription handler
+       int req_seq = 1;
+       int function_id = 0;
+       int action_id = 1;
+       int action_type = 0;
+       int subsequent_action = 0; // continue
+       int time_to_wait = 4; // 10ms
+
+       int message_type = 1;
+       int procedure_code = 27;
+       std::string egnb_id = "Testgnb";
+       std::string plmn_id = "Testplmn";
+
+       unsigned char event_buf[128];
+       size_t event_buf_len = 128;
+       bool res;
+
+
+       e2sm_event_trigger_helper trigger_data;
+       e2sm_event_trigger event_trigger;
+
+       trigger_data.egNB_id = egnb_id;
+       trigger_data.plmn_id = plmn_id;
+       trigger_data.egNB_id_type = 2;
+       trigger_data.interface_direction = 1;
+       trigger_data.procedure_code = procedure_code;
+       trigger_data.message_type = message_type;
+       //======================================================
+
+       // Encode the event trigger definition
+       res = event_trigger.encode_event_trigger(&event_buf[0], &event_buf_len, trigger_data);
+       if (!res){
+               mdclog_write(MDCLOG_ERR, "Error : %s, %d: Could not encode subscription Request. Reason = %s\n", __FILE__, __LINE__, event_trigger.get_error().c_str());
+               return false;
+       }
+       mdclog_write(MDCLOG_INFO, "Encoded event trigger definition into PDU of size %lu bytes\n", event_buf_len);
+
+
+       // create the subscription
+       subscription_helper subscr_req;
+       subscription_request e2ap_sub_req;
+
+       subscr_req.clear();
+       subscr_req.set_request(request_id, req_seq);
+       subscr_req.set_function_id(function_id);
+       subscr_req.add_action(action_id, action_type, "", subsequent_action, time_to_wait);
+
+       subscr_req.set_event_def(&event_buf[0], event_buf_len);
+       // generate the request pdu
+       res = e2ap_sub_req.encode_e2ap_subscription(&buffer[0], buf_len, subscr_req);
+       if(! res){
+               mdclog_write(MDCLOG_ERR, "%s, %d: Error encoding subscription pdu. Reason = ", __FILE__, __LINE__);
+               return false;
+       }
+       return true;
+}
+bool XappMsgHandler::encode_subscription_delete_request(unsigned char* buffer, size_t *buf_len){
+
+       subscription_helper sub_helper;
+       sub_helper.set_request(0, 0); // requirement of subscription manager ... ?
+       sub_helper.set_function_id(0);
+
+       subscription_delete e2ap_sub_req_del;
+
+         // generate the delete request pdu
+
+         bool res = e2ap_sub_req_del.encode_e2ap_subscription(&buffer[0], buf_len, sub_helper);
+         if(! res){
+           mdclog_write(MDCLOG_ERR, "%s, %d: Error encoding subscription delete request pdu. Reason = %s", __FILE__, __LINE__, e2ap_sub_req_del.get_error().c_str());
+           return false;
+         }
+
+       return true;
+
+}
+
+bool XappMsgHandler::decode_subscription_response(unsigned char* data_buf, size_t data_size){
+
+       bool res = true;
+       E2N_E2AP_PDU_t *e2pdu = 0;
+
+       asn_dec_rval_t rval;
+
+       ASN_STRUCT_RESET(asn_DEF_E2N_E2AP_PDU, e2pdu);
+
+       rval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&e2pdu, data_buf, data_size);
+       switch(rval.code)
+       {
+               case RC_OK:
+                         //Put in Subscription Response Object.
+                          asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+
+                          break;
+               case RC_WMORE:
+                               mdclog_write(MDCLOG_ERR, "RC_WMORE");
+                               res = false;
+                               break;
+               case RC_FAIL:
+                               mdclog_write(MDCLOG_ERR, "RC_FAIL");
+                               res = false;
+                               break;
+               default:
+                               break;
+        }
+       ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2pdu);
+       return res;
+
+}
+bool XappMsgHandler::decode_subscription_delete_response(unsigned char* data_buf, size_t data_size){
+
+       bool res = true;
+       E2N_E2AP_PDU_t *e2pdu = 0;
+
+       asn_dec_rval_t rval;
+
+       ASN_STRUCT_RESET(asn_DEF_E2N_E2AP_PDU, e2pdu);
+
+       rval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&e2pdu, data_buf, data_size);
+       switch(rval.code)
+       {
+               case RC_OK:
+                         //Put in Subscription Delete Response Object.
+                          asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+                          break;
+               case RC_WMORE:
+                               mdclog_write(MDCLOG_ERR, "RC_WMORE");
+                               res = false;
+                               break;
+               case RC_FAIL:
+                               mdclog_write(MDCLOG_ERR, "RC_FAIL");
+                               res = false;
+                               break;
+               default:
+                               break;
+        }
+       ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2pdu);
+       return res;
+
+}
+bool XappMsgHandler::decode_subscription_response_failure(unsigned char* data_buf, size_t data_size){
+
+       bool res = true;
+       E2N_E2AP_PDU_t *e2pdu = 0;
+
+       asn_dec_rval_t rval;
+
+       ASN_STRUCT_RESET(asn_DEF_E2N_E2AP_PDU, e2pdu);
+
+       rval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&e2pdu, data_buf, data_size);
+       switch(rval.code)
+       {
+               case RC_OK:
+                         //Extract Subscription Response Failure.
+                          asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+                          break;
+               case RC_WMORE:
+                               mdclog_write(MDCLOG_ERR, "RC_WMORE");
+                               res = false;
+                               break;
+               case RC_FAIL:
+                               mdclog_write(MDCLOG_ERR, "RC_FAIL");
+                               res = false;
+                               break;
+               default:
+                               break;
+        }
+       ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2pdu);
+       return res;
+
+}
+
+bool XappMsgHandler::decode_subscription_delete_response_failure(unsigned char* data_buf, size_t data_size){
+
+       bool res = true;
+       E2N_E2AP_PDU_t *e2pdu = 0;
+
+       asn_dec_rval_t rval;
+
+       ASN_STRUCT_RESET(asn_DEF_E2N_E2AP_PDU, e2pdu);
+
+       rval = asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&e2pdu, data_buf, data_size);
+       switch(rval.code)
+       {
+               case RC_OK:
+                         //Extract Subscription Delete Response Failure.
+                          asn_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2pdu);
+                               break;
+               case RC_WMORE:
+                               mdclog_write(MDCLOG_ERR, "RC_WMORE");
+                               res = false;
+                               break;
+               case RC_FAIL:
+                               mdclog_write(MDCLOG_ERR, "RC_FAIL");
+                               res = false;
+                               break;
+               default:
+                               break;
+        }
+       ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2pdu);
+       return res;
+
+}
+
+//For processing received messages.
+rmr_mbuf_t * XappMsgHandler::operator()(rmr_mbuf_t *message){
+
+  if (message->len > MAX_RMR_RECV_SIZE){
+    mdclog_write(MDCLOG_ERR, "Error : %s, %d, RMR message larger than %d. Ignoring ...", __FILE__, __LINE__, MAX_RMR_RECV_SIZE);
+    return message;
+  }
+
+  switch(message->mtype){
+         //need to fix the health check.
+         case (RIC_HEALTH_CHECK_REQ):
+               message->mtype = RIC_HEALTH_CHECK_RESP;        // if we're here we are running and all is ok
+           message->sub_id = -1;
+         break;
+
+         case (RIC_SUB_RESP):
+               //Received Subscription Response Message
+               decode_subscription_response(message->payload,message->len);
+           message = NULL;
+         break;
+
+         case (RIC_SUB_DEL_RESP):
+               decode_subscription_delete_response(message->payload,message->len);
+               message = NULL;
+         break;
+
+         case (RIC_SUB_FAILURE):
+               decode_subscription_response_failure(message->payload, message->len);
+           message = NULL;
+      break;
+
+         case (RIC_SUB_DEL_FAILURE):
+               decode_subscription_delete_response_failure(message->payload,message->len);
+           message = NULL;
+         break;
+         //  case A1_POLICY_REQ:
+        // break;
+
+
+  default:
+    mdclog_write(MDCLOG_ERR, "Error :: Unknown message type %d received from RMR", message->mtype);
+
+  }
+
+  return message;
+
+};
+
+
diff --git a/src/xapp-mgmt/msgs_proc.hpp b/src/xapp-mgmt/msgs_proc.hpp
new file mode 100644 (file)
index 0000000..ec15933
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * msgs_proc.hpp
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+#pragma once
+
+#ifndef XAPP_MSG_XAPP_MSG_HPP_
+#define XAPP_MSG_XAPP_MSG_HPP_
+
+#include <iostream>
+#include<rmr/rmr.h>
+#include <rmr/RIC_message_types.h>
+#include <mdclog/mdclog.h>
+
+
+#include <subscription_request.hpp>
+#include <subscription_response.hpp>
+#include <subscription_delete_request.hpp>
+#include <subscription_delete_response.hpp>
+#include "subscription_request.hpp"
+#include "subscription_helper.hpp"
+#include "e2sm.hpp"
+#include <e2ap_indication.hpp>
+#include <e2ap_control.hpp>
+#include <e2ap_control_response.hpp>
+
+#define MAX_RMR_RECV_SIZE 2<<15
+
+class XappMsgHandler{
+
+private:
+       unsigned char* message_buffer;
+       size_t* message_length;
+
+public:
+        rmr_mbuf_t * operator() (rmr_mbuf_t *);
+
+        bool encode_subscription_request(unsigned char*, size_t* );
+        bool encode_subscription_delete_request(unsigned char*, size_t* );
+
+        bool decode_subscription_response(unsigned char*, size_t );
+        bool decode_subscription_delete_response(unsigned char*, size_t );
+        bool decode_subscription_response_failure(unsigned char*, size_t );
+        bool decode_subscription_delete_response_failure(unsigned char*, size_t );
+
+
+};
+
+
+#endif /* XAPP_MSG_XAPP_MSG_HPP_ */
diff --git a/src/xapp-mgmt/subs_mgmt.cc b/src/xapp-mgmt/subs_mgmt.cc
new file mode 100644 (file)
index 0000000..af53220
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * subs_mgmt.cc
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+#include "subs_mgmt.hpp"
+
+#include <errno.h>
+
+
+SubscriptionHandler::SubscriptionHandler(unsigned int timeout_seconds, unsigned int num_tries):_time_out(std::chrono::seconds(timeout_seconds)), _num_retries(num_tries){
+  init();   
+};
+
+void SubscriptionHandler::init(void){
+  
+  _data_lock = std::make_unique<std::mutex>();
+  _cv = std::make_unique<std::condition_variable>();
+  
+}
+
+void SubscriptionHandler::clear(void){
+  {
+    std::lock_guard<std::mutex> lock(*(_data_lock).get());
+    requests_table.clear();
+    subscription_responses.clear();
+  }
+  
+};
+
+size_t SubscriptionHandler::num_pending(void) const {
+  return requests_table.size();
+}
+
+size_t SubscriptionHandler::num_complete(void) const {
+  return subscription_responses.size();
+}
+
+
+void SubscriptionHandler::set_timeout(unsigned int timeout_seconds){
+  _time_out = std::chrono::seconds(timeout_seconds);
+}
+
+void SubscriptionHandler::set_num_retries(unsigned int num_tries){
+  _num_retries = num_tries;
+};
+
+
+
+bool SubscriptionHandler::add_request_entry(subscription_identifier id, int status){
+
+  // add entry in hash table if it does not exist
+  auto search = requests_table.find(id);
+  if(search != requests_table.end()){
+    return false;
+  }
+  
+  requests_table[id] = status;
+  return true;
+
+};
+
+bool SubscriptionHandler::set_request_status(subscription_identifier id, int status){
+  
+  // change status of a request only if it exists.
+  auto search = requests_table.find(id);
+  if(search != requests_table.end()){
+    requests_table[id] = status;
+    return true;
+  }
+
+  return false;
+  
+};
+
+
+bool SubscriptionHandler::delete_request_entry(subscription_identifier id){
+
+  auto search = requests_table.find(id);
+  if (search != requests_table.end()){
+    requests_table.erase(search);
+    return true;
+  }
+
+  return false;
+};
+  
+bool SubscriptionHandler::add_subscription_entry(subscription_identifier id, subscription_response_helper &he){
+
+  auto search = subscription_responses.find(id);
+  if (search == subscription_responses.end()){
+    subscription_responses[id] = he;
+    return true;
+  }
+
+  return false;
+}
+
+
+bool SubscriptionHandler::delete_subscription_entry(subscription_identifier id){
+
+  auto search = subscription_responses.find(id);
+  if(search == subscription_responses.end()){
+    return false;
+  }
+  else{
+    subscription_responses.erase(search);
+    return true;
+  }
+  
+}
+
+subscription_response_helper *  const SubscriptionHandler::get_subscription(subscription_identifier id){
+  auto search = subscription_responses.find(id);
+  if(search == subscription_responses.end()){
+    return NULL;
+  }
+  else{
+    return &(subscription_responses[id]);
+  }
+};
+
+
+// Handles responses from RMR
+void SubscriptionHandler::Response(int message_type, unsigned char *payload, int payload_length, const char * node_id){
+
+  bool res;
+  std::string node(node_id);
+  int type;
+  int procedureCode;
+  bool valid_response  =false;
+  
+  E2N_E2AP_PDU_t * e2ap_recv;
+  asn_dec_rval_t retval;
+
+  subscription_response sub_resp;
+  subscription_delete_response sub_del_resp;
+
+  subscription_response_helper he_response;
+
+
+  e2ap_recv = 0;
+  retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_recv), payload, payload_length);
+
+  if(retval.code != RC_OK){
+    mdclog_write(MDCLOG_ERR, "%s, %d: Error decoding E2AP PDU of RMR type %d. Bytes decoded = %lu out of %d\n", __FILE__, __LINE__, message_type, retval.consumed, payload_length);
+    ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_recv);
+    return ;
+  }
+  
+  type = e2ap_recv->present;
+  mdclog_write(MDCLOG_INFO, "Received RMR message of type = %d", type);
+  
+  if(type == E2N_E2AP_PDU_PR_successfulOutcome){
+    
+    procedureCode =  e2ap_recv->choice.successfulOutcome->procedureCode;
+    mdclog_write(MDCLOG_INFO, "Received E2N_E2AP PDU  successful outcome message with procedureCode = %d", procedureCode);  
+
+    if( procedureCode == E2N_ProcedureCode_id_ricSubscription){  
+      // subscription response
+      // decode the message
+      sub_resp.get_fields(e2ap_recv->choice.successfulOutcome, he_response);
+      {
+       std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+       // get the id
+       subscription_identifier id = std::make_tuple (node, he_response.get_request_id());
+
+       // get status of id 
+       int req_status = get_request_status(id);
+       if (req_status == request_pending ){
+         res = add_subscription_entry(id, he_response);
+         if(res)
+           set_request_status(id, request_success);
+         
+         else{
+           set_request_status(id, request_duplicate);
+           mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %s, %d seems to be a duplicate. Subscription already present in subscription table\n", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id));
+         }
+         
+         valid_response = true;
+       }
+       else if (req_status > 0){
+         // we don't change status of response since it was not in pending
+         // we simply fail
+         mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %s,%d is not in request_pending state, is in State = %d\n", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id), req_status);
+         
+       }
+       else{
+         mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find id %s, %d in request queue for subscription", __FILE__, __LINE__,  std::get<0>(id).c_str(), std::get<1>(id));
+       }         
+       
+      }
+      
+    }
+    
+    else if( procedureCode == E2N_ProcedureCode_id_ricSubscriptionDelete){
+      
+      res = sub_del_resp.get_fields(e2ap_recv->choice.successfulOutcome, he_response);
+      {
+       std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+
+       // get the id
+       subscription_identifier id = std::make_tuple (node, he_response.get_request_id());
+       
+       int req_status = get_request_status(id);
+       if (req_status == delete_request_pending ){
+         // Remove the subscription from the table 
+         res = delete_subscription_entry(id);
+         if(res){
+           set_request_status(id, delete_request_success);
+           valid_response = true;
+         }
+         else{
+           set_request_status(id, delete_request_failed);
+           mdclog_write(MDCLOG_ERR,  "%s, %d: Error deleting subscription entry for  %s, %d", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id));
+           valid_response = true;
+         } 
+       }      
+       else if (req_status > 0){
+         // we don't change status since it was not in pending
+         // we simply fail
+         mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %s, %d for deletion  is not in delete_pending state, is in State = %d\n", __FILE__, __LINE__, id, std::get<0>(id).c_str(), std::get<1>(id));
+       }
+       else{
+         mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find request id  %s, %d in request queue for deletion ", __FILE__, __LINE__,  std::get<0>(id).c_str(), std::get<1>(id));
+       }
+
+      }
+    }
+
+    else{
+      mdclog_write(MDCLOG_ERR,  "%s, %d: Subscription Handler Response received E2AP PDU success  response with an non-subscription response related type  %d", __FILE__, __LINE__, procedureCode);
+    }
+    
+  }
+  
+  else if(type == E2N_E2AP_PDU_PR_unsuccessfulOutcome){
+    
+    procedureCode = e2ap_recv->choice.unsuccessfulOutcome->procedureCode;
+    mdclog_write(MDCLOG_INFO, "Received E2AP PDU  unsuccessful outcome message with procedureCode = %d", procedureCode);  
+    
+    if(procedureCode == E2N_ProcedureCode_id_ricSubscription){
+      
+      sub_resp.get_fields(e2ap_recv->choice.unsuccessfulOutcome, he_response);
+      {
+       std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+
+       // get the id
+       subscription_identifier id = std::make_tuple (node, he_response.get_request_id());
+
+       int req_status = get_request_status(id);
+       if(req_status == request_pending){
+         set_request_status(id, request_failed);
+         valid_response = true;
+         mdclog_write(MDCLOG_ERR, "Subscription request %d failed", id);
+       }
+       else if (req_status > 0){
+         // we don't changet status since it was not in pending
+         // we simply fail
+         mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %s, %d is not in request_pending state, is in State = %d\n", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id), req_status);
+       }
+       else{
+         mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find id %s, %d in request queue for subscription ", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id));
+       }
+      }
+    }
+    
+    else if(procedureCode == E2N_ProcedureCode_id_ricSubscriptionDelete){
+      
+      res = sub_del_resp.get_fields(e2ap_recv->choice.unsuccessfulOutcome, he_response);       
+      {
+       std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+       // get the id
+       subscription_identifier id = std::make_tuple (node, he_response.get_request_id());
+       
+       int req_status = get_request_status(id);
+       if(req_status == delete_request_pending){
+         set_request_status(id, delete_request_failed);
+         mdclog_write(MDCLOG_INFO, "Subscription delete request %s,%d failed", std::get<0>(id).c_str(), std::get<1>(id));
+         valid_response = true;
+       }
+       else if (req_status > 0){
+         mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %s,%d for deletion  is not in delete_pending state, is in State = %d\n", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id), req_status);
+       }
+       else{
+         mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find id  %s,%d  in request queue for deletion ", __FILE__, __LINE__, std::get<0>(id).c_str(), std::get<1>(id));
+       }
+       
+      }
+    }
+    else{
+      mdclog_write(MDCLOG_ERR,  "%s, %d: Susbcription Handler Response received E2AP PDU failure response with a non-subscription response related type  %d", __FILE__, __LINE__,  procedureCode);
+
+    }
+  }
+  else{
+    mdclog_write(MDCLOG_ERR,  "%s, %d: Susbcription Handler Response received E2AP PDU with non response type  %d", __FILE__, __LINE__, type);
+  }
+  
+  
+  ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_recv);
+  
+  // wake up all waiting users ...
+  if(valid_response){
+    _cv.get()->notify_all();
+  }
+  
+}
+
+
+int const SubscriptionHandler::get_request_status(subscription_identifier id){
+  auto search = requests_table.find(id);
+  if (search == requests_table.end()){
+    return -1;
+  }
+  
+  return search->second;
+}
+                                  
+ bool SubscriptionHandler::is_subscription_entry(subscription_identifier id){
+  auto search = subscription_responses.find(id);
+  if (search != subscription_responses.end())
+    return true;
+  else
+    return false;
+}
+
+bool SubscriptionHandler::is_request_entry(subscription_identifier id){
+  auto search = requests_table.find(id);
+  if (search != requests_table.end())
+    return true;
+  else
+    return false;
+}
+
+
+void SubscriptionHandler::get_subscription_keys(std::vector<subscription_identifier> & key_list){
+  for(auto & e: subscription_responses){
+    key_list.push_back(e.first);
+  }
+}
diff --git a/src/xapp-mgmt/subs_mgmt.hpp b/src/xapp-mgmt/subs_mgmt.hpp
new file mode 100644 (file)
index 0000000..77458d3
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+==================================================================================
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+/*
+ * subs_mgmt.hpp
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+
+#pragma once
+
+#ifndef SUBSCRIPTION_HANDLER
+#define SUBSCRIPTION_HANDLER
+
+#include <functional>
+#include <mdclog/mdclog.h>
+#include <mutex>
+#include <condition_variable>
+#include <unordered_map>
+#include <chrono>
+#include <tuple>
+
+#include "subscription_delete_request.hpp"
+#include "subscription_delete_response.hpp"
+#include "subscription_request.hpp"
+#include "subscription_response.hpp"
+
+#define SUBSCR_SUCCESS 0
+#define SUBSCR_ERR_TX 1
+#define SUBSCR_ERR_TIMEOUT 2
+#define SUBSCR_ERR_FAIL 3
+#define SUBSCR_ERR_UNKNOWN 4
+#define SUBSCR_ERR_DUPLICATE 5
+#define SUBSCR_ERR_ENCODE  6
+#define SUBSCR_ERR_MISSING 7
+
+using namespace std;
+
+typedef enum {
+    request_pending = 1,
+    request_success,
+    request_failed,
+    delete_request_pending,
+    delete_request_success,
+    delete_request_failed,
+    request_duplicate
+}Subscription_Status_Types;
+
+using subscription_identifier = std::tuple<std::string , int>;
+
+struct subscription_hasher {
+  size_t operator()(const subscription_identifier & key) const {
+    return  std::hash<std::string>{}(std::get<0>(key) + std::to_string(std::get<1>(key)));
+  }
+};
+
+class SubscriptionHandler {
+                           
+public:
+
+       SubscriptionHandler(unsigned int timeout_seconds = 5, unsigned int num_retries = 2);
+  
+  void init(void);
+
+  template <typename Transmitter>
+  int request_subscription(std::string, int ,   Transmitter &&);
+
+  template<typename Transmitter>
+  int request_subscription_delete(subscription_helper  &, subscription_response_helper &, std::string,  int ,  Transmitter &&);
+
+  void  Response(int, unsigned char *, int, const char *);
+  int const get_request_status(subscription_identifier);
+  subscription_response_helper * const get_subscription(subscription_identifier);
+  
+  unsigned int get_next_id(void);
+  void set_timeout(unsigned int);
+  void set_num_retries(unsigned int);
+  
+  bool is_subscription_entry(subscription_identifier); 
+  bool is_request_entry(subscription_identifier);
+  void get_subscription_keys(std::vector<subscription_identifier> &);
+  void clear(void);
+  size_t  num_pending(void) const;
+  size_t  num_complete(void) const ;
+
+
+  
+private:
+
+  
+  bool add_request_entry(subscription_identifier, int);
+  bool set_request_status(subscription_identifier, int);
+  bool delete_request_entry(subscription_identifier);
+  bool get_subscription_entry(subscription_identifier);
+  bool add_subscription_entry(subscription_identifier, subscription_response_helper &he);
+  bool delete_subscription_entry(subscription_identifier);
+  
+  std::unordered_map<subscription_identifier, int, subscription_hasher> requests_table;
+  std::unordered_map<subscription_identifier, subscription_response_helper, subscription_hasher> subscription_responses; // stores list of successful subscriptions
+  
+  std::unique_ptr<std::mutex> _data_lock;
+  std::unique_ptr<std::condition_variable> _cv;
+
+  std::chrono::seconds _time_out;
+  unsigned int _num_retries = 2;
+  unsigned int unique_request_id = 0;
+  
+};
+
+template <typename Transmitter>
+int SubscriptionHandler::request_subscription(std::string node_id, int msgcode, Transmitter && tx){
+
+  // generate subscription identifier
+  subscription_identifier sub_id = std::make_tuple (node_id, 0); //0 is the function id which is hardcoded, which should come from rnib
+
+
+  bool res;
+  // put entry in request table
+  {
+    std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+    res = add_request_entry(sub_id, request_pending);
+    if(! res){
+      mdclog_write(MDCLOG_ERR, "%s, %d : Error adding new subscription request %s, %d to queue because request with identical key already present",  __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      return SUBSCR_ERR_DUPLICATE;
+    }
+  }
+
+  // acquire lock ...
+  std::unique_lock<std::mutex> _local_lock(*(_data_lock.get()));
+
+
+  // Send the message
+  res = tx();
+
+  if (!res){
+    // clear state
+    delete_request_entry(sub_id);
+    mdclog_write(MDCLOG_ERR, "%s, %d :: Error transmitting subscription request %s, %d", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id) );
+    return SUBSCR_ERR_TX;
+  };
+
+
+  // record time stamp ..
+  auto start = std::chrono::system_clock::now();
+  res = SUBSCR_ERR_UNKNOWN;
+
+  while(1){
+    // release lock and wait to be woken up
+    _cv.get()->wait_for(_local_lock, _time_out);
+
+    // we have woken and acquired data_lock
+    // check status and return appropriate object
+
+    int status = get_request_status(sub_id);
+
+    if (status == request_success){
+      // retreive  & store the subscription response (why?)
+      // response = subscription_responses[sub_id];
+      mdclog_write(MDCLOG_INFO, "Successfully subscribed for request %s, %d", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      res = SUBSCR_SUCCESS;
+      break;
+    }
+
+    if (status == request_pending){
+      // woken up spuriously or timed out
+      auto end = std::chrono::system_clock::now();
+      std::chrono::duration<double> f = end - start;
+
+      if ( f > _num_retries * _time_out){
+       mdclog_write(MDCLOG_ERR, "%s, %d:: Subscription request %s, %d timed out waiting for response ", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+       res = SUBSCR_ERR_TIMEOUT;
+       break;
+      }
+      else{
+       mdclog_write(MDCLOG_INFO, "Subscription request %s, %d Waiting for response ....", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+       continue;
+      }
+    }
+
+    if(status == request_failed){
+      mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Subscription Request %s, %d  got failure response .. \n", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      res = SUBSCR_ERR_FAIL;
+      break;
+    }
+
+    if (status == request_duplicate){
+      mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Subscription Request %s, %d is duplicate : subscription already present in table .. \n", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      res = SUBSCR_ERR_DUPLICATE;
+      break;
+
+    }
+
+    // if we are here, some spurious
+    // status obtained or request failed . we return appropriate error code
+    mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Spurious time out caused by invalid state of request %s, %d -- state = %d. Deleting request entry and failing .. \n", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id), status);
+    res = SUBSCR_ERR_UNKNOWN;
+    break;
+  };
+
+  delete_request_entry(sub_id);
+
+  // release data lock
+  _local_lock.unlock();
+  std::cout <<"Returning  res = " << res << " for request = " << std::get<0>(sub_id).c_str() << "," <<  std::get<1>(sub_id) << std::endl;
+  return res;
+};
+
+
+/*template <typename Transmitter>
+int  SubscriptionHandler::request_subscription_delete(subscription_helper &he, subscription_response_helper &response, std::string node_id,  int TxCode, Transmitter && tx){
+
+  int res;
+  // generate subscription identifier
+  subscription_identifier sub_id = std::make_tuple (node_id, he.get_function_id());
+
+  // First check if we have this subscription
+  if(! is_subscription_entry(sub_id)){
+    mdclog_write(MDCLOG_ERR, "subscription with id %s, %d  does not exist. Cannot be deleted",std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+    return SUBSCR_ERR_MISSING;
+  }
+
+  // Also check if such a request is queued
+  if (is_request_entry(sub_id)){
+    mdclog_write(MDCLOG_ERR, "Subscription delete request  with id %s, %d  already in queue",std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+    return SUBSCR_ERR_DUPLICATE;
+  }
+
+  subscription_delete e2ap_sub_req_del;
+
+  // generate the delete request pdu
+  unsigned char buffer[128];
+  size_t buf_len = 128;
+
+  res = e2ap_sub_req_del.encode_e2ap_subscription(&buffer[0], &buf_len, he);
+  if(! res){
+    mdclog_write(MDCLOG_ERR, "%s, %d: Error encoding subscription delete request pdu. Reason = %s", __FILE__, __LINE__, e2ap_sub_req_del.get_error().c_str());
+    return SUBSCR_ERR_ENCODE;
+  }
+
+  // put entry in request table
+  {
+    std::lock_guard<std::mutex> lock(*(_data_lock.get()));
+    res = add_request_entry(sub_id, delete_request_pending);
+    if(!res){
+      mdclog_write(MDCLOG_ERR, "%s, %d: Duplicate  subscription delete request = %s, %d", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id) );
+      return SUBSCR_ERR_DUPLICATE;
+    }
+  }
+
+  std::unique_lock<std::mutex> _local_lock(*(_data_lock.get()));
+
+  // Send the message
+  res = tx(TxCode,  buf_len, buffer);
+
+  if (!res){
+    delete_request_entry(sub_id);
+    mdclog_write(MDCLOG_ERR, "Error transmitting delete subscription request %s, %d", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+    return SUBSCR_ERR_TX;
+  };
+
+
+  // record time stamp ..
+  auto start = std::chrono::system_clock::now();
+
+  res = SUBSCR_ERR_UNKNOWN;
+  while(1){
+
+    // wait to be woken up
+    _cv.get()->wait_for(_local_lock, _time_out);
+
+    // check status and return appropriate object
+    int status = get_request_status(sub_id);
+    if (status == delete_request_success){
+      mdclog_write(MDCLOG_INFO, "Successfully deleted subscription id %s, %d", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      res = SUBSCR_SUCCESS;
+      break;
+    }
+
+    if (status == delete_request_pending){
+      // woken up spuriously or timed out
+      auto end = std::chrono::system_clock::now();
+      std::chrono::duration<double> f = end - start;
+
+      if (f > _num_retries * _time_out){
+       mdclog_write(MDCLOG_ERR, "Subscription delete request %s, %d timed out waiting for response ", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+       res = SUBSCR_ERR_TIMEOUT;
+       break;
+      }
+      else{
+       mdclog_write(MDCLOG_INFO, "Subscription delete request %s, %d Waiting for response ....", std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      }
+
+      continue;
+    }
+
+    if(status == delete_request_failed){
+      mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Subscription Delete Request %s, %d  got failure response .. \n", __FILE__, __LINE__, std::get<0>(sub_id).c_str(), std::get<1>(sub_id));
+      res = SUBSCR_ERR_FAIL;
+      break;
+    }
+
+    // if we are here, some spurious
+    // status obtained. we return false
+
+    mdclog_write(MDCLOG_ERR, "Error :: %s, %d : Spurious time out caused by invalid state of  delete request %s, %d -- state = %d. Deleting request entry and failing .. \n", __FILE__, __LINE__,std::get<0>(sub_id).c_str(), std::get<1>(sub_id), status);
+    res =  SUBSCR_ERR_UNKNOWN;
+    break;
+
+  };
+
+  delete_request_entry(sub_id);
+
+  // release data lock
+  _local_lock.unlock();
+  std::cout <<"Returning  res = " << res << " for " << std::get<0>(sub_id) << "," << std::get<1>(sub_id) << std::endl;
+  return res;
+};*/
+
+#endif
diff --git a/src/xapp-utils/xapp_config.cc b/src/xapp-utils/xapp_config.cc
new file mode 100644 (file)
index 0000000..f9a4640
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+/*
+ * xapp_config.cc
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+
+#include "xapp_config.hpp"
+
+string& XappSettings::operator[](const SettingName& theName){
+    return theSettings[theName];
+}
+
+void XappSettings::loadCmdlineSettings(int argc, char **argv){
+
+          // Parse command line options to over ride
+         static struct option long_options[] =
+           {
+                       {"xappname", required_argument, 0, 'n'},
+                               {"xappid", required_argument, 0, 'x'},
+                               {"port", required_argument, 0, 'p'},
+                               {"threads", required_argument,    0, 't'},
+                               {"a1-schema", required_argument, 0, 'a'},
+                               {"ves-schema", required_argument, 0, 'v'},
+                               {"ves-url", required_argument, 0, 'u'},
+                               {"ves-interval", required_argument, 0, 'i'},
+                               {"gNodeB", required_argument, 0, 'g'},
+                               {"opmode", required_argument, 0, 'c'}
+
+           };
+
+
+          while(1) {
+
+               int option_index = 0;
+               char c = getopt_long(argc, argv, "n:p:t:s:g:a:v:u:i:c:x:", long_options, &option_index);
+
+               if(c == -1){
+                   break;
+                }
+
+               switch(c)
+                 {
+
+                 case 'n':
+                   theSettings[XAPP_NAME].assign(optarg);
+                   break;
+
+                 case 'p':
+                   theSettings[HW_PORTS].assign(optarg);
+                   break;
+
+                 case 't':
+                       theSettings[THREADS].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "Number of threads set to %s from command line e\n", theSettings[THREADS].c_str());
+                   break;
+
+                 case 'a':
+                       theSettings[A1_SCHEMA_FILE].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "Schema file set to %s from command line ", theSettings[A1_SCHEMA_FILE].c_str());
+                   break;
+
+                 case 'v':
+                   theSettings[VES_SCHEMA_FILE].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "VES Schema file set to %s from command line ", theSettings[VES_SCHEMA_FILE].c_str());
+                   break;
+
+                 case 'c':
+                   theSettings[OPERATING_MODE].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "Operating mode set from command line to %s\n", theSettings[OPERATING_MODE].c_str());
+                   break;
+
+                 case 'u':
+                   theSettings[VES_COLLECTOR_URL].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "VES collector url set to %s from command line ", theSettings[VES_COLLECTOR_URL].c_str());
+                   break;
+
+                 case 'x':
+                   theSettings[XAPP_ID].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "XAPP ID set to  %s from command line ", theSettings[XAPP_ID].c_str());
+                   break;
+
+                 case 'i':
+                       theSettings[VES_MEASUREMENT_INTERVAL].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "Measurement interval set to %s from command line\n", theSettings[VES_MEASUREMENT_INTERVAL].c_str());
+                   break;
+
+                 case 'g':
+                   theSettings[GNODEB].assign(optarg);
+                   mdclog_write(MDCLOG_INFO, "gNodeB List set to %s from command line ", theSettings[GNODEB].c_str());
+                   break;
+
+                 case 'h':
+                   usage(argv[0]);
+                   exit(0);
+
+                 default:
+                   usage(argv[0]);
+                   exit(1);
+                 }
+          };
+
+}
+
+void XappSettings::loadDefaultSettings(){
+
+
+                if(theSettings[XAPP_NAME].empty()){
+                 theSettings[XAPP_NAME] = DEFAULT_PORT;
+                 }
+
+                 if(theSettings[XAPP_ID].empty()){
+                         theSettings[XAPP_ID] = DEFAULT_PORT;
+                 }
+                 if(theSettings[LOG_LEVEL].empty()){
+                         theSettings[LOG_LEVEL] = DEFAULT_LOG_LEVEL;
+                 }
+                 if(theSettings[HW_PORTS].empty()){
+                         theSettings[HW_PORTS] = DEFAULT_PORT;
+                 }
+                 if(theSettings[MSG_MAX_BUFFER].empty()){
+                         theSettings[MSG_MAX_BUFFER] = DEFAULT_BUFFER;
+                 }
+
+                 if(theSettings[A1_SCHEMA_FILE].empty()){
+                         theSettings[A1_SCHEMA_FILE] = DEFAULT_A1_SCHEMA_FILE;
+                 }
+
+                 if(theSettings[VES_SCHEMA_FILE].empty()){
+                         theSettings[VES_SCHEMA_FILE] = DEFAULT_VES_SCHEMA_FILE;
+                 }
+
+                 if(theSettings[VES_COLLECTOR_URL].empty()){
+                         theSettings[VES_COLLECTOR_URL] = DEFAULT_VES_COLLECTOR_URL;
+                 }
+
+                if(theSettings[VES_MEASUREMENT_INTERVAL].empty()){
+                         theSettings[VES_MEASUREMENT_INTERVAL] = DEFAULT_VES_MEASUREMENT_INTERVAL;
+                 }
+
+                if(theSettings[GNODEB].empty()){
+                         theSettings[GNODEB] = DEFAULT_GNODEB;
+                 }
+
+                if(theSettings[OPERATING_MODE].empty()){
+                         theSettings[OPERATING_MODE] = DEFAULT_OPERATING_MODE;
+                 }
+
+}
+
+void XappSettings::loadEnvVarSettings(){
+
+         if (const char *env_xname = std::getenv("XAPP_NAME")){
+                 theSettings[XAPP_NAME].assign(env_xname);
+                 mdclog_write(MDCLOG_INFO,"Xapp Name set to %s from environment variable", theSettings[XAPP_NAME].c_str());
+         }
+         if (const char *env_xid = std::getenv("XAPP_ID")){
+                  theSettings[XAPP_ID].assign(env_xid);
+                  mdclog_write(MDCLOG_INFO,"Xapp ID set to %s from environment variable", theSettings[XAPP_ID].c_str());
+         }
+
+         if (const char *env_ports = std::getenv("HW_PORTS")){
+                 theSettings[HW_PORTS].assign(env_ports);
+                 mdclog_write(MDCLOG_INFO,"Ports set to %s from environment variable", theSettings[HW_PORTS].c_str());
+         }
+         if (const char *env_ports = std::getenv("MSG_MAX_BUFFER")){
+                         theSettings[MSG_MAX_BUFFER].assign(env_ports);
+                         mdclog_write(MDCLOG_INFO,"Ports set to %s from environment variable", theSettings[MSG_MAX_BUFFER].c_str());
+                 }
+
+        if (const char *env_schema = std::getenv("A1_SCHEMA_FILE")){
+                 theSettings[A1_SCHEMA_FILE].assign(env_schema);
+                 mdclog_write(MDCLOG_INFO, "A1 Schema file set to %s from environment variable", theSettings[A1_SCHEMA_FILE].c_str());
+         }
+         if (const char *env_schema = std::getenv("VES_SCHEMA_FILE")){
+                 theSettings[VES_SCHEMA_FILE].assign(env_schema);
+                 mdclog_write(MDCLOG_INFO, "VES Schema file set to %s from environment variable", theSettings[VES_SCHEMA_FILE].c_str());
+         }
+         if (const char *env_schema = std::getenv("VES_COLLECTOR_URL")){
+                 theSettings[VES_COLLECTOR_URL].assign(env_schema);
+                 mdclog_write(MDCLOG_INFO, "VES Collector url set to %s from environment variable", theSettings[VES_COLLECTOR_URL].c_str());
+
+         }
+         if (const char *env_schema = std::getenv("VES_MEASUREMENT_INTERVAL")){
+                 theSettings[VES_MEASUREMENT_INTERVAL].assign(env_schema);
+                 mdclog_write(MDCLOG_INFO, "VES Measurement Interval set to %s from environment variable", theSettings[VES_MEASUREMENT_INTERVAL].c_str());
+         }
+
+         if (char *env_gnodeb = std::getenv("GNODEB")){
+                 theSettings[GNODEB].assign(env_gnodeb);
+                 mdclog_write(MDCLOG_INFO, "GNODEB file set to %s from environment variable", theSettings[GNODEB].c_str());
+         }
+
+
+}
+
+void XappSettings::usage(char *command){
+       std::cout <<"Usage : " << command << " " << std::endl;
+       std::cout <<" --name[-n] xapp_instance_name "<< std::endl;
+    std::cout <<" --port[-p] port to listen on e.g tcp:4561  "<< std::endl;
+    std::cout << "--threads[-t] number of listener threads "<< std::endl ;
+    std::cout << "--a1-schema[-a] a1 schema file location" << std::endl;
+    std::cout << "--ves-schema[-v] ves schema file location" << std::endl;
+    std::cout << "--samples [-s]  samples file location with samples for all jsons" << std::endl;
+    std::cout << "--ves-url [-u] ves collector url" << std::endl;
+    std::cout << "--gNodeB[][-g] gNodeB" << std::endl;
+    std::cout << "--interval[-i] measurement interval to send to ves collector (in seconds)" << std::endl;
+    std::cout << "--opmode [-c] type of operatoring mode : either REPORT or CONTROL. In REPORT, does not send a control message back to gNodeB" << std::endl;
+}
diff --git a/src/xapp-utils/xapp_config.hpp b/src/xapp-utils/xapp_config.hpp
new file mode 100644 (file)
index 0000000..389703e
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+/*
+ * xapp_config.hpp
+ * Created on: 2019
+ * Author: Ashwin Shridharan, Shraboni Jana
+ */
+
+#ifndef SRC_XAPP_CONFIG_XAPP_CONFIG_HPP_
+#define SRC_XAPP_CONFIG_XAPP_CONFIG_HPP_
+
+#include <getopt.h>
+#include <map>
+#include <iostream>
+#include <cstdlib>
+#include <mdclog/mdclog.h>
+
+#define MAX_SLEEP 86400
+
+#define DEFAULT_A1_SCHEMA_FILE "/etc/xapp/a1-schema.json"
+#define DEFAULT_XAPP_ID "hw-xapp-123"
+#define DEFAULT_VES_SCHEMA_FILE "/etc/xapp/ves-schema.json"
+#define DEFAULT_VES_COLLECTOR_URL "127.0.0.1:6350"
+#define DEFAULT_VES_MEASUREMENT_INTERVAL 10
+#define DEFAULT_PORT "4560"
+#define DEFAULT_BUFFER "1024"
+#define DEFAULT_GNODEB "GNB123"
+#define DEFAULT_OPERATING_MODE "report"
+#define DEFAULT_LOG_LEVEL      MDCLOG_WARN
+
+#define ASN_BUFF_MAX_SIZE              512
+#define MAX_SUBSCRIPTION_ATTEMPTS      10
+#define HELLOWORLD_POLICY_ID 00000
+#define DEFAULT_THREADS 1
+
+using namespace std;
+
+struct XappSettings{
+
+public:
+       typedef enum{
+                 XAPP_ID,
+                 XAPP_NAME,
+                 HW_PORTS,
+                 MSG_MAX_BUFFER,
+                 GNODEB,
+                 THREADS,
+                 A1_SCHEMA_FILE,
+                 VES_SCHEMA_FILE,
+                 SAMPLE_FILE,
+                 VES_COLLECTOR_URL,
+                 VES_MEASUREMENT_INTERVAL,
+                 LOG_LEVEL,
+                 OPERATING_MODE
+       }SettingName;
+
+       void loadDefaultSettings();
+       void loadCmdlineSettings(int, char **);
+       void loadEnvVarSettings();
+       void usage(char*);
+       string& operator[](const SettingName& theName);
+private:
+       typedef map<SettingName, std::string> SettingCollection;
+       SettingCollection theSettings;
+
+};
+
+
+
+#endif /* SRC_XAPP_CONFIG_XAPP_CONFIG_HPP_ */
diff --git a/src/xapp-utils/xapp_rmr.cc b/src/xapp-utils/xapp_rmr.cc
new file mode 100755 (executable)
index 0000000..f757667
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+
+
+#include "xapp_rmr.hpp"
+
+XappRmr::XappRmr(std::string xname, std::string port, int rmrattempts){
+
+       _proto_port = port;
+       _xapp_name = xname;
+       _nattempts = rmrattempts;
+       _xapp_rmr_ctx = NULL;
+       _xapp_received_buff = NULL;
+       _xapp_send_buff =NULL;
+       _rmr_is_ready = false;
+
+};
+
+XappRmr::~XappRmr(void){
+
+       // free memory
+       if(_xapp_received_buff)
+               rmr_free_msg(_xapp_received_buff);
+
+       if(_xapp_send_buff)
+               rmr_free_msg(_xapp_send_buff);
+
+       if (_xapp_rmr_ctx){
+               rmr_close(_xapp_rmr_ctx);
+       }
+};
+
+//Get RMR Context.
+void XappRmr::xapp_rmr_init(){
+
+       // Initialize the RMR context
+       _xapp_rmr_ctx = rmr_init(const_cast<char*>(_proto_port.c_str()), RMR_MAX_RCV_BYTES, RMRFL_NONE);
+
+       if ( _xapp_rmr_ctx == NULL){
+               mdclog_write(MDCLOG_ERR,"Error Initializing RMR, file= %s, line=%d",__FILE__,__LINE__);
+       }
+       while( ! rmr_ready(_xapp_rmr_ctx) ) {
+               mdclog_write(MDCLOG_INFO,">>> waiting for RMR, file= %s, line=%d",__FILE__,__LINE__);
+               sleep(1);
+       }
+       _rmr_is_ready = true;
+       mdclog_write(MDCLOG_INFO,"RMR Context is Ready, file= %s, line=%d",__FILE__,__LINE__);
+
+       return;
+
+}
+
+bool XappRmr::xapp_rmr_rts()
+{
+       _xapp_send_buff = rmr_realloc_payload( _xapp_send_buff, 128, false, false );  // ensure payload is large enough
+       strncpy( (char*)_xapp_send_buff->payload, "OK\n", rmr_payload_size( _xapp_send_buff) );
+       rmr_rts_msg(_xapp_rmr_ctx, _xapp_send_buff );
+       _xapp_send_buff = NULL;
+       return true;
+}
+
+//RMR Send with payload and header.
+bool XappRmr::xapp_rmr_send(xapp_rmr_header *hdr, void *payload){
+
+       if( _xapp_send_buff == NULL ) {
+               _xapp_send_buff = rmr_alloc_msg(_xapp_rmr_ctx, RMR_DEF_SIZE);
+       }
+
+
+       _xapp_send_buff->mtype  = hdr->message_type;
+
+       memcpy(_xapp_send_buff->payload, payload, hdr->payload_length);
+
+       _xapp_send_buff->len = hdr->payload_length;
+       if(!_rmr_is_ready) {
+               mdclog_write(MDCLOG_ERR,"RMR Context is Not Ready in SENDER, file= %s, line=%d",__FILE__,__LINE__);
+               return false;
+       }
+       if( _xapp_send_buff == NULL ) {
+               return false;
+       }
+
+
+       while(_nattempts > 0){
+               _xapp_send_buff = rmr_send_msg(_xapp_rmr_ctx,_xapp_send_buff);
+
+               if(!_xapp_send_buff) {
+                       mdclog_write(MDCLOG_ERR,"Error In Sending Message , file= %s, line=%d",__FILE__,__LINE__);
+                       _nattempts--;
+               }
+               else if (_xapp_send_buff->state == RMR_OK){
+                       mdclog_write(MDCLOG_INFO,"The okay message is %d, file= %s, line=%d", RMR_OK, __FILE__,__LINE__);
+                       _nattempts = 0;
+                       return true;
+               }
+               else
+               {
+                       mdclog_write(MDCLOG_INFO,"Need to retry RMR MSG NUM %d, file= %s, line=%d",_xapp_send_buff->state, __FILE__,__LINE__);
+                       _nattempts--;
+               }
+               sleep(1);
+       }
+       return false;
+}
+
diff --git a/src/xapp-utils/xapp_rmr.hpp b/src/xapp-utils/xapp_rmr.hpp
new file mode 100755 (executable)
index 0000000..2ba6fb1
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+*/
+
+#ifndef XAPP_RMR_XAPP_RMR_H_
+#define XAPP_RMR_XAPP_RMR_H_
+
+
+#ifdef __GNUC__
+#define likely(x)  __builtin_expect((x), 1)
+#define unlikely(x) __builtin_expect((x), 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <error.h>
+#include <assert.h>
+#include <thread>
+#include <functional>
+#include <map>
+#include <mutex>
+#include <sys/epoll.h>
+#include <rmr/rmr.h>
+#include <rmr/RIC_message_types.h>
+#include <mdclog/mdclog.h>
+#include <vector>
+
+typedef struct{
+       struct timespec ts;
+       int32_t message_type;
+       int32_t state;
+       int32_t payload_length;
+       unsigned char xid[RMR_MAX_XID]; //space for user transaction id.
+       unsigned char sid[RMR_MAX_SID]; //sender ID for return to sender needs.(ACKS required)
+       unsigned char src[RMR_MAX_SRC]; //name of the sender (source)
+}  xapp_rmr_header;
+
+
+class XappRmr{
+private:
+       std::string _xapp_name;
+       std::string _proto_port;
+       int _nattempts;
+       bool _rmr_is_ready;
+       void* _xapp_rmr_ctx;
+       rmr_mbuf_t*             _xapp_send_buff;                                        // send buffer
+       rmr_mbuf_t*             _xapp_received_buff;                                    // received buffer
+
+
+public:
+
+       XappRmr(std::string, std::string, int rmrattempts=10);
+       ~XappRmr(void);
+       void xapp_rmr_init(void);
+
+       template <class MessageProcessor>
+       void xapp_rmr_receive(MessageProcessor&&, XappRmr *parent);
+       bool xapp_rmr_send(xapp_rmr_header*, void*);
+       bool xapp_rmr_rts();
+
+};
+
+//RMR receive
+template <class MessageProcessor>
+void XappRmr::xapp_rmr_receive(MessageProcessor&& msgproc, XappRmr *parent){
+               char*   listen_port;
+
+               if( (listen_port = getenv( "RMR_RCV_PORT" )) == NULL ) {
+                       mdclog_write(MDCLOG_ERR,"No Listening port assigned, file= %s, line=%d",__FILE__,__LINE__);
+               }
+
+               if(!_rmr_is_ready){
+                       mdclog_write( MDCLOG_ERR, "RMR Shows Not Ready in RECEIVER, file= %s, line=%d ",__FILE__,__LINE__);
+                       return;
+               }
+
+                 while( 1 ) {
+                         parent->_xapp_received_buff = rmr_rcv_msg( parent->_xapp_rmr_ctx, parent->_xapp_received_buff );                                              // block until one arrives
+                       if( parent->_xapp_received_buff->mtype < 0 || parent->_xapp_received_buff->state != RMR_OK ) {
+                               mdclog_write(MDCLOG_ERR, "bad msg:  state=%d  errno=%d, file= %s, line=%d", parent->_xapp_received_buff->state, errno, __FILE__,__LINE__ );
+                               return;
+                       } else {
+                               std::cout << "The Message Received is:" << (char*)parent->_xapp_received_buff->payload <<std::endl;
+                               std::cout << "The Message Received Type is:" << _xapp_received_buff->mtype <<std::endl;
+                               _xapp_send_buff = msgproc(_xapp_received_buff);
+                               if(_xapp_send_buff !=NULL)
+                                       xapp_rmr_rts();
+                               //sleep(10);
+                               //_xapp_received_buff = NULL;
+
+                       }
+
+               }
+           return;
+}
+
+#endif /* XAPP_RMR_XAPP_RMR_H_ */
diff --git a/src/xapp-utils/xapp_sdl.cc b/src/xapp-utils/xapp_sdl.cc
new file mode 100644 (file)
index 0000000..b098273
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+
+/*
+ * xapp_sdl.cc
+ *
+ *  Created on: Mar, 2020
+ *  Author: Shraboni Jana
+ */
+#include "xapp_sdl.hpp"
+/*need to work on the SDL FLow.
+As per Matti
+An xApp can use the SDL for two things:
+- persisting state for itself (in case it fails and recovers)
+- making information available for other xApps. The xApp would typically write using SDL directly. The consumer of the data could also use SDL directly or use an access library like in the case of the R-NIB.
+*/
+void XappSDL::insert_data(){
+       //connecting to the Redis and generating a random key for namespace "hwxapp"
+
+                DataMap dmap;
+                char key[4]={'a','b','c'};
+                std::cout << "KEY: "<< key << std::endl;
+                Key k = key;
+                Data d;
+                uint8_t num = 101;
+                d.push_back(num);
+                dmap.insert({k,d});
+                sdl->set(ns, dmap);
+}
+
+
diff --git a/src/xapp-utils/xapp_sdl.hpp b/src/xapp-utils/xapp_sdl.hpp
new file mode 100644 (file)
index 0000000..6472352
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+
+/*
+ * xapp_sdl.hpp
+ *
+ *  Created on: Mar, 2020
+ *  Author: Shraboni Jana
+ */
+#pragma once
+
+#ifndef SRC_XAPP_UTILS_XAPP_SDL_HPP_
+#define SRC_XAPP_UTILS_XAPP_SDL_HPP_
+
+#include <iostream>
+#include <string>
+#include <memory>
+#include <vector>
+#include <map>
+#include <set>
+#include <sdl/syncstorage.hpp>
+
+
+using namespace std;
+using Namespace = std::string;
+using Key = std::string;
+using Data = std::vector<uint8_t>;
+using DataMap = std::map<Key, Data>;
+using Keys = std::set<Key>;
+
+class XappSDL{
+private:
+       std::unique_ptr<shareddatalayer::SyncStorage> sdl;
+       Namespace ns;
+public:
+
+       XappSDL(std::string s) {
+               Namespace temp(s);
+               ns = temp;
+               sdl = (shareddatalayer::SyncStorage::create());
+       };
+       void insert_data();
+};
+
+#endif /* SRC_XAPP_UTILS_XAPP_SDL_HPP_ */
diff --git a/src/xapp.cc b/src/xapp.cc
new file mode 100644 (file)
index 0000000..ca737e6
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ */
+/*
+ * xapp.cc
+ *
+ *  Created on: Mar, 2020
+ *  Author: Shraboni Jana
+ */
+
+#include "xapp.hpp"
+
+Xapp::Xapp(XappSettings &config, XappRmr &rmr){
+       rmr_ref = &rmr;
+       config_ref = &config;
+       xapp_mutex = NULL;
+       return;
+}
+
+
+Xapp::Xapp(XappSettings &config, XappRmr &rmr, XappSDL &sdl){
+       rmr_ref = &rmr;
+       config_ref = &config;
+       sdl_ref = &sdl;
+       //sdl_ref.insert_data();
+       xapp_mutex = NULL;
+
+       return;
+}
+Xapp::~Xapp(void){
+
+       //Joining the threads
+       int threadcnt = xapp_rcv_thread.size();
+       for(int i=0; i<threadcnt; i++){
+               if(xapp_rcv_thread[i].joinable())
+                       xapp_rcv_thread[i].join();
+       }
+       delete xapp_mutex;
+};
+void Xapp::startup() {
+       //send subscriptions and read A1 policies.
+       startup_subscribe_requests();
+       startup_get_policies();
+       return;
+}
+
+void Xapp::start_xapp_receiver(){
+       //start a receiver thread. Can be multiple receiver threads for more than 1 listening port.
+
+       xapp_mutex = new std::mutex();
+
+       std::vector<std::unique_ptr <XappMsgHandler>> message_procs;
+       mdclog_write(MDCLOG_INFO,"Receiver Thread file= %s, line=%d",__FILE__,__LINE__);
+       std::unique_ptr<XappMsgHandler> mp_handler = std::make_unique<XappMsgHandler>();
+       std::lock_guard<std::mutex> guard(*xapp_mutex);
+       std::thread th_recv([&](){ rmr_ref->xapp_rmr_receive(std::move(*mp_handler.get()), rmr_ref);});
+       xapp_rcv_thread.push_back(std::move(th_recv));
+
+
+       return;
+
+
+
+}
+void Xapp::shutdown(){
+
+       return;
+
+}
+
+
+void Xapp::startup_subscribe_requests(void ){
+   size_t data_size = ASN_BUFF_MAX_SIZE;
+   unsigned char       data[data_size];
+
+   std::vector<std::string> gNodeBs;
+   gNodeBs.push_back("GNB1001"); //this line should come from RNIB
+
+
+   for(auto &it: gNodeBs){
+     int attempt = 0;
+        XappMsgHandler msg;
+
+ /*     bool res_encode = msg.encode_subscription_request(data, &data_size);
+        if(!res_encode) exit(0);*/
+       char *strMsg = "HelloWorld\0";
+       strncpy((char *)data,strMsg,strlen(strMsg));
+       data_size = sizeof(data);
+
+        xapp_rmr_header rmr_header;
+        rmr_header.message_type = RIC_SUB_RESP;
+        rmr_header.payload_length = data_size;
+     while(1){
+
+                auto transmitter = std::bind(&XappRmr::xapp_rmr_send,rmr_ref, &rmr_header, (void*)data);
+                transmitter(); //this will go to subscription manager.
+                break;
+     }
+   }
+}
+
+void Xapp::startup_get_policies(void){
+
+  int policy_id = HELLOWORLD_POLICY_ID;
+
+  std::string policy_query = "{\"policy_id\":" + std::to_string(policy_id) + "}";
+  unsigned char * message = (unsigned char *)calloc(policy_query.length(), sizeof(unsigned char));
+  memcpy(message, policy_query.c_str(),  policy_query.length());
+  xapp_rmr_header header;
+  header.payload_length = policy_query.length();
+  header.message_type = A1_POLICY_QUERY;
+  mdclog_write(MDCLOG_INFO, "Sending request for policy id %d\n", policy_id);
+  rmr_ref->xapp_rmr_send(&header, (void *)message);
+  free(message);
+
+}
+void Xapp::sdl_data(void) {
+       sdl_ref->insert_data();
+}
+/*void Xapp::rnib_data(void) {
+
+          printf("Using rnibreader lib from C:\n");
+          open();
+          void *result = getListGnbIds();
+          if(result == NULL){
+
+               printf("ERROR: no data from getListGnbIds\n");
+               return;
+           }
+           printf("getListGnbIds response: %s\n", (char *)result);
+           close();
+           free(result);
+           return;
+
+}*/
+
+
+
+
+
+
diff --git a/src/xapp.hpp b/src/xapp.hpp
new file mode 100644 (file)
index 0000000..bcfff5b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+==================================================================================
+
+        Copyright (c) 2018-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.
+==================================================================================
+ *//*
+ * xapp.hpp
+ *
+ *  Modified: Mar, 2020 (Shraboni Jana)
+ *
+ */
+
+#pragma once
+
+#ifndef SRC_XAPP_HPP_
+#define SRC_XAPP_HPP_
+
+#include <iostream>
+#include <string>
+#include <memory>
+#include <csignal>
+#include <stdio.h>
+#include "xapp_rmr.hpp"
+#include "xapp_sdl.hpp"
+#include "rapidjson/writer.h"
+
+#include "msgs_proc.hpp"
+#include "subs_mgmt.hpp"
+#include "xapp_config.hpp"
+//#include "rnib/rnibreader.h"
+
+
+using namespace std;
+using namespace std::placeholders;
+
+class Xapp{
+public:
+
+  Xapp(XappSettings &, XappRmr &);
+  Xapp(XappSettings &, XappRmr &, XappSDL &);
+  ~Xapp(void);
+
+  void startup();
+  void shutdown(void);
+
+  void start_xapp_receiver();
+
+  Xapp(Xapp const &)=delete;
+  Xapp& operator=(Xapp const &) = delete;
+
+private:
+  void startup_subscribe_requests(void );
+  void shutdown_subscribe_deletes(void);
+  void startup_get_policies(void );
+  void sdl_data(void);
+  void rnib_data(void);
+
+  XappRmr * rmr_ref;
+  XappSettings * config_ref;
+  XappSDL *sdl_ref = NULL;
+  std::mutex *xapp_mutex;
+  std::vector<std::thread> xapp_rcv_thread;
+};
+
+
+#endif /* SRC_XAPP_HPP_ */