1#![feature(libc)]
2
3extern crate libc;
4extern crate rustc_serialize;
5extern crate rand;
6extern crate eui48;
7
8use libc::{c_char};
9use std::path::Path;
10use std::fs::File;
11use std::io::prelude::*;
12use std::io::BufReader;
13use std::ops::Add;
14use std::time::{SystemTime, Duration, UNIX_EPOCH};
15use std::ffi::CStr;
16use rand::{OsRng, Rng};
17use rustc_serialize::hex::FromHex;
18use eui48::{MacAddress, Eui48};
19
20#[no_mangle]
23pub extern fn uuid_gen_new(ptr: *const c_char) -> *mut UUIDGen {
24 let eui_cstr = unsafe {
25 assert!(!ptr.is_null());
26 CStr::from_ptr(ptr)
27 };
28 let mut eui: [u8; 6] = Default::default();
29 eui.copy_from_slice(&eui_cstr.to_bytes()[0..6]);
30 Box::into_raw(Box::new(UUIDGen::new(eui)))
31}
32
33#[no_mangle]
34pub extern fn uuid_gen_free(ptr: *mut UUIDGen) {
35 if ptr.is_null() { return }
36 unsafe {
37 Box::from_raw(ptr);
38 }
39}
40
41#[no_mangle]
42pub extern fn uuid_gen_nonce64(gen_ptr: *mut UUIDGen, nonce_ptr: *mut u8) {
43 let gen = unsafe {
44 assert!(!gen_ptr.is_null());
45 &mut *gen_ptr
46 };
47 let nonce64: [u8; 8] = gen.nonce64();
48 let nonce64: &[u8] = &nonce64[0..8];
49 unsafe { std::ptr::copy(&(nonce64)[0], nonce_ptr, 8) }
50}
51
52#[no_mangle]
53pub extern fn uuid_gen_uuid128(gen_ptr: *mut UUIDGen, uuid_ptr: *mut u8) {
54 let gen = unsafe {
55 assert!(!gen_ptr.is_null());
56 &mut *gen_ptr
57 };
58 let uuid128: [u8; 16] = gen.uuid128();
59 let uuid128: &[u8] = &uuid128[0..16];
60 unsafe { std::ptr::copy(&(uuid128)[0], uuid_ptr, 16) }
61}
62
63#[derive(Debug)]
66pub struct UUIDGen(MacAddress);
67
68impl UUIDGen {
69
70 pub fn new(eui: Eui48) -> UUIDGen {
71 UUIDGen(MacAddress::new(eui))
72 }
73
74 pub fn nonce64(&self) -> [u8; 8] {
76 let nanosec_bytes = nanosecs_since_epoch56();
77
78 let mut rng = OsRng::new()
79 .expect("Failed to initialise RNG.");
80 let r = rng.gen::<[u8; 1]>();
81
82 let mut bytes = [0; 8];
83 bytes[0] = nanosec_bytes[0];
84 bytes[1] = nanosec_bytes[1];
85 bytes[2] = nanosec_bytes[2];
86 bytes[3] = nanosec_bytes[3];
87 bytes[4] = nanosec_bytes[4];
88 bytes[5] = nanosec_bytes[5];
89 bytes[6] = nanosec_bytes[6];
90 bytes[7] = r[0];
91 bytes
92 }
93
94 pub fn uuid128(&self) -> [u8; 16] {
96 let nanosec_bytes = nanosecs_since_epoch();
97
98 let mut rng = OsRng::new()
99 .expect("Failed to initialise RNG.");
100 let r = rng.gen::<[u8; 2]>();
101
102 let mac_bytes = self.0.as_bytes();
103 let mut bytes = [0; 16];
104 bytes[0] = nanosec_bytes[0];
105 bytes[1] = nanosec_bytes[1];
106 bytes[2] = nanosec_bytes[2];
107 bytes[3] = nanosec_bytes[3];
108 bytes[4] = nanosec_bytes[4];
109 bytes[5] = nanosec_bytes[5];
110 bytes[6] = nanosec_bytes[6];
111 bytes[7] = nanosec_bytes[7];
112 bytes[8] = mac_bytes[0];
113 bytes[9] = mac_bytes[1];
114 bytes[10] = mac_bytes[2];
115 bytes[11] = mac_bytes[3];
116 bytes[12] = mac_bytes[4];
117 bytes[13] = mac_bytes[5];
118 bytes[14] = r[0];
119 bytes[15] = r[1];
120 bytes
121 }
122}
123
124fn epoch_min() -> SystemTime {
129 let secs_years_47: u64 = 60 * 60 * 24 * 365 * 47;
130 UNIX_EPOCH.add(Duration::new(secs_years_47, 0))
131}
132
133fn little_endian_inv56(x: u64) -> [u8; 7] {
136 let mut bytes: [u8; 7] = [0; 7];
137 bytes[0] = (x & 0xFF) as u8;
138 for i in 1..7 {
139 bytes[i] = ((x & (0xFF << i * 8)) >> i * 8) as u8;
140 }
141 bytes
142}
143
144fn little_endian_inv64(x: u64) -> [u8; 8] {
147 let mut bytes: [u8; 8] = [0; 8];
148 bytes[0] = (x & 0xFF) as u8;
149 for i in 1..8 {
150 bytes[i] = ((x & (0xFF << i * 8)) >> i * 8) as u8;
151 }
152 bytes
153}
154
155fn nanosecs_since_epoch56() -> [u8; 7] {
157 let now = SystemTime::now();
158 let duration = now.duration_since(epoch_min())
159 .expect("Failed to get duration since unix epoch.");
160
161 let secs: u64 = duration.as_secs() as u64 * 1_000_000_0;
163 let nanosecs: u64 = secs + (duration.subsec_nanos() / 1_00) as u64;
164
165 little_endian_inv56(nanosecs)
166}
167
168fn nanosecs_since_epoch() -> [u8; 8] {
170 let now = SystemTime::now();
171 let duration = now.duration_since(epoch_min())
172 .expect("Failed to get duration since unix epoch.");
173
174 let secs: u64 = duration.as_secs() as u64 * 1_000_000_0;
176 let nanosecs: u64 = secs + (duration.subsec_nanos() / 1_00) as u64;
177
178 little_endian_inv64(nanosecs)
179}
180
181pub fn read_interface_eui(iface: &str) -> Eui48 {
183 let path = Path::new("/sys/class/net").join(Path::new(iface)).join("address");
184
185 let f = File::open(path)
186 .expect("Network interface not found.");
187
188 let mut reader = BufReader::new(f);
189 let mut line = String::new();
190
191 reader.read_line(&mut line)
192 .expect("Unable to read iface.");
193
194 let mut eui: Eui48 = [0; 6];
195 for i in 0..6 {
196 let byte: String = line.drain(0..2).collect();
197 line.drain(0..1);
198 let byte_v = byte.from_hex()
199 .expect(format!("Failed to decode mac_address byte {}", i).as_str());
200 eui[i] = byte_v[0];
201 }
202
203 eui
204}
205
206#[cfg(test)]
211mod tests {
212 use super::*;
213 use std::collections::HashMap;
214 use rustc_serialize::hex::ToHex;
215
216 #[test]
217 fn uuid_gen() {
218
219 let eui = read_interface_eui("new0");
220 let gen = UUIDGen::new(eui);
221
222 let mut entries = HashMap::new();
224
225 for i in 1..4_294_967_296 as u64 {
226 let key = gen.nonce64().to_hex();
227 if !entries.contains_key(&key) {
228 entries.insert(key, ());
229 } else {
230 println!("Found collision at {} where key = {}", i, key);
231 }
232 }
233 }
234}