webRTC Coturn server return null iceCandidate? - webrtc

I installed coturn server on an Ubuntu VPS for testing purposes, the testing of the coturn server on Trickle ICE looks great and everything is fine, but when I try to make a connection it returns null iceCandidate when peers are from different networks and it works fine when peers are in the same local network.
This is my Trickle ICE test results:
This is what I get when console logging the iceCandidate:
And this is my iceservers:
const iceServers = {
iceServer: [
{
urls: "stun:stun.biodietfood.com:3478",
},
{
urls: "turn:turn.biodietfood.com:3478?transport=tcp",
username: "myuser",
credential: "mypassword",
},
],
};
And this is my code to make peer connection and sending an offer:
rtcPeerConnection = new RTCPeerConnection(); //create peer connection
rtcPeerConnection.setConfiguration(iceServers);
rtcPeerConnection.onicecandidate = onIceCandidate; //generate ice candidate
rtcPeerConnection.onicecandidateerror = iceCandidateError;
rtcPeerConnection.ontrack = onAddStream; // generate the remote stream to send to other user
rtcPeerConnection.addTrack(localStream.getTracks()[0], localStream); // adding video
rtcPeerConnection.addTrack(localStream.getTracks()[1], localStream); // adding audio
rtcPeerConnection // creating offer
.createOffer({ iceRestart: true })
.then((sessionDescription) => {
rtcPeerConnection.setLocalDescription(sessionDescription);
socket.emit("offer", {
type: "offer",
sdp: sessionDescription,
room: roomNumber,
});
})
.catch((err) => {
console.log(err);
});
The same code is used for creating an answer with little modifications.
How can I solve the problem?

Related

addTrack after etablished connection

I need to add my track and send to other peers after having etablished the connection I've followed the MDN example
pc.onnegotiationneeded = async () => {
try {
makingOffer = true;
await pc.setLocalDescription();
signaler.send({ description: pc.localDescription });
} catch(err) {
console.error(err);
} finally {
makingOffer = false;
}
};
onnegotiationneeded is fired when we call pc.addTrack so I will remake the process offer -> answer -> ICE.
So I have a function which call getUserMedia and set the local video I've added a callback to apply addTrack to my peers
const handleActiveVideo = async (cb) => {
const devices = await getVideoDevices();
const localStream = await createLocalStream(devices[0].deviceId);
setLocalVideoEl(localStream, devices[0].deviceId);
cb((pc) => {
localStream.getTracks().forEach((track) => {
pc.connection.addTrack(track, localStream);
});
});
};
But if I do that with an etablished connection when I add my local stream to the track with one peer it's ok all work fine but with my second peer I have this error on Firefox
Remote description indicates ICE restart but offer did not request ICE
restart (new remote description changes either the ice-ufrag or
ice-pwd)
with Chrome
DOMException: Failed to execute 'setRemoteDescription' on
'RTCPeerConnection': Failed to set remote answer sdp: Failed to apply
the description for m= section with mid='0': Failed to set SSL role
for the transport.
To recapitulate
connect my 2 peers without any tracks on both sides
start the video with my Peer1 ok I can see the video with my Peer2
start the video with my Peer2 error on Peer2 in the answer
setRemoteDescription(description);

WebRTC works locally, but not over Internet [duplicate]

This question already has answers here:
How do you get around NATs using WebRTC without a TURN server?
(2 answers)
Closed 2 years ago.
I'm trying to get a simple proof of concept WebRTC app going. I've got code that works on the local network, but not over the Internet.
I believe I've got a bug outlined here, but I can't figure it out.
server.js (expressjs)
require('dotenv').config();
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
app.use(express.static('public'));
io.on('connection', (socket) => {
socket.on('join', () => socket.broadcast.emit('join', socket.id));
socket.on('offer', (id, sdp) => socket.to(id).emit('offer', socket.id, sdp));
socket.on('answer', (id, sdp) => socket.to(id).emit('answer', socket.id, sdp));
socket.on('candidate', (id, candidate) => socket.to(id).emit('candidate', socket.id, candidate));
});
const port = process.env.PORT || 443;
http.listen(port, () => console.log("listening on :" + port));
client.js (built w/ webpack)
import io from 'socket.io-client';
console.log('getting video stream');
navigator.mediaDevices.getUserMedia({ video: true }).then(myStream => {
const socket = io.connect();
console.log('joining');
socket.emit('join');
let connections = {};
socket.on('join', async peer_id => {
const connection = newConnection(peer_id);
console.log('creating offer');
const sdp = await connection.createOffer();
console.log('setting local desc');
await connection.setLocalDescription(sdp);
console.log('sending offer');
socket.emit('offer', peer_id, connection.localDescription);
});
socket.on('offer', async (peer_id, remoteDescription) => {
const connection = newConnection(peer_id);
console.log('setting remote desc');
await connection.setRemoteDescription(remoteDescription);
console.log('creating answer');
const sdp = await connection.createAnswer();
console.log('setting local desc');
await connection.setLocalDescription(sdp);
console.log('sending answer');
socket.emit('answer', peer_id, connection.localDescription);
});
socket.on('answer', (peer_id, remoteDescription) => {
console.log('setting remote desc');
connections[peer_id].setRemoteDescription(remoteDescription);
});
socket.on('candidate', (peer_id, candidate) => {
console.log('adding candidate');
connections[peer_id].addIceCandidate(candidate);
});
function newConnection(peer_id) {
console.log('creating connection');
const connection = new RTCPeerConnection(
{ iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }] }
);
connections[peer_id] = connection;
connection.onconnectionstatechange = () => console.log('connection state', connection.connectionState);
console.log('searching for candidates');
connection.onicecandidate = event => {
if (event.candidate) {
console.log('sending candidate');
socket.emit('candidate', peer_id, event.candidate);
} else {
console.log('all candidates found');
}
};
console.log('listening for tracks');
connection.ontrack = event => {
console.log('track received');
const stream = new MediaStream();
stream.addTrack(event.track);
document.getElementById('video').srcObject = stream;
};
for (const track of myStream.getTracks()) {
console.log('sending track');
connection.addTrack(track);
}
return connection;
}
});
Logs from local network peers (connected)
first peer
getting video stream
joining
creating connection
searching for candidates
listening for tracks
sending track
creating offer
setting local desc
sending offer
(2) sending candidate
setting remote desc
adding candidate
track received
connection state connecting
all candidates found
connection state connected
second peer
getting video stream
joining
creating connection
searching for candidates
listening for tracks
sending track
setting remote desc
track received
creating answer
setting local desc
sending answer
sending candidate
connection state connecting
all candidates found
connection state connected
(2) adding candidate
Logs from peers over the Internet (failed)
first peer
getting video stream
joining
creating connection
searching for candidates
listening for tracks
sending track
creating offer
setting local desc
sending offer
(3) sending candidate
all candidates found
setting remote desc
track received
connection state connecting
(5) adding candidate
connection state failed
second peer
getting video stream
joining
creating connection
searching for candidates
listening for tracks
sending track
setting remote desc
track received
creating answer
setting local desc
sending answer
(5) sending candidate
(3) adding candidate
connection state connecting
connection state failed
all candidates found
WebRTC isn't going to work on all connection pairings unless you use TURN.
You will see some peers able to connect though, you can read about all the cases that matter in my answer here

Kurento Media server 6.6 and one 2 one application behind Nat

I am running KMS server and kurento one to one call behind Nat. I can only connect my call when I am under VPN. Outside Vpn I am not able to connect the call.
let options = {
localVideo: video,
mediaConstraints: constraints,
onicecandidate: localParticipant.onIceCandidate.bind(localParticipant),
configuration : { iceServers : [
{"url":"stun:74.125.200.127:19302"},
] }
};
localParticipant.rtcPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function(error) {
if (error) {
return console.error(error);
}
localVideoCurrentId = sessionId;
localVideo = document.getElementById('local_video');
localVideo.src = localParticipant.rtcPeer.localVideo.src;
localVideo.muted = true;
this.generateOffer(localParticipant.offerToReceiveVideo.bind(localParticipant));
});
The stun server here is the ip for this domain stun.l.google.com.

Send email using Nodemailer with GoDaddy hosted email

I am trying to send an email using nodemailer and a custom email address configured through GoDaddy. Here is a screen shot of the "custom configurations" page in c-panel:
and my code:
const nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
service: 'Godaddy',
secureConnection: false,
auth: {
user: 'info#mywebsite.com',
pass: 'mypassword'
}
});
var mailOptions = {
from: 'info#mywebsite.com',
to: 'otheremail#gmail.com',
subject: 'Sending Email using Node.js',
text: 'That was easy!',
html: '<h1>Welcome</h1><p>That was easy!</p>'
};
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
and my error log:
{ Error: connect EHOSTUNREACH 173.201.192.101:25
at Object.exports._errnoException (util.js:1012:11)
at exports._exceptionWithHostPort (util.js:1035:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1080:14)
code: 'ECONNECTION',
errno: 'EHOSTUNREACH',
syscall: 'connect',
address: '173.201.192.101',
port: 25,
command: 'CONN' }
I've tried changing the port number, making it secure vs non-ssl, using my website address as the host, and pretty much everything else I can think of. I have successfully sent an email from the godaddy email using one of the webmail clients. Has anyone else ever encountered this or have recommendations on things to try?
I am trying to send emails using nodemailer from Google Cloud Function using GoDaddy SMTP settings. I do not have Office365 enabled on my GoDaddy hosting. None of the above options worked for me today (12 November 2019). TLS need to be enabled.
I had to use the following configuration:
const mailTransport = nodemailer.createTransport({
host: "smtpout.secureserver.net",
secure: true,
secureConnection: false, // TLS requires secureConnection to be false
tls: {
ciphers:'SSLv3'
},
requireTLS:true,
port: 465,
debug: true,
auth: {
user: "put your godaddy hosted email here",
pass: "put your email password here"
}
});
Then, I could send a test email as follows:
const mailOptions = {
from: `put your godaddy hosted email here`,
to: `bharat.biswal#gmail.com`,
subject: `This is a Test Subject`,
text: `Hi Bharat
Happy Halloween!
If you need any help, please contact us.
Thank You. And Welcome!
Support Team
`,
};
mailTransport.sendMail(mailOptions).then(() => {
console.log('Email sent successfully');
}).catch((err) => {
console.log('Failed to send email');
console.error(err);
});
you should make some changes in your transporter:
var smtpTrans = nodeMailer.createTransport({
service: 'Godaddy',
host: "smtpout.secureserver.net",
secureConnection: true,
port: 465,
auth: {
user: "username",
pass: "password"
}
});
I realize this is an old post, but just wanted to add to this since the GoDaddy SMTP server has changed, just in case someone else comes across this and has the same problem I had. The answer by #tirmey did not work for me, but this did.
let nodemailer = require('nodemailer');
let mailerConfig = {
host: "smtp.office365.com",
secureConnection: true,
port: 587,
auth: {
user: "username#email.com",
pass: "password"
}
};
let transporter = nodemailer.createTransport(mailerConfig);
let mailOptions = {
from: mailerConfig.auth.user,
to: 'SomePerson#email.com',
subject: 'Some Subject',
html: `<body>` +
`<p>Hey Dude</p>` +
`</body>`
};
transporter.sendMail(mailOptions, function (error) {
if (error) {
console.log('error:', error);
} else {
console.log('good');
}
});
Solutions proposed above seem no longer valid, none of them worked for me. Following solution works for me:
const nodemailer = require('nodemailer');
const os = require('os');
let mailerConfig = {
host: os.hostname(),
port: 25,
};
let transporter = nodemailer.createTransport(mailerConfig);
transporter.sendMail({
from: '<from>',
to: '<to>',
subject: '<subject>',
text: '<text>'
}, (err, info) => {
console.log(info);
console.log(err);
});
I could solve the problem by using this code and some points that I brought them after codes:
const smtpTransport = nodemailer.createTransport({
host: "smtp.office365.com",
secure: false,
port: 587,
auth : {
user : 'info#my-domain.com',
pass : 'Password'
}
});
const mailOptions = {
to: 'target-mail#',
subject: 'Test 01',
html: 'Body',
from : 'info#resoluship.com'
};
await smtpTransport.sendMail(mailOptions);
Don't forget to use 'from' attribute in mailOptions
Don't use ',' in your 'from' attribute
For me, the solution for production shared hosting server was completely different than for testing.
It seems no authentication or credentials are required for it to work.
I created this code from this document describing how to use an SMTP relay server. You can use this with nodemailer. GoDaddy support told me I couldn't but I don't think they know about third party tools.
https://au.godaddy.com/help/send-form-mail-using-an-smtp-relay-server-953
async function main() {
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'localhost', //use localhost for linux cPanel hosting
port: 25,
secure: false,
// no need for authentication
tls: {
rejectUnauthorized: false
}
});
// send mail with defined transport object
let info = await transporter.sendMail({
to: "you#youremail.com", // list of receivers
subject: `New Message from ${name}`, // Subject line
text: `yourtext`, // plain text body
html: `your text in html`, // html body
headers: {
priority: 'high'
},
from: "you#youremail.com" // sender address
});
// send success page if successful
if (res.statusCode === 200) {
res.sendFile(path.join(__dirname, 'views/success.ejs'))
}
console.log("Message sent: %s", info.messageId, res.statusCode);
}
main().catch(console.error);
The most common problem with this error is the antivirus. So disable it for 10 minutes if you are testing it locally.

How to hook into XirSys' signaling server instead of Priologic

I'm using EasyRTC to develop a video chat app. The ICE configuration is set up following the guide on XirSys site:
easyrtc.on("getIceConfig", function(connectionObj, callback){
var iceConfig = [];
request.post('https://api.xirsys.com/getIceServers', {
form: {
ident: '***',
secret: '***',
domain: '***',
application: 'default',
room: 'default',
secure: 1
},
},
function (error, response, body) {
console.log(arguments);
if (!error && response.statusCode == 200) {
iceConfig = JSON.parse(body).d.iceServers;
console.log(iceConfig);
callback(null, iceConfig);
}
else {
console.log(error);
}
});
});
It's working, I can run the EasyRTC demos but there's no STUN/TURN hit in the XirSys console. I suspect this is because the app is still using the public signaling server from Priologic.
The documentation on XirSys' site mentions a "later tutorial" for how to change the signaling server but I couldn't find any.
Does anybody know how to do it?
Thanks.
UPDATE
The problem seems to persist after migrating to the new platform version and changing the request above with:
request({
url: 'https://service.xirsys.com/ice',
qs: {
ident: '***',
secret: '***',
domain: '***',
application: "default",
room: "default",
secure: 1
},
json: true
},
function(error, response, body) {
if (!error && response.statusCode == 200) {
iceConfig = body.d.iceServers;
callback(null, iceConfig);
} else {
console.log(error);
}
});
I answered this question directly via email, but for consistency, will update here as well.
The new XirSys platform went live, yesterday, which has full usage monitoring capabilities within the dashboard. Please give this a go, but remember that the meters will not update until 10 minutes after a disconnection from the TURN server. Also, it may help to use Wireshark or some other network sniffer, so as to accurately see how your connections are failing / working.
Many thanks,
Lee
CTO # XirSys