use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
use gsm_map::operations::mo_forward_sm::MoForwardSmArg;
use gsm_map::operations::sri_sm::RoutingInfoForSmArg;
use gsm_map::types::{op_codes, SmRpDa, SmRpOa};
use sccp::{GlobalTitle, SccpAddress, SubsystemNumber, UnitData};
use tcap::{Begin, Component, Invoke, OperationCode, TcapMessage};
fn sample_msisdn() -> Vec<u8> {
vec![0x91, 0x51, 0x55, 0x10, 0x00, 0x99, 0xF9]
}
fn sample_sc_addr() -> Vec<u8> {
vec![0x91, 0x51, 0x55, 0x10, 0x00]
}
fn sri_sm_arg() -> RoutingInfoForSmArg {
RoutingInfoForSmArg {
msisdn: sample_msisdn().into(),
sm_rp_pri: true,
service_centre_address: sample_sc_addr().into(),
gprs_support_indicator: None,
sm_rp_mti: None,
sm_rp_smea: None,
}
}
fn mo_forward_sm_arg() -> MoForwardSmArg {
let mut ui = vec![
0x04, 0x0B, 0x91, 0x51, 0x55, 0x10, 0x00, 0x99, 0xF9, 0x00, 0x00,
];
ui.extend_from_slice(&[0xAB; 19]);
MoForwardSmArg {
sm_rp_da: SmRpDa::ServiceCentreAddressDa(sample_sc_addr().into()),
sm_rp_oa: SmRpOa::MsIsdn(sample_msisdn().into()),
sm_rp_ui: ui.into(),
imsi: None,
}
}
fn called_hlr() -> SccpAddress {
let gt = GlobalTitle::Gt0100 {
translation_type: 0,
numbering_plan: 1, encoding_scheme: 1, nature_of_address: 4,
digits: "15550100123".to_string(), };
SccpAddress::with_gt(gt, Some(SubsystemNumber::Hlr))
}
fn calling_gmsc() -> SccpAddress {
let gt = GlobalTitle::Gt0100 {
translation_type: 0,
numbering_plan: 1,
encoding_scheme: 1,
nature_of_address: 4,
digits: "15550100999".to_string(), };
SccpAddress::with_gt(gt, Some(SubsystemNumber::Msc))
}
fn build_stack(op_code: i64, map_param: Vec<u8>) -> Vec<u8> {
let invoke = Invoke {
invoke_id: 1,
linked_id: None,
operation_code: OperationCode::Local(op_code),
parameter: Some(rasn::types::Any::new(map_param)),
};
let begin = Begin {
otid: vec![0x00, 0x00, 0x00, 0x01].into(),
dialogue_portion: None,
components: Some(vec![Component::Invoke(invoke)]),
};
let tcap_bytes = tcap::encode(&TcapMessage::Begin(begin)).expect("tcap encode");
let udt = UnitData::new(called_hlr(), calling_gmsc(), tcap_bytes);
udt.encode().expect("sccp encode")
}
fn parse_stack(wire: &[u8]) -> Vec<u8> {
let udt = UnitData::decode(wire).expect("sccp decode");
let msg = tcap::decode(&udt.data).expect("tcap decode");
let TcapMessage::Begin(begin) = msg else {
panic!("expected Begin");
};
let components = begin.components.expect("components");
let Component::Invoke(invoke) = &components[0] else {
panic!("expected Invoke");
};
invoke
.parameter
.as_ref()
.expect("parameter")
.as_bytes()
.to_vec()
}
fn bench_integration(c: &mut Criterion) {
let mut g = c.benchmark_group("integration");
g.throughput(Throughput::Elements(1));
let sri_arg = sri_sm_arg();
let sri_param = rasn::ber::encode(&sri_arg).expect("encode sri arg");
let sri_wire = build_stack(op_codes::SEND_ROUTING_INFO_FOR_SM, sri_param.clone());
g.bench_function("sri_sm/encode_full_stack", |b| {
b.iter_batched(
|| sri_arg.clone(),
|arg| {
let param = rasn::ber::encode(&arg).unwrap();
build_stack(op_codes::SEND_ROUTING_INFO_FOR_SM, param)
},
BatchSize::SmallInput,
)
});
g.bench_function("sri_sm/decode_full_stack", |b| {
b.iter(|| {
let param = parse_stack(&sri_wire);
rasn::ber::decode::<RoutingInfoForSmArg>(¶m).unwrap()
})
});
let mo_arg = mo_forward_sm_arg();
let mo_param = rasn::ber::encode(&mo_arg).expect("encode mo arg");
let mo_wire = build_stack(op_codes::MO_FORWARD_SM, mo_param.clone());
g.bench_function("mo_forward_sm/encode_full_stack", |b| {
b.iter_batched(
|| mo_arg.clone(),
|arg| {
let param = rasn::ber::encode(&arg).unwrap();
build_stack(op_codes::MO_FORWARD_SM, param)
},
BatchSize::SmallInput,
)
});
g.bench_function("mo_forward_sm/decode_full_stack", |b| {
b.iter(|| {
let param = parse_stack(&mo_wire);
rasn::ber::decode::<MoForwardSmArg>(¶m).unwrap()
})
});
g.finish();
}
criterion_group!(benches, bench_integration);
criterion_main!(benches);