blob: 211523e5799fdc90bd27db5d598c24f2353cf96c [file] [log] [blame]
var events = require ("events");
var net = require ("net");
var raw = require ("./build/Release/raw");
var util = require ("util");
function _expandConstantObject (object) {
var keys = [];
for (key in object)
keys.push (key);
for (var i = 0; i < keys.length; i++)
object[object[keys[i]]] = parseInt (keys[i]);
}
var AddressFamily = {
1: "IPv4",
2: "IPv6"
};
_expandConstantObject (AddressFamily);
var Protocol = {
0: "None",
1: "ICMP",
6: "TCP",
17: "UDP",
58: "ICMPv6"
};
_expandConstantObject (Protocol);
for (var key in events.EventEmitter.prototype) {
raw.SocketWrap.prototype[key] = events.EventEmitter.prototype[key];
}
function Socket (options) {
Socket.super_.call (this);
this.requests = [];
this.buffer = new Buffer ((options && options.bufferSize)
? options.bufferSize
: 4096);
this.recvPaused = false;
this.sendPaused = true;
this.wrap = new raw.SocketWrap (
((options && options.protocol)
? options.protocol
: 0),
((options && options.addressFamily)
? options.addressFamily
: AddressFamily.IPv4)
);
var me = this;
this.wrap.on ("sendReady", this.onSendReady.bind (me));
this.wrap.on ("recvReady", this.onRecvReady.bind (me));
this.wrap.on ("error", this.onError.bind (me));
this.wrap.on ("close", this.onClose.bind (me));
};
util.inherits (Socket, events.EventEmitter);
Socket.prototype.close = function () {
this.wrap.close ();
return this;
}
Socket.prototype.getOption = function (level, option, value, length) {
return this.wrap.getOption (level, option, value, length);
}
Socket.prototype.onClose = function () {
this.emit ("close");
}
Socket.prototype.onError = function (error) {
this.emit ("error", error);
this.close ();
}
Socket.prototype.onRecvReady = function () {
var me = this;
try {
this.wrap.recv (this.buffer, function (buffer, bytes, source) {
var newBuffer = buffer.slice (0, bytes);
me.emit ("message", newBuffer, source);
});
} catch (error) {
me.emit ("error", error);
}
}
Socket.prototype.onSendReady = function () {
if (this.requests.length > 0) {
var me = this;
var req = this.requests.shift ();
try {
if (req.beforeCallback)
req.beforeCallback ();
this.wrap.send (req.buffer, req.offset, req.length,
req.address, function (bytes) {
req.afterCallback.call (me, null, bytes);
});
} catch (error) {
req.afterCallback.call (me, error, 0);
}
} else {
if (! this.sendPaused)
this.pauseSend ();
}
}
Socket.prototype.pauseRecv = function () {
this.recvPaused = true;
this.wrap.pause (this.recvPaused, this.sendPaused);
return this;
}
Socket.prototype.pauseSend = function () {
this.sendPaused = true;
this.wrap.pause (this.recvPaused, this.sendPaused);
return this;
}
Socket.prototype.resumeRecv = function () {
this.recvPaused = false;
this.wrap.pause (this.recvPaused, this.sendPaused);
return this;
}
Socket.prototype.resumeSend = function () {
this.sendPaused = false;
this.wrap.pause (this.recvPaused, this.sendPaused);
return this;
}
Socket.prototype.send = function (buffer, offset, length, address,
beforeCallback, afterCallback) {
if (! afterCallback) {
afterCallback = beforeCallback;
beforeCallback = null;
}
if (length + offset > buffer.length) {
afterCallback.call (this, new Error ("Buffer length '" + buffer.length
+ "' is not large enough for the specified offset '" + offset
+ "' plus length '" + length + "'"));
return this;
}
if (! net.isIP (address)) {
afterCallback.call (this, new Error ("Invalid IP address '" + address + "'"));
return this;
}
var req = {
buffer: buffer,
offset: offset,
length: length,
address: address,
afterCallback: afterCallback,
beforeCallback: beforeCallback
};
this.requests.push (req);
if (this.sendPaused)
this.resumeSend ();
return this;
}
Socket.prototype.setOption = function (level, option, value, length) {
if (arguments.length > 3)
this.wrap.setOption (level, option, value, length);
else
this.wrap.setOption (level, option, value);
}
exports.createChecksum = function () {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
var object = arguments[i];
if (object instanceof Buffer) {
sum = raw.createChecksum (sum, object, 0, object.length);
} else {
sum = raw.createChecksum (sum, object.buffer, object.offset,
object.length);
}
}
return sum;
}
exports.writeChecksum = function (buffer, offset, checksum) {
buffer.writeUInt8 ((checksum & 0xff00) >> 8, offset);
buffer.writeUInt8 (checksum & 0xff, offset + 1);
return buffer;
}
exports.createSocket = function (options) {
return new Socket (options || {});
};
exports.AddressFamily = AddressFamily;
exports.Protocol = Protocol;
exports.Socket = Socket;
exports.SocketLevel = raw.SocketLevel;
exports.SocketOption = raw.SocketOption;
exports.htonl = raw.htonl;
exports.htons = raw.htons;
exports.ntohl = raw.ntohl;
exports.ntohs = raw.ntohs;