Node.js - "Rebind" UDP socket server to a new port - node.js

Which is the most efficient way to change a UDP server's listening port on runtime on Node.js?
I have a default port 41234 for my web app but I want the end-user to be able to change this through a settings textbox, which would call the updatePort().
Using the following code the new (neither the old) port isn't actually listening for datagrams, as I cant receive anything.
var SRV_PORT = 41234;
var server = dgram.createSocket("udp4");
server.on("error", function (err) {
print("server error:\n" + err.stack);
server.close();
});
server.on("message", function (msg, rinfo) {
//code for incoming datagram analysis here
});
server.on("listening", function () {
var address = server.address();
print("server listening " + address.address + ":" + address.port);
});
//start the UDP server with the default SRV_PORT
server.bind(SRV_PORT);
function updatePort(newPort) {
server.close();
server = dgram.createSocket("udp4");
server.bind(newPort);
}

The reason you wouldn't get any messages after updating the port is because you've assigned a new socket instance to server and do not have any event handlers attached anymore.

Related

socket.io how to get server socket listen address and port

here is my simplified code example on server side, i need to get to which ip (preferably hostname) and port the server socket is listening, given the socket argument on my callback and assuming i don't have accessible io variable here
function myCallback(socket, data){
//how do i get, to which ip or hostname and port the socket argument is listening
}
io.on('connection', function(socket){
socket.on('event',function(data){
myCallback(socket,data);
});
});
You can use:
function myCallback(socket, data) {
var address = socket.handshake.address;
console.log('New connection from ' + address.address + ':' + address.port);
}

The nodejs net.createServer function results in a blank server.address value in Bluemix

The net module has a createServer function that allows you to create a network wrapper. This works fine on a local runtime of Nodejs, but when running in Bluemix it is unable to determine the host address. The server seems to get created, but upon further inspection I find the server.address to be blank.
var tls = require('tls');
var fs = require('fs');
var net = require('net');
var tunnelHost = (process.env.VCAP_APP_HOST || 'localhost');
var tunnelPort = 8888;
var server;
var gatewayOptions = {
host: 'http://cap-sg-prd-5.integration.ibmcloud.com/',
port: '15133',
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
ca: fs.readFileSync('ca.pem')
};
console.log("starting createSecureTunnel");
//create a server end point to use as a network wrapper for the secure gateway
server = net.createServer(function (connListener){
console.log('net server created');
connListener.on('end', function() {
console.log('client disconnected');
});
connListener.on('uncaughtException', function(err){
console.log('exception caught: ' + JSON.stringify(err));
});
//connect to farside, local/private server
connectFarside(connListener, function(err, remoteSocket){
if (err){
console.log(err);
}
console.log('connection made');
remoteSocket.pipe(connListener);
console.log('remote socket connecte to local connListener');
connListener.pipe(remoteSocket);
console.log('local connListener connected to remote socket');
});
});
//setup listener for network wrapper
server.listen(tunnelPort, tunnelHost, function(){
console.log('tunnel created at: ' + tunnelHost +":"+ tunnelPort); //.address +":"+ server.address().port);
});
//createa a TLS connection to the secure gateway
function connectFarside(conn, callback) {
console.log("starting connectFarside");
try {
console.log("initiating farside connection");
var socket = tls.connect(gatewayOptions, function(){
console.log("tunnel connected to " + gatewayOptions.host +":"+ gatewayOptions.port);
callback(null, socket);
});
socket.on("error", function(err){
console.log("Socket error: " + JSON.stringify(err));
});
} catch(err) {
console.log(err);
callback(err);
}
}
Bluemix gives your app a port to run on, this is the reason it is not working in Bluemix. You are starting to start your app on port 8888 with the following line of code.
var tunnelPort = 8888;
It should be changed to
var tunnelPort = process.env.VCAP_APP_PORT || 8888;
The above line will read an environment variable called VCAP_PORT where Bluemix assigns a port to your app, if it is not running Bluemix it will run on port 8888.
Your app will be accessible over the web on port 80 and 443. Bluemix will load balance to your app for you.
You can specify the server address when listening to the server
var net = require('net')
var server = net.createServer(handler)
server.listen(port, address)
Try with address = '0.0.0.0' and see if it works
Partially solved by using the cf-autoconfig module. It helps to reconfigure modules for use on Cloud Foundry platforms. By including this as the first line in my app, it mostly works. It doesn't use the port number. But at least I can access the wrapper.
So I added this as the first line
require("cf-autoconfig");
Then I changed the server.listen to this
//setup listener for network wrapper
server.listen(tunnelPort, function(){
console.log('tunnel created at: ' + tunnelHost +":"+ tunnelPort); //.address +":"+ server.address().port);
});
Now if I use my app name, I can connect to the server created by net.createServer().
I would still like to know how to get the port to work, so this can be used inside of a web application to provide the tunneling.

TCP hole punching in Node.js

I'm trying to punch a TCP hole through two NATs in node.js. The problem is I can't figure out how to choose which local port the connection should use?
After creating a connection with the public server, you also need to listen on the exact same local (!!) port that was used to establish that connection.
I extended your testcode to a complete tcp hole punching proof of concept:
// server.js
var server = require('net').createServer(function (socket) {
console.log('> Connect to this public endpoint with clientB:', socket.remoteAddress + ':' + socket.remotePort);
}).listen(4434, function (err) {
if(err) return console.log(err);
console.log('> (server) listening on:', server.address().address + ':' + server.address().port)
});
// clientA.js
var c = require('net').createConnection({host : 'PUBLIC_IP_OF_SERVER', port : 4434}, function () {
console.log('> connected to public server via local endpoint:', c.localAddress + ':' + c.localPort);
// do not end the connection, keep it open to the public server
// and start a tcp server listening on the ip/port used to connected to server.js
var server = require('net').createServer(function (socket) {
console.log('> (clientA) someone connected, it\s:', socket.remoteAddress, socket.remotePort);
socket.write("Hello there NAT traversal man, this is a message from a client behind a NAT!");
}).listen(c.localPort, c.localAddress, function (err) {
if(err) return console.log(err);
console.log('> (clientA) listening on:', c.localAddress + ':' + c.localPort);
});
});
// clientB.js
// read the server's output to find the public endpoint of A:
var c = require('net').createConnection({host : 'PUBLIC_IP_OF_CLIENT_A', port : PUBLIC_PORT_OF_CLIENT_A},function () {
console.log('> (clientB) connected to clientA!');
c.on('data', function (data) {
console.log(data.toString());
});
});
For a more complete version with signalling happening on the server, I refer to my code here: https://github.com/SamDecrock/node-tcp-hole-punching
The socket is assigned a local port. To reuse the same port you can connect to the client using the same socket that was used to communicate with the server. This works for you because you are doing TCP hole punching. However, you cannot choose a port yourself.
Here is some test code:
// server.js
require('net').createServer(function(c) {
c.write(c.remotePort.toString(10));
}).listen(4434);
//client.js
var c = require('net').createConnection({host : '127.0.0.1', port : 4434});
c.on('data', function(data) {
console.log(data.toString(), c.localPort);
c.end();
});
c.on('end', function() {
c.connect({host : '127.0.0.1', port : 4434});
});

Node.js UDP client to handle a response from a udp server

I am trying to write an app in node.js to send a udp request to a device ( which has udp server) and then receive the response and display it. The device acts in such a way that upon receipt of a request on its port 11220 it returns a response immediately.
The code below sends a udp request to the device and the device responses back immediately ( I can see it in wireshark) but I can not handle/display the revived message. Or at least I just want to be able to display a message upon receipt of a reply from the device. Please let me know what is missing in my code or show me a complete code to do it. Very much appreciated.
As well, I do not prefer to use socket.io etc.
var PORT = 11220 ;
var HOST = '192.168.1.111';
var dgram = require('dgram');
var message = new Buffer(9);
var client = dgram.createSocket('udp4');
client.send(message, 0, message.length, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT);
client.close();
});
client.on('listening', function () {
var address = server.address();
console.log('UDP Server listening on ' + address.address + ":" + address.port);
});
client.on('message', function (message, remote) {
// CAN I HANDLE THE RECIVED REPLY HERE????
console.log(remote.address + ':' + remote.port +' - ' + message);
});
Just stumbled across the question so I thought I'd pipe in with an answer:
In your client.send function, calling client.close(); will close the UDP connection between your server and the client. Therefore, if you want to listen for messages, you should not call that immediately after you send your message.
Secondly, loganfsmyth's comment provided some good advice - you should add your event handlers first, then send the message.
In the end, this was the changed code needed to get your scenario working
var client = dgram.createSocket('udp4');
client.on('listening', function () {
var address = client.address();
console.log('UDP Server listening on ' + address.address + ":" + address.port);
});
client.on('message', function (message, remote) {
console.log(remote.address + ':' + remote.port +' - ' + message);
});
client.send(message, 0, message.length, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT);
});

Listening to port that Windows app uses results in EADDRINUSE

I have a Windows application that sends/receives TCP messages on a certain port. I hooked up the simple echo example on the Node.js website but I get the EADDRINUSE error.
I assume this is because my app is using that port.
What I was trying to do is to listen to that port and then hook a browser up to listen to what the server is sending out.
Ok, think I got it working:
var sys = require("sys"),
net = require("net");
var client = net.createConnection(10100);
client.setEncoding("UTF8");
client.addListener("connect", function() {
sys.puts("Client connected.");
// close connection after 2sec
setTimeout(function() {
sys.puts("Sent to server: close");
client.write("close", "UTF8");
}, 2000);
});
client.addListener("data", function(data) {
sys.puts("Response from server: " + data);
if (data == "close") client.end();
});
client.addListener("close", function(data) {
sys.puts("Disconnected from server");
});
If you want to intercept data sent to and from an applicaiton, I would recommend using Wireshark. If you want to capture this data from an applicaiton, I would recommend you use WinPCap.

Resources