1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
// Copyright 2015-2017 Parity Technologies (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/>.

//! IPC RPC interface

use std::io::{Read, Write};
use std::marker::Sync;
use semver::Version;

#[derive(Debug, PartialEq, Eq, Clone)]
/// Handshake for client and server to negotiate api/protocol version
pub struct Handshake {
	pub protocol_version: Version,
	pub api_version: Version,
}

/// Allows to configure custom version and custom handshake response for
/// ipc host
pub trait IpcConfig {
	/// Current service api version
	/// Should be increased if any of the methods changes signature
	fn api_version() -> Version {
		Version::parse("1.0.0").unwrap()
	}

	/// Current ipc protocol version
	/// Should be increased only if signature of system methods changes
	fn protocol_version() -> Version {
		Version::parse("1.0.0").unwrap()
	}

	/// Default handshake requires exact versions match
	fn handshake(handshake: &Handshake) -> bool {
		handshake.protocol_version == Self::protocol_version() &&
			handshake.api_version == Self::api_version()
	}
}

/// Error in dispatching or invoking methods via IPC
#[derive(Debug)]
pub enum Error {
	UnkownSystemCall,
	ClientUnsupported,
	RemoteServiceUnsupported,
	HandshakeFailed,
}

/// Allows implementor to be attached to generic worker and dispatch rpc requests
/// over IPC
pub trait IpcInterface : IpcConfig {
	/// reads the message from io, dispatches the call and returns serialized result
	fn dispatch<R>(&self, r: &mut R) -> Vec<u8> where R: Read;

	/// deserializes the payload from buffer, dispatches invoke and returns serialized result
	/// (for non-blocking io)
	fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec<u8>;
}

/// serializes method invocation (method_num and parameters) to the stream specified by `w`
pub fn invoke<W>(method_num: u16, params: &Option<Vec<u8>>, w: &mut W) where W: Write {
	// creating buffer to contain all message
	let buf_len = match *params { None => 2, Some(ref val) => val.len() + 2 };
	let mut buf = vec![0u8; buf_len];

	// writing method_num as u16
	buf[1] = (method_num & 255) as u8;
	buf[0] = (method_num >> 8) as u8;

	// serializing parameters only if provided with any
	if params.is_some() {
		buf[2..buf_len].clone_from_slice(params.as_ref().unwrap());
	}

	if w.write(&buf).unwrap() != buf_len
	{
		// if write was inconsistent
		panic!("failed to write to socket");
	}
}

/// IpcSocket, read/write generalization
pub trait IpcSocket: Read + Write + Sync + Send {
}

/// Basically something that needs only socket to be spawned
pub trait WithSocket<S: IpcSocket> {
	fn init(socket: S) -> Self;
}


impl IpcSocket for ::devtools::TestSocket {}

impl IpcSocket for ::nanomsg::Socket {}