github.com/pion/webrtc/v3@v3.2.24/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/v2/vnet"
    20  	"github.com/pion/webrtc/v3"
    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.SetVNet(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.SetVNet(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  
   148  	// Set the handler for Peer connection state
   149  	// This will notify you when the peer has connected/disconnected
   150  	answerPeerConnection.OnConnectionStateChange(func(s webrtc.PeerConnectionState) {
   151  		fmt.Printf("Peer Connection State has changed: %s (answerer)\n", s.String())
   152  
   153  		if s == webrtc.PeerConnectionStateFailed {
   154  			// Wait until PeerConnection has had no network activity for 30 seconds or another failure. It may be reconnected using an ICE Restart.
   155  			// Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout.
   156  			// Note that the PeerConnection may come back from PeerConnectionStateDisconnected.
   157  			fmt.Println("Peer Connection has gone to failed exiting")
   158  			os.Exit(0)
   159  		}
   160  	})
   161  
   162  	// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
   163  	// send it to the other peer
   164  	answerPeerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
   165  		if i != nil {
   166  			panicIfError(offerPeerConnection.AddICECandidate(i.ToJSON()))
   167  		}
   168  	})
   169  
   170  	// Set ICE Candidate handler. As soon as a PeerConnection has gathered a candidate
   171  	// send it to the other peer
   172  	offerPeerConnection.OnICECandidate(func(i *webrtc.ICECandidate) {
   173  		if i != nil {
   174  			panicIfError(answerPeerConnection.AddICECandidate(i.ToJSON()))
   175  		}
   176  	})
   177  
   178  	offerDataChannel, err := offerPeerConnection.CreateDataChannel("label", nil)
   179  	panicIfError(err)
   180  
   181  	msgSendLoop := func(dc *webrtc.DataChannel, interval time.Duration) {
   182  		for {
   183  			time.Sleep(interval)
   184  			panicIfError(dc.SendText("My DataChannel Message"))
   185  		}
   186  	}
   187  
   188  	offerDataChannel.OnOpen(func() {
   189  		// Send test from offerer every 100 msec
   190  		msgSendLoop(offerDataChannel, 100*time.Millisecond)
   191  	})
   192  
   193  	answerPeerConnection.OnDataChannel(func(answerDataChannel *webrtc.DataChannel) {
   194  		answerDataChannel.OnOpen(func() {
   195  			// Send test from answerer every 200 msec
   196  			msgSendLoop(answerDataChannel, 200*time.Millisecond)
   197  		})
   198  	})
   199  
   200  	offer, err := offerPeerConnection.CreateOffer(nil)
   201  	panicIfError(err)
   202  	panicIfError(offerPeerConnection.SetLocalDescription(offer))
   203  	panicIfError(answerPeerConnection.SetRemoteDescription(offer))
   204  
   205  	answer, err := answerPeerConnection.CreateAnswer(nil)
   206  	panicIfError(err)
   207  	panicIfError(answerPeerConnection.SetLocalDescription(answer))
   208  	panicIfError(offerPeerConnection.SetRemoteDescription(answer))
   209  
   210  	// Block forever
   211  	select {}
   212  }
   213  
   214  func panicIfError(err error) {
   215  	if err != nil {
   216  		panic(err)
   217  	}
   218  }