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 }