### Create Synchronous NAT-PMP Client (Default Gateway) Source: https://context7.com/fengyc/natpmp/llms.txt Constructs a synchronous `Natpmp` instance by auto-detecting the system's default gateway. Internally binds a UDP socket to the gateway on port 5351. Returns errors if the gateway cannot be determined or socket setup fails. ```rust use natpmp::* fn main() -> Result<()> let mut n = Natpmp::new()?; println!("Connected to gateway: {}", n.gateway()); Ok(()) } ``` -------------------------------- ### Request UDP Port Mapping and Process Response Source: https://context7.com/fengyc/natpmp/llms.txt This snippet demonstrates sending a UDP port mapping request and then reading and processing the response. A short delay is included to allow for the response. The example shows how to map a local UDP port to a public port. ```rust use std::thread; use std::time::Duration; use natpmp::{Natpmp, Protocol, Result}; fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; thread::sleep(Duration::from_millis(250)); print_response(n.read_response_or_retry()?); // Assuming print_response is defined elsewhere // [UDP] private=4020, public=4020, lifetime=30s, epoch=3601s Ok(()) } ``` -------------------------------- ### Natpmp::new Source: https://context7.com/fengyc/natpmp/llms.txt Creates a synchronous NAT-PMP client using the default gateway. Internally binds a non-blocking UDP socket and connects it to the gateway on port 5351 (the NAT-PMP port). Returns errors if the gateway cannot be determined or the socket setup fails. ```APIDOC ## Natpmp::new ### Description Constructs a `Natpmp` instance by auto-detecting the system's default gateway via `get_default_gateway()`. Internally binds a non-blocking UDP socket and connects it to the gateway on port 5351 (the NAT-PMP port). Returns errors if the gateway cannot be determined or the socket setup fails. ### Method Rust struct constructor ### Endpoint N/A (local function) ### Parameters None ### Request Example ```rust use natpmp::* fn main() -> Result<()> { let mut n = Natpmp::new()?; println!("Connected to gateway: {}", n.gateway()); Ok(()) } ``` ### Response #### Success Response A `Natpmp` instance. #### Response Example `Natpmp` instance with gateway information. ``` -------------------------------- ### Get NAT-PMP Request Timeout for Retry Source: https://context7.com/fengyc/natpmp/llms.txt Retrieves the remaining time until the next NAT-PMP request retransmission. Useful for integrating with event loops or select/poll mechanisms. Returns Duration::ZERO if the timeout has passed or an error if no request is pending. ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_public_address_request()?; loop { let timeout = n.get_natpmp_request_timeout()?; if timeout <= Duration::from_millis(10) { match n.read_response_or_retry() { Ok(Response::Gateway(gr)) => { println!("Public IP: {}", gr.public_address()); break; } Err(Error::NATPMP_TRYAGAIN) => {} // Retry Err(e) => return Err(e), _ => {} // Unexpected response } } else { thread::sleep(Duration::from_millis(10)); } } Ok(()) } ``` -------------------------------- ### Initialize Natpmp with Default Gateway Source: https://github.com/fengyc/natpmp/blob/master/README.md Creates a new Natpmp object using the system's default gateway. Ensure the `natpmp` crate is added as a dependency. ```rust use natpmp::* let n = Natpmp::new()?; ``` -------------------------------- ### Create Async async-std NAT-PMP Client (Default Gateway) Source: https://context7.com/fengyc/natpmp/llms.txt Initializes an asynchronous NAT-PMP client using the async-std runtime and the system's default gateway. The API is identical to the tokio variant. Requires the 'async-std' feature. ```toml [dependencies] natpmp = { version = "...", features = ["async-std"] } ``` -------------------------------- ### Async Port Mapping with async-std Source: https://context7.com/fengyc/natpmp/llms.txt Demonstrates how to create an async-std NAT-PMP client and continuously send port mapping requests in a background task. It prints the mapped ports or logs errors. ```rust use std::sync::Arc; use std::time::Duration; use natpmp::* use async_std::task; fn main() -> Result<()> { task::block_on(async { let n = Arc::new(new_async_std_natpmp().await.unwrap()); let n_cloned = n.clone(); task::spawn(async move { loop { if let Err(e) = n_cloned .send_port_mapping_request(Protocol::UDP, 4020, 4020, 30) .await { eprintln!("Send error: {}", e); break; } async_std::task::sleep(Duration::from_secs(25)).await; } }); match n.read_response_or_retry().await { Ok(Response::UDP(ur)) => { println!("UDP mapped {} -> {}", ur.private_port(), ur.public_port()); } _ => eprintln!("Unexpected response"), } }); Ok(()) } ``` -------------------------------- ### Create async-std NAT-PMP Client with Specific Gateway Source: https://context7.com/fengyc/natpmp/llms.txt Initializes an async-std NAT-PMP client targeting a specific gateway IP address. It then requests the public IP address and prints it or logs any errors. ```rust use natpmp::* use async_std::task; fn main() -> Result<()> { task::block_on(async { let gateway = "192.168.0.1".parse().unwrap(); let mut n = new_async_std_natpmp_with(gateway).await.unwrap(); n.send_public_address_request().await.unwrap(); match n.read_response_or_retry().await { Ok(Response::Gateway(gr)) => println!("External IP: {}", gr.public_address()), Err(e) => eprintln!("Error: {}", e), _ => {} } }); Ok(()) } ``` -------------------------------- ### Create Async Tokio NAT-PMP Client (Default Gateway) Source: https://context7.com/fengyc/natpmp/llms.txt Initializes an asynchronous NAT-PMP client using the tokio runtime and the system's default gateway. The client can be shared across tasks using Arc. Requires the 'tokio' feature. ```rust use std::sync::Arc; use std::time::Duration; use natpmp::* #[tokio::main] async fn main() -> Result<()> { let n = Arc::new(new_tokio_natpmp().await?); println!("Gateway: {}", n.gateway()); let n_sender = n.clone(); tokio::spawn(async move { loop { if let Err(e) = n_sender .send_port_mapping_request(Protocol::UDP, 4020, 4020, 30) .await { eprintln!("Send error: {}", e); break; } tokio::time::sleep(Duration::from_secs(25)).await; // re-register before expiry } }); match n.read_response_or_retry().await? { Response::UDP(ur) => { println!("UDP mapped {} -> {}", ur.private_port(), ur.public_port()); } _ => eprintln!("Unexpected response"), } Ok(()) } ``` -------------------------------- ### Create Async Tokio NAT-PMP Client (Specified Gateway) Source: https://context7.com/fengyc/natpmp/llms.txt Creates an asynchronous NAT-PMP client with tokio, allowing specification of a custom gateway IP address. Useful for multi-interface environments. Requires the 'tokio' feature. ```rust use natpmp::* #[tokio::main] async fn main() -> Result<()> { let gateway = "192.168.1.1".parse().unwrap(); let mut n = new_tokio_natpmp_with(gateway).await?; n.send_public_address_request().await?; match n.read_response_or_retry().await? { Response::Gateway(gr) => println!("External IP: {}", gr.public_address()), _ => eprintln!("Unexpected response"), } Ok(()) } ``` -------------------------------- ### new_tokio_natpmp_with Source: https://context7.com/fengyc/natpmp/llms.txt Creates an asynchronous NAT-PMP client using tokio with a specified gateway address. ```APIDOC ## `new_tokio_natpmp_with` — Create an async tokio NAT-PMP client with a specified gateway ### Description Same as `new_tokio_natpmp` but accepts an explicit `Ipv4Addr` gateway. Useful for environments with multiple network interfaces or when the default gateway detection is insufficient. ### Method `new_tokio_natpmp_with(gateway: Ipv4Addr).await` ### Parameters - **gateway** (`Ipv4Addr`): The IP address of the NAT-PMP gateway. ### Response - `Ok(NatpmpAsync)`: An initialized asynchronous NAT-PMP client. ### Request Example ```rust use natpmp::*; #[tokio::main] async fn main() -> Result<()> { let gateway = "192.168.1.1".parse().unwrap(); let mut n = new_tokio_natpmp_with(gateway).await?; n.send_public_address_request().await?; match n.read_response_or_retry().await? { Response::Gateway(gr) => println!("External IP: {}", gr.public_address()), _ => eprintln!("Unexpected response"), } Ok(()) } ``` ``` -------------------------------- ### Initialize Natpmp with Specified Gateway Source: https://github.com/fengyc/natpmp/blob/master/README.md Creates a new Natpmp object for a specific gateway IP address. Requires parsing the IP string. Ensure the `natpmp` crate is added as a dependency. ```rust use std::str::FromStr; use natpmp::* let n = Natpmp::new("192.168.0.1").parse.unwrap())?; ``` -------------------------------- ### Natpmp::new_with Source: https://context7.com/fengyc/natpmp/llms.txt Creates a synchronous NAT-PMP client with a specified gateway. Useful when the default gateway detection is not suitable or when testing against a specific router. ```APIDOC ## Natpmp::new_with ### Description Constructs a `Natpmp` instance targeting an explicit IPv4 gateway address. Useful when the default gateway detection is not suitable or when testing against a specific router. ### Method Rust struct constructor ### Endpoint N/A (local function) ### Parameters * **gateway** (Ipv4Addr) - Required - The IPv4 address of the gateway to connect to. ### Request Example ```rust use std::net::Ipv4Addr; use natpmp::* fn main() -> Result<()> { let gateway: Ipv4Addr = "192.168.0.1".parse().unwrap(); let mut n = Natpmp::new_with(gateway)?; assert_eq!(n.gateway(), &gateway); println!("NAT-PMP client targeting: {}", n.gateway()); Ok(()) } ``` ### Response #### Success Response A `Natpmp` instance. #### Response Example `Natpmp` instance with the specified gateway. ``` -------------------------------- ### new_tokio_natpmp Source: https://context7.com/fengyc/natpmp/llms.txt Creates an asynchronous NAT-PMP client using the tokio runtime and the system's default gateway. ```APIDOC ## `new_tokio_natpmp` — Create an async NAT-PMP client using tokio (default gateway) ### Description Creates a `NatpmpAsync` using the system's default gateway. Requires the `tokio` feature (enabled by default). The returned client can be wrapped in `Arc` for concurrent send/receive tasks. ### Method `new_tokio_natpmp().await` ### Parameters None ### Response - `Ok(NatpmpAsync)`: An initialized asynchronous NAT-PMP client. ### Request Example ```rust use std::sync::Arc; use std::time::Duration; use natpmp::*; #[tokio::main] async fn main() -> Result<()> { let n = Arc::new(new_tokio_natpmp().await?); println!("Gateway: {}", n.gateway()); let n_sender = n.clone(); tokio::spawn(async move { loop { if let Err(e) = n_sender .send_port_mapping_request(Protocol::UDP, 4020, 4020, 30) .await { eprintln!("Send error: {}", e); break; } tokio::time::sleep(Duration::from_secs(25)).await; // re-register before expiry } }); match n.read_response_or_retry().await? { Response::UDP(ur) => { println!("UDP mapped {} -> {}", ur.private_port(), ur.public_port()); } _ => eprintln!("Unexpected response"), } Ok(()) } ``` ``` -------------------------------- ### new_async_std_natpmp Source: https://context7.com/fengyc/natpmp/llms.txt Creates an asynchronous NAT-PMP client using the async-std runtime and the system's default gateway. ```APIDOC ## `new_async_std_natpmp` — Create an async NAT-PMP client using async-std (default gateway) ### Description Creates a `NatpmpAsync` backed by the `async-std` runtime. Requires enabling the `async-std` feature in `Cargo.toml`. The API is identical to the tokio variant. ### Method `new_async_std_natpmp().await` ### Parameters None ### Response - `Ok(NatpmpAsync)`: An initialized asynchronous NAT-PMP client. ### Request Example ```rust // Requires `async-std` feature enabled for natpmp crate // use std::sync::Arc; // use std::time::Duration; // use natpmp::*; // #[async_std::main] // async fn main() -> Result<()> { // let n = Arc::new(new_async_std_natpmp().await?); // println!("Gateway: {}", n.gateway()); // let n_sender = n.clone(); // async_std::task::spawn(async move { // loop { // if let Err(e) = n_sender // .send_port_mapping_request(Protocol::UDP, 4020, 4020, 30) // .await // { // eprintln!("Send error: {}", e); // break; // } // async_std::task::sleep(Duration::from_secs(25)).await; // re-register before expiry // } // }); // match n.read_response_or_retry().await? { // Response::UDP(ur) => { // println!("UDP mapped {} -> {}", ur.private_port(), ur.public_port()); // } // _ => eprintln!("Unexpected response"), // } // Ok(()) // } ``` ``` -------------------------------- ### Create Synchronous NAT-PMP Client (Specified Gateway) Source: https://context7.com/fengyc/natpmp/llms.txt Constructs a `Natpmp` instance targeting an explicit IPv4 gateway address. Useful for testing or when the default gateway detection is unsuitable. ```rust use std::net::Ipv4Addr; use natpmp::* fn main() -> Result<()> let gateway: Ipv4Addr = "192.168.0.1".parse().unwrap(); let mut n = Natpmp::new_with(gateway)?; assert_eq!(n.gateway(), &gateway); println!("NAT-PMP client targeting: {}", n.gateway()); Ok(()) } ``` -------------------------------- ### new_async_std_natpmp_with Source: https://context7.com/fengyc/natpmp/llms.txt Creates an async async-std NAT-PMP client with a specified gateway address. This function is useful when you need to target a specific gateway on your network. ```APIDOC ## new_async_std_natpmp_with ### Description Async-std equivalent of `new_tokio_natpmp_with`, targeting a specific gateway address. ### Method `new_async_std_natpmp_with(gateway: std::net::IpAddr) -> impl Future>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use natpmp::*; use async_std::task; fn main() -> Result<()> { task::block_on(async { let gateway = "192.168.0.1".parse().unwrap(); let mut n = new_async_std_natpmp_with(gateway).await.unwrap(); n.send_public_address_request().await.unwrap(); match n.read_response_or_retry().await { Ok(Response::Gateway(gr)) => println!("External IP: {}", gr.public_address()), Err(e) => eprintln!("Error: {}", e), _ => {{}} } }); Ok(()) } ``` ### Response #### Success Response (200) `NatpmpAsync` client instance. #### Response Example None ``` -------------------------------- ### Async Port Mapping Request with Tokio Source: https://context7.com/fengyc/natpmp/llms.txt Demonstrates creating and removing TCP port mappings using Tokio. It first removes an existing mapping by setting lifetime to 0, then creates a new mapping with a 120s lifetime and prints the details. ```rust use natpmp::* #[tokio::main] async fn main() -> Result<()> { let n = new_tokio_natpmp().await?; // Remove an existing mapping by setting lifetime to 0 n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 0).await?; let _ = n.read_response_or_retry().await?; // Create a new mapping with 120s lifetime n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 120).await?; match n.read_response_or_retry().await? { Response::TCP(tr) => { println!("TCP: {}:{} lifetime={{:?}}", tr.private_port(), tr.public_port(), tr.lifetime()); } _ => eprintln!("Unexpected response"), } Ok(()) } ``` -------------------------------- ### Basic NAT-PMP Public Address Request Source: https://context7.com/fengyc/natpmp/llms.txt This snippet shows the basic usage of the `natpmp` crate to send a public address request and handle the response or potential errors. It requires a 250ms sleep to allow the gateway to respond. ```rust use natpmp::Natpmp; use natpmp::Result; fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_public_address_request()?; match n.read_response_or_retry() { Ok(r) => println!("Got response: {:?}", r), Err(e) => handle_error(e), // Assuming handle_error is defined elsewhere } Ok(()) } ``` -------------------------------- ### Async Public Address Request with Tokio Source: https://context7.com/fengyc/natpmp/llms.txt Sends an asynchronous request for the gateway's public IP address using Tokio. It prints the public address and epoch, or returns an error if sending fails. ```rust use natpmp::* #[tokio::main] async fn main() -> Result<()> { let mut n = new_tokio_natpmp().await?; n.send_public_address_request().await?; let response = n.read_response_or_retry().await?; if let Response::Gateway(gr) = response { println!("Public address: {}", gr.public_address()); println!("Epoch: {}", gr.epoch()); } Ok(()) } ``` -------------------------------- ### Add Async-Std Feature to Cargo.toml Source: https://github.com/fengyc/natpmp/blob/master/README.md Instructs how to add the `async-std` feature for asynchronous operations using the `natpmp` library. Choose this if you are not using Tokio. ```bash cargo add natpmp --features async-std ``` -------------------------------- ### Async Response Reading with Tokio Source: https://context7.com/fengyc/natpmp/llms.txt Reads a NAT-PMP response asynchronously using Tokio, retrying up to 9 times on receive errors. It handles and prints responses for Gateway, UDP, and TCP mappings. ```rust use natpmp::* #[tokio::main] async fn main() -> Result<()> { let n = new_tokio_natpmp().await?; n.send_public_address_request().await?; match n.read_response_or_retry().await? { Response::Gateway(gr) => { println!("Public IP: {}", gr.public_address()); println!("Uptime epoch: {}s", gr.epoch()); } Response::UDP(ur) => println!("UDP mapping: {} -> {}", ur.private_port(), ur.public_port()), Response::TCP(tr) => println!("TCP mapping: {} -> {}", tr.private_port(), tr.public_port()), } Ok(()) } ``` -------------------------------- ### Add Tokio Feature to Cargo.toml Source: https://github.com/fengyc/natpmp/blob/master/README.md Instructs how to add the `tokio` feature for asynchronous operations using the `natpmp` library. This is the default feature. ```bash cargo add natpmp --features tokio ``` -------------------------------- ### Discover Default IPv4 Gateway Source: https://context7.com/fengyc/natpmp/llms.txt Queries the system's routing table to find the default gateway's IPv4 address. Returns an error if no gateway is found. Useful for manually constructing NAT-PMP client instances. ```rust use natpmp::* fn main() -> Result<()> let gateway = get_default_gateway()?; println!("Default gateway: {}", gateway); // Output: Default gateway: 192.168.1.1 Ok(()) } ``` -------------------------------- ### Handle NAT-PMP Errors Source: https://context7.com/fengyc/natpmp/llms.txt This snippet demonstrates how to match and handle various NAT-PMP specific errors returned by the library functions. It covers protocol-level errors and socket-level failures. ```rust use natpmp::Error; fn handle_error(e: Error) { match e { Error::NATPMP_TRYAGAIN => println!("Not ready, retry later"), Error::NATPMP_ERR_NOPENDINGREQ => println!("No pending request"), Error::NATPMP_ERR_NOGATEWAYSUPPORT => println!("Gateway does not support NAT-PMP"), Error::NATPMP_ERR_NOTAUTHORIZED => println!("Not authorized by gateway"), Error::NATPMP_ERR_NETWORKFAILURE => println!("Network failure at gateway"), Error::NATPMP_ERR_OUTOFRESOURCES => println!("Gateway out of resources"), Error::NATPMP_ERR_CANNOTGETGATEWAY => println!("Cannot detect default gateway"), Error::NATPMP_ERR_SOCKETERROR => println!("Socket creation failed"), Error::NATPMP_ERR_CONNECTERR => println!("Cannot connect to gateway"), Error::NATPMP_ERR_SENDERR => println!("Send failed"), Error::NATPMP_ERR_RECVFROM => println!("Receive failed"), Error::NATPMP_ERR_WRONGPACKETSOURCE => println!("Packet not from gateway"), Error::NATPMP_ERR_UNSUPPORTEDVERSION => println!("Unsupported NAT-PMP version"), Error::NATPMP_ERR_UNSUPPORTEDOPCODE => println!("Unsupported NAT-PMP opcode"), Error::NATPMP_ERR_UNDEFINEDERROR => println!("Undefined server error"), _ => println!("Other error: {}", e), } } ``` -------------------------------- ### Handle NAT-PMP Response Types Source: https://github.com/fengyc/natpmp/blob/master/README.md Pattern matches on the received response to handle different types of NAT-PMP replies, such as Gateway information, UDP mappings, or TCP mappings. ```rust match response { Response::Gateway(gr) => {} Response::UDP(ur) => {} Response::TCP(tr) => {} } ``` -------------------------------- ### Request Port Mapping Source: https://github.com/fengyc/natpmp/blob/master/README.md Sends a request to map a specific internal port to an external port using either UDP or TCP. The third and fourth arguments specify the internal and external ports, respectively, and the last argument is the lease duration in seconds. ```rust n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; ``` -------------------------------- ### Request UDP or TCP Port Mapping Source: https://context7.com/fengyc/natpmp/llms.txt Sends a NAT-PMP port mapping request for UDP or TCP. It maps an internal private port to a desired public port with a specified lifetime. The gateway may assign a different public port than requested. A lifetime of 0 removes the mapping. ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> let mut n = Natpmp::new()?; // Request TCP mapping: internal port 8080 -> external port 8080, 60s lifetime n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 60)?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::TCP(tr) => { println!("Private port: {}", tr.private_port()); // 8080 println!("Public port: {}", tr.public_port()); // may differ println!("Lifetime: {:?}", tr.lifetime()); // Duration { secs: 60, .. } println!("Epoch: {}", tr.epoch()); } _ => eprintln!("Unexpected response type"), } // Request UDP mapping: internal port 4020 -> external port 4020, 30s lifetime n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::UDP(ur) => { println!("UDP private: {}, public: {}", ur.private_port(), ur.public_port()); } _ => eprintln!("Unexpected response type"), } Ok(()) } ``` -------------------------------- ### get_default_gateway Source: https://context7.com/fengyc/natpmp/llms.txt Queries the system's routing table to find the default gateway's IPv4 address. Returns `Error::NATPMP_ERR_CANNOTGETGATEWAY` if no gateway is found. Useful as a building block when constructing a `Natpmp` or `NatpmpAsync` instance manually. ```APIDOC ## get_default_gateway ### Description Queries the system's routing table to find the default gateway's IPv4 address. Returns `Error::NATPMP_ERR_CANNOTGETGATEWAY` if no gateway is found. Useful as a building block when constructing a `Natpmp` or `NatpmpAsync` instance manually. ### Method Rust function call ### Endpoint N/A (local function) ### Parameters None ### Request Example ```rust use natpmp::* fn main() -> Result<()> { let gateway = get_default_gateway()?; println!("Default gateway: {}", gateway); // Output: Default gateway: 192.168.1.1 Ok(()) } ``` ### Response #### Success Response An `Ipv4Addr` representing the default gateway. #### Response Example `192.168.1.1` ``` -------------------------------- ### Request Public Address Source: https://github.com/fengyc/natpmp/blob/master/README.md Sends a request to the NAT device to determine the external IP address. This should be called after initializing the Natpmp object. ```rust n.send_public_address_request()?; ``` -------------------------------- ### NatpmpAsync::send_port_mapping_request Source: https://context7.com/fengyc/natpmp/llms.txt Asynchronously requests a port mapping on the gateway. This method is the async version of the synchronous port mapping request and has identical signature and semantics. ```APIDOC ## NatpmpAsync::send_port_mapping_request ### Description Async counterpart to the synchronous port mapping request. Encodes the NAT-PMP packet and sends it to the connected gateway socket. The method signature and semantics are identical to the sync version. ### Method `send_port_mapping_request(&mut self, protocol: Protocol, private_port: u16, public_port: u16, lifetime: u32) -> impl Future>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use natpmp::*; #[tokio::main] async fn main() -> Result<()> { let n = new_tokio_natpmp().await?; // Remove an existing mapping by setting lifetime to 0 n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 0).await?; let _ = n.read_response_or_retry().await?; // Create a new mapping with 120s lifetime n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 120).await?; match n.read_response_or_retry().await? { Response::TCP(tr) => { println!("TCP: {}:{} lifetime={{:?}}", tr.private_port(), tr.public_port(), tr.lifetime()); } _ => eprintln!("Unexpected response") } Ok(()) } ``` ### Response #### Success Response (200) `Ok(())` on successful send. #### Response Example None ``` -------------------------------- ### Read NAT-PMP Response with Retry Source: https://context7.com/fengyc/natpmp/llms.txt Polls for a NAT-PMP response, automatically retrying with exponential backoff if no response is immediately available. Handles UDP port mapping responses and other errors. ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; // Poll manually or sleep then read thread::sleep(Duration::from_millis(250)); loop { match n.read_response_or_retry() { Ok(Response::UDP(ur)) => { println!("Mapped {} -> {}", ur.private_port(), ur.public_port()); break; } Err(Error::NATPMP_TRYAGAIN) => { // Not ready yet; the library has already retransmitted thread::sleep(Duration::from_millis(50)); } Err(e) => return Err(e), _ => eprintln!("Unexpected response"), } } Ok(()) } ``` -------------------------------- ### Request Gateway's Public IP Address Source: https://context7.com/fengyc/natpmp/llms.txt Sends a NAT-PMP public address request to the gateway. The response is retrieved using `read_response_or_retry`. On success, it contains the external IPv4 address and epoch time. ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> let mut n = Natpmp::new()?; n.send_public_address_request()?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::Gateway(gr) => { println!("Public IP: {}", gr.public_address()); println!("Seconds since epoch: {}", gr.epoch()); // Output: Public IP: 203.0.113.42 } _ => eprintln!("Unexpected response type"), } Ok(()) } ``` -------------------------------- ### NatpmpAsync::send_public_address_request Source: https://context7.com/fengyc/natpmp/llms.txt Asynchronously requests the gateway's public IP address. This is the async counterpart to the synchronous version and sends a NAT-PMP opcode-0 packet. ```APIDOC ## NatpmpAsync::send_public_address_request ### Description Async counterpart to `Natpmp::send_public_address_request`. Sends a NAT-PMP opcode-0 packet to the gateway's UDP port 5351. Returns `Error::NATPMP_ERR_SENDERR` on failure. ### Method `send_public_address_request(&mut self) -> impl Future>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use natpmp::*; #[tokio::main] async fn main() -> Result<()> { let mut n = new_tokio_natpmp().await?; n.send_public_address_request().await?; let response = n.read_response_or_retry().await?; if let Response::Gateway(gr) = response { println!("Public address: {}", gr.public_address()); println!("Epoch: {}", gr.epoch()); } Ok(()) } ``` ### Response #### Success Response (200) `Ok(())` on successful send. #### Response Example None ``` -------------------------------- ### Natpmp::send_port_mapping_request Source: https://context7.com/fengyc/natpmp/llms.txt Sends a NAT-PMP port mapping request for the given protocol (`Protocol::UDP` or `Protocol::TCP`), mapping an internal private port to a desired public port for a specified lifetime in seconds. A lifetime of `0` removes the mapping. The gateway may assign a different public port than requested. ```APIDOC ## Natpmp::send_port_mapping_request ### Description Sends a NAT-PMP port mapping request for the given protocol (`Protocol::UDP` or `Protocol::TCP`), mapping an internal private port to a desired public port for a specified lifetime in seconds. A lifetime of `0` removes the mapping. The gateway may assign a different public port than requested. ### Method Rust method call ### Endpoint N/A (local function) ### Parameters * **protocol** (Protocol) - Required - The protocol for the mapping (`Protocol::UDP` or `Protocol::TCP`). * **private_port** (u16) - Required - The internal private port to map. * **public_port** (u16) - Required - The desired external public port. * **lifetime** (u32) - Required - The lifetime of the mapping in seconds. `0` removes the mapping. ### Request Example ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> { let mut n = Natpmp::new()?; // Request TCP mapping: internal port 8080 -> external port 8080, 60s lifetime n.send_port_mapping_request(Protocol::TCP, 8080, 8080, 60)?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::TCP(tr) => { println!("Private port: {}", tr.private_port()); // 8080 println!("Public port: {}", tr.public_port()); // may differ println!("Lifetime: {:?}", tr.lifetime()); // Duration { secs: 60, .. } println!("Epoch: {}", tr.epoch()); } _ => eprintln!("Unexpected response type"), } // Request UDP mapping: internal port 4020 -> external port 4020, 30s lifetime n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::UDP(ur) => { println!("UDP private: {}, public: {}", ur.private_port(), ur.public_port()); } _ => eprintln!("Unexpected response type"), } Ok(()) } ``` ### Response #### Success Response `Response::TCP(TcpMappingResponse)` or `Response::UDP(UdpMappingResponse)` containing details of the established mapping. #### Response Example `Response::TCP(TcpMappingResponse { private_port: u16, public_port: u16, lifetime: Duration, epoch: u32 })` ``` -------------------------------- ### Natpmp::read_response_or_retry Source: https://context7.com/fengyc/natpmp/llms.txt Attempts to read a response from the gateway for a previously sent request. Implements RFC 6886 exponential backoff for retries. ```APIDOC ## `Natpmp::read_response_or_retry` — Read a pending NAT-PMP response with automatic retry ### Description Attempts to read a response from the gateway for a previously sent request. Implements RFC 6886 exponential backoff: if no response is available (`NATPMP_TRYAGAIN`), retransmits using doubling delays (250ms, 500ms, 1s, …) for up to 9 attempts. Returns `Error::NATPMP_ERR_NOGATEWAYSUPPORT` after exhausting all retries. ### Method `Natpmp::read_response_or_retry()` ### Parameters None ### Response - `Ok(Response)`: A successful NAT-PMP response. - `Err(Error::NATPMP_TRYAGAIN)`: No response available, retry is handled internally with backoff. - `Err(Error::NATPMP_ERR_NOGATEWAYSUPPORT)`: All retries exhausted without a response. ### Request Example ```rust use std::thread; use std::time::Duration; use natpmp::*; fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_port_mapping_request(Protocol::UDP, 4020, 4020, 30)?; // Poll manually or sleep then read thread::sleep(Duration::from_millis(250)); loop { match n.read_response_or_retry() { Ok(Response::UDP(ur)) => { println!("Mapped {} -> {}", ur.private_port(), ur.public_port()); break; } Err(Error::NATPMP_TRYAGAIN) => { // Not ready yet; the library has already retransmitted thread::sleep(Duration::from_millis(50)); } Err(e) => return Err(e), _ => eprintln!("Unexpected response"), } } Ok(()) } ``` ``` -------------------------------- ### Read NAT-PMP Response Source: https://github.com/fengyc/natpmp/blob/master/README.md Reads the response from the NAT device after sending a request. Includes a small delay to allow the response to arrive. This function will retry if no response is immediately available. ```rust use std::thread; use std::time::Duration; thread::sleep(Duration::from_millis(250)); let response = n.read_response_or_retry()?; ``` -------------------------------- ### Process NAT-PMP Responses Source: https://context7.com/fengyc/natpmp/llms.txt This function processes different types of NAT-PMP responses, including gateway information, UDP port mappings, and TCP port mappings. It extracts relevant details like public IP, ports, lifetime, and epoch. ```rust use natpmp::Response; fn print_response(r: Response) { match r { Response::Gateway(gr) => { println!("[Gateway] public_address={}, epoch={}s", gr.public_address(), gr.epoch()); } Response::UDP(ur) => { println!("[UDP] private={}, public={}, lifetime={{:?}}, epoch={{}}s", ur.private_port(), ur.public_port(), ur.lifetime(), ur.epoch()); } Response::TCP(tr) => { println!("[TCP] private={}, public={}, lifetime={{:?}}, epoch={{}}s", tr.private_port(), tr.public_port(), tr.lifetime(), tr.epoch()); } } } ``` -------------------------------- ### NatpmpAsync::read_response_or_retry Source: https://context7.com/fengyc/natpmp/llms.txt Asynchronously reads a NAT-PMP response from the gateway socket. This method retries up to 9 times on receive errors before returning an error, and parses the received bytes into a typed `Response`. ```APIDOC ## NatpmpAsync::read_response_or_retry ### Description Awaits a response from the gateway socket. Unlike the sync version which uses time-based backoff, the async version retries up to `NATPMP_MAX_ATTEMPS` (9) times on receive errors before returning `Error::NATPMP_ERR_RECVFROM`. Parses the raw bytes into a typed `Response`. ### Method `read_response_or_retry(&self) -> impl Future>` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use natpmp::*; #[tokio::main] async fn main() -> Result<()> { let n = new_tokio_natpmp().await?; n.send_public_address_request().await?; match n.read_response_or_retry().await? { Response::Gateway(gr) => { println!("Public IP: {}", gr.public_address()); println!("Uptime epoch: {}s", gr.epoch()); } Response::UDP(ur) => println!("UDP mapping: {} -> {}", ur.private_port(), ur.public_port()), Response::TCP(tr) => println!("TCP mapping: {} -> {}", tr.private_port(), tr.public_port()), } Ok(()) } ``` ### Response #### Success Response (200) `Response` enum containing the parsed NAT-PMP response (e.g., `Response::Gateway`, `Response::UDP`, `Response::TCP`). #### Response Example None ``` -------------------------------- ### Natpmp::send_public_address_request Source: https://context7.com/fengyc/natpmp/llms.txt Sends a NAT-PMP public address request packet to the gateway. The response is retrieved later by calling `read_response_or_retry`. On success, the response will be `Response::Gateway(GatewayResponse)` containing the external IPv4 address. ```APIDOC ## Natpmp::send_public_address_request ### Description Sends a NAT-PMP public address request packet to the gateway. The response is retrieved later by calling `read_response_or_retry`. On success, the response will be `Response::Gateway(GatewayResponse)` containing the external IPv4 address. ### Method Rust method call ### Endpoint N/A (local function) ### Parameters None ### Request Example ```rust use std::thread; use std::time::Duration; use natpmp::* fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_public_address_request()?; thread::sleep(Duration::from_millis(250)); match n.read_response_or_retry()? { Response::Gateway(gr) => { println!("Public IP: {}", gr.public_address()); println!("Seconds since epoch: {}", gr.epoch()); // Output: Public IP: 203.0.113.42 } _ => eprintln!("Unexpected response type"), } Ok(()) } ``` ### Response #### Success Response `Response::Gateway(GatewayResponse)` containing the public IP address and epoch. #### Response Example `Response::Gateway(GatewayResponse { public_address: Ipv4Addr, epoch: u32 })` ``` -------------------------------- ### Natpmp::get_natpmp_request_timeout Source: https://context7.com/fengyc/natpmp/llms.txt Returns the Duration until the current pending request is due for its next retransmission attempt. Useful for integrating into select/poll loops. ```APIDOC ## `Natpmp::get_natpmp_request_timeout` — Get time remaining until the next retry ### Description Returns the `Duration` until the current pending request is due for its next retransmission attempt. Returns `Duration::ZERO` if the retry time has already passed, and `Error::NATPMP_ERR_NOPENDINGREQ` if no request is in flight. Useful for integrating into select/poll loops. ### Method `Natpmp::get_natpmp_request_timeout()` ### Parameters None ### Response - `Ok(Duration)`: The time remaining until the next retry. - `Err(Error::NATPMP_ERR_NOPENDINGREQ)`: No request is currently in flight. ### Request Example ```rust use std::thread; use std::time::Duration; use natpmp::*; fn main() -> Result<()> { let mut n = Natpmp::new()?; n.send_public_address_request()?; loop { let timeout = n.get_natpmp_request_timeout()?; if timeout <= Duration::from_millis(10) { match n.read_response_or_retry() { Ok(Response::Gateway(gr)) => { println!("Public IP: {}", gr.public_address()); break; } Err(Error::NATPMP_TRYAGAIN) => {} // Retry handled by read_response_or_retry Err(e) => return Err(e), _ => {} // Ignore other unexpected responses for this example } } else { thread::sleep(Duration::from_millis(10)); } } Ok(()) } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.