Skip to content

Instantly share code, notes, and snippets.

@iczero
Last active December 21, 2018 06:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iczero/42fef451daa8b8cce72b71d303a2d646 to your computer and use it in GitHub Desktop.
Save iczero/42fef451daa8b8cce72b71d303a2d646 to your computer and use it in GitHub Desktop.
// dependencies: pngjs raw-socket
// part of a filing cabinet!
const ping = require('./net-ping.js');
const util = require('util');
const PNG = require('pngjs').PNG;
const fs = require('fs');
const cluster = require('cluster');
const IMAGE = 'draw.png';
const X_OFFSET = 0;
const Y_OFFSET = 0;
const INNER_DELAY = 0;
const LOOP_DELAY = 100;
const PARALLELISM = 1;
if (cluster.isMaster) {
for (let i = 0; i < PARALLELISM; i++) cluster.fork();
} else {
let session = ping.createSession({
packetSize: 12,
networkProtocol: ping.NetworkProtocol.IPv6
});
let draw = util.promisify(function draw(x, y, r, g, b, cb) {
session.pingHost(`2001:4c08:2028:${x}:${y}:${r.toString(16)}:${g.toString(16)}:${b.toString(16)}`, cb);
});
let sleep = util.promisify(setTimeout);
(async () => {
let image = await new Promise((resolve, reject) => {
let image = fs.createReadStream(IMAGE).pipe(new PNG({
filterType: -1,
inputColorType: 6
}));
image.on('parsed', () => resolve(image));
});
let width = image.width;
let height = image.height;
for (;;) {
for (let x = 0; x < width; x++) {
if (INNER_DELAY) await sleep(INNER_DELAY);
for (let y = 0; y < height; y++) {
let idx = (image.width * y + x) << 2;
let red = image.data[idx];
let green = image.data[idx + 1];
let blue = image.data[idx + 2];
let alpha = image.data[idx + 3];
if (alpha === 0) continue;
draw(x + X_OFFSET, y + Y_OFFSET, red, green, blue);
}
}
console.log(cluster.worker.id, 'drawn');
if (LOOP_DELAY) await sleep(LOOP_DELAY);
}
})();
}
// stolen and modified from npm net-ping module
const EventEmitter = require('events');
const rawSocket = require('raw-socket');
/**
* Add inverses to an object
* @param {Object} obj
*/
function _addInverseProps(obj) {
for (let [key, value] of Object.entries(obj)) obj[value] = key;
}
let NetworkProtocol = {
1: 'IPv4',
2: 'IPv6'
};
_addInverseProps(NetworkProtocol);
/** Represents a session */
class Session extends EventEmitter {
/**
* The constructor
* @param {Object} options
*/
constructor(options) {
super();
options = options || {};
this.packetSize = options.packetSize || 16;
if (this.packetSize < 8) this.packetSize = 8;
this.addressFamily = (options.networkProtocol === NetworkProtocol.IPv6)
? rawSocket.AddressFamily.IPv6
: rawSocket.AddressFamily.IPv4;
this._debug = (options && options._debug) ? true : false;
this.defaultTTL = (options && options.ttl) ? options.ttl : 128;
this.socket = null;
this.getSocket();
}
/**
* Close the session
* @return {Session} this
*/
close() {
if (this.socket) this.socket.close();
this.flush(new Error('Socket closed'));
this.socket = null;
return this;
}
/**
* Print debug message for request
* @param {String} target
* @param {Object} req
*/
_debugRequest(target, req) {
console.log('request: addressFamily=' + this.addressFamily + ' target='
+ req.target + ' buffer='
+ req.buffer.toString('hex'));
}
/**
* Flush the session
* @param {Error} error Error to send to sockets
*/
flush(error) {
for (let id of Object.keys(this.reqs)) {
let req = this.reqRemove(id);
let sent = req.sent ? req.sent : new Date();
req.callback(error, req.target, sent);
}
}
/**
* Initialize the socket
* @return {Socket} The initialized socket
*/
getSocket() {
if (this.socket) return this.socket;
let protocol = this.addressFamily == rawSocket.AddressFamily.IPv6
? rawSocket.Protocol.ICMPv6
: rawSocket.Protocol.ICMP;
let options = {
addressFamily: this.addressFamily,
protocol: protocol
};
this.socket = rawSocket.createSocket(options);
this.socket.on('error', this.onSocketError.bind(this));
this.socket.on('close', this.onSocketClose.bind(this));
this.ttl = null;
this.setTTL(this.defaultTTL);
return this.socket;
}
/**
* Called before the message is sent
* @param {Object} req
*/
onBeforeSocketSend(req) {
// this.setTTL(req.ttl ? req.ttl : this.defaultTTL);
}
/** Called on socket close event */
onSocketClose() {
this.emit('close');
this.flush(new Error('Socket closed'));
}
/**
* Called on socket error event
* @param {Error} error
*/
onSocketError(error) {
this.emit('error', error);
}
/**
* Called when the message is sent
* @param {Object} req
* @param {Error} error
*/
onSocketSend(req, error) {
if (!req.sent) req.sent = new Date();
req.callback(error, req.target, req.sent);
}
/**
* Ping a host
* @param {String} target The target to ping
* @param {Function} callback The callback
* @return {Session} this
*/
pingHost(target, callback) {
let req = {
callback,
target
};
req.buffer = this.toBuffer(req);
if (this._debug) this._debugRequest(req.target, req);
this.send(req);
return this;
}
/**
* Send a request
* @param {Object} req
*/
send(req) {
let buffer = req.buffer;
// Resume readable events if the raw socket is paused
if (this.getSocket().recvPaused) this.getSocket().resumeRecv();
this.getSocket().send(buffer, 0, buffer.length, req.target,
this.onBeforeSocketSend.bind(this, req),
this.onSocketSend.bind(this, req));
}
/**
* Set the TTL of the message
* @param {Number} ttl
*/
setTTL(ttl) {
if (this.ttl && this.ttl == ttl) return;
let level = this.addressFamily == rawSocket.AddressFamily.IPv6
? rawSocket.SocketLevel.IPPROTO_IPV6
: rawSocket.SocketLevel.IPPROTO_IP;
this.getSocket().setOption(level, rawSocket.SocketOption.IP_TTL, ttl);
this.ttl = ttl;
}
/**
* Encode the request into a buffer
* @param {Object} req
* @return {Buffer}
*/
toBuffer(req) {
let buffer = Buffer.alloc(this.packetSize);
let type = this.addressFamily == rawSocket.AddressFamily.IPv6 ? 128 : 8;
buffer.writeUInt8(type, 0);
buffer.writeUInt8(0, 1);
buffer.writeUInt16BE(0, 2);
rawSocket.writeChecksum(buffer, 2, rawSocket.createChecksum(buffer));
return buffer;
}
}
exports.createSession = function(options) {
return new Session(options || {});
};
exports.NetworkProtocol = NetworkProtocol;
exports.Session = Session;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment