summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMatt Ranney <mjr@ranney.com>2010-07-05 13:38:13 -0700
committerRyan Dahl <ry@tinyclouds.org>2010-07-15 10:27:44 -0700
commit4e50197e5330b7f1f603981f6dc817cac7f9a4f9 (patch)
treee012835aeb46ab7b5e74bbdc471e054d17ff9df6 /lib
parente7c4f8cdaa5905a45fa990354023330f3309e4ae (diff)
downloadnode-new-4e50197e5330b7f1f603981f6dc817cac7f9a4f9.tar.gz
Datagram socket refactor. Add tests and documentation.
Support setTTL() and setBroadcast() socket options.
Diffstat (limited to 'lib')
-rw-r--r--lib/dgram.js249
-rw-r--r--lib/dns.js2
2 files changed, 133 insertions, 118 deletions
diff --git a/lib/dgram.js b/lib/dgram.js
index ed9eec716b..9c27c8b4d8 100644
--- a/lib/dgram.js
+++ b/lib/dgram.js
@@ -7,12 +7,9 @@ var Buffer = require('buffer').Buffer;
var IOWatcher = process.IOWatcher;
var binding = process.binding('net');
var socket = binding.socket;
-var bind = binding.bind;
var recvfrom = binding.recvfrom;
-var sendto = binding.sendto;
var close = binding.close;
var ENOENT = binding.ENOENT;
-var setBroadcast = binding.setBroadcast;
function isPort (x) { return parseInt(x) >= 0; }
var pool = null;
@@ -31,18 +28,19 @@ function getPool() {
return pool;
}
-function Socket (broadcast, listener) {
+function Socket (type, listener) {
events.EventEmitter.call(this);
var self = this;
- if (typeof(broadcast) != 'boolean') {
- listener = broadcast;
- broadcast = false;
+ self.type = type;
+ if (type === "unix_dgram" || type === "udp4" || type === "udp6") {
+ self.fd = socket(self.type);
+ } else {
+ throw new Error("Bad socket type specified. Valid types are: unix_dgram, udp4, udp6");
}
- self.broadcast = broadcast;
- if (listener) {
- self.addListener('message', listener);
+ if (typeof listener === 'function') {
+ self.on('message', listener);
}
self.watcher = new IOWatcher();
@@ -59,156 +57,173 @@ function Socket (broadcast, listener) {
p.used += rinfo.size;
}
};
+
+ if (self.type === "udp4" || self.type === "udp6") {
+ self._startWatcher();
+ }
}
sys.inherits(Socket, events.EventEmitter);
exports.Socket = Socket;
-exports.createSocket = function (broadcast, listener) {
- return new Socket(broadcast, listener);
+exports.createSocket = function (type, listener) {
+ return new Socket(type, listener);
};
Socket.prototype.bind = function () {
var self = this;
- if (self.fd) throw new Error('Server already opened');
-
- if (!isPort(arguments[0])) {
- /* TODO: unix path dgram */
- self.fd = socket('unix_dgram');
- self.type = 'unix_dgram';
- var path = arguments[0];
- self.path = path;
- // unlink sockfile if it exists
- fs.stat(path, function (err, r) {
- if (err) {
- if (err.errno == ENOENT) {
- bind(self.fd, path);
- process.nextTick(function() {
- self._startWatcher();
- });
- } else {
- throw r;
- }
+
+ if (this.type === "unix_dgram") { // bind(path)
+ if (typeof arguments[0] !== "string") {
+ throw new Error("unix_dgram sockets must be bound to a path in the filesystem");
+ }
+ this.path = arguments[0];
+
+ fs.unlink(this.path, function (err) { // unlink old file, OK if it doesn't exist
+ if (err && err.errno !== ENOENT) {
+ throw err;
} else {
- if (!r.isFile()) {
- throw new Error("Non-file exists at " + path);
- } else {
- fs.unlink(path, function (err) {
- if (err) {
- throw err;
- } else {
- bind(self.fd, path);
- process.nextTick(function() {
- self._startWatcher();
- });
- }
- });
+ try {
+ binding.bind(self.fd, self.path);
+ self._startWatcher();
+ self.emit("listening");
+ } catch (err) {
+ console.log("Error in unix_dgram bind of " + self.path);
+ console.log(err.stack);
+ throw err;
}
}
});
- } else if (!arguments[1]) {
- // Don't bind(). OS will assign a port with INADDR_ANY.
- // The port can be found with server.address()
- self.type = 'udp4';
- self.fd = socket(self.type);
- bind(self.fd, arguments[0]);
- process.nextTick(function() {
- self._startWatcher();
- });
- } else {
- // the first argument is the port, the second an IP
- var port = arguments[0];
- dns.lookup(arguments[1], function (err, ip, addressType) {
- if (err) {
- self.emit('error', err);
+ } else if (this.type === "udp4" || this.type === "udp6") { // bind(port, [address])
+ if (arguments[1] === undefined) {
+ // Not bind()ing a specific address. Use INADDR_ANY and OS will pick one.
+ // The address can be found with server.address()
+ binding.bind(self.fd, arguments[0]);
+ this.emit("listening");
+ } else {
+ // the first argument is the port, the second an address
+ this.port = arguments[0];
+ if (dns.isIP(arguments[1])) {
+ this.address = arguments[1];
+ binding.bind(self.fd, port, arguments[1]);
+ this.emit("listening");
} else {
- self.type = addressType == 4 ? 'udp4' : 'udp6';
- self.fd = socket(self.type);
- bind(self.fd, port, ip);
- process.nextTick(function() {
- self._startWatcher();
+ dns.lookup(arguments[1], function (err, ip, addressType) {
+ // TODO - only look up proper record for address family
+ if (err) {
+ self.emit('error', err);
+ } else {
+ self.ip = ip;
+ binding.bind(self.fd, self.port, ip);
+ self.emit("listening");
+ }
});
}
- });
+ }
}
};
Socket.prototype._startWatcher = function () {
- this.watcher.set(this.fd, true, false);
- this.watcher.start();
- this.emit("listening");
+ if (! this._watcherStarted) {
+ this.watcher.set(this.fd, true, false); // listen for read ready, not write ready
+ this.watcher.start();
+ this._watcherStarted = true;
+ }
};
Socket.prototype.address = function () {
- return getsockname(this.fd);
+ return binding.getsockname(this.fd);
};
-Socket.prototype.send = function(port, addr, buffer, offset, length) {
- var self = this;
+Socket.prototype.setBroadcast = function(arg) {
+ if (arg) {
+ return binding.setBroadcast(this.fd, 1);
+ } else {
+ return binding.setBroadcast(this.fd, 0);
+ }
+};
- var lastArg = arguments[arguments.length - 1];
- var callback = typeof lastArg === 'function' ? lastArg : null;
+Socket.prototype.setTTL = function(arg) {
+ var newttl = parseInt(arg);
+
+ if (newttl > 0 && newttl < 256) {
+ return binding.setTTL(this.fd, newttl);
+ } else {
+ throw new Error("New TTL must be between 1 and 255");
+ }
+};
- if (!isPort(arguments[0])) {
- try {
- if (!self.fd) {
- self.type = 'unix_dgram';
- self.fd = socket(self.type);
- }
- var bytes = sendto(self.fd, buffer, offset, length, 0, port, addr);
- } catch (e) {
- if (callback) callback(e);
- return;
- }
+// translate arguments from JS API into C++ API, after optional DNS lookup
+Socket.prototype.send = function(buffer, offset, length) {
+ var self = this;
- if (callback) callback(null, bytes);
+ if (typeof offset !== "number" || typeof length !== "number") {
+ throw new Error("send takes offset and length as args 2 and 3");
+ }
- } else {
- dns.lookup(arguments[1], function (err, ip, addressType) {
- // DNS error
- if (err) {
- if (callback) callback(err);
- self.emit('error', err);
- return;
- }
+ if (this.type === "unix_dgram") { // send(buffer, offset, length, path [, callback])
+ if (typeof arguments[3] !== "string") {
+ throw new Error("unix_dgram sockets must send to a path in the filesystem");
+ }
- try {
- if (!self.fd) {
- self.type = addressType == 4 ? 'udp4' : 'udp6';
- self.fd = socket(self.type);
- setBroadcast(self.fd, self.broadcast);
- process.nextTick(function() {
- self._startWatcher();
- });
+ self.sendto(buffer, offset, length, arguments[3], null, arguments[4]);
+ } else if (this.type === "udp4" || this.type === "udp6") { // send(buffer, offset, length, port, address [, callback])
+ if (typeof arguments[4] !== "string") {
+ throw new Error(this.type + " sockets must send to port, address");
+ }
+
+ if (dns.isIP(arguments[4])) {
+ self.sendto(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
+ } else {
+ var port = arguments[3],
+ callback = arguments[5];
+
+ // TODO - only look up proper record for address family
+ dns.lookup(arguments[4], function (err, ip, addressType) {
+ if (err) { // DNS error
+ if (callback) {
+ callback(err);
+ }
+ self.emit('error', err);
+ return;
}
- var bytes = sendto(self.fd, buffer, offset, length, 0, port, ip);
- } catch (err) {
- // socket creation, or sendto error.
- if (callback) callback(err);
- return;
- }
+ self.sendto(buffer, offset, length, port, ip, callback);
+ });
+ }
+ }
+};
- if (callback) callback(null, bytes);
- });
+Socket.prototype.sendto = function(buffer, offset, length, port, addr, callback) {
+ try {
+ var bytes = binding.sendto(this.fd, buffer, offset, length, 0, port, addr);
+ } catch (err) {
+ if (callback) {
+ callback(err);
+ }
+ return;
+ }
+
+ if (callback) {
+ callback(null, bytes);
}
};
Socket.prototype.close = function () {
var self = this;
- if (!self.fd) throw new Error('Not running');
+ if (!this.fd) throw new Error('Not running');
- self.watcher.stop();
+ this.watcher.stop();
+ this._watcherStarted = false;
- close(self.fd);
- self.fd = null;
+ close(this.fd);
+ this.fd = null;
- if (self.type === "unix_dgram") {
- fs.unlink(self.path, function () {
+ if (this.type === "unix_dgram" && this.path) {
+ fs.unlink(this.path, function () {
self.emit("close");
});
} else {
- self.emit("close");
+ this.emit("close");
}
};
-
diff --git a/lib/dns.js b/lib/dns.js
index 52aa034272..afd5cb1fcc 100644
--- a/lib/dns.js
+++ b/lib/dns.js
@@ -71,7 +71,7 @@ var channel = new dns.Channel({SOCK_STATE_CB: function (socket, read, write) {
updateTimer();
}});
-
+exports.isIP = dns.isIP;
exports.resolve = function (domain, type_, callback_) {
var type, callback;