use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::ops::{Deref, DerefMut, Range};
use std::{env, fs, mem, task, thread};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::borrow::Cow;
use std::pin::Pin;
use std::io;
use futures::stream::{FuturesUnordered, StreamExt};
use futures::future::poll_fn;
use mio::{Events, Interest, Poll, Token, Waker};
use mio::net::{TcpListener, TcpStream};
use pin_project_lite::pin_project;
use tracing::{debug, error, trace, warn};
use futures::task::ArcWake;
use crate::error::{Error, ErrorKind, Result};
use crate::buf::{Buf, BufMut};
use super::ior::{AltIiopAddr, CodesetsComponent, ComponentKind, IiopProfile, Ior, ProfileKind};
use super::codeset::{AnyCodeset, Codeset, Codesets, WideCodeset};
use super::{MAX_MESSAGE_LEN, EVENTS_CAPACITY, OBJECT_REPO_ID};
use super::cdr::{CdrReader, CdrWrite, CdrWriter, CdrSender};
use super::io::{WriteExt as _, ReadExt as _};
use super::endian::Endian;
use super::giop::{
LocateReply, LocateStatus, Message, MessageLen, MessageWhole, Reply, ReplyStatus, Target,
SystemException, CompletionStatus,
Version, exception};
const LISTENER_TOKEN: Token = Token(0);
const WAKER_TOKEN: Token = Token(1);
const FIRST_CONNECTION_TOKEN: usize = 2;
const RUN: u8 = 0;
const STOP: u8 = 1;
const DROP: u8 = 2;
const DONE: u8 = 3;
const VERSION: Version = Version::V12;
const REPLY_MIN_LEN: usize = 512;
#[derive(Debug)]
pub struct Server<O: ServerObject> {
shared: Arc<Shared<O>>,
}
impl<O: ServerObject> Server<O> {
pub fn bind(addr: SocketAddr) -> Result<Self> {
let mut listener = TcpListener::bind(addr)
.map_err(|err| Error::new(ErrorKind::Corba)
.with_append_description(format_args!("Could not listen on {addr}"))
.with_source(Box::new(err)))?;
let local_addr = listener.local_addr()
.map_err(|err| Error::new(ErrorKind::Corba)
.with_append_description(format_args!("Could not read back the address of the listener bound to {addr}"))
.with_source(Box::new(err)))?;
let poll = Poll::new()
.map_err(|err| Error::new(ErrorKind::Internal)
.with_description("Failed to create the poll of a CORBA server")
.with_source(Box::new(err)))?;
poll.registry().register(&mut listener, LISTENER_TOKEN, Interest::READABLE)
.map_err(|err| Error::new(ErrorKind::Internal)
.with_description("Failed to register the listener of a CORBA server with the poll")
.with_source(Box::new(err)))?;
let waker = Arc::new(Waker::new(poll.registry(), WAKER_TOKEN)
.map_err(|err| Error::new(ErrorKind::Internal)
.with_description("Failed to create the waker of a CORBA server")
.with_source(Box::new(err)))?);
let addrs = local_addrs(local_addr);
let host = Arc::from(addrs[0].to_string());
let shared = Arc::new(Shared {
objects: Mutex::new(HashMap::new()),
local_addr,
addrs,
host,
state: AtomicU8::new(RUN),
waits: Mutex::new(Vec::new()),
waker: Arc::clone(&waker),
});
let thread = Thread {
shared: ThreadShared {
global: Arc::clone(&shared),
tasks: FuturesUnordered::new(),
},
listener,
connections: HashMap::new(),
task_waker: futures::task::waker(Arc::new(PollWaker {
waker,
failed: AtomicBool::new(false),
})),
next_token: FIRST_CONNECTION_TOKEN,
poll,
events: Events::with_capacity(EVENTS_CAPACITY),
};
let done = Done(Arc::clone(&shared));
thread::Builder::new()
.name("corba-server".to_string())
.spawn(move || {
let _done = done;
thread.main();
})
.map_err(|err| Error::new(ErrorKind::Internal)
.with_description("Failed to start the polling thread of a CORBA server")
.with_source(Box::new(err)))?;
Ok(Self { shared })
}
pub fn local_addr(&self) -> SocketAddr {
self.shared.local_addr
}
#[inline]
pub fn addrs(&self) -> &[IpAddr] {
&self.shared.addrs
}
#[inline]
pub fn host(&self) -> Arc<str> {
Arc::clone(&self.shared.host)
}
pub fn register(&self, object: Arc<O>) -> Result<String> {
let ior = self.build_ior(&object)?;
let key = Box::<[u8]>::from(object.id());
trace!(?key, "Serving an object");
if self.shared.objects.lock().unwrap().insert(key, object).is_some() {
debug!("Replaced the object served under the same key");
}
Ok(ior)
}
pub fn deregister(&self, id: &[u8]) -> bool {
self.shared.objects.lock().unwrap().remove(id).is_some()
}
pub fn is_registered(&self, id: &[u8]) -> bool {
self.shared.objects.lock().unwrap().contains_key(id)
}
pub fn get(&self, id: &[u8]) -> Option<Arc<O>> {
self.shared.objects.lock().unwrap().get(id).cloned()
}
fn build_ior(&self, object: &O) -> Result<String> {
let port = self.shared.local_addr.port();
fn conversions<C: AnyCodeset>(all: &[C]) -> Cow<'static, [u32]> {
Cow::Owned(all.iter()
.copied()
.filter(|codeset| *codeset != C::NATIVE)
.map(AnyCodeset::id)
.collect())
}
let mut components = vec![
ComponentKind::Codesets(CodesetsComponent {
native_codeset: Codeset::NATIVE.id(),
conversion_codesets: conversions(Codeset::ALL),
native_wide_codeset: WideCodeset::NATIVE.id(),
conversion_wide_codesets: conversions(WideCodeset::ALL),
}).build()?,
];
for addr in self.shared.addrs.iter().skip(1) {
components.push(ComponentKind::AltIiopAddr(AltIiopAddr {
host: Cow::Owned(addr.to_string()),
port,
}).build()?);
}
let profile = ProfileKind::Iiop(IiopProfile {
version: VERSION,
host: Cow::Owned(self.shared.addrs[0].to_string()),
port,
object_key: Cow::Borrowed(object.id()),
components: Cow::Owned(components),
}).build()?;
let type_id = object.repo_ids().first().copied()
.unwrap_or(OBJECT_REPO_ID);
let mut writer = CdrWriter::new();
writer.write_endian()?;
writer.write(&Ior {
type_id: Cow::Borrowed(type_id),
profiles: Cow::Owned(vec![profile]),
})?;
Ok(format!("IOR:{:X}", writer.into_buf()))
}
pub fn stop(&self) {
self.shared.state.fetch_max(STOP, Ordering::AcqRel);
if let Err(err) = self.shared.waker.wake() {
warn!(%err, "Failed to wake the polling thread of the CORBA server up to stop it");
}
}
pub fn wait(&self) -> impl Future<Output = ()> + Send + '_ {
poll_fn(|cx| self.shared.poll_done(cx))
}
}
impl<O: ServerObject> Drop for Server<O> {
fn drop(&mut self) {
self.shared.state.fetch_max(DROP, Ordering::AcqRel);
self.shared.objects.lock().unwrap().clear();
if let Err(err) = self.shared.waker.wake() {
warn!(%err, "Failed to wake the polling thread of the CORBA server up to drop it");
}
}
}
#[derive(Debug)]
struct Shared<O: ServerObject> {
objects: Mutex<HashMap<Box<[u8]>, Arc<O>>>,
local_addr: SocketAddr,
addrs: Box<[IpAddr]>,
host: Arc<str>,
state: AtomicU8,
waits: Mutex<Vec<task::Waker>>,
waker: Arc<Waker>,
}
impl<O: ServerObject> Shared<O> {
fn get_object(&self, target: &Target<'_>) -> Option<Arc<O>> {
let key = target.key()?;
self.objects.lock().unwrap().get(key).map(Arc::clone)
}
fn has_object(&self, target: &Target<'_>) -> bool {
let Some(key) = target.key() else { return false };
self.objects.lock().unwrap().contains_key(key)
}
#[inline]
fn state(&self) -> u8 {
self.state.load(Ordering::Acquire)
}
fn poll_done(&self, cx: &mut task::Context<'_>) -> task::Poll<()> {
let mut waits = self.waits.lock().unwrap();
if self.state() == DONE {
return task::Poll::Ready(());
}
if !waits.iter().any(|waker| waker.will_wake(cx.waker())) {
waits.push(cx.waker().clone());
}
task::Poll::Pending
}
}
struct Done<O: ServerObject>(Arc<Shared<O>>);
impl<O: ServerObject> Drop for Done<O> {
fn drop(&mut self) {
let shared = &self.0;
shared.objects.lock().unwrap().clear();
let waits = {
let mut waits = shared.waits.lock().unwrap();
shared.state.store(DONE, Ordering::Release);
mem::take(&mut *waits)
};
for waker in waits {
waker.wake();
}
}
}
#[derive(Debug)]
struct Thread<O: ServerObject> {
shared: ThreadShared<O>,
listener: TcpListener,
connections: HashMap<Token, Connection>,
task_waker: task::Waker,
next_token: usize,
poll: Poll,
events: Events,
}
#[derive(Debug)]
struct ThreadShared<O: ServerObject> {
global: Arc<Shared<O>>,
tasks: FuturesUnordered<RequestTask<O>>,
}
impl<O: ServerObject> Thread<O> {
fn main(mut self) {
while self.shared.global.state() == RUN {
if let Err(err) = self.run() {
error!(%err, "Failed to poll the sources of the CORBA server, stopping it");
break;
}
}
if self.shared.global.state() != DROP {
self.drain();
}
debug!(addr = %self.shared.global.local_addr, "Stopped the polling thread of the CORBA server");
}
fn run(&mut self) -> Result<()> {
match self.poll.poll(&mut self.events, None) {
Ok(()) => {}
Err(err) if err.kind() == io::ErrorKind::Interrupted => return Ok(()),
Err(err) => return Err(Error::new(ErrorKind::Internal)
.with_description("Failed to poll the sources of a CORBA server")
.with_source(Box::new(err))),
}
self.handle_events();
self.poll_tasks();
Ok(())
}
fn drain(&mut self) {
if let Err(err) = self.poll.registry().deregister(&mut self.listener) {
debug!(%err, "Failed to take the listener of the stopped CORBA server out of the poll");
}
loop {
self.poll_tasks();
if self.shared.tasks.is_empty() && self.connections.values().all(Connection::is_flushed) {
return;
}
if self.shared.global.state() == DROP {
debug!(tasks = self.shared.tasks.len(), "Dropped the stopped CORBA server before it answered every request");
return;
}
match self.poll.poll(&mut self.events, None) {
Ok(()) => {}
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) => {
warn!(%err, "Failed to poll the sources of the stopped CORBA server");
return;
}
}
for event in &self.events {
let token = event.token();
let Some(connection) = self.connections.get_mut(&token) else {
continue;
};
let failure = match event.is_writable() {
true => connection.flush().err(),
false => None,
};
if failure.is_some() || event.is_read_closed() || event.is_write_closed() {
self.connections.remove(&token);
}
}
}
}
fn handle_events(&mut self) {
let events = mem::replace(&mut self.events, Events::with_capacity(0));
for event in &events {
let token = event.token();
if token == LISTENER_TOKEN {
self.accept();
continue;
}
if token == WAKER_TOKEN {
continue;
}
let Some(connection) = self.connections.get_mut(&token) else {
warn!(?event, "Received a poll event for no known connection, ignoring");
continue;
};
let mut failure = None;
if event.is_writable() {
failure = connection.flush().err();
}
if failure.is_none() && event.is_readable() {
failure = connection.receive(&self.shared).err();
}
if failure.is_none() && event.is_read_closed() {
failure = Some(Error::new(ErrorKind::Corba)
.with_description("The client closed the connection"));
}
if let Some(err) = failure {
debug!(addr = %connection.addr, ?err, "Lost the connection to the CORBA client");
self.connections.remove(&token);
}
}
self.events = events;
}
fn accept(&mut self) {
loop {
let (mut stream, addr) = match self.listener.accept() {
Ok(accepted) => accepted,
Err(err) if err.kind() == io::ErrorKind::Interrupted => continue,
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
Err(err) => {
warn!(%err, "Failed to accept a CORBA client");
break;
}
};
if let Err(err) = stream.set_nodelay(true) {
debug!(%addr, %err, "Failed to disable Nagle's algorithm on the stream");
}
let token = Token(self.next_token);
self.next_token += 1;
if let Err(err) = self.poll.registry().register(&mut stream, token, Interest::READABLE | Interest::WRITABLE) {
warn!(%addr, %err, "Failed to register the socket of the CORBA client with the poll, dropping it");
continue;
}
debug!(%addr, "Accepted a CORBA client");
self.connections.insert(token, Connection {
token,
stream,
addr,
recv_state: RecvState {
buf: Buf::new(),
fragments: HashMap::new(),
adjacent: None,
fragment_buf: None,
},
send_state: SendState {
writer: CdrWriter::new().into_sender(),
},
});
}
}
fn poll_tasks(&mut self) {
let Thread { shared, connections, task_waker, .. } = self;
let mut cx = task::Context::from_waker(task_waker);
while let task::Poll::Ready(Some((answer, reply))) = shared.tasks.poll_next_unpin(&mut cx) {
if !answer.response_expected {
continue;
}
let Some(connection) = connections.get_mut(&answer.token) else {
trace!(request_id = answer.request_id, "Dropping the answer to a request whose connection is gone");
continue;
};
if let Err(err) = connection.send_answer(&answer, reply) {
debug!(addr = %connection.addr, %err, "Lost the connection to the CORBA client");
connections.remove(&answer.token);
}
}
}
}
#[derive(Debug)]
struct Connection {
token: Token,
stream: TcpStream,
addr: SocketAddr,
recv_state: RecvState,
send_state: SendState,
}
impl Connection {
fn receive<O: ServerObject>(&mut self, shared: &ThreadShared<O>) -> Result<()> {
let mut stream = &self.stream;
let (len, eof) = stream.read_nb_to_cdr(&mut self.recv_state.buf)
.map_err(|err| Error::new(ErrorKind::Corba)
.with_description("The connection to the client failed while it was being read")
.with_source(Box::new(err)))?;
trace!(addr = %self.addr, len, eof, "Read from the CORBA client");
let failure = loop {
match self.dispatch(shared) {
Ok(true) => {}
Ok(false) => break None,
Err(err) => break Some(err),
}
};
let flushed = self.flush();
if let Some(err) = failure {
return Err(err);
}
flushed?;
if eof {
return Err(Error::new(ErrorKind::Corba)
.with_description("The client closed the connection"));
}
Ok(())
}
fn dispatch<O: ServerObject>(&mut self, shared: &ThreadShared<O>) -> Result<bool> {
let recv = &mut self.recv_state;
let buffer = recv.fragment_buf.as_ref()
.unwrap_or(&recv.buf);
let mut reader = CdrReader::new(buffer)
.with_codesets(self.send_state.writer.codesets());
let message = reader.read::<Message>()
.map_err(|err| Error::new(ErrorKind::InvalidData)
.with_description("The client sent a GIOP message that could not be read")
.with_parent(err))?;
let body_at = reader.position();
let message_len = body_at + message.body_len();
let (
response_expected,
object,
request,
) = match message {
Message::Incomplete(total_len) => {
if total_len > MAX_MESSAGE_LEN {
return Err(Error::new(ErrorKind::InvalidData)
.with_description(format!("The client announced a message of {total_len} octets, more than the {MAX_MESSAGE_LEN} allowed")));
}
let buf = recv.buf.make_mut();
buf.try_reserve(total_len.saturating_sub(buf.len()))?;
return Ok(false);
}
Message::InvalidVersion(major, minor) => {
debug!(addr = %self.addr, major, minor, "Refusing a GIOP message in a version this server does not speak");
return self.refuse_message(message_len);
}
Message::InvalidKind(version, kind) => {
debug!(addr = %self.addr, %version, kind, "Refusing a GIOP message of a kind this server has no notion of");
return self.refuse_message(message_len);
}
Message::Request(request) if !request.fragment_follows() => {
if recv.adjacent.is_some() {
return Err(Error::new(ErrorKind::InvalidData)
.with_description("The client sent a whole GIOP message in the middle of one it was sending in fragments"));
}
let codesets = request.find_codesets();
let addressed = shared.global.get_object(request.target());
let response_expected = request.response_expected();
let server_request = ServerRequest {
codesets: self.send_state.writer.codesets(),
id: request.request_id(),
version: request.version(),
operation: request.operation_range()
.expect("a GIOP request that was read names the operation it is for"),
body_at,
endian: request.endian(),
buf: recv.fragment_buf.take()
.unwrap_or_else(|| recv.buf.split_to(message_len)),
};
match codesets {
Ok(None) => {}
Ok(Some(codesets)) => {
trace!(addr = %self.addr, ?codesets, "The CORBA client announced its codesets");
self.send_state.writer.set_codesets(Some(codesets));
}
Err(err) => {
let err = Error::new(ErrorKind::InvalidData)
.with_description("The client sent a GIOP request whose codesets could not be read")
.with_parent(err);
if response_expected {
self.send_error(server_request.version, server_request.id, &err)?;
}
return Ok(true);
}
}
(response_expected, addressed, server_request)
}
Message::Request(request) => {
if recv.adjacent.is_some() {
return Err(Error::new(ErrorKind::InvalidData)
.with_description("The client sent a whole GIOP message in the middle of one it was sending in fragments"));
}
let request_id = request.request_id();
let version = request.version();
if version < Version::V12 {
recv.adjacent = Some(request_id);
}
let part = recv.buf.split_to(message_len).into_mut();
let _ = recv.fragments.insert(request_id, part);
return Ok(true);
}
Message::Fragment(frag) => {
let Some(request_id) = frag.request_id().or(recv.adjacent) else {
return Err(Error::new(ErrorKind::InvalidData)
.with_description("The client sent a GIOP fragment of no message at all"));
};
let fragment_follows = frag.fragment_follows();
let data = reader.read_octet_slice(frag.body_len())
.expect("a fragment carries the octets it says it carries");
let Some(part) = recv.fragments.get_mut(&request_id) else {
return Err(Error::new(ErrorKind::InvalidData)
.with_description(format!("The client sent a GIOP fragment of the request {request_id}, which no message was announced for")));
};
if part.len() + data.len() > MAX_MESSAGE_LEN {
return Err(Error::new(ErrorKind::InvalidData)
.with_description(format!("The client sent a GIOP message of more than {MAX_MESSAGE_LEN} octets in fragments")));
}
part.extend_from_slice(&data);
let _ = recv.buf.split_to(message_len);
if fragment_follows {
return Ok(true);
}
let part = recv.fragments.remove(&request_id)
.expect("the message being put back together was just written into");
recv.adjacent = None;
let mut writer = CdrWriter::from_buf(part);
let res = writer.write(&MessageWhole);
recv.fragment_buf = Some(writer.into_buf().freeze());
res.map_err(|err| Error::new(ErrorKind::InvalidData)
.with_description("A GIOP message could not be put back together")
.with_parent(err))?;
return Ok(true);
}
Message::LocateRequest(locate) => {
let request_id = locate.request_id();
let version = locate.version();
let status = shared.global.has_object(locate.target())
.then_some(LocateStatus::ObjectHere)
.unwrap_or(LocateStatus::UnknownObject);
let _ = recv.buf.split_to(message_len);
trace!(addr = %self.addr, request_id, ?status, "Answering a locate request");
self.send_message(&Message::LocateReply(LocateReply::new(version, request_id, status)), None)?;
return Ok(true);
}
Message::CancelRequest(cancel) => {
trace!(addr = %self.addr, request_id = cancel.request_id(), "Ignoring the cancellation of a request");
let _ = recv.buf.split_to(message_len);
return Ok(true);
}
_ => {
return Err(Error::new(ErrorKind::InvalidData)
.with_description("The client sent a GIOP message that is not a request"));
}
};
let Some(object) = object else {
debug!(addr = %self.addr, request_id = request.id, "Refusing a request to an object that is not served");
if response_expected {
self.send_exception(request.version, request.id,
&SystemException::new(exception::OBJECT_NOT_EXIST))?;
}
return Ok(true);
};
if self.builtin_operation(&*object, response_expected, &request)? {
return Ok(true);
}
let answer = Answer {
token: self.token,
version: request.version,
request_id: request.id,
response_expected,
};
shared.tasks.push(RequestTask {
fut: object.request(request),
answer,
});
Ok(true)
}
fn builtin_operation<O: ServerObject>(&mut self, object: &O, response_expected: bool, request: &ServerRequest) -> Result<bool> {
if !matches!(request.operation(), b"_is_a" | b"_non_existent" | b"_not_existent" | b"_interface") {
return Ok(false);
}
if !response_expected {
return Ok(true);
}
match request.operation() {
b"_is_a" => {
let mut reader = request.read();
let repo_id = match reader.read_string() {
Ok(repo_id) => repo_id,
Err(err) => {
self.send_error(request.version, request.id, &err)?;
return Ok(true);
}
};
let is_a = repo_id == OBJECT_REPO_ID || object.repo_ids().iter().any(|declared| *declared == repo_id);
let reply = request.make_reply(ReplyStatus::NoException);
self.send_message(&Message::Reply(reply), Some(&is_a))?;
}
b"_non_existent" | b"_not_existent" => {
let reply = request.make_reply(ReplyStatus::NoException);
self.send_message(&Message::Reply(reply), Some(&false))?;
}
_ => {
self.send_exception(request.version, request.id,
&SystemException::new(exception::NO_IMPLEMENT))?;
}
}
Ok(true)
}
fn is_flushed(&self) -> bool {
self.send_state.writer.buffer().is_empty()
}
fn flush(&mut self) -> Result<()> {
let mut stream = &self.stream;
stream.write_nb_from_cdr(&mut self.send_state.writer)
.map_err(|err| Error::new(ErrorKind::Corba)
.with_description("The connection to the client failed while it was being written to")
.with_source(Box::new(err)))
}
fn send_message(&mut self, message: &Message<'_>, body: Option<&dyn CdrWrite>) -> Result<()> {
let writer = &mut *self.send_state.writer;
let origin = writer.origin();
let at = writer.position();
writer.set_origin(at);
let res = writer.write(message)
.and_then(|()| body.map_or(Ok(()), |body| writer.write(body)))
.and_then(|()| writer.write(&MessageLen));
writer.set_origin(origin);
if res.is_err() {
writer.set_position(at);
}
res.map_err(|err| Error::new(ErrorKind::Corba)
.with_description("A GIOP message this server answers with could not be written")
.with_parent(err))
}
fn refuse_message(&mut self, message_len: usize) -> Result<bool> {
if self.recv_state.adjacent.is_some() {
return Err(Error::new(ErrorKind::InvalidData)
.with_description("The client sent a GIOP message this server made nothing of in the middle of one it was sending in fragments"));
}
let _ = self.recv_state.buf.split_to(message_len);
self.send_message(&Message::MessageError(VERSION), None)?;
Ok(true)
}
fn send_answer(&mut self, answer: &Answer, reply: Result<ServerReply>) -> Result<()> {
match reply {
Ok(reply) => match reply.finalize() {
Ok(buffer) => self.send_state.writer.interleave(buffer),
Err(err) => {
warn!(addr = %self.addr, request_id = answer.request_id, %err,
"Failed to write the answer of an object");
self.send_exception(answer.version, answer.request_id,
&SystemException::new(exception::MARSHAL)
.with_completion_status(CompletionStatus::Yes))?;
}
},
Err(err) => self.send_error(answer.version, answer.request_id, &err)?,
}
self.flush()
}
fn send_exception(&mut self, version: Version, request_id: u32, exception: &SystemException) -> Result<()> {
let reply = Reply::new(version, request_id, ReplyStatus::SystemException);
self.send_message(&Message::Reply(reply), Some(exception))
}
fn send_error(&mut self, version: Version, request_id: u32, err: &Error) -> Result<()> {
let (exception_id, completion_status) = system_exception(err.kind());
debug!(addr = %self.addr, request_id, exception_id, %completion_status, %err,
"Answering a request with a system exception");
self.send_exception(version, request_id, &SystemException::new(exception_id)
.with_completion_status(completion_status))
}
}
#[derive(Debug)]
struct RecvState {
buf: Buf<u8, 1>,
fragments: HashMap<u32, BufMut<u8, 1>>,
adjacent: Option<u32>,
fragment_buf: Option<Buf<u8, 1>>,
}
#[derive(Debug)]
struct SendState {
writer: CdrSender,
}
pub trait ServerObject: Send + Sync + 'static {
type RequestFuture: Future<Output = Result<ServerReply>> + Send + 'static;
fn id(&self) -> &[u8];
fn repo_ids(&self) -> &[&str];
fn request(self: Arc<Self>, req: ServerRequest) -> Self::RequestFuture;
}
#[derive(Debug, Clone, Copy)]
struct Answer {
token: Token,
version: Version,
request_id: u32,
response_expected: bool,
}
pin_project! {
struct RequestTask<O: ServerObject> {
#[pin]
fut: O::RequestFuture,
answer: Answer,
}
}
impl<O: ServerObject> Future for RequestTask<O> {
type Output = (Answer, Result<ServerReply>);
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
let this = self.project();
this.fut.poll(cx).map(|reply| (*this.answer, reply))
}
}
#[derive(Debug)]
pub struct ServerRequest {
buf: Buf<u8, 1>,
codesets: Option<Codesets>,
id: u32,
version: Version,
operation: Range<usize>,
body_at: usize,
endian: Endian,
}
impl ServerRequest {
#[inline]
pub fn operation(&self) -> &[u8] {
&self.buf.as_bytes()[self.operation.clone()]
}
#[inline]
fn make_reply(&self, status: ReplyStatus) -> Reply<'_> {
Reply::new(self.version, self.id, status)
}
pub fn read(&self) -> CdrReader<'_> {
let mut reader = CdrReader::new(&self.buf).with_endian(self.endian).with_codesets(self.codesets);
reader.set_position(self.body_at);
reader
}
pub fn reply(&self, status: ReplyStatus) -> Result<ServerReply> {
let mut writer = CdrWriter::with_capacity(REPLY_MIN_LEN).with_codesets(self.codesets);
writer.write(&Message::Reply(self.make_reply(status)))?;
Ok(ServerReply {
writer,
})
}
pub fn reply_user_exception(&self, repo_id: &str) -> Result<ServerReply> {
let mut reply = self.reply(ReplyStatus::UserException)?;
reply.write_string(repo_id)?;
Ok(reply)
}
pub fn reply_system_exception(&self, exception: &SystemException<'_>) -> Result<ServerReply> {
let mut reply = self.reply(ReplyStatus::SystemException)?;
reply.write(exception)?;
Ok(reply)
}
}
#[derive(Debug)]
pub struct ServerReply {
writer: CdrWriter,
}
impl ServerReply {
fn finalize(mut self) -> Result<Buf<u8, 1>> {
self.writer.write(&MessageLen)?;
Ok(self.writer.into_buf().freeze())
}
}
impl Deref for ServerReply {
type Target = CdrWriter;
#[inline]
fn deref(&self) -> &Self::Target {
&self.writer
}
}
impl DerefMut for ServerReply {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.writer
}
}
fn system_exception(kind: ErrorKind<'_>) -> (&'static str, CompletionStatus) {
match kind {
ErrorKind::InvalidData => (exception::MARSHAL, CompletionStatus::No),
ErrorKind::NotHandled => (exception::BAD_OPERATION, CompletionStatus::No),
ErrorKind::NotImplemented => (exception::NO_IMPLEMENT, CompletionStatus::No),
ErrorKind::DevNotFound => (exception::OBJECT_NOT_EXIST, CompletionStatus::No),
ErrorKind::TimedOut => (exception::TIMEOUT, CompletionStatus::Maybe),
ErrorKind::Internal => (exception::INTERNAL, CompletionStatus::Maybe),
_ => (exception::UNKNOWN, CompletionStatus::Maybe),
}
}
#[derive(Debug)]
struct PollWaker {
waker: Arc<Waker>,
failed: AtomicBool,
}
impl ArcWake for PollWaker {
fn wake_by_ref(arc_self: &Arc<Self>) {
let Err(err) = arc_self.waker.wake() else {
return;
};
if !arc_self.failed.swap(true, Ordering::Relaxed) {
warn!(%err, "Failed to wake the polling thread of the CORBA server up for a task that is ready");
}
}
}
fn local_addrs(bound: SocketAddr) -> Box<[IpAddr]> {
if !bound.ip().is_unspecified() {
return Box::from([bound.ip()]);
}
fn route_addr(to: (IpAddr, u16), from: IpAddr) -> Option<IpAddr> {
let socket = UdpSocket::bind((from, 0)).ok()?;
socket.connect(to).ok()?;
Some(socket.local_addr().ok()?.ip())
}
let mut addrs = Vec::new();
let mut push = |addr: IpAddr| {
if !addr.is_unspecified() && !addr.is_loopback() && !addrs.contains(&addr) {
addrs.push(addr);
}
};
if let Some(addr) = route_addr((IpAddr::V4(Ipv4Addr::new(192, 0, 2, 1)), 9), IpAddr::V4(Ipv4Addr::UNSPECIFIED)) {
push(addr);
}
if let Some(addr) = route_addr((IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)), 9), IpAddr::V6(Ipv6Addr::UNSPECIFIED)) {
push(addr);
}
if let Ok(name) = fs::read_to_string("/etc/hostname")
.map(|name| name.trim().to_string())
.or_else(|_| env::var("HOSTNAME"))
&& !name.is_empty()
&& let Ok(resolved) = (&*name, 0u16).to_socket_addrs() {
for addr in resolved {
push(addr.ip());
}
}
if addrs.is_empty() {
addrs.push(IpAddr::V4(Ipv4Addr::LOCALHOST));
}
addrs.into_boxed_slice()
}