dope_sys/io/socket/msg/
source.rs1use std::{net, os::fd::AsFd as _};
2
3use crate::{
4 Errno,
5 io::socket::{self, Domain, Kind, addr, gso},
6};
7
8#[derive(Clone, Copy, Debug)]
10pub struct Address(net::SocketAddr);
11
12impl Address {
13 pub const fn get(self) -> net::SocketAddr {
14 self.0
15 }
16}
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum Error {
21 Family {
22 bind: net::SocketAddr,
23 peer: net::SocketAddr,
24 },
25 Open(socket::Create),
26 Bind(Errno),
27 Connect(Errno),
28 Local(addr::Local<Errno>),
29 Address(addr::Error),
30 Unspecified(net::SocketAddr),
31}
32
33pub trait Source: socket::Prepare + addr::Source + gso::Source + Sized {
35 type Control: Copy + AsRef<[u8]>;
36 type Combined;
38
39 fn control(source: Address) -> Self::Control;
40 fn compose(source: Self::Control, gso: Option<<Self as gso::Source>::Mode>) -> Self::Combined;
41 fn release(control: Self::Combined) -> (Self::Control, Option<<Self as gso::Source>::Mode>);
42 fn bytes(control: &mut Self::Combined) -> &[u8];
43
44 fn source(
46 bind: net::SocketAddr,
47 peer: net::SocketAddr,
48 ) -> Result<(Address, Self::Control), Error> {
49 if bind.is_ipv4() != peer.is_ipv4() {
50 return Err(Error::Family { bind, peer });
51 }
52 let local = if bind.ip().to_canonical().is_unspecified() {
53 let file = Self::open(Domain::for_addr(&peer), Kind::Dgram).map_err(Error::Open)?;
54 let mut local = bind;
55 local.set_port(0);
56 addr::Internet::from_std::<Self>(local)
57 .as_addr()
58 .try_bind::<Self, Errno>(file.as_fd())
59 .map_err(Error::Bind)?;
60 addr::Internet::from_std::<Self>(peer)
61 .as_addr()
62 .try_connect::<Self, Errno>(file.as_fd())
63 .map_err(Error::Connect)?;
64 let mut storage = addr::Storage::empty();
65 addr::Addr::local::<Self, Errno>(file.as_fd(), &mut storage).map_err(Error::Local)?;
66 let mut local = storage.to_std().map_err(Error::Address)?;
67 if local.ip().to_canonical().is_unspecified() {
68 return Err(Error::Unspecified(local));
69 }
70 local.set_port(bind.port());
71 Address(local)
72 } else {
73 Address(bind)
74 };
75 Ok((local, Self::control(local)))
76 }
77}