use crate::ndr::NdrEncoder;
use crate::transport::RpcTcp;
use crate::{Result, RpcError, Syntax};
pub const IID_IOBJECT_EXPORTER: &str = "99fcfec4-5260-101b-bbcb-00aa0021347a";
pub const IID_ISYSTEM_ACTIVATOR: &str = "000001a0-0000-0000-c000-000000000046";
pub const IID_IREMUNKNOWN: &str = "00000131-0000-0000-c000-000000000046";
pub const IID_IWBEM_LEVEL1_LOGIN: &str = "f309ad18-d86a-11d0-a075-00c04fb68820";
pub const IID_IWBEM_SERVICES: &str = "9556dc99-828c-11cf-a37e-00aa003240c7";
pub const CLSID_WBEM_LEVEL1_LOGIN: &str = "8bc3f05e-d86b-11d0-a075-00c04fb68820";
pub const COMVERSION_MAJOR: u16 = 5;
pub const COMVERSION_MINOR: u16 = 7;
pub fn orpc_this(cid: &[u8; 16]) -> Vec<u8> {
orpc_this_flags(cid, 1)
}
pub fn orpc_this_flags(cid: &[u8; 16], flags: u32) -> Vec<u8> {
let mut e = NdrEncoder::new();
e.u16(COMVERSION_MAJOR);
e.u16(COMVERSION_MINOR);
e.u32(flags);
e.u32(0); e.uuid(cid); e.null_ptr(); e.into_bytes()
}
pub struct ObjectExporter {
rpc: RpcTcp,
}
impl ObjectExporter {
pub async fn connect(host: &str) -> Result<Self> {
let addr = if host.contains(':') {
host.to_string()
} else {
format!("{host}:135")
};
let mut rpc = RpcTcp::connect(&addr).await?;
rpc.bind(Syntax::new(IID_IOBJECT_EXPORTER, 0, 0)).await?;
Ok(ObjectExporter { rpc })
}
pub async fn server_alive(&mut self) -> Result<i32> {
let resp = self.rpc.call(3, &[]).await?;
let hr = resp
.get(0..4)
.map(|b| i32::from_le_bytes(b.try_into().unwrap()))
.unwrap_or(0);
if hr != 0 {
return Err(RpcError::Fault(hr as u32));
}
Ok(hr)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn orpc_this_layout() {
let cid = [0xABu8; 16];
let b = orpc_this(&cid);
assert_eq!(b.len(), 32, "ORPCTHIS is 32 bytes");
assert_eq!(&b[0..2], &5u16.to_le_bytes()); assert_eq!(&b[2..4], &7u16.to_le_bytes()); assert_eq!(&b[4..8], &[1, 0, 0, 0]); assert_eq!(&b[8..12], &[0, 0, 0, 0]); assert_eq!(&b[12..28], &cid); assert_eq!(&b[28..32], &[0, 0, 0, 0]); }
#[tokio::test]
#[ignore = "live DC"]
async fn server_alive_live() {
let Ok(dc) = std::env::var("ADH_DC") else {
return;
};
let mut oe = ObjectExporter::connect(&dc)
.await
.expect("connect IObjectExporter");
let hr = oe.server_alive().await.expect("ServerAlive");
assert_eq!(hr, 0, "ServerAlive HRESULT should be S_OK");
}
}