2 ==================================================================================
3 Copyright (c) 2018-2019 AT&T Intellectual Property.
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 ==================================================================================
19 /* Author : Ashwin Sridharan
24 #include <subscription_handler.hpp>
27 subscription_handler::subscription_handler(void){
30 _time_out = std::chrono::seconds(5);
34 // unsigned char buffer[128];
35 // size_t buf_len = 128;
37 // E2N_E2AP_PDU_t e2ap_pdu;
38 // subscription_request e2ap_sub_req;
40 // int request_id = 2;
42 // int function_id = 0;
44 // int action_type = 0;
45 // int message_type = 1;
47 // subscription_helper sgnb_add_subscr_req;
49 // //sgnb_add_subscr_req.clear();
50 // sgnb_add_subscr_req.set_request(request_id, req_seq);
51 // sgnb_add_subscr_req.set_function_id(function_id);
52 // sgnb_add_subscr_req.add_action(action_id, action_type);
53 // std::string test = "This is a test";
54 // sgnb_add_subscr_req.set_event_def(test.c_str(), test.length());
55 // std::cout <<"Constructor ........" << std::endl;
56 // // generate the request pdu
57 // res = e2ap_sub_req.encode_e2ap_subscription(&buffer[0], &buf_len, &e2ap_pdu, sgnb_add_subscr_req);
59 // mdclog_write(MDCLOG_ERR, "%s, %d: Error encoding subscription pdu. Reason = ", __FILE__, __LINE__);
62 // std::cout <<"Encoded subscription request pdu " << std::endl;
67 subscription_handler::subscription_handler(unsigned int timeout_seconds, unsigned int num_tries):_time_out(std::chrono::seconds(timeout_seconds)), _num_retries(num_tries){
71 void subscription_handler::init(void){
73 _data_lock = std::make_unique<std::mutex>();
74 _cv = std::make_unique<std::condition_variable>();
78 void subscription_handler::clear(void){
80 std::lock_guard<std::mutex> lock(*(_data_lock).get());
81 requests_table.clear();
82 subscription_responses.clear();
87 size_t subscription_handler::num_pending(void) const {
88 return requests_table.size();
91 size_t subscription_handler::num_complete(void) const {
92 return subscription_responses.size();
96 void subscription_handler::set_timeout(unsigned int timeout_seconds){
97 _time_out = std::chrono::seconds(timeout_seconds);
100 void subscription_handler::set_num_retries(unsigned int num_tries){
101 _num_retries = num_tries;
105 unsigned int subscription_handler::get_next_id(void){
106 std::lock_guard<std::mutex> lock(*(_data_lock).get());
107 unique_request_id ++;
108 return unique_request_id;
111 bool subscription_handler::add_request_entry(int id, int status){
113 // add entry in hash table if it does not exist
114 auto search = requests_table.find(id);
115 if(search != requests_table.end()){
119 requests_table[id] = status;
124 bool subscription_handler::set_request_status(int id, int status){
126 // change status of a request only if it exists.
128 auto search = requests_table.find(id);
129 if(search != requests_table.end()){
130 requests_table[id] = status;
139 bool subscription_handler::delete_request_entry(int id){
141 auto search = requests_table.find(id);
142 if (search != requests_table.end()){
143 requests_table.erase(search);
150 bool subscription_handler::add_subscription_entry(int id, subscription_response_helper &he){
152 auto search = subscription_responses.find(id);
153 if (search == subscription_responses.end()){
154 subscription_responses[id] = he;
162 bool subscription_handler::delete_subscription_entry(int id){
164 auto search = subscription_responses.find(id);
165 if(search == subscription_responses.end()){
169 subscription_responses.erase(search);
175 subscription_response_helper * const subscription_handler::get_subscription(int id){
176 auto search = subscription_responses.find(id);
177 if(search == subscription_responses.end()){
181 return &(subscription_responses[id]);
186 // Handles responses from RMR
187 void subscription_handler::Response(int message_type, unsigned char *payload, int payload_length){
193 bool valid_response =false;
195 E2N_E2AP_PDU_t * e2ap_recv;
196 asn_dec_rval_t retval;
198 subscription_response sub_resp;
199 subscription_delete_response sub_del_resp;
201 subscription_response_helper he_response;
205 retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_recv), payload, payload_length);
207 if(retval.code != RC_OK){
208 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);
209 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_recv);
213 type = e2ap_recv->present;
214 mdclog_write(MDCLOG_INFO, "Received RMR message of type = %d", type);
216 if(type == E2N_E2AP_PDU_PR_successfulOutcome){
218 procedureCode = e2ap_recv->choice.successfulOutcome->procedureCode;
219 mdclog_write(MDCLOG_INFO, "Received E2N_E2AP PDU successful outcome message with procedureCode = %d", procedureCode);
221 if( procedureCode == E2N_ProcedureCode_id_ricSubscription){
222 // subscription response
223 // decode the message
224 sub_resp.get_fields(e2ap_recv->choice.successfulOutcome, he_response);
227 std::lock_guard<std::mutex> lock(*(_data_lock.get()));
229 id = he_response.get_request_id();
231 int req_status = get_request_status(id);
232 if (req_status == request_pending ){
233 res = add_subscription_entry(id, he_response);
235 set_request_status(id, request_success);
238 set_request_status(id, request_duplicate);
239 mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d seems to be a duplicate\n", __FILE__, __LINE__, id);
242 valid_response = true;
244 else if (req_status > 0){
245 // we don't change status of response since it was not in pending
247 mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d is not in request_pending state, is in State = %d\n", __FILE__, __LINE__, id, req_status);
251 mdclog_write(MDCLOG_ERR, "%s, %d: Could not find id %d in request queue for subscription", __FILE__, __LINE__, id);
258 else if( procedureCode == E2N_ProcedureCode_id_ricSubscriptionDelete){
260 res = sub_del_resp.get_fields(e2ap_recv->choice.successfulOutcome, he_response);
262 std::lock_guard<std::mutex> lock(*(_data_lock.get()));
264 id = he_response.get_request_id();
265 int req_status = get_request_status(id);
266 if (req_status == delete_request_pending ){
267 // Remove the subscription from the table
268 res = delete_subscription_entry(id);
270 set_request_status(id, delete_request_success);
271 valid_response = true;
274 set_request_status(id, delete_request_failed);
275 std::string error_string = "Error deleting subscription entry for id = ";
276 mdclog_write(MDCLOG_ERR, "%s, %d: %s, %d", __FILE__, __LINE__, error_string.c_str(), id);
277 valid_response = true;
280 else if (req_status > 0){
281 // we don't change status since it was not in pending
283 mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d for deletion is not in delete_pending state, is in State = %d\n", __FILE__, __LINE__, id, req_status);
286 mdclog_write(MDCLOG_ERR, "%s, %d: Could not find id %d in request queue for deletion ", __FILE__, __LINE__, id);
293 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);
298 else if(type == E2N_E2AP_PDU_PR_unsuccessfulOutcome){
300 procedureCode = e2ap_recv->choice.unsuccessfulOutcome->procedureCode;
301 mdclog_write(MDCLOG_INFO, "Received E2AP PDU unsuccessful outcome message with procedureCode = %d", procedureCode);
303 if(procedureCode == E2N_ProcedureCode_id_ricSubscription){
305 sub_resp.get_fields(e2ap_recv->choice.unsuccessfulOutcome, he_response);
307 std::lock_guard<std::mutex> lock(*(_data_lock.get()));
308 id = he_response.get_request_id();
309 int req_status = get_request_status(id);
310 if(req_status == request_pending){
311 set_request_status(id, request_failed);
312 valid_response = true;
313 mdclog_write(MDCLOG_ERR, "Subscription request %d failed", id);
315 else if (req_status > 0){
316 // we don't changet status since it was not in pending
318 mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d is not in request_pending state, is in State = %d\n", __FILE__, __LINE__, id, req_status);
321 mdclog_write(MDCLOG_ERR, "%s, %d: Could not find id %d in request queue for subscription ", __FILE__, __LINE__, id);
326 else if(procedureCode == E2N_ProcedureCode_id_ricSubscriptionDelete){
328 res = sub_del_resp.get_fields(e2ap_recv->choice.unsuccessfulOutcome, he_response);
330 std::lock_guard<std::mutex> lock(*(_data_lock.get()));
332 id = he_response.get_request_id();
333 int req_status = get_request_status(id);
334 if(req_status == delete_request_pending){
335 set_request_status(id, delete_request_failed);
336 mdclog_write(MDCLOG_INFO, "Subscription delete request %d failed", id);
337 valid_response = true;
339 else if (req_status > 0){
340 mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d for deletion is not in delete_pending state, is in State = %d\n", __FILE__, __LINE__, id, req_status);
343 mdclog_write(MDCLOG_ERR, "%s, %d: Could not find id %d in request queue for deletion ", __FILE__, __LINE__, id);
349 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);
354 mdclog_write(MDCLOG_ERR, "%s, %d: Susbcription Handler Response received E2AP PDU with non response type %d", __FILE__, __LINE__, type);
358 ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_recv);
360 // wake up all waiting users ...
362 _cv.get()->notify_all();
368 int const subscription_handler::get_request_status(int id){
369 auto search = requests_table.find(id);
370 if (search == requests_table.end()){
374 return search->second;
377 bool subscription_handler::is_subscription_entry(int id){
378 auto search = subscription_responses.find(id);
379 if (search != subscription_responses.end())
385 bool subscription_handler::is_request_entry(int id){
386 auto search = requests_table.find(id);
387 if (search != requests_table.end())