upnp_example/main.rs
1// Copyright 2023 Protocol Labs.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21#![doc = include_str!("../README.md")]
22
23use std::error::Error;
24
25use futures::prelude::*;
26use libp2p::{noise, swarm::SwarmEvent, upnp, yamux, Multiaddr};
27use tracing_subscriber::EnvFilter;
28
29#[tokio::main]
30async fn main() -> Result<(), Box<dyn Error>> {
31 let _ = tracing_subscriber::fmt()
32 .with_env_filter(EnvFilter::from_default_env())
33 .try_init();
34
35 let mut swarm = libp2p::SwarmBuilder::with_new_identity()
36 .with_tokio()
37 .with_tcp(
38 Default::default(),
39 noise::Config::new,
40 yamux::Config::default,
41 )?
42 .with_behaviour(|_| upnp::tokio::Behaviour::default())?
43 .build();
44
45 // Tell the swarm to listen on all interfaces and a random, OS-assigned
46 // port.
47 swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
48
49 // Dial the peer identified by the multi-address given as the second
50 // command-line argument, if any.
51 if let Some(addr) = std::env::args().nth(1) {
52 let remote: Multiaddr = addr.parse()?;
53 swarm.dial(remote)?;
54 println!("Dialed {addr}")
55 }
56
57 loop {
58 match swarm.select_next_some().await {
59 SwarmEvent::NewListenAddr { address, .. } => println!("Listening on {address:?}"),
60 SwarmEvent::Behaviour(upnp::Event::NewExternalAddr(addr)) => {
61 println!("New external address: {addr}");
62 }
63 SwarmEvent::Behaviour(upnp::Event::GatewayNotFound) => {
64 println!("Gateway does not support UPnP");
65 break;
66 }
67 SwarmEvent::Behaviour(upnp::Event::NonRoutableGateway) => {
68 println!("Gateway is not exposed directly to the public Internet, i.e. it itself has a private IP address.");
69 break;
70 }
71 _ => {}
72 }
73 }
74 Ok(())
75}