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 }