Skip to content

Instantly share code, notes, and snippets.

@o0Ignition0o
Last active July 29, 2018 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save o0Ignition0o/a034745f92a9c3f75429a93aa20ddc1a to your computer and use it in GitHub Desktop.
Save o0Ignition0o/a034745f92a9c3f75429a93aa20ddc1a to your computer and use it in GitHub Desktop.
is_valid_ipv4_addr
#![crate_type = "staticlib"]
#![feature(test)]
extern crate test;
extern crate libc;
use std::slice;
fn is_valid_ipv4_addr<'a>(addr: &'a [u8]) -> bool {
let mut maybe_octet: Option<u8> = None;
let mut dots: u8 = 0;
for c in addr {
match c {
46 => {
if maybe_octet.is_none() {
// ip address cannot start with a '.'
return false;
}
dots = dots + 1;
maybe_octet = None;
}
c => {
if *c < 48 as u8 || *c > 57 {
return false;
}
match maybe_octet {
None => {
maybe_octet = Some(*c - 48);
}
Some(octet) => {
if *c == 48 && octet == 0 {
// Leading 0 is not allowed
return false;
}
if let Some(times_ten) = octet.checked_mul(10) {
if let Some(plus_c) = times_ten.checked_add(*c - 48) {
maybe_octet = Some(plus_c)
} else {
// Addition overflowed
return false;
}
} else {
// Multiplication overflowed
return false;
}
}
}
}
}
}
dots == 3 && maybe_octet.is_some()
}
#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn rust_net_is_valid_ipv4_addr<'a>(addr: &'a u8, addrLen: i32) -> bool {
let address = unsafe { slice::from_raw_parts(addr, addrLen as usize) };
is_valid_ipv4_addr(address)
}
#[cfg(test)]
mod tests {
use is_valid_ipv4_addr;
use test::{black_box, Bencher};
#[test]
fn test_with_localhost() {
let ip: Vec<char> = vec!['1', '2', '7', '.', '0', '.', '0', '.', '1'];
assert!(is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_zeroes() {
let ip: Vec<char> = vec!['0', '.', '0', '.', '0', '.', '0'];
assert!(is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_max() {
let ip: Vec<char> = vec![
'2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5',
];
assert!(is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_too_high_ip() {
let ip: Vec<char> = vec![
'2', '5', '6', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5',
];
assert!(!is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_ip_starting_with_a_dot() {
let ip: Vec<char> = vec![
'.', '2', '5', '6', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5',
];
assert!(!is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_ip_starting_with_4_digits() {
let ip: Vec<char> = vec![
'1', '1', '1', '1', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5',
];
assert!(!is_valid_ipv4_addr(&ip));
}
#[test]
fn test_with_too_long_ip() {
let ip: Vec<char> = vec![
'2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2',
'5', '5',
];
assert!(!is_valid_ipv4_addr(&ip));
}
#[bench]
fn bench_is_valid_ipv4_address(bench: &mut Bencher) {
let ip: Vec<char> = vec![
'1', '9', '2', '.', '1', '6', '8', '.', '1', '0', '1', '.', '1', '1', '7',
];
bench.iter(|| black_box(is_valid_ipv4_addr(&ip)));
}
}
@o0Ignition0o
Copy link
Author

test tests::bench_is_valid_ipv4_address ... ok
test tests::test_with_localhost ... ok
test tests::test_with_too_high_ip ... ok
test tests::test_with_ip_starting_with_4_digits ... ok
test tests::test_with_max ... ok
test tests::test_with_ip_starting_with_a_dot ... ok
test tests::test_with_zeroes ... ok
test tests::test_with_too_long_ip ... ok
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

test tests::bench_is_valid_ipv4_address ... bench:          27 ns/iter (+/- 5)
test result: ok. 0 passed; 0 failed; 7 ignored; 1 measured; 0 filtered out

@hawkw
Copy link

hawkw commented Jul 29, 2018

if *c < '0' || *c > '9' {
     return false;
}

might read somewhat clearer as

if !c.is_digit() {
     return false;
}

(see https://doc.rust-lang.org/beta/std/primitive.char.html#method.is_digit)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment