Add code generator for string attribute

This commit is contained in:
moznion
2020-11-25 00:43:11 +09:00
parent 7e6831e282
commit 84943f10eb
8 changed files with 548 additions and 18 deletions
+34 -4
View File
@@ -1,12 +1,12 @@
use crate::attribute::Attribute;
pub type Type = u8;
pub type AVPType = u8;
pub const TYPE_INVALID: Type = 1;
pub const TYPE_INVALID: AVPType = 255;
#[derive(Debug, Clone, PartialEq)]
pub struct AVP {
typ: Type,
typ: AVPType,
attribute: Attribute,
}
@@ -43,10 +43,40 @@ impl Attributes {
Ok(Attributes(attrs))
}
pub fn add(&mut self, typ: Type, attribute: Attribute) {
pub(crate) fn add(&mut self, typ: AVPType, attribute: Attribute) {
self.0.push(AVP { typ, attribute })
}
pub(crate) fn del(&mut self, typ: AVPType) {
self.0 = self
.0
.iter()
.filter(|&avp| avp.typ != typ)
.cloned()
.collect();
}
pub(crate) fn lookup(&self, typ: AVPType) -> Option<&Attribute> {
self.0.iter().find_map(|avp| {
if avp.typ == typ {
return Some(&avp.attribute);
}
None
})
}
pub(crate) fn lookup_all(&self, typ: AVPType) -> Vec<&Attribute> {
self.0
.iter()
.filter_map(|avp| {
if avp.typ == typ {
Some(&avp.attribute);
}
None
})
.collect()
}
pub fn attributes_encoded_len(&self) -> Result<u16, String> {
let mut n: u16 = 0;
for attr in &self.0 {
+133 -12
View File
@@ -1,10 +1,12 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::BufRead;
use std::io::{BufRead, BufWriter, Write};
use std::path::Path;
use std::str::FromStr;
use std::{env, io, process};
use getopts::Options;
use inflector::Inflector;
use regex::Regex;
const ATTRIBUTE_KIND: &str = "ATTRIBUTE";
@@ -13,15 +15,38 @@ const VALUE_KIND: &str = "VALUE";
#[derive(Debug)]
struct RadiusAttribute {
name: String,
identifier: u16,
typ: String,
typ: u8,
value_type: RadiusAttributeValueType,
is_encrypt: bool,
}
#[derive(Debug)]
struct RadiusValue {
name: String,
identifier: u16,
typ: u16,
}
#[derive(Debug)]
enum RadiusAttributeValueType {
STRING,
OCTETS,
IPADDR,
INTEGER,
VSA,
}
impl FromStr for RadiusAttributeValueType {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
"STRING" => Ok(RadiusAttributeValueType::STRING),
"OCTETS" => Ok(RadiusAttributeValueType::OCTETS),
"IPADDR" => Ok(RadiusAttributeValueType::IPADDR),
"INTEGER" => Ok(RadiusAttributeValueType::INTEGER),
"VSA" => Ok(RadiusAttributeValueType::VSA),
_ => Err(()),
}
}
}
fn print_usage(program: &str, opts: &Options) {
@@ -47,15 +72,104 @@ fn main() {
.parse(&args[1..])
.unwrap_or_else(|f| panic!(f.to_string()));
let dict_file_path = matches.free[0].clone();
let dict_file_path = Path::new(&matches.free[0]);
if !dict_file_path.exists() {
panic!("no such dictionary file => {}", &matches.free[0]);
}
let rfc_code = dict_file_path.extension().unwrap().to_str().unwrap();
let struct_name = rfc_code.to_uppercase();
let (radius_attributes, radius_attribute_to_values) = parse_dict_file(dict_file_path).unwrap();
println!("{:?}", radius_attributes);
println!("{:?}", radius_attribute_to_values);
let mut buf_writer = BufWriter::new(File::create(&matches.free[1]).unwrap());
generate_header(&mut buf_writer, &struct_name);
generate_attributes_code(&mut buf_writer, &radius_attributes);
generate_footer(&mut buf_writer);
}
fn generate_header(w: &mut BufWriter<File>, struct_name: &String) {
let code = format!(
"// Code generated by machine generator; DO NOT EDIT.
use crate::attribute::Attribute;
use crate::attributes::AVPType;
use crate::packet::Packet;
pub struct {struct_name} {{
}}
impl {struct_name} {{
",
struct_name = struct_name
);
w.write_all(code.as_bytes()).unwrap();
}
fn generate_footer(w: &mut BufWriter<File>) {
w.write_all(b"}\n").unwrap();
}
fn generate_attributes_code(w: &mut BufWriter<File>, attrs: &[RadiusAttribute]) {
for attr in attrs {
generate_attribute_code(w, attr);
}
}
fn generate_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {
match attr.value_type {
RadiusAttributeValueType::STRING => generate_string_attribute_code(w, attr),
RadiusAttributeValueType::OCTETS => generate_octets_attribute_code(w, attr),
RadiusAttributeValueType::IPADDR => generate_ipaddr_attribute_code(w, attr),
RadiusAttributeValueType::INTEGER => generate_integer_attribute_code(w, attr),
RadiusAttributeValueType::VSA => generate_vsa_attribute_code(w, attr),
}
}
fn generate_string_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {
let attr_name = attr.name.clone();
let type_identifier = format!("{}_TYPE", attr_name.to_screaming_snake_case());
let type_calling = format!("Self::{}", type_identifier);
let code = format!(
"pub const {type_identifier}: AVPType = {type_value};
pub fn add_{method_identifier}(packet: &mut Packet, value: &str) {{
let attr = Attribute::from_string(value);
packet.add({type_calling}, &attr);
}}
pub fn delete_{method_identifier}(packet: &mut Packet) {{
packet.delete({type_calling});
}}
pub fn lookup_{method_identifier}(packet: &Packet) -> Option<&Attribute> {{
packet.lookup({type_calling})
}}
pub fn lookup_all_{method_identifier}(packet: &Packet) -> Vec<&Attribute> {{
packet.lookup_all({type_calling})
}}
",
method_identifier = attr_name.to_snake_case(),
type_identifier = type_identifier,
type_calling = type_calling,
type_value = attr.typ,
);
w.write_all(code.as_bytes()).unwrap();
}
fn generate_octets_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {}
fn generate_ipaddr_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {}
fn generate_integer_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {}
fn generate_vsa_attribute_code(w: &mut BufWriter<File>, attr: &RadiusAttribute) {}
type DictParsed = (Vec<RadiusAttribute>, HashMap<String, Vec<RadiusValue>>);
fn parse_dict_file(dict_file_path: String) -> Result<DictParsed, String> {
fn parse_dict_file(dict_file_path: &Path) -> Result<DictParsed, String> {
let line_filter_re = Regex::new(r"^(?:#.*|)$").unwrap();
let tabs_re = Regex::new(r"\t+").unwrap();
@@ -80,7 +194,14 @@ fn parse_dict_file(dict_file_path: String) -> Result<DictParsed, String> {
match kind {
ATTRIBUTE_KIND => {
let type_descriptions = items[3].split(' ').collect::<Vec<&str>>();
let typ = type_descriptions[0].to_string();
let typ = match RadiusAttributeValueType::from_str(type_descriptions[0]) {
Ok(t) => t,
Err(_) => {
return Err(
format!("invalid type has come => {}", type_descriptions[0]).to_owned()
);
}
};
let is_encrypt = if type_descriptions.len() >= 2 {
type_descriptions[1] == "encrypt=1" // FIXME: ad-hoc!!!
} else {
@@ -89,8 +210,8 @@ fn parse_dict_file(dict_file_path: String) -> Result<DictParsed, String> {
radius_attributes.push(RadiusAttribute {
name: items[1].to_string(),
identifier: items[2].parse().unwrap(),
typ,
typ: items[2].parse().unwrap(),
value_type: typ,
is_encrypt,
});
}
@@ -100,7 +221,7 @@ fn parse_dict_file(dict_file_path: String) -> Result<DictParsed, String> {
let radius_value = RadiusValue {
name,
identifier: items[3].parse().unwrap(),
typ: items[3].parse().unwrap(),
};
match radius_attribute_to_values.get_mut(&attribute_name) {
+2
View File
@@ -1,3 +1,4 @@
extern crate inflector;
#[macro_use]
extern crate log;
@@ -8,5 +9,6 @@ pub mod code;
pub mod packet;
pub mod request;
pub mod request_handler;
pub mod rfc2865;
pub mod secret_provider;
pub mod server;
+18 -1
View File
@@ -2,7 +2,8 @@ use std::convert::TryInto;
use rand::Rng;
use crate::attributes::Attributes;
use crate::attribute::Attribute;
use crate::attributes::{AVPType, Attributes};
use crate::code::Code;
const MAX_PACKET_LENGTH: usize = 4096;
@@ -177,6 +178,22 @@ impl Packet {
_ => false,
}
}
pub fn add(&mut self, typ: AVPType, attr: &Attribute) {
self.attributes.add(typ, attr.clone());
}
pub fn delete(&mut self, typ: AVPType) {
self.attributes.del(typ);
}
pub fn lookup(&self, typ: AVPType) -> Option<&Attribute> {
self.attributes.lookup(typ)
}
pub fn lookup_all(&self, typ: AVPType) -> Vec<&Attribute> {
self.attributes.lookup_all(typ)
}
}
#[cfg(test)]
+218
View File
@@ -0,0 +1,218 @@
// Code generated by machine generator; DO NOT EDIT.
use crate::attribute::Attribute;
use crate::attributes::AVPType;
use crate::packet::Packet;
pub struct RFC2865 {}
impl RFC2865 {
pub const USER_NAME_TYPE: AVPType = 1;
pub fn add_user_name(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::USER_NAME_TYPE, &attr);
}
pub fn delete_user_name(packet: &mut Packet) {
packet.delete(Self::USER_NAME_TYPE);
}
pub fn lookup_user_name(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::USER_NAME_TYPE)
}
pub fn lookup_all_user_name(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::USER_NAME_TYPE)
}
pub const USER_PASSWORD_TYPE: AVPType = 2;
pub fn add_user_password(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::USER_PASSWORD_TYPE, &attr);
}
pub fn delete_user_password(packet: &mut Packet) {
packet.delete(Self::USER_PASSWORD_TYPE);
}
pub fn lookup_user_password(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::USER_PASSWORD_TYPE)
}
pub fn lookup_all_user_password(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::USER_PASSWORD_TYPE)
}
pub const FILTER_ID_TYPE: AVPType = 11;
pub fn add_filter_id(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::FILTER_ID_TYPE, &attr);
}
pub fn delete_filter_id(packet: &mut Packet) {
packet.delete(Self::FILTER_ID_TYPE);
}
pub fn lookup_filter_id(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::FILTER_ID_TYPE)
}
pub fn lookup_all_filter_id(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::FILTER_ID_TYPE)
}
pub const REPLY_MESSAGE_TYPE: AVPType = 18;
pub fn add_reply_message(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::REPLY_MESSAGE_TYPE, &attr);
}
pub fn delete_reply_message(packet: &mut Packet) {
packet.delete(Self::REPLY_MESSAGE_TYPE);
}
pub fn lookup_reply_message(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::REPLY_MESSAGE_TYPE)
}
pub fn lookup_all_reply_message(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::REPLY_MESSAGE_TYPE)
}
pub const CALLBACK_NUMBER_TYPE: AVPType = 19;
pub fn add_callback_number(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::CALLBACK_NUMBER_TYPE, &attr);
}
pub fn delete_callback_number(packet: &mut Packet) {
packet.delete(Self::CALLBACK_NUMBER_TYPE);
}
pub fn lookup_callback_number(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::CALLBACK_NUMBER_TYPE)
}
pub fn lookup_all_callback_number(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::CALLBACK_NUMBER_TYPE)
}
pub const CALLBACK_ID_TYPE: AVPType = 20;
pub fn add_callback_id(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::CALLBACK_ID_TYPE, &attr);
}
pub fn delete_callback_id(packet: &mut Packet) {
packet.delete(Self::CALLBACK_ID_TYPE);
}
pub fn lookup_callback_id(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::CALLBACK_ID_TYPE)
}
pub fn lookup_all_callback_id(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::CALLBACK_ID_TYPE)
}
pub const FRAMED_ROUTE_TYPE: AVPType = 22;
pub fn add_framed_route(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::FRAMED_ROUTE_TYPE, &attr);
}
pub fn delete_framed_route(packet: &mut Packet) {
packet.delete(Self::FRAMED_ROUTE_TYPE);
}
pub fn lookup_framed_route(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::FRAMED_ROUTE_TYPE)
}
pub fn lookup_all_framed_route(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::FRAMED_ROUTE_TYPE)
}
pub const CALLED_STATION_ID_TYPE: AVPType = 30;
pub fn add_called_station_id(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::CALLED_STATION_ID_TYPE, &attr);
}
pub fn delete_called_station_id(packet: &mut Packet) {
packet.delete(Self::CALLED_STATION_ID_TYPE);
}
pub fn lookup_called_station_id(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::CALLED_STATION_ID_TYPE)
}
pub fn lookup_all_called_station_id(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::CALLED_STATION_ID_TYPE)
}
pub const CALLING_STATION_ID_TYPE: AVPType = 31;
pub fn add_calling_station_id(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::CALLING_STATION_ID_TYPE, &attr);
}
pub fn delete_calling_station_id(packet: &mut Packet) {
packet.delete(Self::CALLING_STATION_ID_TYPE);
}
pub fn lookup_calling_station_id(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::CALLING_STATION_ID_TYPE)
}
pub fn lookup_all_calling_station_id(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::CALLING_STATION_ID_TYPE)
}
pub const NAS_IDENTIFIER_TYPE: AVPType = 32;
pub fn add_nas_identifier(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::NAS_IDENTIFIER_TYPE, &attr);
}
pub fn delete_nas_identifier(packet: &mut Packet) {
packet.delete(Self::NAS_IDENTIFIER_TYPE);
}
pub fn lookup_nas_identifier(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::NAS_IDENTIFIER_TYPE)
}
pub fn lookup_all_nas_identifier(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::NAS_IDENTIFIER_TYPE)
}
pub const LOGIN_LAT_SERVICE_TYPE: AVPType = 34;
pub fn add_login_lat_service(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::LOGIN_LAT_SERVICE_TYPE, &attr);
}
pub fn delete_login_lat_service(packet: &mut Packet) {
packet.delete(Self::LOGIN_LAT_SERVICE_TYPE);
}
pub fn lookup_login_lat_service(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::LOGIN_LAT_SERVICE_TYPE)
}
pub fn lookup_all_login_lat_service(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::LOGIN_LAT_SERVICE_TYPE)
}
pub const LOGIN_LAT_NODE_TYPE: AVPType = 35;
pub fn add_login_lat_node(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::LOGIN_LAT_NODE_TYPE, &attr);
}
pub fn delete_login_lat_node(packet: &mut Packet) {
packet.delete(Self::LOGIN_LAT_NODE_TYPE);
}
pub fn lookup_login_lat_node(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::LOGIN_LAT_NODE_TYPE)
}
pub fn lookup_all_login_lat_node(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::LOGIN_LAT_NODE_TYPE)
}
pub const FRAMED_APPLE_TALK_ZONE_TYPE: AVPType = 39;
pub fn add_framed_apple_talk_zone(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::FRAMED_APPLE_TALK_ZONE_TYPE, &attr);
}
pub fn delete_framed_apple_talk_zone(packet: &mut Packet) {
packet.delete(Self::FRAMED_APPLE_TALK_ZONE_TYPE);
}
pub fn lookup_framed_apple_talk_zone(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::FRAMED_APPLE_TALK_ZONE_TYPE)
}
pub fn lookup_all_framed_apple_talk_zone(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::FRAMED_APPLE_TALK_ZONE_TYPE)
}
pub const LOGIN_LAT_PORT_TYPE: AVPType = 63;
pub fn add_login_lat_port(packet: &mut Packet, value: &str) {
let attr = Attribute::from_string(value);
packet.add(Self::LOGIN_LAT_PORT_TYPE, &attr);
}
pub fn delete_login_lat_port(packet: &mut Packet) {
packet.delete(Self::LOGIN_LAT_PORT_TYPE);
}
pub fn lookup_login_lat_port(packet: &Packet) -> Option<&Attribute> {
packet.lookup(Self::LOGIN_LAT_PORT_TYPE)
}
pub fn lookup_all_login_lat_port(packet: &Packet) -> Vec<&Attribute> {
packet.lookup_all(Self::LOGIN_LAT_PORT_TYPE)
}
}