340 lines
9.6 KiB
Rust
340 lines
9.6 KiB
Rust
//! The `lb:net` library provides an asynchronous network API for creating TCP or UDP servers and
|
|
//! clients.
|
|
//!
|
|
//! # Exports
|
|
//!
|
|
//! See [`lb_libnet`] for items exported by this library.
|
|
use derive_more::{From, FromStr};
|
|
use luaffi::{cdef, metatype};
|
|
use std::{
|
|
io,
|
|
net::{AddrParseError, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
|
};
|
|
use tokio::net::{TcpListener, TcpSocket, TcpStream};
|
|
|
|
/// Items exported by the `lb:net` library.
|
|
///
|
|
/// This library can be obtained by calling `require` in Lua.
|
|
///
|
|
/// ```lua
|
|
/// local net = require("lb:net");
|
|
/// ```
|
|
#[cdef]
|
|
pub struct lb_libnet;
|
|
|
|
#[metatype]
|
|
impl lb_libnet {
|
|
#[new]
|
|
extern "Lua-C" fn new() -> Self {
|
|
Self
|
|
}
|
|
|
|
/// See [`Ipv4Addr::LOCALHOST`].
|
|
pub extern "Lua-C" fn localhost_v4(&self) -> lb_ipaddr {
|
|
lb_ipaddr(Ipv4Addr::LOCALHOST.into())
|
|
}
|
|
|
|
/// See [`Ipv6Addr::LOCALHOST`].
|
|
pub extern "Lua-C" fn localhost_v6(&self) -> lb_ipaddr {
|
|
lb_ipaddr(Ipv6Addr::LOCALHOST.into())
|
|
}
|
|
|
|
/// See [`Ipv4Addr::UNSPECIFIED`].
|
|
pub extern "Lua-C" fn unspecified_v4(&self) -> lb_ipaddr {
|
|
lb_ipaddr(Ipv4Addr::UNSPECIFIED.into())
|
|
}
|
|
|
|
/// See [`Ipv6Addr::UNSPECIFIED`].
|
|
pub extern "Lua-C" fn unspecified_v6(&self) -> lb_ipaddr {
|
|
lb_ipaddr(Ipv6Addr::UNSPECIFIED.into())
|
|
}
|
|
|
|
/// See [`Ipv4Addr::BROADCAST`].
|
|
pub extern "Lua-C" fn broadcast_v4(&self) -> lb_ipaddr {
|
|
lb_ipaddr(Ipv4Addr::BROADCAST.into())
|
|
}
|
|
|
|
/// Creates an [`lb_ipaddr`] from the given input.
|
|
///
|
|
/// If `s` is an [`lb_ipaddr`], a copy of that value is returned. If `s` is an
|
|
/// [`lb_socketaddr`], the IP address part of the socket address is returned. Otherwise, parses
|
|
/// `s` as an IP address string. Both IPv4 or IPv6 addresses are supported.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Throws if `s` cannot be parsed as an IP address.
|
|
pub extern "Lua" fn ipaddr(&self, s: any) -> lb_ipaddr {
|
|
if __istype(__ct.lb_ipaddr, s) {
|
|
__new(__ct.lb_ipaddr, s) // copy constructor
|
|
} else if __istype(__ct.lb_socketaddr, s) {
|
|
s.ip()
|
|
} else {
|
|
self.__parse_ipaddr(s)
|
|
}
|
|
}
|
|
|
|
extern "Lua-C" fn __parse_ipaddr(&self, s: &str) -> Result<lb_ipaddr, AddrParseError> {
|
|
s.parse()
|
|
}
|
|
|
|
/// Creates an [`lb_socketaddr`] from the given input.
|
|
///
|
|
/// A socket address is an IP address with a port number.
|
|
///
|
|
/// If `s` is an [`lb_socketaddr`], a copy of that value is returned. If `s` is an
|
|
/// [`lb_ipaddr`], a socket address with that IP address is returned. Otherwise, parses `s` as a
|
|
/// socket address string. Both IPv4 and IPv6 addresses are supported.
|
|
///
|
|
/// If `port` is not specified, `0` is used as the default.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Throws if `s` cannot be parsed as an IP or socket address.
|
|
pub extern "Lua" fn socketaddr(&self, s: any, port: any) -> lb_socketaddr {
|
|
if port != () {
|
|
self.__new_socketaddr(self.ipaddr(s), port)
|
|
} else {
|
|
if __istype(__ct.lb_socketaddr, s) {
|
|
__new(__ct.lb_socketaddr, s) // copy constructor
|
|
} else if __istype(__ct.lb_ipaddr, s) {
|
|
self.__new_socketaddr(s, 0) // default port 0
|
|
} else {
|
|
self.__parse_socketaddr(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "Lua-C" fn __new_socketaddr(&self, ip: &lb_ipaddr, port: u16) -> lb_socketaddr {
|
|
SocketAddr::new(ip.0, port).into()
|
|
}
|
|
|
|
extern "Lua-C" fn __parse_socketaddr(&self, s: &str) -> Result<lb_socketaddr, AddrParseError> {
|
|
s.parse()
|
|
}
|
|
|
|
/// Creates a new TCP socket configured for IPv4.
|
|
///
|
|
/// See [`TcpSocket::new_v4`].
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Throws if an error was encountered during the socket creation.
|
|
pub extern "Lua-C" fn tcp_v4(&self) -> io::Result<lb_tcpsocket> {
|
|
TcpSocket::new_v4().map(lb_tcpsocket)
|
|
}
|
|
|
|
/// Creates a new TCP socket configured for IPv6.
|
|
///
|
|
/// See [`TcpSocket::new_v6`].
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// Throws if an error was encountered during the socket creation.
|
|
pub extern "Lua-C" fn tcp_v6(&self) -> io::Result<lb_tcpsocket> {
|
|
TcpSocket::new_v6().map(lb_tcpsocket)
|
|
}
|
|
}
|
|
|
|
/// An IP address, either IPv4 or IPv6.
|
|
///
|
|
/// # Example
|
|
///
|
|
/// This example creates an [`lb_ipaddr`] by parsing an IP address string.
|
|
///
|
|
/// ```lua
|
|
/// local net = require("lb:net");
|
|
/// local addr = net:ipaddr("127.0.0.1"); -- ipv4 loopback address
|
|
///
|
|
/// assert(addr:is_v4());
|
|
/// assert(addr:is_loopback());
|
|
/// ```
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, From, FromStr)]
|
|
#[cdef]
|
|
pub struct lb_ipaddr(#[opaque] IpAddr);
|
|
|
|
#[metatype]
|
|
impl lb_ipaddr {
|
|
/// See [`IpAddr::is_unspecified`].
|
|
pub extern "Lua-C" fn is_unspecified(&self) -> bool {
|
|
self.0.is_unspecified()
|
|
}
|
|
|
|
/// See [`IpAddr::is_loopback`].
|
|
pub extern "Lua-C" fn is_loopback(&self) -> bool {
|
|
self.0.is_loopback()
|
|
}
|
|
|
|
/// See [`IpAddr::is_multicast`].
|
|
pub extern "Lua-C" fn is_multicast(&self) -> bool {
|
|
self.0.is_multicast()
|
|
}
|
|
|
|
/// Returns the string `"v4"` if this is an IPv4 address or `"v6"` if this is an IPv6 address.
|
|
pub extern "Lua" fn family(&self) -> string {
|
|
if self.is_v6() { "v6" } else { "v4" }
|
|
}
|
|
|
|
/// Returns `true` if this is an IPv4 address.
|
|
pub extern "Lua-C" fn is_v4(&self) -> bool {
|
|
self.0.is_ipv4()
|
|
}
|
|
|
|
/// See [`Ipv4Addr::is_private`].
|
|
pub extern "Lua-C" fn is_v4_private(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => v4.is_private(),
|
|
IpAddr::V6(_) => false,
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv4Addr::is_link_local`].
|
|
pub extern "Lua-C" fn is_v4_link_local(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => v4.is_link_local(),
|
|
IpAddr::V6(_) => false,
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv4Addr::is_broadcast`].
|
|
pub extern "Lua-C" fn is_v4_broadcast(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => v4.is_broadcast(),
|
|
IpAddr::V6(_) => false,
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv4Addr::is_documentation`].
|
|
pub extern "Lua-C" fn is_v4_documentation(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => v4.is_documentation(),
|
|
IpAddr::V6(_) => false,
|
|
}
|
|
}
|
|
|
|
/// Returns `true` if this is an IPv6 address.
|
|
pub extern "Lua-C" fn is_v6(&self) -> bool {
|
|
self.0.is_ipv6()
|
|
}
|
|
|
|
/// See [`Ipv6Addr::is_unique_local`].
|
|
pub extern "Lua-C" fn is_v6_unique_local(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(_) => false,
|
|
IpAddr::V6(v6) => v6.is_unique_local(),
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv6Addr::is_unicast_link_local`].
|
|
pub extern "Lua-C" fn is_v6_unicast_link_local(&self) -> bool {
|
|
match self.0 {
|
|
IpAddr::V4(_) => false,
|
|
IpAddr::V6(v6) => v6.is_unicast_link_local(),
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv4Addr::to_ipv6_compatible`].
|
|
pub extern "Lua-C" fn to_v6_compat(&self) -> Self {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => Self(v4.to_ipv6_compatible().into()),
|
|
IpAddr::V6(_) => *self,
|
|
}
|
|
}
|
|
|
|
/// See [`Ipv4Addr::to_ipv6_mapped`].
|
|
pub extern "Lua-C" fn to_v6_mapped(&self) -> Self {
|
|
match self.0 {
|
|
IpAddr::V4(v4) => Self(v4.to_ipv6_mapped().into()),
|
|
IpAddr::V6(_) => *self,
|
|
}
|
|
}
|
|
|
|
/// See [`IpAddr::to_canonical`].
|
|
pub extern "Lua-C" fn canonical(&self) -> Self {
|
|
self.0.to_canonical().into()
|
|
}
|
|
|
|
/// Returns the string representation of this address.
|
|
#[tostring]
|
|
pub extern "Lua-C" fn tostring(&self) -> String {
|
|
self.0.to_string()
|
|
}
|
|
}
|
|
|
|
/// A socket address, which is an IP address with a port number.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, From, FromStr)]
|
|
#[cdef]
|
|
pub struct lb_socketaddr(#[opaque] SocketAddr);
|
|
|
|
#[metatype]
|
|
impl lb_socketaddr {
|
|
/// Returns the IP part of this address.
|
|
pub extern "Lua-C" fn ip(&self) -> lb_ipaddr {
|
|
self.0.ip().into()
|
|
}
|
|
|
|
/// Sets the IP part of this address.
|
|
///
|
|
/// This function accepts the same arguments as [`ipaddr`](lb_libnet::ipaddr).
|
|
pub extern "Lua" fn set_ip(&mut self, s: any) -> &mut Self {
|
|
if __istype(__ct.lb_ipaddr, s) {
|
|
self.__set_ip(s);
|
|
} else if __istype(__ct.lb_socketaddr, s) {
|
|
self.__set_ip(s.ip());
|
|
} else {
|
|
self.__set_ip_parse(s);
|
|
}
|
|
self
|
|
}
|
|
|
|
extern "Lua-C" fn __set_ip(&mut self, ip: &lb_ipaddr) {
|
|
self.0.set_ip(ip.0);
|
|
}
|
|
|
|
extern "Lua-C" fn __set_ip_parse(&mut self, s: &str) -> Result<(), AddrParseError> {
|
|
s.parse().map(|ip| self.0.set_ip(ip))
|
|
}
|
|
|
|
/// Returns the port part of this address.
|
|
pub extern "Lua-C" fn port(&self) -> u16 {
|
|
self.0.port()
|
|
}
|
|
|
|
/// Sets the port part of this address.
|
|
pub extern "Lua" fn set_port(&mut self, port: number) -> &mut Self {
|
|
self.__set_port(port);
|
|
self
|
|
}
|
|
|
|
extern "Lua-C" fn __set_port(&mut self, port: u16) {
|
|
self.0.set_port(port)
|
|
}
|
|
|
|
/// Returns the string representation of this address.
|
|
#[tostring]
|
|
pub extern "Lua-C" fn tostring(&self) -> String {
|
|
self.0.to_string()
|
|
}
|
|
}
|
|
|
|
/// A TCP socket which has not yet been converted to a [`lb_tcpstream`] or [`lb_tcplistener`].
|
|
#[derive(Debug, From)]
|
|
#[cdef]
|
|
pub struct lb_tcpsocket(#[opaque] TcpSocket);
|
|
|
|
#[metatype]
|
|
impl lb_tcpsocket {}
|
|
|
|
#[derive(Debug, From)]
|
|
#[cdef]
|
|
pub struct lb_tcpstream(#[opaque] TcpStream);
|
|
|
|
#[metatype]
|
|
impl lb_tcpstream {}
|
|
|
|
#[derive(Debug, From)]
|
|
#[cdef]
|
|
pub struct lb_tcplistener(#[opaque] TcpListener);
|
|
|
|
#[metatype]
|
|
impl lb_tcplistener {}
|