I've implemented a server/client implementation of node-ssdp(npm install node-ssdp). Everything "appears" to work but my client does not pick up the server's packet. I am receiving a lot of other payloads from different devices/locations but not the payload from my node-ssdp server.
I'm running on the same machine and I'm running on OSX. I have two separate node projects: one for my client and one for my server.
Note: I've also tried running the server on one machine and the client on a separate machine, in case there was an issue with loopback or something. I also verified via Wireshark that the packets from the server were being read by the client machine. It is sending a NOTIFY * HTTP/1.1 in the headers.
Here are my implementations for client and server:
Server
var SSDP = require('node-ssdp').Server
, server = new SSDP({
location: 'http://' + require('ip').address() + ':33333',
ssdpPort: 33333
})
console.log(require('ip').address())
server.addUSN('upnp:rootdevice')
server.addUSN('urn:schemas-upnp-org:device:MediaServer:1')
server.addUSN('urn:schemas-upnp-org:service:ContentDirectory:1')
server.addUSN('urn:schemas-upnp-org:service:ConnectionManager:1')
server.on('advertise-alive', function (heads) {
console.log('advertise-alive', heads)
// Expire old devices from your cache.
// Register advertising device somewhere (as designated in http headers heads)
})
server.on('advertise-bye', function (heads) {
console.log('advertise-bye', heads)
// Remove specified device from cache.
})
// start server on all interfaces
console.log('starting ssdp server')
server.start()
Client
var ssdp = require('node-ssdp').Client
, client = new ssdp({
})
client.on('notify', function () {
//console.log('Got a notification.')
})
client.on('response', function inResponse(headers, code, rinfo) {
console.log('Got a response to an m-search:\n%d\n%s\n%s', code, JSON.stringify(headers, null, ' '), JSON.stringify(rinfo, null, ' '))
})
client.search('ssdp:all')
// And after 10 seconds, you want to stop
setTimeout(function () {
client.stop()
}, 10000)
I am running out of ideas. It's weird because I've previously implemented a UDP multicast solution and it works. SSDP is, from what I understand, UDP multicast behind the scenes.
From the github issue itself, apparently adding sourcePort to the configuration solved the issue. https://github.com/diversario/node-ssdp/issues/75#issuecomment-292054892
Related
Background:
I have a NodeJS TCP stream server with SSL (tls server) which simply forwards data from client A to client B. i.e. it listens to connections on port 9000 (client A) and writes the received data to an existing persistent connection on port 9001 (client B). The connection between NodeJS and client B is persistent, never broken. Everything is running on my local machine.
Problem:
When using JMeter as client A and sending 300 requests (threads) with a ramp-up period of 1 second, a few requests never arrive at client B.
Troubleshooting done so far:
First I checked the logs of NodeJS application, which indicated that 300 requests were received from client A, and 300 requests were sent to client B.
Then I checked the logs of the client B, which indicated that only 298 requests arrived.
Next I monitored the local network using WireShark, which to my surprise indicated that 300 requests arrived from Client A to server, but only 298 of them were sent to client B.
Server side function which writes data to client B:
The function is a class member, where vSocket is a NodeJS TLSSocket which represents the persisted connection with client B. In the server logs, I get "Writing data to socket." and "Wrote data to socket." 300 times. I never get "Unexpected error while writing data to socket." or "Write returned false.".
public async SendAsync (pData: string): Promise<void> {
return new Promise<void>((pResolve, pReject) => {
try {
this.uLogger.Debug('Writing data to socket.', pData);
const rc = this.vSocket.write(pData, (pError) => {
if (pError) {
this.uLogger.Error('Unexpected error while writing data to socket.', pError);
return pReject(pError);
}
this.uLogger.Debug('Wrote data to socket.', pData);
if (this.vKeepConnectionOpen == false) {
this.uLogger.Debug('Not keeping this socket open.');
this.CloseAsync();
}
return pResolve();
});
if (rc == false) {
this.uLogger.Debug('Write returned false.', this.uId);
}
} catch (error) {
this.uLogger.Error('Unexpected error while writing data to socket.', error);
return pReject(error);
}
});
}
socket.write(data[, encoding][, callback]):
The docs say that -
Returns true if the entire data was flushed successfully to the kernel buffer. Returns false if all or part of the data was queued in user memory.
Since in my case this function never returns false, I assume NodeJS has successfully written the data to OS buffer, and the data should have been sent.
This problem is frequently replicable, and more likely to occur when I send hundreds of requests with JMeter. It is less likely to occur with 10 requests, and has never happened with < 5 requests.
I don't understand what's happening here, any help is appreciated.
I'm trying to read in data from an arduino using serialport, and serve it to a web browser.
Without the webserver (ie. if I just leave out that 'listen' call at the end), the serial data gets constantly streamed in with the expected 5 updates per second shown in the console.
But when I add the 'listen' call, nothing is shown on the console until I make a request to the server with my web browser, at which time the console gets at most only one log entry added (but sometimes still nothing).
The data shown in the web browser is the 'old' data from whenever the last request was made, not the current latest data from the arduino. In other words, the serial data is processed a little after each http request is served - not very useful.
const http = require('http');
const serialport = require('serialport');
var serial = new serialport('/dev/ttyUSB0', {
baudRate: 115200
});
var jsonStr = '';
var jsonObj = {};
function handleData(data) {
jsonStr += data;
if ( data.indexOf('}') > -1 ) {
try {
jsonObj = JSON.parse(jsonStr);
console.log(jsonObj);
}
catch(e) {}
jsonStr = '';
}
};
serial.on('data', function (data) {
handleData(data);
});
const app = http.createServer((request, response) => {
response.writeHead(200, {"Content-Type": "text/html"});
response.write(JSON.stringify(jsonObj));
response.end();
});
app.listen(3000);
(The data coming from the arduino is already a JSON string which is why I'm looking for a '}' to start parsing it.)
I also tried using the 'readable' event for getting the serial data but it makes no difference:
serial.on('readable', function () {
handleData(serial.read());
});
If I understand it correctly, the listen call itself is not blocking, it merely registers an event listener/callback to be triggered later. As an accepted answer in a related question says: "Think of server.listen(port) as being kinda similar to someElement.addEventListener('click', handler) in the browser."
If node.js is single threaded then why does server.listen() return?
So why is that 'listen' preventing the serial connection from receiving anything, except for briefly each time a request is served? Is there no way I can use these two features without them interfering with each other?
I discovered that the code worked as expected on a different computer, even though the other computer was using the exact same operating system (Fedora 20) and the exact same version of node.js (v10.15.0) which had been installed in the exact same way (built from source).
I also found that it worked ok on the original computer with a more recent version of Fedora (29).
This likely points to some slight difference in usb/serial drivers which I don't have the time, knowledge or need to delve into. I'll just use the configurations I know will work.
hope someone out there can help me on this one!
Task:
Send xml files to ActiveMQ.
Environments:
Developing:
OS X 10.10.5
node 4.4.3
stompit 0.25.0
Production:
Ubuntu 16.04
node 7.8.0 (tried 4.4.3 too with same results)
stompit 0.25.0
I'm always connecting this way.
var server1 = { 'host': 'activemq-1.server.lan' };
var server2 = { 'host': 'activemq-2.server.lan' };
var servers = [server1, server2];
var reconnectOptions = { 'maxReconnects': 10 };
var manager = new stompit.ConnectFailover(servers, reconnectOptions);
Headers, i set for each frame:
const sendHeaders = {
'destination' : '/queue/name_of_queue',
'content-type' : 'text/plain',
'persistent' : 'true'
};
I'm not allowed to set the content-length header, as this would force the server to interpret the stream as a binary stream.
When connected to the server, i connect to a PostgreSQL server to fetch the data to send.
What works:
var frame = client.send(sendHeaders);
frame.write(row.pim_content);
frame.end();
But it only works at the developing machine. When running this in production environment, the script runs without throwing errors, but never sends the message to the server.
So I tried a different method, just to have a callback when the server receives a message.
var channel = new stompit.Channel(manager);
channel.send(sendHeaders, xml_content, (err)=>{
if(err){
console.log(err);
} else {
console.log('Message successfully transferred');
}
});
Now i get the same results for production and development. It is working as expected, but ...
It only works as long as the body (xml_content) has a maximum length of 1352 characters. When adding an additional character, the callback of channel.send() is never going to be fired.
I'm running out of ideas what to check/test next to get that thing working. I hope someone is reading this, laughing and pointing me to the right direction. Any ideas greatly appreciated!
Thanks in advance,
Stefan
I have two servers using NodeJS on the same domain. (server1.example.com and server2.example.com)
I'd like to send messages from one server to the other in a secure way.
Right now, I'm using sending my message by sending a HTTPS POST such as https://example.com with {secret:XXXXX,message:1234}.
Is there a cleaner way to do this? If so, what would be the exact steps needed?
Note: I have a SSL certifiate on the site. Both servers are on the same domain.
There are a few options I can think of, though of course, it depends on the amount of encryption and security you are looking for, if HTTPS is not strong enough for what is required for the specific communication. (Though as mentioned you do have HTTPS.)
You can have the sending server issue a whole JWT route. Send the information with a Token and verify it on the other side. Make sure the Token has a short TTL as well. (If you really want to go for broke here, you can start implementing the OAuth2 framework, though that may be complete overkill.)
Additionally, you can create a Websocket HTTPS server, and only accept the information from the information on a specific incoming port. That will allow you to use the JWT and further verify by the port access. The port you open will only be allowed to accept packets from a specific IP, which is your outgoing server.
You can add yet another layer as you are doing by encrypting the entire message (via one of the Node NPM modules or via Crypto), so both the message and secret are hashed.
You can also add a cache layer (either Redis or a Node-Cache module), where all the decryption will be done to speed up the process.
Another trick to use, though you have to work out the actual schedule, is to mix up the various hashing routines you use based on process or on different hours, or whatever schedule you wish.
Finally, a sometimes overlooked option is to install a firewall on the receiving computer with very specific rules on what to receive and from where. (This though is not a Node process, and can take time to get right.)
None of the above is linked to Express though, or middleware. I assume if you adopt any of the above you will need a few NPM modules in the end result.
Probably forgot a few options but hope this helps.
Just to add to the other solutions already posted, you could just use certificates on both ends, that way you could do the authentication at the TLS layer instead of the application layer if that helps at all.
Assuming you're using node on both servers, you could achieve this like so:
Create one custom CA, and then one certificate and one private key for each server.
Each server might have code like:
const tls = require('tls');
function onMessage(socket, msg) {
// `msg` is a parsed message received from `socket`
}
// Receive incoming messages
tls.createServer({
rejectUnauthorized: true,
requestCert: true,
ca: MY_CUSTOM_CA,
cert: THIS_SERVER_CERT,
key: THIS_SERVER_PRIVATE_KEY
}, (socket) => {
if (!socket.authorized)
return socket.end(); // Certificate did not check out
console.log('Connection accepted');
// example protocol: newline-delimited JSON
var jsonBuffer = '';
socket.setEncoding('utf8');
socket.on('data', (chunk) => {
var chunks = chunk.split('\n');
var numComplete = chunks.length - 1;
// Last line does not have trailing newline
var incompleteChunk = chunks[numComplete];
if (numComplete === 0) {
jsonBuffer += incompleteChunk;
return;
}
chunks[0] = jsonBuffer + chunks[0];
for (var i = 0; i < numComplete; ++i) {
try {
onMessage(socket, JSON.parse(chunks[i]));
} catch (ex) {}
}
jsonBuffer = incompleteChunk;
});
socket.on('end', () => {
console.log('Connection ended');
});
}).listen(MY_PORT);
// Send outgoing messages
function sendMessages(host, port, msgs, cb) {
if (!Array.isArray(msgs))
msgs = [msgs];
var req = tls.connect({
host,
port,
rejectUnauthorized: true,
ca: MY_CUSTOM_CA,
cert: THIS_SERVER_CERT,
key: THIS_SERVER_PRIVATE_KEY
}, () => {
if (!this.authorized)
return this.end(); // Certificate did not check out
for (var i = 0; i < msgs.length; ++i)
this.write(JSON.stringify(msgs[i]) + '\n');
this.end();
}).once('error', onError).once('close', onClose);
function onError(err) {
req.removeListener('close', onClose);
cb(err);
}
function onClose() {
cb();
}
}
Add incoming message handling in onMessage() and send outgoing messages with sendMessages().
You could also just keep a single socket open all the time instead of using a new connection per set of outgoing messages, but that would be a little more involved because you'd need to add an application-level keepalive mechanism and such, but it's certainly doable.
You could harden your security some more by verifying the host of the request, via the HOST or ORIGIN header.
Check out: https://stackoverflow.com/questions/18498726/how-do-i-get-the-domain-originating-the-request-in-express-js
Essentially, you'd be making sure that the request with the encrypted secret actually came from a specific server, and not just any.
I want to send and later display a video in the browser. I have the application that takes the video from my camera and converts it to bytes, later on - it sends it through UDP to a specific port.
Now - I have the node.js script that receives already the bytes:
var PORT = 19777;
var MULTICAST_GROUP = "224.0.0.251";
var dgram = require("dgram");
var payload = new Buffer('A wild message appears');
var client = dgram.createSocket("udp4");
client.on("message", function(message, rinfo) {
console.log("received: ",message,rinfo);
});
client.on("listening", function() {
console.log("listening on ",client.address());
client.setBroadcast(true);
client.setTTL(64);
client.setMulticastTTL(64);
client.setMulticastLoopback(true);
client.addMembership(MULTICAST_GROUP);
client.send(payload, 0, payload.length, PORT, MULTICAST_GROUP, function(err,bytes) {
console.log("err: "+err+" bytes: "+bytes);
// client.close();
});
});
client.on("close", function() {
console.log("closed");
});
client.on("error", function(err) {
console.log("error: ",err);
});
client.bind(19777);
and after running that - I see the packets in the console.
I need to process each packet (e.g. check whether it is from the current frame) - which hopefully generates the video stream on the other site - and - somehow - send it to the client's browser. At this point I don't even know how to process the packets itself - where and how are they stored after receiving them, if I can send it later to the browser, how to play it in the browser (html5?), etc...
I'm a total beginner when it comes to node.js and similar, so I've read a lot during last hours and I found an article that recommends Kaazing WebSocket Gateway, but I'm not sure if it's still an acceptable standard for that. Also, I found the webRTC, but I'm not sure if I can use it with custom stream (since I'm not using any popular video codects).
Could anyone give me any hint how to process now? I found some stackoverflow previous question, but the solution provided there is no longer online.. I'm lost in that completely and I will appreciate any help from you guys,
thanks!