200 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // Copyright 2012 Timothy J Fontaine <tjfontaine@gmail.com>
 | |
| //
 | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| // of this software and associated documentation files (the "Software"), to deal
 | |
| // in the Software without restriction, including without limitation the rights
 | |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| // copies of the Software, and to permit persons to whom the Software is
 | |
| // furnished to do so, subject to the following conditions:
 | |
| //
 | |
| // The above copyright notice and this permission notice shall be included in
 | |
| // all copies or substantial portions of the Software.
 | |
| //
 | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
| // THE SOFTWARE
 | |
| 
 | |
| var dgram = require('dgram'),
 | |
|     EventEmitter = require('events').EventEmitter,
 | |
|     ipaddr = require('ipaddr.js'),
 | |
|     net = require('net'),
 | |
|     util = require('util');
 | |
| 
 | |
| var UDPSocket = exports.UDPSocket = function(socket, remote) {
 | |
|   this._socket = socket;
 | |
|   this._remote = remote;
 | |
|   this._buff = undefined;
 | |
|   this.base_size = 512;
 | |
|   this.bound = false;
 | |
|   this.unref = undefined;
 | |
|   this.ref = undefined;
 | |
| };
 | |
| util.inherits(UDPSocket, EventEmitter);
 | |
| 
 | |
| UDPSocket.prototype.buffer = function(size) {
 | |
|   this._buff = new Buffer(size);
 | |
|   return this._buff;
 | |
| };
 | |
| 
 | |
| UDPSocket.prototype.send = function(len) {
 | |
|   this._socket.send(this._buff, 0, len, this._remote.port,
 | |
|                     this._remote.address);
 | |
| };
 | |
| 
 | |
| UDPSocket.prototype.bind = function(type) {
 | |
|   var self = this;
 | |
| 
 | |
|   if (this.bound) {
 | |
|     this.emit('ready');
 | |
|   } else {
 | |
|     this._socket = dgram.createSocket(type);
 | |
|     this._socket.on('listening', function() {
 | |
|       self.bound = true;
 | |
|       if (self._socket.unref) {
 | |
|         self.unref = function() {
 | |
|           self._socket.unref();
 | |
|         }
 | |
|         self.ref = function() {
 | |
|           self._socket.ref();
 | |
|         }
 | |
|       }
 | |
|       self.emit('ready');
 | |
|     });
 | |
| 
 | |
|     this._socket.on('message', this.emit.bind(this, 'message'));
 | |
| 
 | |
|     this._socket.on('close', function() {
 | |
|       self.bound = false;
 | |
|       self.emit('close');
 | |
|     });
 | |
| 
 | |
|     this._socket.bind();
 | |
|   }
 | |
| };
 | |
| 
 | |
| UDPSocket.prototype.close = function() {
 | |
|   this._socket.close();
 | |
| };
 | |
| 
 | |
| UDPSocket.prototype.remote = function(remote) {
 | |
|   return new UDPSocket(this._socket, remote);
 | |
| };
 | |
| 
 | |
| var TCPSocket = exports.TCPSocket = function(socket) {
 | |
|   UDPSocket.call(this, socket);
 | |
|   this.base_size = 4096;
 | |
|   this._rest = undefined;
 | |
| };
 | |
| util.inherits(TCPSocket, UDPSocket);
 | |
| 
 | |
| TCPSocket.prototype.buffer = function(size) {
 | |
|   this._buff = new Buffer(size + 2);
 | |
|   return this._buff.slice(2);
 | |
| };
 | |
| 
 | |
| TCPSocket.prototype.send = function(len) {
 | |
|   this._buff.writeUInt16BE(len, 0);
 | |
|   this._socket.write(this._buff.slice(0, len + 2));
 | |
| };
 | |
| 
 | |
| TCPSocket.prototype.bind = function(server) {
 | |
|   var self = this;
 | |
| 
 | |
|   if (this.bound) {
 | |
|     this.emit('ready');
 | |
|   } else {
 | |
|     this._socket = net.connect(server.port, server.address);
 | |
| 
 | |
|     this._socket.on('connect', function() {
 | |
|       self.bound = true;
 | |
|       if (self._socket.unref) {
 | |
|         self.unref = function() {
 | |
|           self._socket.unref();
 | |
|         }
 | |
|         self.ref = function() {
 | |
|           self._socket.ref();
 | |
|         }
 | |
|       }
 | |
|       self.emit('ready');
 | |
|     });
 | |
| 
 | |
|     this._socket.on('timeout', function() {
 | |
|       self.bound = false;
 | |
|       self.emit('close');
 | |
|     });
 | |
| 
 | |
|     this._socket.on('close', function() {
 | |
|       self.bound = false;
 | |
|       self.emit('close');
 | |
|     });
 | |
| 
 | |
|     this.catchMessages();
 | |
|   }
 | |
| };
 | |
| 
 | |
| TCPSocket.prototype.catchMessages = function() {
 | |
|   var self = this;
 | |
|   this._socket.on('data', function(data) {
 | |
|     var len, tmp;
 | |
|     if (!self._rest) {
 | |
|       self._rest = data;
 | |
|     } else {
 | |
|       tmp = new Buffer(self._rest.length + data.length);
 | |
|       self._rest.copy(tmp, 0);
 | |
|       data.copy(tmp, self._rest.length);
 | |
|       self._rest = tmp;
 | |
|     }
 | |
|     while (self._rest && self._rest.length > 2) {
 | |
|       len = self._rest.readUInt16BE(0);
 | |
|       if (self._rest.length >= len + 2) {
 | |
|         self.emit('message', self._rest.slice(2, len + 2), self);
 | |
|         self._rest = self._rest.slice(len + 2);
 | |
|       } else {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| };
 | |
| 
 | |
| TCPSocket.prototype.close = function() {
 | |
|   this._socket.end();
 | |
| };
 | |
| 
 | |
| TCPSocket.prototype.remote = function() {
 | |
|   return this;
 | |
| };
 | |
| 
 | |
| exports.reverseIP = function(ip) {
 | |
|   var address, kind, reverseip, parts;
 | |
|   address = ipaddr.parse(ip.split(/%/)[0]);
 | |
|   kind = address.kind();
 | |
| 
 | |
|   switch (kind) {
 | |
|     case 'ipv4':
 | |
|       address = address.toByteArray();
 | |
|       address.reverse();
 | |
|       reverseip = address.join('.') + '.IN-ADDR.ARPA';
 | |
|       break;
 | |
|     case 'ipv6':
 | |
|       parts = [];
 | |
|       address.toNormalizedString().split(':').forEach(function(part) {
 | |
|         var i, pad = 4 - part.length;
 | |
|         for (i = 0; i < pad; i++) {
 | |
|           part = '0' + part;
 | |
|         }
 | |
|         part.split('').forEach(function(p) {
 | |
|           parts.push(p);
 | |
|         });
 | |
|       });
 | |
|       parts.reverse();
 | |
|       reverseip = parts.join('.') + '.IP6.ARPA';
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   return reverseip;
 | |
| };
 |