1. Transitioned to using latest asn1c compiler
[ric-app/admin.git] / test / mock_e2term_server.cc
1 /*==================================================================================
2
3         Copyright (c) 2018-2019 AT&T Intellectual Property.
4
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
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
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 ==================================================================================
17 */
18
19 /* Author : Ashwin Sridharan
20    Date   : Feb 2019
21 */
22
23
24 /* 
25
26    A mock e2term for testing 
27    -- accepts a subscription request 
28   -- accepts a delete subscription request
29   
30
31   -- when subscription is active,  sends out indication messages with X2AP SgNBAdditionRequest at specified rate
32      and monitors control request
33
34   -- when delete is requested, stops sending ...
35   
36
37 */
38
39
40 #include <string.h>
41 #include <stdio.h>
42 #include <iostream>
43 #include <fstream>
44 #include <csignal>
45 #include <chrono>
46 #include <xapp_utils.hpp>
47 #include <getopt.h>
48 #include <rmr/RIC_message_types.h>
49 #include <xapp_utils.hpp>
50 #include <subscription_request.hpp>
51 #include <subscription_response.hpp>
52 #include <subscription_delete_request.hpp>
53 #include <subscription_delete_response.hpp>
54
55 #include <e2sm.hpp>
56 #include <e2ap_indication.hpp>
57 #include <e2ap_control.hpp>
58 #include <e2ap_control_response.hpp>
59 #include <sgnb_addition_request.hpp>
60 #include <sgnb_addition_response.hpp>
61
62 #define X2_SGNB_ADDITION_REQUEST "test-data/X2AP-PDU-SgNBAdditionRequest.per"
63
64
65 unsigned long int num_indications = 0;
66 unsigned long int num_controls = 0;
67 unsigned long int num_accepts = 0;
68 unsigned long int num_rejects = 0;
69 unsigned long int num_errors = 0;
70
71 bool verbose_flag = false;
72 bool RunProgram = true;
73 bool subscription_active = false;
74 int action_type = E2N_RICindicationType::E2N_RICindicationType_report;
75
76
77
78 void usage(char *command){
79     std::cout <<"Usage : " << command << " ";
80     std::cout <<" --name[-n] xapp_instance_name ";
81     std::cout <<" --port[-p] port to listen on e.g tcp:4591 ";
82     std::cout << "--verbose ";
83     std::cout <<" --rate[-r] rate to send indication messages";
84     std::cout << std::endl;
85 }
86
87 void EndProgram(int signum){
88   std::cout <<"Signal received. Stopping program ....." << std::endl;
89   RunProgram = false;
90 }
91
92 bool  Message_Handler(rmr_mbuf_t *message){
93
94   bool res;
95   int i;
96   unsigned char meid[32];
97   unsigned char src[32];
98   
99   subscription_helper he;
100   subscription_response_helper he_resp;
101   
102   subscription_request sub_req;
103   subscription_response sub_resp;
104
105   subscription_delete sub_del_req;
106   subscription_delete_response sub_del_resp;
107   
108   ric_control_request control_req;
109   ric_control_response control_resp;
110   ric_control_helper  control_data;
111
112   e2sm_control e2sm_control_proc;
113   
114   asn_dec_rval_t retval;
115   size_t mlen;
116   
117   E2N_E2AP_PDU_t *e2ap_pdu_recv = 0;
118   X2N_X2AP_PDU_t *x2ap_pdu_recv = 0;
119   E2N_E2SM_gNB_X2_eventTriggerDefinition_t *event = 0;
120   std::vector<Action> * actions;
121
122   bool send_msg = true;
123   
124   rmr_get_meid(message, meid);
125   rmr_get_src(message, src);
126   
127   switch(message->mtype){
128   case RIC_SUB_REQ:
129     
130     std::cout <<"*** Received message from src = " << src  << " for gNodeB = " << meid << " of size = " << message->len  << " and type = " << message->mtype << std::endl;
131     
132     e2ap_pdu_recv = 0;
133     retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
134
135     if(retval.code == RC_OK){
136       he.clear();
137       sub_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
138     }
139     else{
140       std::cerr <<"Error decoding E2AP Subscription response PDU. Reason = " << strerror(errno) << std::endl;
141       send_msg = false;
142       goto finished_sub_req;
143
144     }
145
146     std::cout <<"==============================\nReceived Subscription Request with ID = " << he.get_request_id() << std::endl;
147     //xer_fprint(stdout, &asn_DEF_E2AP_PDU, e2ap_pdu_recv);
148
149
150     // get action type (we support only one action in subscription request currently ....
151     actions = he.get_list();
152     action_type = (*actions)[0].get_type();
153     std::cout << "Action type in subscription request ID = "<<  he.get_request_id() << " set to " << action_type << std::endl;
154     
155     // decode the event trigger ...
156     {
157       e2sm_event_trigger_helper event_trigger_data;
158       event = 0; // used for decoding
159       retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, (void**)&(event), (unsigned char *)he.get_event_def(), he.get_event_def_size());
160       if (retval.code != RC_OK){
161         std::cerr <<"Error decoding event trigger in subscription request. Reason = " << strerror(errno) << std::endl;
162         send_msg = false;
163         goto finished_sub_req;
164       }
165       //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
166       //xer_fprint(stdout, &asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
167       //std::cout <<"++++++++++++++ EVENT TRIGGER ++++++++++++++++++++++++++++++++++" << std::endl;
168       
169     }
170     
171     // set up response object
172     he_resp.set_request(he.get_request_id(), he.get_req_seq());
173     he_resp.set_function_id(he.get_function_id());
174     i = 0;
175
176     // ideally should move all actions to not admitted if failed
177     // but we ignore admitted list anyway when we set up the PDU
178     // for now, just copy to both lists :)  ...
179     for(auto &e : *(he.get_list())){
180       he_resp.add_action(e.get_id());
181       he_resp.add_action(e.get_id(), 1, 2);
182       
183       i++;
184     }
185     mlen = RMR_BUFFER_SIZE;
186
187     res = sub_resp.encode_e2ap_subscription_response(&message->payload[0], &mlen,  he_resp, true);
188     if (!res){
189       std::cerr << "Error encoding subscription response successful. Reason = " << sub_resp.get_error() << std::endl;
190       send_msg = false;
191       goto finished_sub_req;
192     }
193     message->mtype = RIC_SUB_RESP;
194     subscription_active = true;
195     
196     
197   finished_sub_req:
198     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
199     ASN_STRUCT_FREE(asn_DEF_E2N_E2SM_gNB_X2_eventTriggerDefinition, event);
200     if(send_msg){
201       message->len = mlen;
202       
203       // also set subscription id ?
204       std::cout <<"Sending Subscription Response with RMR type " << message->mtype << " and size = " << message->len << std::endl;
205       std::cout <<"======================================" << std::endl;
206       return true;
207     }
208     else{
209       break;
210     }
211     
212   case RIC_SUB_DEL_REQ:
213
214     e2ap_pdu_recv = 0;
215     retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
216     if(retval.code == RC_OK){
217       he.clear();
218       sub_del_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, he);
219     }
220     else{
221       std::cerr <<"Error decoding E2AP Subscription Delete Request PDU. Reason = " << strerror(errno) << std::endl;
222       send_msg = false;
223       goto finished_sub_del;
224     }
225
226     std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
227     xer_fprint(stdout, &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
228     std::cout <<"==============================\nReceived Subscription Delete Request with ID = " << he.get_request_id() << std::endl;
229
230     // FILE *pfile;
231     // pfile = fopen("subscription_delete.per", "wb");
232     // fwrite(message->payload, 1, message->len, pfile);
233     // fclose(pfile);
234     
235     // set up response object
236     std::cout <<"Generating response ...." << std::endl;
237     he_resp.clear();
238     he_resp.set_request(he.get_request_id(), he.get_req_seq());
239     he_resp.set_function_id(he.get_function_id());
240     mlen = RMR_BUFFER_SIZE;    
241     res = sub_del_resp.encode_e2ap_subscription_delete_response(&message->payload[0], &mlen,  he_resp, true);
242     if (!res){
243       std::cerr << "Error encoding subscription delete  response failure . Reason = " << sub_resp.get_error() << std::endl;
244       send_msg = false;
245       goto finished_sub_del;
246     }
247
248   finished_sub_del:
249     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
250     
251     if(send_msg){
252       message->mtype = RIC_SUB_DEL_RESP;
253       message->len = mlen;
254       subscription_active = false;
255       return true;
256     }
257     else{
258       break;
259     }
260     
261   case RIC_CONTROL_REQ:
262     num_controls ++;
263     e2ap_pdu_recv = 0;
264     retval =  asn_decode(0,ATS_ALIGNED_BASIC_PER, &asn_DEF_E2N_E2AP_PDU, (void**)&(e2ap_pdu_recv), message->payload, message->len);
265     if(retval.code != RC_OK){
266       std::cerr <<"Error decoding RIC Control Request" << std::endl;
267       goto finished_ctrl;
268     }
269     
270     if (verbose_flag){
271       std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
272       xer_fprint(stdout,  &asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
273     }
274     
275     res = control_req.get_fields(e2ap_pdu_recv->choice.initiatingMessage, control_data);
276     if(!res){
277       std::cout <<"Error getting data from E2AP control request" << std::endl;
278       break;
279     }
280
281     // Decode the X2AP PDU : directly embedded in Control Msg IE
282     x2ap_pdu_recv = 0;
283     retval = asn_decode(0, ATS_ALIGNED_BASIC_PER, &asn_DEF_X2N_X2AP_PDU, (void **)&x2ap_pdu_recv, control_data.control_msg, control_data.control_msg_size );
284     if (retval.code != RC_OK){
285       std::cerr <<"Error decoding X2AP PDU in control request message of size " << control_data.control_msg_size  << std::endl;
286       num_errors ++;
287       goto finished_ctrl;
288     }
289     
290     if(verbose_flag){
291       xer_fprint(stdout, &asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
292       std::cout <<"++++++++ RECEIVED CONTROL REQUEST +++++++++++++++++++++++++++++" << std::endl;
293       
294     }
295
296     if(x2ap_pdu_recv->present == X2N_X2AP_PDU_PR_successfulOutcome && x2ap_pdu_recv->choice.successfulOutcome->procedureCode == X2N_ProcedureCode_id_sgNBAdditionPreparation && x2ap_pdu_recv->choice.successfulOutcome->value.present == X2N_SuccessfulOutcome__value_PR_SgNBAdditionRequestAcknowledge ){
297       num_accepts ++;
298     }
299     else if ( x2ap_pdu_recv->present == X2N_X2AP_PDU_PR_unsuccessfulOutcome && x2ap_pdu_recv->choice.unsuccessfulOutcome->procedureCode == X2N_ProcedureCode_id_sgNBAdditionPreparation && x2ap_pdu_recv->choice.unsuccessfulOutcome->value.present == X2N_UnsuccessfulOutcome__value_PR_SgNBAdditionRequestReject ){
300       num_rejects ++;
301     }
302     else{
303       std::cerr <<"Unknown X2AP PDU : message type = " << x2ap_pdu_recv->present << std::endl;
304     }
305
306     
307     // generate control ack ? 
308     // control_data.control_status = 0;
309     // mlen = RMR_BUFFER_SIZE;
310     // res = control_resp.encode_e2ap_control_response(message->payload, &mlen, control_data, true);
311
312     // if (!res){
313     //   std::cerr <<"Error encoding control response ack. Reason = " << control_resp.get_error() << std::endl;
314     // }
315   finished_ctrl:
316     ASN_STRUCT_FREE(asn_DEF_E2N_E2AP_PDU, e2ap_pdu_recv);
317     ASN_STRUCT_FREE(asn_DEF_X2N_X2AP_PDU, x2ap_pdu_recv);
318     
319     break;
320
321   default:
322     std::cerr <<"Error ! Unknown RMR message of type " << message->mtype << " received" << std::endl;
323     break;
324   }
325   
326   return false;
327 };
328
329
330
331
332 int main(int argc, char *argv[]){
333
334   char name[128] = "mock_subscription_mgr";
335   char port[16] = "tcp:4591";
336   double rate = 1; // default rate to send at
337   int verbose_flag = 0;
338   
339   // Parse command line options
340   static struct option long_options[] =
341     {
342         /* Thse options require arguments */
343         {"name", required_argument, 0, 'n'},
344         {"port", required_argument, 0, 'p'},
345         {"rate", required_argument, 0, 'r'},
346         {"verbose", no_argument, &verbose_flag, 1},
347
348     };
349
350
351    while(1) {
352
353         int option_index = 0;
354         char c = getopt_long(argc, argv, "n:p:a:r:", long_options, &option_index);
355         if(c == -1){
356             break;
357          }
358
359         switch(c)
360         {
361
362         case 0:
363           /* An option flag was set.
364              Do nothing for now */
365           break;
366           
367         case 'n':
368           strcpy(name, optarg);
369           break;
370           
371         case 'p':
372           strcpy(port, optarg);
373           break;
374           
375
376         case 'r':
377           rate = atof(optarg);
378           if (rate < 0){
379             std::cerr <<"Error : Transmit rate must be >= 0/sec" << std::endl;
380             exit(-1);
381           }
382           
383           if (rate > 1000){
384             std::cerr <<"Error : maximum allowed rate = 1000/sec" << std::endl;
385             exit(-1);
386           }
387           break;
388           
389         case 'h':
390           usage(argv[0]);
391           exit(0);
392
393           
394         default:
395           std::cout <<"Error ! " << std::endl;
396           usage(argv[0]);
397           exit(1);
398         }
399    };
400
401    int log_level = MDCLOG_WARN;
402    if (verbose_flag){
403      log_level = MDCLOG_INFO;
404    }
405    init_logger(name, static_cast<mdclog_severity_t>(log_level));
406
407    XaPP my_xapp = XaPP(name, port, 16384, 1);
408    my_xapp.Start(Message_Handler);
409
410    
411    
412    e2sm_indication e2sm_indication_obj;
413    bool res;
414    FILE *pfile;
415    
416
417    //==== e2sm indication header : just some
418    e2sm_header_helper indication_header;
419    // random fill for now 
420    indication_header.egNB_id="hello";
421    indication_header.plmn_id="there";
422    indication_header.interface_direction = 1;
423    indication_header.egNB_id_type = 2;
424    unsigned char buf_header[32];
425    size_t buf_header_size = 32;
426    
427    res = e2sm_indication_obj.encode_indication_header(&buf_header[0], &buf_header_size, indication_header);
428    if(!res){
429      std::cout <<"Error encoding indication header. Reason = " << e2sm_indication_obj.get_error() << std::endl;
430      exit(-1);
431    }
432
433    //====== x2ap sgnb addition request created by us
434    unsigned char x2ap_buf[1024];
435    size_t x2ap_buf_size = 1024;
436    pfile = fopen(X2_SGNB_ADDITION_REQUEST, "r");
437    if(pfile == NULL){
438      std::cerr <<"Error ! Could not find test per file " << X2_SGNB_ADDITION_REQUEST << std::endl;
439      exit(-1);
440    }
441    
442    x2ap_buf_size = fread((char *)x2ap_buf, sizeof(char), 1024, pfile);
443    fclose(pfile);
444
445   
446    //==== e2ap indication for generated x2ap pdus
447    ric_indication_helper dinput ;   
448    dinput.action_id = 100;
449    dinput.func_id = 10;
450    dinput.indication_sn = 100;
451    dinput.req_id = 6;
452    dinput.req_seq_no = 11;
453
454    
455
456    /* encoding pdu put here */
457    size_t data_size = 16384;
458    unsigned char data[data_size];
459    
460    ric_indication indication_pdu;
461
462
463    // prepare packet to send. we send
464    // same packet every time for now
465    dinput.indication_header = buf_header;
466    dinput.indication_header_size = buf_header_size;
467    dinput.indication_msg = x2ap_buf;
468    dinput.indication_msg_size = x2ap_buf_size;
469    dinput.indication_type = 1; // for now always ask for control back
470    res = indication_pdu.encode_e2ap_indication(&data[0], &data_size, dinput);
471    if (!res){
472      std::cout <<"Error encoding E2AP Indication PDU. Reason = " << indication_pdu.get_error().c_str() <<  std::endl;
473      exit(-1);
474    }
475        
476
477    //Register signal handler to stop 
478    signal(SIGINT, EndProgram);
479    signal(SIGTERM, EndProgram);
480
481    unsigned long int interval = 0;
482
483    if (rate > 0){
484      interval = 1000.0/rate;
485    }
486    else{
487      interval = 10;
488    }
489    
490    auto start_time = std::chrono::steady_clock::now();
491    int count = 0;
492
493
494    while(RunProgram){
495
496      if ( subscription_active && rate > 0 ){
497        my_xapp.Send(RIC_INDICATION, data_size, data);
498        num_indications ++;
499      }
500      
501      std::this_thread::sleep_for(std::chrono::milliseconds(interval));
502      count ++;
503    }
504    
505    
506    auto end_time = std::chrono::steady_clock::now();
507    double  duration = std::chrono::duration_cast<std::chrono::seconds>(end_time - start_time).count();
508
509    std::cout <<"Number of SgNB Addition Request (in E2AP Indication) sent = " << num_indications << std::endl;
510    std::cout <<"Number of control responses received = " << num_controls << std::endl;
511    std::cout <<"Number of SgNB Addition Acknowledges = " << num_accepts << std::endl;
512    std::cout <<"NUmber of SgNB Addition Rejects = " << num_rejects << std::endl;
513    std::cout <<"Number of E2AP control requests we could not decode = " << num_errors << std::endl;
514    
515    std::cout <<"Duration = " << duration  << " E2AP Indication Tx Rate = " << num_indications/duration << std::endl;
516    my_xapp.Stop();
517
518    std::cout <<"Stopped RMR thread .." << std::endl;
519    return 0;
520       
521
522 };
523
524
525
526
527
528