commit
b441750cc9
71
Cargo.lock
generated
71
Cargo.lock
generated
@ -2,6 +2,7 @@
|
|||||||
name = "parity"
|
name = "parity"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bincode 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clippy 0.0.63 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clippy 0.0.63 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)",
|
"ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)",
|
||||||
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -9,6 +10,9 @@ dependencies = [
|
|||||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore 1.1.0",
|
"ethcore 1.1.0",
|
||||||
"ethcore-devtools 1.1.0",
|
"ethcore-devtools 1.1.0",
|
||||||
|
"ethcore-ipc 1.1.0",
|
||||||
|
"ethcore-ipc-codegen 1.1.0",
|
||||||
|
"ethcore-ipc-nano 1.1.0",
|
||||||
"ethcore-rpc 1.1.0",
|
"ethcore-rpc 1.1.0",
|
||||||
"ethcore-util 1.1.0",
|
"ethcore-util 1.1.0",
|
||||||
"ethcore-webapp 1.1.0",
|
"ethcore-webapp 1.1.0",
|
||||||
@ -23,6 +27,9 @@ dependencies = [
|
|||||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_codegen 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syntex 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -63,6 +70,17 @@ dependencies = [
|
|||||||
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -78,6 +96,11 @@ name = "blastfig"
|
|||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -254,6 +277,36 @@ dependencies = [
|
|||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ethcore-ipc"
|
||||||
|
version = "1.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ethcore-devtools 1.1.0",
|
||||||
|
"nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
|
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ethcore-ipc-codegen"
|
||||||
|
version = "1.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"aster 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore-ipc 1.1.0",
|
||||||
|
"quasi 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quasi_codegen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syntex 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syntex_syntax 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ethcore-ipc-nano"
|
||||||
|
version = "1.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ethcore-ipc 1.1.0",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-rpc"
|
name = "ethcore-rpc"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -659,6 +712,24 @@ name = "modifier"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nanomsg"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#26449b15f29b850bcf62a577f1ee3a56474a0bc9"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nanomsg-sys"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "git+https://github.com/ethcore/nanomsg.rs.git#26449b15f29b850bcf62a577f1ee3a56474a0bc9"
|
||||||
|
dependencies = [
|
||||||
|
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net2"
|
name = "net2"
|
||||||
version = "0.2.23"
|
version = "0.2.23"
|
||||||
|
@ -8,6 +8,9 @@ build = "build.rs"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rustc_version = "0.1"
|
rustc_version = "0.1"
|
||||||
|
syntex = "*"
|
||||||
|
serde_codegen = "0.7.0"
|
||||||
|
"ethcore-ipc-codegen" = { path = "ipc/codegen" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
@ -30,6 +33,10 @@ ethcore-devtools = { path = "devtools" }
|
|||||||
ethcore-rpc = { path = "rpc", optional = true }
|
ethcore-rpc = { path = "rpc", optional = true }
|
||||||
ethcore-webapp = { path = "webapp", optional = true }
|
ethcore-webapp = { path = "webapp", optional = true }
|
||||||
semver = "0.2"
|
semver = "0.2"
|
||||||
|
ethcore-ipc-nano = { path = "ipc/nano" }
|
||||||
|
"ethcore-ipc" = { path = "ipc/rpc" }
|
||||||
|
bincode = "*"
|
||||||
|
serde = "0.7.0"
|
||||||
|
|
||||||
[dependencies.hyper]
|
[dependencies.hyper]
|
||||||
version = "0.8"
|
version = "0.8"
|
||||||
|
25
build.rs
25
build.rs
@ -15,11 +15,36 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate rustc_version;
|
extern crate rustc_version;
|
||||||
|
extern crate syntex;
|
||||||
|
extern crate ethcore_ipc_codegen as codegen;
|
||||||
|
extern crate serde_codegen;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::Path;
|
||||||
use rustc_version::{version_meta, Channel};
|
use rustc_version::{version_meta, Channel};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if let Channel::Nightly = version_meta().channel {
|
if let Channel::Nightly = version_meta().channel {
|
||||||
println!("cargo:rustc-cfg=nightly");
|
println!("cargo:rustc-cfg=nightly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
// ipc pass
|
||||||
|
{
|
||||||
|
let src = Path::new("parity/hypervisor/service.rs.in");
|
||||||
|
let dst = Path::new(&out_dir).join("hypervisor_service_ipc.rs");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
codegen::register(&mut registry);
|
||||||
|
registry.expand("", &src, &dst).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// serde pass
|
||||||
|
{
|
||||||
|
let src = Path::new(&out_dir).join("hypervisor_service_ipc.rs");
|
||||||
|
let dst = Path::new(&out_dir).join("hypervisor_service_cg.rs");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
serde_codegen::register(&mut registry);
|
||||||
|
registry.expand("", &src, &dst).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,6 @@ fn implement_dispatch_arm_invoke_stmt(
|
|||||||
) -> ast::Stmt
|
) -> ast::Stmt
|
||||||
{
|
{
|
||||||
let function_name = builder.id(dispatch.function_name.as_str());
|
let function_name = builder.id(dispatch.function_name.as_str());
|
||||||
let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str());
|
|
||||||
|
|
||||||
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
|
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
|
||||||
let arg_ident = builder.id(arg_name);
|
let arg_ident = builder.id(arg_name);
|
||||||
@ -216,10 +215,6 @@ fn implement_dispatch_arm_invoke_stmt(
|
|||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&output_type_id, ext_cx).into_iter());
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"), ::syntax::parse::token::Plain)));
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
|
||||||
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
|
tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
|
||||||
@ -231,7 +226,6 @@ fn implement_dispatch_arm_invoke_stmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
|
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
|
||||||
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
|
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
|
||||||
@ -729,6 +723,7 @@ fn implement_interface(
|
|||||||
Err(e) => { panic!("ipc read error: {:?}, aborting", e); }
|
Err(e) => { panic!("ipc read error: {:?}, aborting", e); }
|
||||||
_ => { }
|
_ => { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// method_num is a 16-bit little-endian unsigned number
|
// method_num is a 16-bit little-endian unsigned number
|
||||||
match method_num[1] as u16 + (method_num[0] as u16)*256 {
|
match method_num[1] as u16 + (method_num[0] as u16)*256 {
|
||||||
// handshake
|
// handshake
|
||||||
|
@ -54,7 +54,7 @@ impl<S> Deref for GuardedSocket<S> where S: WithSocket<Socket> {
|
|||||||
/// Spawns client <`S`> over specified address
|
/// Spawns client <`S`> over specified address
|
||||||
/// creates socket and connects endpoint to it
|
/// creates socket and connects endpoint to it
|
||||||
/// for duplex (paired) connections with the service
|
/// for duplex (paired) connections with the service
|
||||||
pub fn init_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
pub fn init_duplex_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
let mut socket = try!(Socket::new(Protocol::Pair).map_err(|e| {
|
let mut socket = try!(Socket::new(Protocol::Pair).map_err(|e| {
|
||||||
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
SocketError::DuplexLink
|
SocketError::DuplexLink
|
||||||
@ -71,16 +71,38 @@ pub fn init_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns client <`S`> over specified address
|
||||||
|
/// creates socket and connects endpoint to it
|
||||||
|
/// for request-reply connections to the service
|
||||||
|
pub fn init_client<S>(socket_addr: &str) -> Result<GuardedSocket<S>, SocketError> where S: WithSocket<Socket> {
|
||||||
|
let mut socket = try!(Socket::new(Protocol::Req).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::RequestLink
|
||||||
|
}));
|
||||||
|
|
||||||
|
let endpoint = try!(socket.connect(socket_addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", socket_addr, e);
|
||||||
|
SocketError::RequestLink
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(GuardedSocket {
|
||||||
|
client: Arc::new(S::init(socket)),
|
||||||
|
_endpoint: endpoint,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Error occured while establising socket or endpoint
|
/// Error occured while establising socket or endpoint
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SocketError {
|
pub enum SocketError {
|
||||||
/// Error establising duplex (paired) socket and/or endpoint
|
/// Error establising duplex (paired) socket and/or endpoint
|
||||||
DuplexLink
|
DuplexLink,
|
||||||
|
/// Error establising duplex (paired) socket and/or endpoint
|
||||||
|
RequestLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Worker<S> where S: IpcInterface<S> {
|
impl<S> Worker<S> where S: IpcInterface<S> {
|
||||||
/// New worker over specified `service`
|
/// New worker over specified `service`
|
||||||
pub fn new(service: Arc<S>) -> Worker<S> {
|
pub fn new(service: &Arc<S>) -> Worker<S> {
|
||||||
Worker::<S> {
|
Worker::<S> {
|
||||||
service: service.clone(),
|
service: service.clone(),
|
||||||
sockets: Vec::new(),
|
sockets: Vec::new(),
|
||||||
@ -103,7 +125,7 @@ impl<S> Worker<S> where S: IpcInterface<S> {
|
|||||||
if method_sign_len >= 2 {
|
if method_sign_len >= 2 {
|
||||||
|
|
||||||
// method_num
|
// method_num
|
||||||
let method_num = self.buf[1] as u16 * 256 + self.buf[0] as u16;
|
let method_num = self.buf[0] as u16 * 256 + self.buf[1] as u16;
|
||||||
// payload
|
// payload
|
||||||
let payload = &self.buf[2..];
|
let payload = &self.buf[2..];
|
||||||
|
|
||||||
@ -155,6 +177,26 @@ impl<S> Worker<S> where S: IpcInterface<S> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add generic socket for request-reply style communications
|
||||||
|
/// with multiple clients
|
||||||
|
pub fn add_reqrep(&mut self, addr: &str) -> Result<(), SocketError> {
|
||||||
|
let mut socket = try!(Socket::new(Protocol::Rep).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
}));
|
||||||
|
|
||||||
|
let endpoint = try!(socket.bind(addr).map_err(|e| {
|
||||||
|
warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
|
||||||
|
SocketError::DuplexLink
|
||||||
|
}));
|
||||||
|
|
||||||
|
self.sockets.push((socket, endpoint));
|
||||||
|
|
||||||
|
self.rebuild_poll_request();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -206,13 +248,13 @@ mod service_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_create_worker() {
|
fn can_create_worker() {
|
||||||
let worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
|
let worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
assert_eq!(0, worker.sockets.len());
|
assert_eq!(0, worker.sockets.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_add_duplex_socket_to_worker() {
|
fn can_add_duplex_socket_to_worker() {
|
||||||
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap();
|
worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap();
|
||||||
assert_eq!(1, worker.sockets.len());
|
assert_eq!(1, worker.sockets.len());
|
||||||
}
|
}
|
||||||
@ -220,7 +262,7 @@ mod service_tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn worker_can_poll_empty() {
|
fn worker_can_poll_empty() {
|
||||||
let service = Arc::new(DummyService::new());
|
let service = Arc::new(DummyService::new());
|
||||||
let mut worker = Worker::<DummyService>::new(service.clone());
|
let mut worker = Worker::<DummyService>::new(&service);
|
||||||
worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap();
|
worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap();
|
||||||
worker.poll();
|
worker.poll();
|
||||||
assert_eq!(0, service.methods_stack.read().unwrap().len());
|
assert_eq!(0, service.methods_stack.read().unwrap().len());
|
||||||
@ -230,7 +272,7 @@ mod service_tests {
|
|||||||
fn worker_can_poll() {
|
fn worker_can_poll() {
|
||||||
let url = "ipc:///tmp/parity-test30.ipc";
|
let url = "ipc:///tmp/parity-test30.ipc";
|
||||||
|
|
||||||
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
worker.add_duplex(url).unwrap();
|
worker.add_duplex(url).unwrap();
|
||||||
|
|
||||||
let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]);
|
let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]);
|
||||||
@ -245,7 +287,7 @@ mod service_tests {
|
|||||||
fn worker_can_poll_long() {
|
fn worker_can_poll_long() {
|
||||||
let url = "ipc:///tmp/parity-test40.ipc";
|
let url = "ipc:///tmp/parity-test40.ipc";
|
||||||
|
|
||||||
let mut worker = Worker::<DummyService>::new(Arc::new(DummyService::new()));
|
let mut worker = Worker::<DummyService>::new(&Arc::new(DummyService::new()));
|
||||||
worker.add_duplex(url).unwrap();
|
worker.add_duplex(url).unwrap();
|
||||||
|
|
||||||
let message = [0u8; 1024*1024];
|
let message = [0u8; 1024*1024];
|
||||||
|
@ -32,14 +32,14 @@ mod tests {
|
|||||||
|
|
||||||
|
|
||||||
fn init_worker(addr: &str) -> nanoipc::Worker<Service> {
|
fn init_worker(addr: &str) -> nanoipc::Worker<Service> {
|
||||||
let mut worker = nanoipc::Worker::<Service>::new(Arc::new(Service::new()));
|
let mut worker = nanoipc::Worker::<Service>::new(&Arc::new(Service::new()));
|
||||||
worker.add_duplex(addr).unwrap();
|
worker.add_duplex(addr).unwrap();
|
||||||
worker
|
worker
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_create_client() {
|
fn can_create_client() {
|
||||||
let client = nanoipc::init_client::<ServiceClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
|
let client = nanoipc::init_duplex_client::<ServiceClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
|
||||||
assert!(client.is_ok());
|
assert!(client.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
while !worker_is_ready.load(Ordering::Relaxed) { }
|
while !worker_is_ready.load(Ordering::Relaxed) { }
|
||||||
let client = nanoipc::init_client::<ServiceClient<_>>(url).unwrap();
|
let client = nanoipc::init_duplex_client::<ServiceClient<_>>(url).unwrap();
|
||||||
|
|
||||||
let hs = client.handshake();
|
let hs = client.handshake();
|
||||||
|
|
||||||
@ -105,5 +105,4 @@ mod tests {
|
|||||||
|
|
||||||
worker_should_exit.store(true, Ordering::Relaxed);
|
worker_should_exit.store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
158
parity/hypervisor/mod.rs
Normal file
158
parity/hypervisor/mod.rs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Parity interprocess hypervisor module
|
||||||
|
|
||||||
|
// while not included in binary
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub mod service;
|
||||||
|
|
||||||
|
/// Default value for hypervisor ipc listener
|
||||||
|
pub const HYPERVISOR_IPC_URL: &'static str = "ipc:///tmp/parity-internal-hyper-status.ipc";
|
||||||
|
|
||||||
|
use nanoipc;
|
||||||
|
use std::sync::{Arc,RwLock};
|
||||||
|
use hypervisor::service::*;
|
||||||
|
use std::process::{Command,Child};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
type BinaryId = &'static str;
|
||||||
|
|
||||||
|
const BLOCKCHAIN_DB_BINARY: BinaryId = "blockchain";
|
||||||
|
|
||||||
|
pub struct Hypervisor {
|
||||||
|
ipc_addr: String,
|
||||||
|
service: Arc<HypervisorService>,
|
||||||
|
ipc_worker: RwLock<nanoipc::Worker<HypervisorService>>,
|
||||||
|
processes: RwLock<HashMap<BinaryId, Child>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hypervisor {
|
||||||
|
/// initializes the Hypervisor service with the open ipc socket for incoming clients
|
||||||
|
pub fn new() -> Hypervisor {
|
||||||
|
Hypervisor::with_url(HYPERVISOR_IPC_URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts on the specified address for ipc listener
|
||||||
|
fn with_url(addr: &str) -> Hypervisor{
|
||||||
|
Hypervisor::with_url_and_service(addr, HypervisorService::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Starts with the specified address for the ipc listener and
|
||||||
|
/// the specified list of modules in form of created service
|
||||||
|
fn with_url_and_service(addr: &str, service: Arc<HypervisorService>) -> Hypervisor {
|
||||||
|
let worker = nanoipc::Worker::new(&service);
|
||||||
|
Hypervisor{
|
||||||
|
ipc_addr: addr.to_owned(),
|
||||||
|
service: service,
|
||||||
|
ipc_worker: RwLock::new(worker),
|
||||||
|
processes: RwLock::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Since one binary can host multiple modules
|
||||||
|
/// we match binaries
|
||||||
|
fn match_module(module_id: &IpcModuleId) -> Option<BinaryId> {
|
||||||
|
match *module_id {
|
||||||
|
BLOCKCHAIN_MODULE_ID => Some(BLOCKCHAIN_DB_BINARY),
|
||||||
|
// none means the module is inside the main binary
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates IPC listener and starts all binaries
|
||||||
|
fn start(&self) {
|
||||||
|
let mut worker = self.ipc_worker.write().unwrap();
|
||||||
|
worker.add_reqrep(&self.ipc_addr).unwrap_or_else(|e| panic!("Hypervisor ipc worker can not start - critical! ({:?})", e));
|
||||||
|
|
||||||
|
for module_id in self.service.module_ids() {
|
||||||
|
self.start_module(module_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start binary for the specified module
|
||||||
|
/// Does nothing when it is already started on module is inside the
|
||||||
|
/// main binary
|
||||||
|
fn start_module(&self, module_id: IpcModuleId) {
|
||||||
|
Self::match_module(&module_id).map(|binary_id| {
|
||||||
|
let mut processes = self.processes.write().unwrap();
|
||||||
|
{
|
||||||
|
if processes.get(binary_id).is_some() {
|
||||||
|
// already started for another module
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let child = Command::new(binary_id).spawn().unwrap_or_else(
|
||||||
|
|e| panic!("Hypervisor cannot start binary: {}", e));
|
||||||
|
processes.insert(binary_id, child);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports if all modules are checked in
|
||||||
|
pub fn modules_ready(&self) -> bool {
|
||||||
|
self.service.unchecked_count() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for every required module to check in
|
||||||
|
pub fn wait_for_startup(&self) {
|
||||||
|
let mut worker = self.ipc_worker.write().unwrap();
|
||||||
|
while !self.modules_ready() {
|
||||||
|
worker.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::sync::atomic::{AtomicBool,Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use super::service::*;
|
||||||
|
use nanoipc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_init() {
|
||||||
|
let url = "ipc:///tmp/test-parity-hypervisor-10.ipc";
|
||||||
|
let test_module_id = 8080u64;
|
||||||
|
|
||||||
|
let hypervisor = Hypervisor::with_url_and_service(url, HypervisorService::with_modules(vec![test_module_id]));
|
||||||
|
assert_eq!(false, hypervisor.modules_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_wait_for_startup() {
|
||||||
|
let url = "ipc:///tmp/test-parity-hypervisor-20.ipc";
|
||||||
|
let test_module_id = 8080u64;
|
||||||
|
|
||||||
|
let hypervisor_ready = Arc::new(AtomicBool::new(false));
|
||||||
|
let hypervisor_ready_local = hypervisor_ready.clone();
|
||||||
|
|
||||||
|
::std::thread::spawn(move || {
|
||||||
|
while !hypervisor_ready.load(Ordering::Relaxed) { }
|
||||||
|
|
||||||
|
let client = nanoipc::init_client::<HypervisorServiceClient<_>>(url).unwrap();
|
||||||
|
client.handshake().unwrap();
|
||||||
|
client.module_ready(test_module_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
let hypervisor = Hypervisor::with_url_and_service(url, HypervisorService::with_modules(vec![test_module_id]));
|
||||||
|
hypervisor.start();
|
||||||
|
hypervisor_ready_local.store(true, Ordering::Relaxed);
|
||||||
|
hypervisor.wait_for_startup();
|
||||||
|
|
||||||
|
assert_eq!(true, hypervisor.modules_ready());
|
||||||
|
}
|
||||||
|
}
|
19
parity/hypervisor/service.rs
Normal file
19
parity/hypervisor/service.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Parity interprocess hypervisor IPC service
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/hypervisor_service_cg.rs"));
|
69
parity/hypervisor/service.rs.in
Normal file
69
parity/hypervisor/service.rs.in
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::{RwLock,Arc};
|
||||||
|
use std::ops::*;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub type IpcModuleId = u64;
|
||||||
|
|
||||||
|
/// Blockhain database module id
|
||||||
|
pub const BLOCKCHAIN_MODULE_ID: IpcModuleId = 2000;
|
||||||
|
|
||||||
|
/// IPC service that handles module management
|
||||||
|
pub struct HypervisorService {
|
||||||
|
check_list: RwLock<HashMap<IpcModuleId, bool>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Ipc)]
|
||||||
|
impl HypervisorService {
|
||||||
|
fn module_ready(&self, module_id: u64) -> bool {
|
||||||
|
let mut check_list = self.check_list.write().unwrap();
|
||||||
|
check_list.get_mut(&module_id).map(|mut status| *status = true);
|
||||||
|
check_list.iter().any(|(_, status)| !status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HypervisorService {
|
||||||
|
/// New service with the default list of modules
|
||||||
|
pub fn new() -> Arc<HypervisorService> {
|
||||||
|
HypervisorService::with_modules(vec![])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New service with list of modules that will report for being ready
|
||||||
|
pub fn with_modules(module_ids: Vec<IpcModuleId>) -> Arc<HypervisorService> {
|
||||||
|
let mut check_list = HashMap::new();
|
||||||
|
for module_id in module_ids {
|
||||||
|
check_list.insert(module_id, false);
|
||||||
|
}
|
||||||
|
Arc::new(HypervisorService {
|
||||||
|
check_list: RwLock::new(check_list),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Number of modules still being waited for check-in
|
||||||
|
pub fn unchecked_count(&self) -> usize {
|
||||||
|
self.check_list.read().unwrap().iter().filter(|&(_, status)| !status).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of all modules within this service
|
||||||
|
pub fn module_ids(&self) -> Vec<IpcModuleId> {
|
||||||
|
self.check_list.read().unwrap().iter().map(|(module_id, _)| module_id).cloned().collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::ipc::IpcConfig for HypervisorService {}
|
@ -37,6 +37,10 @@ extern crate time;
|
|||||||
extern crate number_prefix;
|
extern crate number_prefix;
|
||||||
extern crate rpassword;
|
extern crate rpassword;
|
||||||
extern crate semver;
|
extern crate semver;
|
||||||
|
extern crate ethcore_ipc as ipc;
|
||||||
|
extern crate ethcore_ipc_nano as nanoipc;
|
||||||
|
extern crate serde;
|
||||||
|
extern crate bincode;
|
||||||
|
|
||||||
// for price_info.rs
|
// for price_info.rs
|
||||||
#[macro_use] extern crate hyper;
|
#[macro_use] extern crate hyper;
|
||||||
@ -73,6 +77,7 @@ use webapp::Listening as WebappServer;
|
|||||||
|
|
||||||
mod price_info;
|
mod price_info;
|
||||||
mod upgrade;
|
mod upgrade;
|
||||||
|
mod hypervisor;
|
||||||
|
|
||||||
fn die_with_message(msg: &str) -> ! {
|
fn die_with_message(msg: &str) -> ! {
|
||||||
println!("ERROR: {}", msg);
|
println!("ERROR: {}", msg);
|
||||||
|
Loading…
Reference in New Issue
Block a user