diff --git a/Cargo.toml b/Cargo.toml index 69dc4fa..3477607 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "hyperscan" -version = "0.1.3" -authors = ["Flier Lu "] +version = "0.1.4" +authors = ["Flier Lu "] build = "build.rs" description = "Hyperscan bindings for Rust with Multiple Pattern and Streaming Scan" homepage = "http://flier.github.io/rust-hyperscan/" @@ -12,29 +12,29 @@ readme = "README.md" keywords = ["regex", "hyperscan", "streaming"] [features] -bindgen = ["libbindgen"] +gen = ["bindgen"] [dependencies] libc = "0.2" log = "0.3" -regex-syntax = "0.3" +regex-syntax = "0.4" [build-dependencies] log = "0.3" -env_logger = "0.3" +env_logger = "0.4" +pkg-config = "0.3" -[build-dependencies.libbindgen] -version = "0.1" -features = ["llvm_stable", "static"] +[build-dependencies.bindgen] +version = "0.22" optional = true [dev-dependencies] -env_logger = "0.3" -regex = "0.1" +env_logger = "0.4" +regex = "0.2" getopts = "0.2" pcap = "0.5" pnet = "0.16" -byteorder = "0.5" +byteorder = "1.0" [lib] name = "hyperscan" diff --git a/build.rs b/build.rs index 064918c..9194463 100644 --- a/build.rs +++ b/build.rs @@ -1,20 +1,53 @@ #[macro_use] extern crate log; -#[cfg(feature = "bindgen")] -extern crate libbindgen; extern crate env_logger; +#[cfg(feature = "gen")] +extern crate bindgen; +extern crate pkg_config; -#[cfg(not(feature = "bindgen"))] +#[cfg(not(feature = "gen"))] use std::fs; use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; -#[cfg(feature = "bindgen")] -fn generate_binding(hyperscan_root: &str, out_file: &Path) { +struct Library { + pub libs: Vec, + pub link_paths: Vec, + pub include_paths: Vec, +} + +fn find_hyperscan() -> Library { + if let Ok(prefix) = env::var("HYPERSCAN_ROOT") { + debug!("building with Hyperscan @ HYPERSCAN_ROOT={}", prefix); + + Library { + libs: vec![From::from("hs")], + link_paths: vec![From::from(format!("{}/lib", prefix))], + include_paths: vec![From::from(format!("{}/include", prefix))], + } + } else if let Ok(pkg_config::Library { libs, link_paths, include_paths, .. }) = + pkg_config::Config::new().statik(true).probe("libhs") { + debug!("building with Hyperscan @ libs={:?}, link_paths={:?}, include_paths={:?}", + libs, + link_paths, + include_paths); + + Library { + libs: libs, + link_paths: link_paths, + include_paths: include_paths, + } + } else { + panic!("please install hyperscan from https://github.com/01org/hyperscan") + } +} + +#[cfg(feature = "gen")] +fn generate_binding(hyperscan_include_path: &str, out_file: &Path) { info!("generating raw Hyperscan wrapper @ {}", out_file.display()); - libbindgen::builder() - .header(format!("{}/include/hs/hs.h", hyperscan_root)) + bindgen::builder() + .header(format!("{}/hs.h", hyperscan_include_path)) .clang_arg("-xc++") .clang_arg("-std=c++11") .no_unstable_rust() @@ -24,11 +57,10 @@ fn generate_binding(hyperscan_root: &str, out_file: &Path) { .write_to_file(out_file) .expect("Fail to write raw wrapper"); - println!("cargo:rerun-if-changed={}/include/hs/hs.h", hyperscan_root); - + println!("cargo:rerun-if-changed={}/hs.h", hyperscan_include_path); } -#[cfg(not(feature = "bindgen"))] +#[cfg(not(feature = "gen"))] fn generate_binding(_: &str, out_file: &Path) { fs::copy("src/raw_bindgen.rs", out_file).expect("fail to copy bindings"); } @@ -36,17 +68,12 @@ fn generate_binding(_: &str, out_file: &Path) { fn main() { env_logger::init().unwrap(); - let hyperscan_root = match env::var("HYPERSCAN_ROOT") { - Ok(prefix) => prefix, - Err(_) => String::from("/usr/local"), - }; - - debug!("building with Hyperscan @ {}", hyperscan_root); + let libhs = find_hyperscan(); let out_dir = env::var("OUT_DIR").unwrap(); let out_file = Path::new(&out_dir).join("raw_bindgen.rs"); - generate_binding(&hyperscan_root, &out_file); + generate_binding(libhs.include_paths[0].to_str().unwrap(), &out_file); if cfg!(target_os = "macos") { println!("cargo:rustc-link-lib=dylib=c++"); @@ -55,6 +82,14 @@ fn main() { println!("cargo:rustc-link-lib=dylib=gcc"); } - println!("cargo:rustc-link-lib=static=hs"); - println!("cargo:rustc-link-search=native={}/lib", hyperscan_root); + for lib in libhs.libs { + if lib.contains("hs") { + println!("cargo:rustc-link-lib=static={}", lib); + } + } + + for link_path in libhs.link_paths { + println!("cargo:rustc-link-search=native={}", + link_path.to_str().unwrap()); + } } diff --git a/examples/pcapscan.rs b/examples/pcapscan.rs index 06dae80..0405b42 100644 --- a/examples/pcapscan.rs +++ b/examples/pcapscan.rs @@ -23,10 +23,8 @@ extern crate getopts; extern crate pcap; extern crate pnet; extern crate byteorder; -#[macro_use] extern crate log; extern crate env_logger; -#[macro_use] extern crate hyperscan; use std::fmt; @@ -51,9 +49,8 @@ use pnet::packet::ipv4::Ipv4Packet; use pnet::packet::udp::UdpPacket; use byteorder::{BigEndian, ReadBytesExt}; -use hyperscan::{Pattern, Patterns, Database, DatabaseBuilder, StreamingDatabase, BlockDatabase, - RawScratch, Scratch, ScratchAllocator, BlockScanner, StreamingScanner, Stream, - RawStream}; +use hyperscan::{Pattern, Patterns, Database, DatabaseBuilder, StreamingDatabase, BlockDatabase, RawScratch, Scratch, + ScratchAllocator, BlockScanner, StreamingScanner, Stream, RawStream}; #[derive(Debug)] enum Error { @@ -97,8 +94,7 @@ trait Milliseconds { impl Milliseconds for Duration { fn ms(&self) -> usize { - (self.as_secs() * MILLIS_PER_SEC) as usize + - (self.subsec_nanos() / NANOS_PER_MILLI) as usize + (self.as_secs() * MILLIS_PER_SEC) as usize + (self.subsec_nanos() / NANOS_PER_MILLI) as usize } } @@ -204,9 +200,7 @@ struct Benchmark { } impl Benchmark { - fn new(db_streaming: StreamingDatabase, - db_block: BlockDatabase) - -> Result { + fn new(db_streaming: StreamingDatabase, db_block: BlockDatabase) -> Result { let mut s = try!(db_streaming.alloc()); try!(s.realloc(&db_block)); @@ -315,8 +309,7 @@ impl Benchmark { // Close all open Hyperscan streams (potentially generating any end-anchored matches) fn close_streams(&mut self) { for ref stream in &self.streams { - if let Err(err) = - stream.close(&self.scratch, Some(Self::on_match), Some(&self.match_count)) { + if let Err(err) = stream.close(&self.scratch, Some(Self::on_match), Some(&self.match_count)) { println!("ERROR: Unable to close stream. Exiting. {}", err); } } @@ -523,8 +516,7 @@ fn main() { let bytes = bench.bytes(); let total_bytes = (bytes * 8 * repeat_count) as f64; let tput_stream_scanning = total_bytes * 1000.0 / streaming_scan.ms() as f64; - let tput_stream_overhead = total_bytes * 1000.0 / - (streaming_scan + streaming_open_close).ms() as f64; + let tput_stream_overhead = total_bytes * 1000.0 / (streaming_scan + streaming_open_close).ms() as f64; let matches_stream = bench.matches(); let match_rate_stream = (matches_stream as f64) / ((bytes * repeat_count) as f64 / 1024.0); diff --git a/src/compile.rs b/src/compile.rs index 105a5df..a1f7c52 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -149,7 +149,7 @@ impl fmt::Display for Pattern { write!(f, "{}:/{}/{}", self.id, - regex_syntax::quote(self.expression.as_str()), + regex_syntax::escape(self.expression.as_str()), self.flags) } } diff --git a/src/raw_bindgen.rs b/src/raw_bindgen.rs index f8a22fe..69d08b2 100644 --- a/src/raw_bindgen.rs +++ b/src/raw_bindgen.rs @@ -1,13 +1,9 @@ /* automatically generated by rust-bindgen */ +pub type __darwin_size_t = ::std::os::raw::c_ulong; #[repr(C)] -#[derive(Debug, Copy)] -pub struct hs_database { - pub _address: u8, -} -impl Clone for hs_database { - fn clone(&self) -> Self { *self } -} +#[derive(Debug, Copy, Clone)] +pub struct hs_database([u8; 0]); /** * A Hyperscan pattern database. * @@ -521,8 +517,20 @@ pub struct hs_compile_error { } #[test] fn bindgen_test_layout_hs_compile_error() { - assert_eq!(::std::mem::size_of::() , 16usize); - assert_eq!(::std::mem::align_of::() , 8usize); + assert_eq!(::std::mem::size_of::() , 16usize , concat ! + ( "Size of: " , stringify ! ( hs_compile_error ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! + ( "Alignment of " , stringify ! ( hs_compile_error ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_compile_error ) ) . message as * const + _ as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_compile_error ) , + "::" , stringify ! ( message ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_compile_error ) ) . expression as * + const _ as usize } , 8usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_compile_error ) , + "::" , stringify ! ( expression ) )); } impl Clone for hs_compile_error { fn clone(&self) -> Self { *self } @@ -567,8 +575,30 @@ pub struct hs_platform_info { } #[test] fn bindgen_test_layout_hs_platform_info() { - assert_eq!(::std::mem::size_of::() , 32usize); - assert_eq!(::std::mem::align_of::() , 8usize); + assert_eq!(::std::mem::size_of::() , 32usize , concat ! + ( "Size of: " , stringify ! ( hs_platform_info ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! + ( "Alignment of " , stringify ! ( hs_platform_info ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_platform_info ) ) . tune as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_platform_info ) , + "::" , stringify ! ( tune ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_platform_info ) ) . cpu_features as * + const _ as usize } , 8usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_platform_info ) , + "::" , stringify ! ( cpu_features ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_platform_info ) ) . reserved1 as * + const _ as usize } , 16usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_platform_info ) , + "::" , stringify ! ( reserved1 ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_platform_info ) ) . reserved2 as * + const _ as usize } , 24usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_platform_info ) , + "::" , stringify ! ( reserved2 ) )); } impl Clone for hs_platform_info { fn clone(&self) -> Self { *self } @@ -616,8 +646,35 @@ pub struct hs_expr_info { } #[test] fn bindgen_test_layout_hs_expr_info() { - assert_eq!(::std::mem::size_of::() , 12usize); - assert_eq!(::std::mem::align_of::() , 4usize); + assert_eq!(::std::mem::size_of::() , 12usize , concat ! ( + "Size of: " , stringify ! ( hs_expr_info ) )); + assert_eq! (::std::mem::align_of::() , 4usize , concat ! ( + "Alignment of " , stringify ! ( hs_expr_info ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_info ) ) . min_width as * const _ + as usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_info ) , "::" , + stringify ! ( min_width ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_info ) ) . max_width as * const _ + as usize } , 4usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_info ) , "::" , + stringify ! ( max_width ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_info ) ) . unordered_matches as * + const _ as usize } , 8usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_info ) , "::" , + stringify ! ( unordered_matches ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_info ) ) . matches_at_eod as * + const _ as usize } , 9usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_info ) , "::" , + stringify ! ( matches_at_eod ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_info ) ) . matches_only_at_eod as + * const _ as usize } , 10usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_info ) , "::" , + stringify ! ( matches_only_at_eod ) )); } impl Clone for hs_expr_info { fn clone(&self) -> Self { *self } @@ -661,8 +718,30 @@ pub struct hs_expr_ext { } #[test] fn bindgen_test_layout_hs_expr_ext() { - assert_eq!(::std::mem::size_of::() , 32usize); - assert_eq!(::std::mem::align_of::() , 8usize); + assert_eq!(::std::mem::size_of::() , 32usize , concat ! ( + "Size of: " , stringify ! ( hs_expr_ext ) )); + assert_eq! (::std::mem::align_of::() , 8usize , concat ! ( + "Alignment of " , stringify ! ( hs_expr_ext ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_ext ) ) . flags as * const _ as + usize } , 0usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_ext ) , "::" , + stringify ! ( flags ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_ext ) ) . min_offset as * const _ + as usize } , 8usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_ext ) , "::" , + stringify ! ( min_offset ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_ext ) ) . max_offset as * const _ + as usize } , 16usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_ext ) , "::" , + stringify ! ( max_offset ) )); + assert_eq! (unsafe { + & ( * ( 0 as * const hs_expr_ext ) ) . min_length as * const _ + as usize } , 24usize , concat ! ( + "Alignment of field: " , stringify ! ( hs_expr_ext ) , "::" , + stringify ! ( min_length ) )); } impl Clone for hs_expr_ext { fn clone(&self) -> Self { *self } @@ -1054,29 +1133,16 @@ extern "C" { pub fn hs_populate_platform(platform: *mut hs_platform_info_t) -> hs_error_t; } -/** - * Definition of the stream identifier type. - */ #[repr(C)] -#[derive(Debug, Copy)] -pub struct hs_stream { - pub _address: u8, -} -impl Clone for hs_stream { - fn clone(&self) -> Self { *self } -} +#[derive(Debug, Copy, Clone)] +pub struct hs_stream([u8; 0]); /** * The stream identifier returned by @ref hs_open_stream(). */ pub type hs_stream_t = hs_stream; #[repr(C)] -#[derive(Debug, Copy)] -pub struct hs_scratch { - pub _address: u8, -} -impl Clone for hs_scratch { - fn clone(&self) -> Self { *self } -} +#[derive(Debug, Copy, Clone)] +pub struct hs_scratch([u8; 0]); /** * A Hyperscan scratch space. */ @@ -1532,4 +1598,4 @@ extern "C" { * @ref HS_SUCCESS on success, other values on failure. */ pub fn hs_free_scratch(scratch: *mut hs_scratch_t) -> hs_error_t; -} \ No newline at end of file +}