github.com/pion/webrtc/v4@v4.0.1/examples/vnet/show-network-usage/main.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !js
     5  // +build !js
     6  
     7  // show-network-usage shows the amount of packets flowing through the vnet
     8  package main
     9  
    10  import (
    11  	"fmt"
    12  	"log"
    13  	"net"
    14  	"os"
    15  	"sync/atomic"
    16  	"time"
    17  
    18  	"github.com/pion/logging"
    19  	"github.com/pion/transport/v3/vnet"
    20  	"github.com/pion/webrtc/v4"
    21  )
    22  
    23  /* VNet Configuration
    24  + - - - - - - - - - - - - - - - - - - - - - - - +
    25                        VNet
    26  | +-------------------------------------------+ |
    27    |              wan:vnet.Router              |
    28  | +---------+----------------------+----------+ |
    29              |                      |
    30  | +---------+----------+ +---------+----------+ |
    31    | offerVNet:vnet.Net | |answerVNet:vnet.Net |
    32  | +---------+----------+ +---------+----------+ |
    33              |                      |
    34  + - - - - - + - - - - - - - - - - -+- - - - - - +
    35              |                      |
    36    +---------+----------+ +---------+----------+
    37    |offerPeerConnection | |answerPeerConnection|
    38    +--------------------+ +--------------------+
    39  */
    40  
    41  func main() {
    42  	var inboundBytes int32  // for offerPeerConnection
    43  	var outboundBytes int32 // for offerPeerConnection
    44  
    45  	// Create a root router
    46  	wan, err := vnet.NewRouter(&vnet.RouterConfig{
    47  		CIDR:          "1.2.3.0/24",
    48  		LoggerFactory: logging.NewDefaultLoggerFactory(),
    49  	})
    50  	panicIfError(err)
    51  
    52  	// Add a filter that monitors the traffic on the router
    53  	wan.AddChunkFilter(func(c vnet.Chunk) bool {
    54  		netType := c.SourceAddr().Network()
    55  		if netType == "udp" {
    56  			dstAddr := c.DestinationAddr().String()
    57  			host, _, err2 := net.SplitHostPort(dstAddr)
    58  			panicIfError(err2)
    59  			if host == "1.2.3.4" {
    60  				// c.UserData() returns a []byte of UDP payload
    61  				atomic.AddInt32(&inboundBytes, int32(len(c.UserData())))
    62  			}
    63  			srcAddr := c.SourceAddr().String()
    64  			host, _, err2 = net.SplitHostPort(srcAddr)
    65  			panicIfError(err2)
    66  			if host == "1.2.3.4" {
    67  				// c.UserData() returns a []byte of UDP payload
    68  				atomic.AddInt32(&outboundBytes, int32(len(c.UserData())))
    69  			}
    70  		}
    71  		return true
    72  	})
    73  
    74  	// Log throughput every 3 seconds
    75  	go func() {
    76  		duration := 2 * time.Second
    77  		for {
    78  			time.Sleep(duration)
    79  
    80  			inBytes := atomic.SwapInt32(&inboundBytes, 0)   // read & reset
    81  			outBytes := atomic.SwapInt32(&outboundBytes, 0) // read & reset
    82  			inboundThroughput := float64(inBytes) / duration.Seconds()
    83  			outboundThroughput := float64(outBytes) / duration.Seconds()
    84  			log.Printf("inbound throughput : %.01f [Byte/s]\n", inboundThroughput)
    85  			log.Printf("outbound throughput: %.01f [Byte/s]\n", outboundThroughput)
    86  		}
    87  	}()
    88  
    89  	// Create a network interface for offerer
    90  	offerVNet, err := vnet.NewNet(&vnet.NetConfig{
    91  		StaticIPs: []string{"1.2.3.4"},
    92  	})
    93  	panicIfError(err)
    94  
    95  	// Add the network interface to the router
    96  	panicIfError(wan.AddNet(offerVNet))
    97  
    98  	offerSettingEngine := webrtc.SettingEngine{}
    99  	offerSettingEngine.SetNet(offerVNet)
   100  	offerAPI := webrtc.NewAPI(webrtc.WithSettingEngine(offerSettingEngine))
   101  
   102  	// Create a network interface for answerer
   103  	answerVNet, err := vnet.NewNet(&vnet.NetConfig{
   104  		StaticIPs: []string{"1.2.3.5"},
   105  	})
   106  	panicIfError(err)
   107  
   108  	// Add the network interface to the router
   109  	panicIfError(wan.AddNet(answerVNet))
   110  
   111  	answerSettingEngine := webrtc.SettingEngine{}
   112  	answerSettingEngine.SetNet(answerVNet)
   113  	answerAPI := webrtc.NewAPI(webrtc.WithSettingEngine(answerSettingEngine))
   114  
   115  	// Start the virtual network by calling Start() on the root router
   116  	panicIfError(wan.Start())
   117  
   118  	offerPeerConnection, err := offerAPI.NewPeerConnection(webrtc.Configuration{})
   119  	panicIfError(err)
   120  	defer func() {
   121  		if cErr := offerPeerConnection.Close(); cErr != nil {
   122  			fmt.Printf("cannot close offerPeerConnection: %v\n", cErr)
   123  		}
   124  	}()
   125  
   126  	answerPeerConnection, err := answerAPI.NewPeerConnection(webrtc.Configuration{})
   127  	panicIfError(err)
   128  	defer func() {
   129  		if cErr := answerPeerConnection.Close(); cErr != nil {
   130  			fmt.Printf("cannot close answerPeerConnection: %v\n", cErr)
   131  		}
   132  	}()
   133  
   134  	// Set the handler for Peer connection state
   135  	// This will notify you when the peer has connected/disconnected
   136  	offerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
   137  		fmt.Printf("Peer Connection State has changed: %s (offerer)\n", s.String())
   138  
   139  		if s == webrtc.PeerConnectionStateFailed {
   140  			// Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart.
   141  			// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
   142  			// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
   143  			fmt.Println("Peer Connection has gone to failed exiting")
   144  			os.Exit(0)
   145  		}
   146  
   147  		if s == webrtc.PeerConnectionStateClosed {
   148  			// PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify
   149  			fmt.Println("Peer Connection has gone to closed exiting")
   150  			os.Exit(0)
   151  		}
   152  	})
   153  
   154  	// Set the handler for Peer connection state
   155  	// This will notify you when the peer has connected/disconnected
   156  	answerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
   157  		fmt.Printf("Peer Connection State has changed: %s (answerer)\n", s.String())
   158  
   159  		if s == webrtc.PeerConnectionStateFailed {
   160  			// Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart.
   161  			// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
   162  			// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
   163  			fmt.Println("Peer Connection has gone to failed exiting")
   164  			os.Exit(0)
   165  		}
   166  
   167  		if s == webrtc.PeerConnectionStateClosed {
   168  			// PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify
   169  			fmt.Println("Peer Connection has gone to closed exiting")
   170  			os.Exit(0)
   171  		}
   172  	})
   173  
   174  	// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
   175  	// send it to the other peer
   176  	answerPeerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
   177  		if i != nil {
   178  			panicIfError(offerPeerConnection.AddICECandidate(i.ToJSON()))
   179  		}
   180  	})
   181  
   182  	// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
   183  	// send it to the other peer
   184  	offerPeerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
   185  		if i != nil {
   186  			panicIfError(answerPeerConnection.AddICECandidate(i.ToJSON()))
   187  		}
   188  	})
   189  
   190  	offerDataChannel, err := offerPeerConnection.CreateDataChannel("label", nil)
   191  	panicIfError(err)
   192  
   193  	msgSendLoop := func(dc *webrtc.DataChannel, interval time.Duration) {
   194  		for {
   195  			time.Sleep(interval)
   196  			panicIfError(dc.SendText("My DataChannel Message"))
   197  		}
   198  	}
   199  
   200  	offerDataChannel.OnOpen(func() {
   201  		// Send test from offerer every 100 msec
   202  		msgSendLoop(offerDataChannel, 100*time.Millisecond)
   203  	})
   204  
   205  	answerPeerConnection.OnDataChannel(func(answerDataChannel *webrtc.DataChannel) {
   206  		answerDataChannel.OnOpen(func() {
   207  			// Send test from answerer every 200 msec
   208  			msgSendLoop(answerDataChannel, 200*time.Millisecond)
   209  		})
   210  	})
   211  
   212  	offer, err := offerPeerConnection.CreateOffer(nil)
   213  	panicIfError(err)
   214  	panicIfError(offerPeerConnection.SetLocalDescription(offer))
   215  	panicIfError(answerPeerConnection.SetRemoteDescription(offer))
   216  
   217  	answer, err := answerPeerConnection.CreateAnswer(nil)
   218  	panicIfError(err)
   219  	panicIfError(answerPeerConnection.SetLocalDescription(answer))
   220  	panicIfError(offerPeerConnection.SetRemoteDescription(answer))
   221  
   222  	// Block forever
   223  	select {}
   224  }
   225  
   226  func panicIfError(err error) {
   227  	if err != nil {
   228  		panic(err)
   229  	}
   230  }