Add client impl

This commit is contained in:
moznion
2020-11-23 16:34:12 +09:00
parent cf03846e73
commit 04b962ab36
4 changed files with 76 additions and 1 deletions

69
src/client.rs Normal file
View File

@@ -0,0 +1,69 @@
use std::net::SocketAddr;
use thiserror::Error;
use tokio::net::UdpSocket;
use crate::client::ClientError::{FailedConnection, FailedParsingUDPResponse, FailedRadiusPacketEncoding, FailedReceivingResponse, FailedSendingPacket, FailedUdpSocketBinding};
use crate::packet::Packet;
#[derive(Error, Debug)]
pub enum ClientError {
#[error("failed to bind a UDP socket => `{0}`")]
FailedUdpSocketBinding(String),
#[error("failed to connect to `{0}` => `{1}`")]
FailedConnection(String, String),
#[error("failed to encode a RADIUS request => `{0}`")]
FailedRadiusPacketEncoding(String),
#[error("failed to send a UDP datagram to `{0}` => `{1}`")]
FailedSendingPacket(String, String),
#[error("failed to receive the UDP response from `{0}` => `{1}`")]
FailedReceivingResponse(String, String),
#[error("failed to parse a UDP response into a RADIUS packet => `{0}`")]
FailedParsingUDPResponse(String),
}
pub struct Client {}
impl Client {
const MAX_DATAGRAM_SIZE: usize = 65507;
pub async fn send_packet(remote_addr: &SocketAddr, request_packet: &Packet) -> Result<Packet, ClientError> {
// TODO retransmission
let local_addr: SocketAddr = if remote_addr.is_ipv4() {
"0.0.0.0:0"
} else {
"[::]:0"
}.parse().unwrap();
let conn = match UdpSocket::bind(local_addr).await {
Ok(conn) => conn,
Err(e) => return Err(FailedUdpSocketBinding(e.to_string())),
};
match conn.connect(remote_addr).await {
Ok(_) => {}
Err(e) => return Err(FailedConnection(remote_addr.to_string(), e.to_string()))
};
let request_data = match request_packet.encode() {
Ok(encoded) => encoded,
Err(e) => return Err(FailedRadiusPacketEncoding(e.to_string()))
};
match conn.send(request_data.as_slice()).await {
Ok(_) => {}
Err(e) => return Err(FailedSendingPacket(remote_addr.to_string(), e.to_string()))
};
let mut buf = vec![0; Self::MAX_DATAGRAM_SIZE];
let len = match conn.recv(&mut buf).await {
Ok(len) => len,
Err(e) => return Err(FailedReceivingResponse(remote_addr.to_string(), e.to_string()))
};
match Packet::parse(&buf[..len].to_vec(), request_packet.get_secret()) {
Ok(response_packet) => Ok(response_packet),
Err(e) => Err(FailedParsingUDPResponse(e.to_string()))
}
}
}

View File

@@ -9,3 +9,4 @@ pub mod server;
pub mod secret_provider;
pub mod request_handler;
pub mod request;
pub mod client;

View File

@@ -29,10 +29,14 @@ impl Packet {
}
}
pub(crate) fn get_identifier(&self) -> u8 {
pub fn get_identifier(&self) -> u8 {
self.identifier
}
pub fn get_secret(&self) -> &Vec<u8> {
&self.secret
}
pub fn parse(bs: &Vec<u8>, secret: &Vec<u8>) -> Result<Self, String> {
if bs.len() < 20 {
return Err("radius packet doesn't have enough length of bytes; that has to be at least 20 bytes".to_owned());

View File

@@ -118,6 +118,7 @@ impl Server {
Err(e) => {
error!("failed to parse given request data to pack into the RADIUS packet; {}", e);
debug!("failed request data => {:?}", request_data);
// TODO error handler?
return;
}
};