///|
/// lockwire native plugin for the live-transport boundary.
///
/// Extends the open `LiveTransportKind`/`LiveTransport` extenums declared in
/// `mokomoking2501/lockwire/live_transport` with the Windows-npcap and Linux-raw-socket
/// backends, and registers handler chains (in `init`) so the protocol adapters
/// can open/send/receive/close through the master `live_*` functions without
/// ever importing this package. A future STM32/ThreadX backend would do the
/// same from its own package — `+=` adds variants, `init` adds behaviour.
///|
pub(all) extenum @live.LiveTransportKind += {
NpcapKind
RawSocketKind
}
///|
/// Live handle carrying the concrete native session plus the local MAC and
/// live-opened flag captured at open time.
pub(all) extenum @live.LiveTransport += {
NpcapLink(NativeNpcapLinkSession, Bytes, Bool)
RawSocketLink(NativeRawSocketLinkSession, Bytes, Bool)
}
///|
fn native_link_err_code(err : NativeLinkError) -> Int {
match err {
SystemError(_, code, _) => code
}
}
///|
fn native_link_err_msg(err : NativeLinkError) -> String {
match err {
SystemError(_, _, msg) => msg
}
}
///|
fn native_npcap_open_config(
open : @live.LiveTransportOpen,
) -> NativeLinkSessionConfig {
let base = native_link_session_config(NativeSessionNpcap)
{
..base,
interface_name: open.interface_name,
ethertype: open.ethertype,
promiscuous: open.promiscuous,
allow_live_open: open.allow_live,
open_timeout_ms: open.open_timeout_ms,
snaplen: open.snaplen,
}
}
///|
fn native_raw_open_config(
open : @live.LiveTransportOpen,
) -> NativeLinkSessionConfig {
let base = native_link_session_config(NativeSessionRawSocket)
{
..base,
interface_name: open.interface_name,
ethertype: open.ethertype,
promiscuous: open.promiscuous,
allow_live_open: open.allow_live,
open_timeout_ms: open.open_timeout_ms,
}
}
///|
fn native_open(
open : @live.LiveTransportOpen,
) -> @live.LiveTransport? raise @live.LiveTransportError {
match open.kind {
NpcapKind => {
let config = native_npcap_open_config(open)
let session = NativeNpcapLinkSession::open(config) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"open",
native_link_err_code(err),
native_link_err_msg(err),
)
}
let mac = native_npcap_local_mac(open.interface_name)
Some(NpcapLink(session, mac, open.allow_live))
}
RawSocketKind => {
let config = native_raw_open_config(open)
let session = NativeRawSocketLinkSession::open(config) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"open",
native_link_err_code(err),
native_link_err_msg(err),
)
}
let mac = native_raw_socket_local_mac(open.interface_name)
Some(RawSocketLink(session, mac, open.allow_live))
}
_ => None
}
}
///|
fn native_send(
t : @live.LiveTransport,
frame : Bytes,
) -> Int? raise @live.LiveTransportError {
match t {
NpcapLink(session, _, _) => {
let n = session.send_frame(frame) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"send",
native_link_err_code(err),
native_link_err_msg(err),
)
}
Some(n)
}
RawSocketLink(session, _, _) => {
let n = session.send_frame(frame) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"send",
native_link_err_code(err),
native_link_err_msg(err),
)
}
Some(n)
}
_ => None
}
}
///|
fn native_receive(
t : @live.LiveTransport,
timeout_ms : Int,
) -> Bytes? raise @live.LiveTransportError {
match t {
NpcapLink(session, _, _) => {
let frame = session.receive_frame(timeout_ms~) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"receive",
native_link_err_code(err),
native_link_err_msg(err),
)
}
Some(frame)
}
RawSocketLink(session, _, _) => {
let frame = session.receive_frame(timeout_ms~) catch {
err =>
raise @live.LiveTransportError::IoFailed(
"receive",
native_link_err_code(err),
native_link_err_msg(err),
)
}
Some(frame)
}
_ => None
}
}
///|
fn native_close(t : @live.LiveTransport) -> Bool raise @live.LiveTransportError {
match t {
NpcapLink(session, _, _) => {
session.close() catch {
err =>
raise @live.LiveTransportError::IoFailed(
"close",
native_link_err_code(err),
native_link_err_msg(err),
)
}
true
}
RawSocketLink(session, _, _) => {
session.close() catch {
err =>
raise @live.LiveTransportError::IoFailed(
"close",
native_link_err_code(err),
native_link_err_msg(err),
)
}
true
}
_ => false
}
}
///|
fn native_local_mac(t : @live.LiveTransport) -> Bytes? {
match t {
NpcapLink(_, mac, _) => Some(mac)
RawSocketLink(_, mac, _) => Some(mac)
_ => None
}
}
///|
fn native_live_opened(t : @live.LiveTransport) -> Bool? {
match t {
NpcapLink(_, _, opened) => Some(opened)
RawSocketLink(_, _, opened) => Some(opened)
_ => None
}
}
///|
fn native_kind_label(kind : @live.LiveTransportKind) -> String? {
match kind {
NpcapKind => Some("npcap")
RawSocketKind => Some("raw-socket")
_ => None
}
}
///|
fn native_now_millis() -> Int64? {
Some(monotonic_millis())
}
///|
fn native_highres() -> Int64? {
Some(highres_micros())
}
///|
fn native_sleep_until(deadline_micros : Int64) -> Int? {
Some(sleep_until_micros(deadline_micros))
}
///|
fn native_rt_supported() -> Int? {
Some(win_rt_supported())
}
///|
fn native_rt_affinity(mask : UInt, priority : Int) -> Int? {
Some(win_rt_set_affinity(mask, priority))
}
///|
fn init {
@live.register_live_transport_open(native_open)
@live.register_live_transport_send(native_send)
@live.register_live_transport_receive(native_receive)
@live.register_live_transport_close(native_close)
@live.register_live_transport_local_mac(native_local_mac)
@live.register_live_transport_live_opened(native_live_opened)
@live.register_live_transport_kind_label(native_kind_label)
@live.register_live_now_millis(native_now_millis)
@live.register_live_highres_micros(native_highres)
@live.register_live_sleep_until(native_sleep_until)
@live.register_live_win_rt_supported(native_rt_supported)
@live.register_live_win_rt_set_affinity(native_rt_affinity)
}