STUN/TURN server connectivity test

2020-01-29 04:56发布

问题:

I am trying to figure out how to test whether a STUN/TURN server is alive and properly responding to connections. Ideally this test would be performed from an external machine, just in case the STUN/TURN machine is down for this case should also be reported by the connectivity test.

Has anyone looked into this case in the past? What solutions would be recommended?

回答1:

Edit: A nice implementation in github.io taken from comment to another answer( choose "relay" in IceTransports value):

Test TURN Server


following Benjamin Trent's advice, I wrote the below code to test TURN server's connectivity, works on both firefox n chrome:

function checkTURNServer(turnConfig, timeout){ 

  return new Promise(function(resolve, reject){

    setTimeout(function(){
        if(promiseResolved) return;
        resolve(false);
        promiseResolved = true;
    }, timeout || 5000);

    var promiseResolved = false
      , myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection   //compatibility for firefox and chrome
      , pc = new myPeerConnection({iceServers:[turnConfig]})
      , noop = function(){};
    pc.createDataChannel("");    //create a bogus data channel
    pc.createOffer(function(sdp){
      if(sdp.sdp.indexOf('typ relay') > -1){ // sometimes sdp contains the ice candidates...
        promiseResolved = true;
        resolve(true);
      }
      pc.setLocalDescription(sdp, noop, noop);
    }, noop);    // create offer and set local description
    pc.onicecandidate = function(ice){  //listen for candidate events
      if(promiseResolved || !ice || !ice.candidate || !ice.candidate.candidate || !(ice.candidate.candidate.indexOf('typ relay')>-1))  return;
      promiseResolved = true;
      resolve(true);
    };
  });   
}

example usage:

checkTURNServer({
    url: 'turn:127.0.0.1',
    username: 'test',
    credential: 'test'
}).then(function(bool){
    console.log('is TURN server active? ', bool? 'yes':'no');
}).catch(console.error.bind(console));

You can run the below snippet to check:

var res = id('result');

id('button').onclick = function(){
	res.innerHTML = 'Checking TURN Server...';
  var url = 'turn:'+id('url').value+':'+id('port').value,
  		useUDP = id('udp').checked;
  url +='?transport=' + (useUDP ? 'udp': 'tcp');
  checkTURNServer({
      urls: url,
      username: id('name').value, 
      credential: id('pass').value
  }, id('time').value).then(function(bool){
  		if(bool)
         res.innerHTML = 'Yep, the TURN server works...';
      else
         throw new Error('Doesn\'t work');
  }).catch(function(e){
  	 console.log(e);
     res.innerHTML = 'TURN server does not work.';
  });
};


function checkTURNServer(turnConfig, timeout){ 
	console.log('turnConfig: ', turnConfig);
  return new Promise(function(resolve, reject){

    setTimeout(function(){
        if(promiseResolved) return;
        resolve(false);
        promiseResolved = true;
    }, timeout || 5000);

    var promiseResolved = false
      , myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection   //compatibility for firefox and chrome
      , pc = new myPeerConnection({iceServers:[turnConfig]})
      , noop = function(){};
    pc.createDataChannel("");    //create a bogus data channel
    pc.createOffer(function(sdp){
      if(sdp.sdp.indexOf('typ relay') > -1){ // sometimes sdp contains the ice candidates...
        promiseResolved = true;
        resolve(true);
      }
      pc.setLocalDescription(sdp, noop, noop);
    }, noop);    // create offer and set local description
    pc.onicecandidate = function(ice){  //listen for candidate events
      if(promiseResolved || !ice || !ice.candidate || !ice.candidate.candidate || !(ice.candidate.candidate.indexOf('typ relay')>-1))  return;
      promiseResolved = true;
      resolve(true);
    };
  });   
}


function id(val){
	return document.getElementById(val);
}
#url{
  width: 250px;
}
#port{
  width: 70px;
}
<h1>
 Test TURN server
</h1>
<div>
TURN URL: <input id='url' placeholder='example.com  or  xxx.yyy.rrr.ddd'  />
Port: <input type='number' value='3478' id='port' placeholder='enter a port number' />
</div>
<div>
Transport: <input type="radio" name="transport" id="tcp" value="tcp" /> TCP
<input type="radio" name="transport" id="udp" value="udp" checked/>UDP
</div>

<div>
Username: <input id="name" placeholder="turn username" />
</div>
<div>
password: <input id="pass" placeholder="turn password" />
</div>

<div>
checking Timeout: <input type='number'  id="time" placeholder="wait time  before checking timeout" value=5000 />
</div>
<div>
<button id='button'>
Check TURN Server
</button>
</div>

<h4 id='result'></h4>



回答2:

You can test your servers here...

https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/



回答3:

Test your TURN and STUN servers here



回答4:

You could set up a 3rd party monitoring service (we use Monitis) or even your own machine to PING the server every minute from 1 or more locations. However this will only tell you if the server is reachable and not necessarily if the TURN/STUN application server still accepts & responds to TURN/STUN packets.

A server side monitoring library for STUN/TURN would make a great GitHub project.



回答5:

Version of @mido function to check the TURN and the STUN server both (original rejects stun-servers):

function checkTurnOrStun(turnConfig, timeout){ 
  return new Promise(function(resolve, reject){

    setTimeout(function(){
        if(promiseResolved){
            if (promiseResolved == 'STUN') resolve('STUN');
            return;
        }
        resolve(false);
        promiseResolved = true;
    }, timeout || 5000);

    var promiseResolved = false
      , myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection   //compatibility for firefox and chrome
      , pc = new myPeerConnection({iceServers:[turnConfig]})
      , noop = function(){};
    pc.createDataChannel("");    //create a bogus data channel
    pc.createOffer(function(sdp){
      if(sdp.sdp.indexOf('typ relay') > -1){ // sometimes sdp contains the ice candidates...
        promiseResolved = 'TURN'; 
        resolve(true);
      }
      pc.setLocalDescription(sdp, noop, noop);
    }, noop);    // create offer and set local description
    pc.onicecandidate = function(ice){  //listen for candidate events
      if( !ice || !ice.candidate || !ice.candidate.candidate)  return;
      if (ice.candidate.candidate.indexOf('typ relay')!=-1) { promiseResolved = 'TURN'; resolve('TURN'); }
      else if (!promiseResolved && (ice.candidate.candidate.indexOf('typ prflx')!=-1 || ice.candidate.candidate.indexOf('typ srflx')!=-1)){
          promiseResolved = 'STUN';
        if (turnConfig.url.indexOf('turn:')!==0) resolve('STUN');
      }
      else return;
    };
  });   
}

checkTurnOrStun({"url": "stun:stunserver.org"}).then(function(result){
    console.log(
    result ? 'YES, Server active as '+result : 'NO, server not active');
}).catch(console.error.bind(console));

checkTurnOrStun({
            url: 'turn:numb.viagenie.ca',
            credential: 'muazkh',
            username: 'webrtc@live.com'
}).then(function(result){
    console.log(
    result ? 'YES, Server active as '+result : 'NO, server not active');
}).catch(console.error.bind(console));


回答6:

If you are open for a commercial tool for high load testing of turn servers like 100,000 virtual users or 1 million virtual users, you may like to check Load Multiplier tool (www.loadmultiplier.com). Also a specific page how to test coturn server is covered here.

Please note that either Load Multiplier tool will simulate a dummy signalling plane (to exchange the SDP between clients). And you can test STUN, TURN and ICE with SRTP / DTLS media.



回答7:

If you want to check the stun server constantly you can execute this command with cron :

stunserver=stun1.l.google.com;stunport=19302;listenport=20000;echo -ne "\x00\x01\x00\x00YOGO\x59\x4f\x47\x4fSTACFLOW" | nc -u -p $listenport $stunserver $stunport -w 0;timeout 1 nc -l -u $listenport | head -c 32 | tail -c 4 | hexdump -e '/1 "%u" "."' | grep -o ".*[^.]" && echo yes-no-problem || mail -s "Error in Tun server:$stunserver:$stunport" root@localhost <<< 'Error in Tun server'

Replace root@localhost with your email to get the report.

stunserver=stun1.l.google.com;
stunport=19302;
listenport=20000; # Change freely this port if not available

Add it to cron and execute it every minute.



标签: webrtc stun turn