├── .gitignore ├── .travis.yml ├── package.json ├── test.js ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "datagram-stream", 3 | "version": "1.1.1", 4 | "description": "Streaming UDP with broadcast, multicast and unicast options", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/wankdanker/node-datagram-stream.git" 12 | }, 13 | "keywords": [ 14 | "udp", 15 | "dgram", 16 | "datagram", 17 | "stream" 18 | ], 19 | "author": "Dan VerWeire", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/wankdanker/node-datagram-stream/issues" 23 | }, 24 | "homepage": "https://github.com/wankdanker/node-datagram-stream", 25 | "devDependencies": { 26 | "tape": "^4.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var udpStream = require('./') 2 | , test = require('tape'); 3 | 4 | test('broadcast destination', function (t) { 5 | t.plan(1); 6 | 7 | var s = udpStream({ broadcast : '255.255.255.255', port : 61616 }); 8 | 9 | s.on('data', function (chunk) { 10 | t.equal('hello', chunk.toString()); 11 | t.end(); 12 | 13 | s.end(); 14 | }); 15 | 16 | s.write('hello'); 17 | }); 18 | 19 | test('multicast destination', function (t) { 20 | t.plan(1); 21 | 22 | var s = udpStream({ multicast : '239.5.5.5', port : 61616, loopback : true }); 23 | 24 | s.on('data', function (chunk) { 25 | t.equal('hello', chunk.toString()); 26 | t.end(); 27 | 28 | s.end(); 29 | }); 30 | 31 | s.write('hello'); 32 | }); 33 | 34 | test('unicast destination', function (t) { 35 | t.plan(1); 36 | 37 | var s = udpStream({ unicast : '127.0.0.1', port : 61616, address: '127.0.0.1' }); 38 | 39 | s.on('data', function (chunk) { 40 | t.equal('hello', chunk.toString()); 41 | t.end(); 42 | 43 | s.end(); 44 | }); 45 | 46 | s.write('hello'); 47 | }); 48 | 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | datagram-stream 2 | --------------- 3 | 4 | [![Build Status](https://travis-ci.org/wankdanker/node-datagram-stream.svg)](https://travis-ci.org/wankdanker/node-datagram-stream) 5 | 6 | A streaming UDP module with broadcast, multicast and unicast options. 7 | 8 | install 9 | ------- 10 | 11 | ```bash 12 | npm install datagram-stream 13 | ``` 14 | 15 | usage 16 | ----- 17 | 18 | ## multicast 19 | 20 | ```js 21 | var udp = require('datagram-stream'); 22 | 23 | var stream = udp({ 24 | address : '0.0.0.0' //address to bind to 25 | , multicast : '239.5.5.5' //multicast ip address to send to and listen on 26 | , port : 5555 //udp port to send to 27 | , bindingPort : 5556 //udp port to listen on. Default: port 28 | , reuseAddr : true //boolean: allow multiple processes to bind to the 29 | // same address and port. Default: true 30 | , loopback : true //boolean: whether or not to receive sent datagrams 31 | // on the loopback device. Only applies to 32 | // multicast. Default: false 33 | }); 34 | 35 | //pipe whatever is received to stdout 36 | stream.pipe(process.stdout); 37 | 38 | //pipe whatever is received on stdin over udp 39 | process.stdin.pipe(stream); 40 | ``` 41 | 42 | ## broadcast 43 | 44 | ```js 45 | var udp = require('datagram-stream'); 46 | 47 | var stream = udp({ 48 | address : '0.0.0.0' //address to bind to 49 | , broadcast : '255.255.255.255' //broadcast ip address to send to 50 | , port : 5555 //udp port to send to 51 | , bindingPort : 5556 //udp port to listen on. Default: port 52 | , reuseAddr : true //boolean: allow multiple processes to bind to the 53 | // same address and port. Default: true 54 | }); 55 | 56 | //pipe whatever is received to stdout 57 | stream.pipe(process.stdout); 58 | 59 | //pipe whatever is received on stdin over udp 60 | process.stdin.pipe(stream); 61 | ``` 62 | 63 | ## unicast 64 | 65 | ```js 66 | var udp = require('datagram-stream'); 67 | 68 | var stream = udp({ 69 | address : '0.0.0.0' //address to bind to 70 | , unicast : '127.0.0.1' //unicast ip address to send to 71 | , port : 5555 //udp port to send to 72 | , bindingPort : 5556 //udp port to listen on. Default: port 73 | , reuseAddr : true //boolean: allow multiple processes to bind to the 74 | // same address and port. Default: true 75 | }); 76 | 77 | //pipe whatever is received to stdout 78 | stream.pipe(process.stdout); 79 | 80 | //pipe whatever is received on stdin over udp 81 | process.stdin.pipe(stream); 82 | ``` 83 | 84 | acknowledgments 85 | --------------- 86 | 87 | I used @dominictarr's [broadcast-stream](https://github.com/dominictarr/broadcast-stream) as a 88 | guide for how to implement the stream. 89 | 90 | 91 | license 92 | ------- 93 | 94 | MIT 95 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var udp = require('dgram') 2 | , pipe = require('stream').prototype.pipe 3 | , nodeVersion = process.version.replace('v','').split(/\./gi).map(function (t) { return parseInt(t, 10) }); 4 | 5 | module.exports = UdpStream; 6 | 7 | function UdpStream (options, cb) { 8 | var options = options || {}; 9 | 10 | var address = options.address || '0.0.0.0'; 11 | var port = options.port || 12345; 12 | var bindingPort = options.bindingPort || port; 13 | var unicast = options.unicast || null; 14 | var broadcast = options.broadcast || null; 15 | var multicast = options.multicast || null; 16 | var multicastTTL = options.multicastTTL || 1; 17 | var destination = unicast || multicast || broadcast; 18 | var loopback = options.loopback || false; 19 | var reuseAddr = (options.reuseAddr === false) ? false : true; 20 | var socket; 21 | 22 | if (nodeVersion[0] === 0 && nodeVersion[1] < 12) { 23 | //node v0.10 does not support passing an object to dgram.createSocket 24 | //not sure if v0.11 does, but assuming it does not. 25 | socket = udp.createSocket('udp4'); 26 | } 27 | else { 28 | socket = udp.createSocket({type: 'udp4', reuseAddr: reuseAddr }); 29 | } 30 | 31 | socket.write = function (message) { 32 | if (typeof message === "string") { 33 | message = new Buffer(message, "utf8"); 34 | } 35 | 36 | socket.send(message, 0, message.length, port, destination); 37 | 38 | return true; 39 | }; 40 | 41 | socket.end = function () { 42 | setImmediate(function () { 43 | socket.emit('end') 44 | socket.close(); 45 | }); 46 | }; 47 | 48 | socket.pause = function () { 49 | socket.paused = true; 50 | return this; 51 | }; 52 | 53 | socket.resume = function () { 54 | socket.paused = false; 55 | return this; 56 | }; 57 | 58 | socket.on('message', function (msg, rinfo) { 59 | msg.rinfo = rinfo; 60 | 61 | socket.emit('data', msg); 62 | }); 63 | 64 | socket.on('error', startupErrorListener); 65 | 66 | socket.bind(bindingPort, address); 67 | 68 | socket.on('listening', function () { 69 | socket.removeListener('error', startupErrorListener); 70 | 71 | if (multicast) { 72 | //set up for multicast 73 | try { 74 | socket.addMembership(multicast); 75 | socket.setMulticastTTL(multicastTTL); 76 | socket.setMulticastLoopback(loopback ? true : false); 77 | } 78 | catch (err) { 79 | socket.emit('error', err); 80 | 81 | return cb && cb(err); 82 | } 83 | } 84 | else if (broadcast) { 85 | socket.setBroadcast(true); 86 | } 87 | 88 | return cb && cb(); 89 | }); 90 | 91 | socket.pipe = pipe; 92 | 93 | return socket; 94 | 95 | function startupErrorListener(err) { 96 | return cb && cb(err); 97 | } 98 | } 99 | --------------------------------------------------------------------------------