Implement basic net module
This commit is contained in:
@@ -1,2 +1,4 @@
|
||||
pub mod rt;
|
||||
pub mod channel;
|
||||
pub mod net;
|
||||
pub mod runtime;
|
||||
pub mod task;
|
||||
|
||||
345
crates/lb/src/net.rs
Normal file
345
crates/lb/src/net.rs
Normal file
@@ -0,0 +1,345 @@
|
||||
//! The `lb:net` module provides an asynchronous network API for creating TCP or UDP servers and
|
||||
//! clients.
|
||||
//!
|
||||
//! See [`lb_libnet`] for items exported by this module.
|
||||
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` module.
|
||||
///
|
||||
/// This module 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" fn tcp_v4(&self) -> lb_tcpsocket {
|
||||
self.__new_tcp_v4()
|
||||
}
|
||||
|
||||
/// 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" fn tcp_v6(&self) -> lb_tcpsocket {
|
||||
self.__new_tcp_v6()
|
||||
}
|
||||
|
||||
extern "Lua-C" fn __new_tcp_v4(&self) -> io::Result<lb_tcpsocket> {
|
||||
TcpSocket::new_v4().map(lb_tcpsocket)
|
||||
}
|
||||
|
||||
extern "Lua-C" fn __new_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 compat_v6(&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 mapped_v6(&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 {}
|
||||
Reference in New Issue
Block a user