use std::{cmp, mem};
use std::collections::{HashSet, HashMap, hash_map};
-use std::sync::RwLock;
+use std::sync::{Arc, RwLock};
use std::net::SocketAddr;
use std::time::{Duration, Instant};
use std::io::{BufRead, BufReader};
use tokio::fs::File;
use tokio::io::write_all;
+use regex::Regex;
+
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub enum AddressState {
Untested,
}
#[derive(Hash, PartialEq, Eq)]
-pub enum StringSetting {
+pub enum RegexSetting {
SubverRegex,
}
pub struct Store {
u64_settings: RwLock<HashMap<U64Setting, u64>>,
- subver_regex: RwLock<String>,
+ subver_regex: RwLock<Arc<Regex>>,
nodes: RwLock<Nodes>,
store: String,
}
u64s.insert(U64Setting::RescanInterval(AddressState::TimeoutDuringRequest), try_read!(l, u64));
u64s.insert(U64Setting::RescanInterval(AddressState::Good), try_read!(l, u64));
u64s.insert(U64Setting::RescanInterval(AddressState::WasGood), try_read!(l, u64));
- future::ok((u64s, try_read!(l, String)))
- }).or_else(|_| -> future::FutureResult<(HashMap<U64Setting, u64>, String), ()> {
+ future::ok((u64s, try_read!(l, Regex)))
+ }).or_else(|_| -> future::FutureResult<(HashMap<U64Setting, u64>, Regex), ()> {
let mut u64s = HashMap::with_capacity(15);
u64s.insert(U64Setting::ConnsPerSec, 50);
u64s.insert(U64Setting::RunTimeout, 120);
u64s.insert(U64Setting::RescanInterval(AddressState::Good), 1800);
u64s.insert(U64Setting::RescanInterval(AddressState::WasGood), 1800);
u64s.insert(U64Setting::MinProtocolVersion, 10000); //XXX
- future::ok((u64s, ".*".to_string()))
+ future::ok((u64s, Regex::new(".*").unwrap()))
});
macro_rules! nodes_uninitd {
settings_future.join(nodes_future).and_then(move |((u64_settings, regex), nodes)| {
future::ok(Store {
u64_settings: RwLock::new(u64_settings),
- subver_regex: RwLock::new(regex),
+ subver_regex: RwLock::new(Arc::new(regex)),
nodes: RwLock::new(nodes),
store,
})
*self.u64_settings.read().unwrap().get(&setting).unwrap()
}
+ pub fn set_u64(&self, setting: U64Setting, value: u64) {
+ *self.u64_settings.write().unwrap().get_mut(&setting).unwrap() = value;
+ }
+
pub fn get_node_count(&self, state: AddressState) -> usize {
self.nodes.read().unwrap().state_next_scan.get(&state).unwrap().len()
}
- pub fn get_string(&self, _setting: StringSetting) -> String {
- self.subver_regex.read().unwrap().clone()
+ pub fn get_regex(&self, _setting: RegexSetting) -> Arc<Regex> {
+ Arc::clone(&*self.subver_regex.read().unwrap())
+ }
+
+ pub fn set_regex(&self, _setting: RegexSetting, value: Regex) {
+ *self.subver_regex.write().unwrap() = Arc::new(value);
}
pub fn add_fresh_nodes(&self, addresses: &Vec<(u32, Address)>) {
use printer::{Printer, Stat};
use peer::Peer;
-use datastore::{AddressState, Store, U64Setting};
+use datastore::{AddressState, Store, U64Setting, RegexSetting};
use tokio::prelude::*;
use tokio::timer::Delay;
state_lock.fail_reason = AddressState::NotFullNode;
return future::err(());
}
+ if !store.get_regex(RegexSetting::SubverRegex).is_match(&ver.user_agent) {
+ printer.add_line(format!("Updating {} to BadVersion subver {}", node, ver.user_agent.replace(|c: char| !c.is_ascii() || c < ' ' || c > '~', "")), true);
+ state_lock.fail_reason = AddressState::BadVersion;
+ return future::err(());
+ }
check_set_flag!(recvd_version, "version");
state_lock.node_services = ver.services;
if let Err(_) = write.try_send(NetworkMessage::Verack) {
}
},
NetworkMessage::Addr(addrs) => {
- if addrs.len() > 1 {
- check_set_flag!(recvd_addrs, "addr");
- unsafe { DATA_STORE.as_ref().unwrap() }.add_fresh_nodes(&addrs);
- }
+ state_lock.recvd_addrs = true;
+ unsafe { DATA_STORE.as_ref().unwrap() }.add_fresh_nodes(&addrs);
},
NetworkMessage::Block(block) => {
if block.header.bitcoin_hash() != state_lock.request.1 ||
use std::sync::{Arc, Mutex};
use std::io::Write;
-use crate::datastore::{Store, AddressState, U64Setting, StringSetting};
+use crate::datastore::{Store, AddressState, U64Setting, RegexSetting};
pub enum Stat {
HeaderCount(u64),
"Minimum protocol version: {} (\"v x\" to change value to x)\n", store.get_u64(U64Setting::MinProtocolVersion)
).as_bytes()).expect("stdout broken?");
out.write_all(format!(
- "Subversion match regex: {} (\"s x\" to change value to x)\n", store.get_string(StringSetting::SubverRegex)
+ "Subversion match regex: {} (\"s x\" to change value to x)\n", store.get_regex(RegexSetting::SubverRegex).as_str()
).as_bytes()).expect("stdout broken?");
out.write_all(b"\nRetry times (in seconds):\n").expect("stdout broken?");
"w x: Change the amount of time a node is considered WAS_GOOD after it fails to x from {} (in seconds)\n",
store.get_u64(U64Setting::WasGoodTimeout)
).as_bytes()).expect("stdout broken?");
- out.write_all(b"p: Enable/disable updating these stats\n").expect("stdout broken?");
out.write_all(b"a x: Scan node x\n").expect("stdout broken?");
out.write_all(b"\x1b[s").expect("stdout broken?"); // Save cursor position and provide a blank line before cursor
out.write_all(b"\x1b[;H\x1b[2K").expect("stdout broken?");