Revision of copyright
[ric-app/kpimon.git] / src / E2AP-c / subscription / subscription_handler.cc
1 /*\r
2 ==================================================================================\r
3         Copyright (c) 2018-2019 SAMSUNG Intellectual Property.\r
4 \r
5    Licensed under the Apache License, Version 2.0 (the "License");\r
6    you may not use this file except in compliance with the License.\r
7    You may obtain a copy of the License at\r
8 \r
9        http://www.apache.org/licenses/LICENSE-2.0\r
10 \r
11    Unless required by applicable law or agreed to in writing, software\r
12    distributed under the License is distributed on an "AS IS" BASIS,\r
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14    See the License for the specific language governing permissions and\r
15    limitations under the License.\r
16 ==================================================================================\r
17 */\r
18 \r
19 #include <subscription_handler.hpp>\r
20 #include <errno.h>\r
21 \r
22 SubscriptionHandler::SubscriptionHandler(void){\r
23 \r
24   init();\r
25   _time_out =  std::chrono::seconds(5);\r
26   _num_retries = 2;\r
27 \r
28   // bool res;\r
29   // unsigned char buffer[128];\r
30   // size_t buf_len = 128;\r
31   \r
32   // E2AP_PDU_t e2ap_pdu;\r
33   // subscription_request e2ap_sub_req;\r
34 \r
35   // int request_id = 2;\r
36   // int req_seq = 1;\r
37   // int function_id = 0;\r
38   // int action_id = 0;\r
39   // int action_type = 0;\r
40   // int message_type = 1;\r
41   \r
42   // subscription_helper sgnb_add_subscr_req;\r
43   \r
44   // //sgnb_add_subscr_req.clear();\r
45   // sgnb_add_subscr_req.set_request(request_id, req_seq);\r
46   // sgnb_add_subscr_req.set_function_id(function_id);\r
47   // sgnb_add_subscr_req.add_action(action_id, action_type);\r
48   // std::string test = "This is a test";\r
49   // sgnb_add_subscr_req.set_event_def(test.c_str(), test.length());\r
50   // std::cout <<"Constructor ........" << std::endl;\r
51   // // generate the request pdu\r
52   // res = e2ap_sub_req.encode_e2ap_subscription(&buffer[0], &buf_len, &e2ap_pdu, sgnb_add_subscr_req);\r
53   // if(! res){\r
54   //   mdclog_write(MDCLOG_ERR, "%s, %d: Error encoding subscription pdu. Reason = ", __FILE__, __LINE__);\r
55    \r
56   // }\r
57   // std::cout <<"Encoded subscription request pdu " << std::endl;\r
58  \r
59  \r
60 }\r
61 \r
62 SubscriptionHandler::SubscriptionHandler(unsigned int timeout_seconds, unsigned int num_tries):_time_out(std::chrono::seconds(timeout_seconds)), _num_retries(num_tries){\r
63   init();\r
64 \r
65    \r
66 };\r
67 \r
68 void SubscriptionHandler::init(void){\r
69   \r
70   _data_lock = std::make_unique<std::mutex>();\r
71   _cv = std::make_unique<std::condition_variable>();\r
72   \r
73 }\r
74 \r
75 void SubscriptionHandler::clear(void){\r
76   {\r
77     std::lock_guard<std::mutex> lock(*(_data_lock).get());\r
78     requests_table.clear();\r
79     subscription_responses.clear();\r
80   }\r
81   \r
82 };\r
83 \r
84 size_t SubscriptionHandler::num_pending(void) const {\r
85   return requests_table.size();\r
86 }\r
87 \r
88 size_t SubscriptionHandler::num_complete(void) const {\r
89   return subscription_responses.size();\r
90 }\r
91 \r
92 \r
93 void SubscriptionHandler::set_timeout(unsigned int timeout_seconds){\r
94   _time_out = std::chrono::seconds(timeout_seconds);\r
95 }\r
96 \r
97 void SubscriptionHandler::set_timeout_flag(bool val){\r
98   _time_out_flag = val;\r
99 }\r
100 \r
101 void SubscriptionHandler::set_num_retries(unsigned int num_tries){\r
102   _num_retries = num_tries;\r
103 };\r
104 \r
105 \r
106 unsigned int SubscriptionHandler::get_next_id(void){\r
107   std::lock_guard<std::mutex> lock(*(_data_lock).get());\r
108   unique_request_id ++;\r
109   return unique_request_id;\r
110 }\r
111 \r
112 bool SubscriptionHandler::add_request_entry(int id, int status){\r
113 \r
114   // add entry in hash table if it does not exist\r
115   auto search = requests_table.find(id);\r
116   if(search != requests_table.end()){\r
117     return false;\r
118   }\r
119   \r
120   requests_table[id] = status;\r
121   return true;\r
122 \r
123 };\r
124 \r
125 bool SubscriptionHandler::set_request_status(int id, int status){\r
126   \r
127   // change status of a request only if it exists.\r
128 \r
129   auto search = requests_table.find(id);\r
130   if(search != requests_table.end()){\r
131     requests_table[id] = status;\r
132     return true;\r
133   }\r
134 \r
135   return false;\r
136   \r
137 };\r
138 \r
139 \r
140 bool SubscriptionHandler::delete_request_entry(int id){\r
141 \r
142   auto search = requests_table.find(id);\r
143   if (search != requests_table.end()){\r
144     requests_table.erase(search);\r
145     return true;\r
146   }\r
147 \r
148   return false;\r
149 };\r
150   \r
151 bool SubscriptionHandler::add_subscription_entry(int id, subscription_response_helper &he){\r
152 \r
153   auto search = subscription_responses.find(id);\r
154   if (search == subscription_responses.end()){\r
155     subscription_responses[id] = he;\r
156     return true;\r
157   }\r
158 \r
159   return false;\r
160 }\r
161 \r
162 \r
163 bool SubscriptionHandler::delete_subscription_entry(int id){\r
164 \r
165   auto search = subscription_responses.find(id);\r
166   if(search == subscription_responses.end()){\r
167     return false;\r
168   }\r
169   else{\r
170     subscription_responses.erase(search);\r
171     return true;\r
172   }\r
173   \r
174 }\r
175 \r
176 subscription_response_helper *  const SubscriptionHandler::get_subscription(int id){\r
177   auto search = subscription_responses.find(id);\r
178   if(search == subscription_responses.end()){\r
179     return NULL;\r
180   }\r
181   else{\r
182     return &(subscription_responses[id]);\r
183   }\r
184 };\r
185 \r
186 \r
187 // Handles responses from RMR\r
188 void SubscriptionHandler::Response(int message_type, unsigned char *payload, int payload_length){\r
189 \r
190   bool res;\r
191   int id;\r
192   int type;\r
193   int procedureCode;\r
194   bool valid_response  =false;\r
195   \r
196   E2AP_PDU_t * e2ap_recv;\r
197   asn_dec_rval_t retval;\r
198 \r
199   subscription_response sub_resp;\r
200 \r
201   subscription_response_helper he_response;\r
202 \r
203   char buf[512];\r
204   size_t buf_size = 512;\r
205 \r
206   e2ap_recv = 0;\r
207   retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2AP_PDU, (void**)&(e2ap_recv), payload, payload_length);\r
208 \r
209   if(retval.code != RC_OK){\r
210     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);\r
211     ASN_STRUCT_FREE(asn_DEF_E2AP_PDU, e2ap_recv);\r
212     return ;\r
213   }\r
214   \r
215   type = e2ap_recv->present;\r
216   mdclog_write(MDCLOG_INFO, "Received RMR message of type = %d", type);\r
217   \r
218   if(type == E2AP_PDU_PR_successfulOutcome){\r
219 \r
220     procedureCode =  e2ap_recv->choice.successfulOutcome->procedureCode;\r
221     mdclog_write(MDCLOG_INFO, "Received E2AP PDU  successful outcome message with procedureCode = %d", procedureCode);  \r
222 \r
223     if( procedureCode == ProcedureCode_id_ricSubscription){  \r
224       // subscription response\r
225       // decode the message\r
226       sub_resp.get_fields(e2ap_recv->choice.successfulOutcome, he_response);\r
227 \r
228       {\r
229         std::lock_guard<std::mutex> lock(*(_data_lock.get()));\r
230         // get the id\r
231         id = he_response.get_request_id();\r
232         // get status of id \r
233         int req_status = get_request_status(id);\r
234         if (req_status == request_pending ){\r
235           res = add_subscription_entry(id, he_response);\r
236           if(res)\r
237             set_request_status(id, request_success);\r
238           \r
239           else{\r
240             set_request_status(id, request_duplicate);\r
241             mdclog_write(MDCLOG_ERR, "Error:: %s, %d: Request %d seems to be a duplicate\n", __FILE__, __LINE__, id);\r
242           }\r
243           \r
244           valid_response = true;\r
245         }\r
246         else if (req_status > 0){\r
247           // we don't change status of response since it was not in pending\r
248           // we simply fail\r
249           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);\r
250           \r
251         }\r
252         else{\r
253           mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find id %d in request queue for subscription", __FILE__, __LINE__,  id);\r
254         }         \r
255         \r
256       }\r
257       \r
258     }\r
259 \r
260     else{\r
261       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);\r
262     }\r
263     \r
264   }\r
265   \r
266   else if(type == E2AP_PDU_PR_unsuccessfulOutcome){\r
267     \r
268     procedureCode = e2ap_recv->choice.unsuccessfulOutcome->procedureCode;\r
269     mdclog_write(MDCLOG_INFO, "Received E2AP PDU  unsuccessful outcome message with procedureCode = %d", procedureCode);  \r
270     \r
271     if(procedureCode == ProcedureCode_id_ricSubscription){\r
272       \r
273       sub_resp.get_fields(e2ap_recv->choice.unsuccessfulOutcome, he_response);\r
274       {\r
275         std::lock_guard<std::mutex> lock(*(_data_lock.get()));  \r
276         id = he_response.get_request_id();\r
277         int req_status = get_request_status(id);\r
278         if(req_status == request_pending){\r
279           set_request_status(id, request_failed);\r
280           valid_response = true;\r
281           mdclog_write(MDCLOG_ERR, "Subscription request %d failed", id);\r
282         }\r
283         else if (req_status > 0){\r
284           // we don't changet status since it was not in pending\r
285           // we simply fail\r
286           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);\r
287         }\r
288         else{\r
289           mdclog_write(MDCLOG_ERR,  "%s, %d: Could not find id   %d in request queue for subscription ", __FILE__, __LINE__, id);\r
290         }\r
291       }\r
292     }\r
293   }\r
294   else{\r
295     mdclog_write(MDCLOG_ERR,  "%s, %d: Susbcription Handler Response received E2AP PDU with non response type  %d", __FILE__, __LINE__, type);\r
296   }\r
297   \r
298   \r
299   ASN_STRUCT_FREE(asn_DEF_E2AP_PDU, e2ap_recv);\r
300   \r
301   // wake up all waiting users ...\r
302   if(valid_response){\r
303     _cv.get()->notify_all();\r
304   }\r
305   \r
306 }\r
307 \r
308 \r
309 int const SubscriptionHandler::get_request_status(int id){\r
310   auto search = requests_table.find(id);\r
311   if (search == requests_table.end()){\r
312     return -1;\r
313   }\r
314   \r
315   return search->second;\r
316 }\r
317                                    \r
318  bool SubscriptionHandler::is_subscription_entry(int id){\r
319   auto search = subscription_responses.find(id);\r
320   if (search != subscription_responses.end())\r
321     return true;\r
322   else\r
323     return false;\r
324 }\r
325 \r
326 bool SubscriptionHandler::is_request_entry(int id){\r
327   auto search = requests_table.find(id);\r
328   if (search != requests_table.end())\r
329     return true;\r
330   else\r
331     return false;\r
332 }\r