Browse Source

Datagram socket refactor. Add tests and documentation.

Support setTTL() and setBroadcast() socket options.
v0.7.4-release
Matt Ranney 15 years ago
committed by Ryan Dahl
parent
commit
4e50197e53
  1. 262
      doc/api.markdown
  2. 215
      lib/dgram.js
  3. 2
      lib/dns.js
  4. 72
      src/node_net.cc
  5. 49
      test/simple/test-dgram-pingpong.js
  6. 52
      test/simple/test-dgram-udp4.js
  7. 56
      test/simple/test-dgram-unix-anon.js
  8. 55
      test/simple/test-dgram-unix.js

262
doc/api.markdown

@ -2351,97 +2351,6 @@ initialDelay will leave the value unchanged from the default
## dgram
This class is used to create datagram sockets, for sending and receiving UDP
and UNIX daemon sockets.
An server listening for UDP packets on port 8125:
var dgram = require('dgram');
var server = dgram.createSocket(function (msg, rinfo) {
console.log("connection from " + rinfo.address + ":"+ rinfo.port);
console.log("server got: " + msg);
});
server.bind(8125, 'localhost');
To listen on the socket `'/tmp/echo.sock'`, change the last line:
server.bind('/tmp/echo.sock');
A client which sends UDP packets to port 8125:
var dgram = require("dgram");
var Buffer = require('buffer').Buffer;
var buf = new Buffer('hello');
var client = dgram.createSocket();
client.send(8125, 'localhost', buf, 0, buf.length);
Note the use of a `Buffer` rather than a string object.
### Event: 'listening'
`function () {}`
Emitted when a server has finished its bind and is ready to receive data.
### Event: 'message'
`function (msg, rinfo) {}`
Emitted when a socket receives data. msg is a `Buffer`, not a string. rinfo.port and rinfo.address contains the sender's port and IP.
### Event: 'error'
`function (exception) { }`
An error on the socket will emit this event.
### Event: 'close'
`function () {}`
Emitted when the socket closes.
### dgram.createSocket(messageListener)
Creates a new dgram socket. The `messageListener` argument is
automatically set as a listener for the `'message'` event.
### socket.bind(port, host=null)
Begin accepting connections on the specified `port` and `host`. If the
`host` is omitted, the server will accept connections directed to any
IPv4 address (`INADDR_ANY`).
### socket.bind(path)
Start a UNIX socket server listening for connections on the given `path`.
### socket.send(port, addr, buffer, offset, length)
Send a packet over the socket to a port and host or IP. `port` and `addr` define the destination, `buffer` should be a `Buffer` object, and offset and length give the start bytes and total bytes to send in this packet.
### socket.send(path, _, buffer, offset, length)
Send a packet over the socket to a UNIX daemon socket. `path` defines the destination, and the second argument is unused. `buffer` should be a `Buffer` object, and offset and length give the start bytes and total bytes to send in this packet.
### socket.close()
Close the socket. This function is asynchronous, the server is finally closed
when the server emits a `'close'` event.
## Crypto ## Crypto
Use `require('crypto')` to access this module. Use `require('crypto')` to access this module.
@ -2648,6 +2557,177 @@ Each DNS query can return an error code.
- `dns.BADQUERY`: the query is malformed. - `dns.BADQUERY`: the query is malformed.
## dgram
Datagram sockets are available through `require('dgram')`. Datagrams are most commonly
handled as IP/UDP messages, but they can also be used over Unix domain sockets.
### Event: 'message'
`function (msg, rinfo) { }`
Emitted when a new datagram is available on a socket. `msg` is a `Buffer` and `rinfo` is
an object with the sender's address information and the number of bytes in the datagram.
### Event: 'listening'
`function () { }`
Emitted when a socket starts listening for datagrams. This happens as soon as UDP sockets
are created. Unix domain sockets do not start listening until calling `bind()` on them.
### Event: 'close'
`function () { }`
Emitted when a socket is closed with `close()`. No new `message` events will be emitted
on this socket.
### dgram.createSocket(type [, callback])
Creates a datagram socket of the specified types. Valid types are:
`udp4`, `udp6`, and `unix_dgram`.
Takes an optional callback which is added as a listener for `message` events.
### dgram.send(buf, offset, length, path [, callback])
For Unix domain datagram sockets, the destination address is a pathname in the filesystem.
An optional callback may be supplied that is invoked after the `sendto` call is completed
by the OS. It is not safe to re-use `buf` until the callback is invoked. Note that
unless the socket is bound to a pathname with `bind()` there is no way to receive messages
on this socket.
Example of sending a message to syslogd on OSX via Unix domain socket `/var/run/syslog`:
var dgram = require('dgram'),
Buffer = require('buffer').Buffer,
client, message;
message = new Buffer("A message to log.");
client = dgram.createSocket("unix_dgram");
client.send(message, 0, message.length, "/var/run/syslog",
function (err, bytes) {
if (err) {
throw err;
}
console.log("Wrote " + bytes + " bytes to socket.");
});
### dgram.send(buf, offset, length, port, address [, callback])
For UDP sockets, the destination port and IP address must be specified. A string
may be supplied for the `address` parameter, and it will be resolved with DNS. An
optional callback may be specified to detect any DNS errors and when `buf` may be
re-used. Note that DNS lookups will delay the time that a send takes place, at
least until the next tick. The only way to know for sure that a send has taken place
is to use the callback.
Example of sending a UDP packet to a random port on `localhost`;
var dgram = require('dgram'),
Buffer = require('buffer').Buffer,
client, message;
message = new Buffer("Some bytes");
client = dgram.createSocket("udp4");
client.send(message, 0, message.length, 41234, "localhost");
client.close();
### dgram.bind(path)
For Unix domain datagram sockets, start listening for incoming datagrams on a
socket specified by `path`. Note that clients may `send()` without `bind()`,
but no datagrams will be received without a `bind()`.
Example of a Unix domain datagram server that echoes back all messages it receives:
var Buffer = require("buffer").Buffer,
dgram = require("dgram"), server
server_path = "/tmp/dgram_server_sock";
server = dgram.createSocket("unix_dgram");
server.on("message", function (msg, rinfo) {
console.log("got: " + msg + " from " + rinfo.address);
server.send(msg, 0, msg.length, rinfo.address);
});
server.on("listening", function () {
console.log("server listening " + server.address().address);
})
server.bind(server_path);
Example of a Unix domain datagram client that talks to this server:
var Buffer = require("buffer").Buffer,
dgram = require("dgram"),
server_path = "/tmp/dgram_server_sock",
client_path = "/tmp/dgram_client_sock", client, message;
message = new Buffer("A message at " + (new Date()));
client = dgram.createSocket("unix_dgram");
client.on("message", function (msg, rinfo) {
console.log("got: " + msg + " from " + rinfo.address);
});
client.on("listening", function () {
console.log("client listening " + client.address().address);
client.send(message, 0, message.length, server_path);
});
client.bind(client_path);
### dgram.bind(port [, address])
For UDP sockets, listen for datagrams on a named `port` and optional `address`. If
`address` is not specified, the OS will try to listen on all addresses.
Example of a UDP server listening on port 41234:
var Buffer = require("buffer").Buffer,
dgram = require("dgram"), server,
message_to_send = new Buffer("A message to send");
server = dgram.createSocket("udp4");
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg + " from " +
rinfo.address + ":" + rinfo.port);
});
server.on("listening", function () {
var address = server.address();
console.log("server listening " +
address.address + ":" + address.port);
});
server.bind(41234);
// server listening 0.0.0.0:41234
### dgram.close()
Close the underlying socket and stop listening for data on it. UDP sockets
automatically listen for messages, even if they did not call `bind()`.
### dgram.address()
Returns an object containing the address information for a socket. For UDP sockets,
this object will contain `address` and `port`. For Unix domain sockets, it will contain
only `address`.
### dgram.setBroadcast(flag)
Sets or clears the `SO_BROADCAST` socket option. When this option is set, UDP packets
may be sent to a local interface's broadcast address.
### dgram.setTTL(ttl)
Sets the `IP_TTL` socket option. TTL stands for "Time to Live," but in this context it
specifies the number of IP hops that a packet is allowed to go through. Each router or
gateway that forwards a packet decrements the TTL. If the TTL is decremented to 0 by a
router, it will not be forwarded. Changing TTL values is typically done for network
probes or when multicasting.
The argument to `setTTL()` is a number of hops between 1 and 255. The default on most
systems is 64.
## Assert ## Assert
This module is used for writing unit tests for your applications, you can This module is used for writing unit tests for your applications, you can

215
lib/dgram.js

@ -7,12 +7,9 @@ var Buffer = require('buffer').Buffer;
var IOWatcher = process.IOWatcher; var IOWatcher = process.IOWatcher;
var binding = process.binding('net'); var binding = process.binding('net');
var socket = binding.socket; var socket = binding.socket;
var bind = binding.bind;
var recvfrom = binding.recvfrom; var recvfrom = binding.recvfrom;
var sendto = binding.sendto;
var close = binding.close; var close = binding.close;
var ENOENT = binding.ENOENT; var ENOENT = binding.ENOENT;
var setBroadcast = binding.setBroadcast;
function isPort (x) { return parseInt(x) >= 0; } function isPort (x) { return parseInt(x) >= 0; }
var pool = null; var pool = null;
@ -31,18 +28,19 @@ function getPool() {
return pool; return pool;
} }
function Socket (broadcast, listener) { function Socket (type, listener) {
events.EventEmitter.call(this); events.EventEmitter.call(this);
var self = this; var self = this;
if (typeof(broadcast) != 'boolean') { self.type = type;
listener = broadcast; if (type === "unix_dgram" || type === "udp4" || type === "udp6") {
broadcast = false; 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) { if (typeof listener === 'function') {
self.addListener('message', listener); self.on('message', listener);
} }
self.watcher = new IOWatcher(); self.watcher = new IOWatcher();
@ -59,156 +57,173 @@ function Socket (broadcast, listener) {
p.used += rinfo.size; p.used += rinfo.size;
} }
}; };
if (self.type === "udp4" || self.type === "udp6") {
self._startWatcher();
}
} }
sys.inherits(Socket, events.EventEmitter); sys.inherits(Socket, events.EventEmitter);
exports.Socket = Socket; exports.Socket = Socket;
exports.createSocket = function (broadcast, listener) { exports.createSocket = function (type, listener) {
return new Socket(broadcast, listener); return new Socket(type, listener);
}; };
Socket.prototype.bind = function () { Socket.prototype.bind = function () {
var self = this; var self = this;
if (self.fd) throw new Error('Server already opened');
if (this.type === "unix_dgram") { // bind(path)
if (!isPort(arguments[0])) { if (typeof arguments[0] !== "string") {
/* TODO: unix path dgram */ throw new Error("unix_dgram sockets must be bound to a path in the filesystem");
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;
} }
} else { this.path = arguments[0];
if (!r.isFile()) {
throw new Error("Non-file exists at " + path); fs.unlink(this.path, function (err) { // unlink old file, OK if it doesn't exist
} else { if (err && err.errno !== ENOENT) {
fs.unlink(path, function (err) {
if (err) {
throw err; throw err;
} else { } else {
bind(self.fd, path); try {
process.nextTick(function() { binding.bind(self.fd, self.path);
self._startWatcher(); 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]) { } else if (this.type === "udp4" || this.type === "udp6") { // bind(port, [address])
// Don't bind(). OS will assign a port with INADDR_ANY. if (arguments[1] === undefined) {
// The port can be found with server.address() // Not bind()ing a specific address. Use INADDR_ANY and OS will pick one.
self.type = 'udp4'; // The address can be found with server.address()
self.fd = socket(self.type); binding.bind(self.fd, arguments[0]);
bind(self.fd, arguments[0]); this.emit("listening");
process.nextTick(function() { } else {
self._startWatcher(); // 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 { } else {
// the first argument is the port, the second an IP
var port = arguments[0];
dns.lookup(arguments[1], function (err, ip, addressType) { dns.lookup(arguments[1], function (err, ip, addressType) {
// TODO - only look up proper record for address family
if (err) { if (err) {
self.emit('error', err); self.emit('error', err);
} else { } else {
self.type = addressType == 4 ? 'udp4' : 'udp6'; self.ip = ip;
self.fd = socket(self.type); binding.bind(self.fd, self.port, ip);
bind(self.fd, port, ip); self.emit("listening");
process.nextTick(function() {
self._startWatcher();
});
} }
}); });
} }
}
}
}; };
Socket.prototype._startWatcher = function () { Socket.prototype._startWatcher = function () {
this.watcher.set(this.fd, true, false); if (! this._watcherStarted) {
this.watcher.set(this.fd, true, false); // listen for read ready, not write ready
this.watcher.start(); this.watcher.start();
this.emit("listening"); this._watcherStarted = true;
}
}; };
Socket.prototype.address = function () { Socket.prototype.address = function () {
return getsockname(this.fd); return binding.getsockname(this.fd);
}; };
Socket.prototype.send = function(port, addr, buffer, offset, length) { Socket.prototype.setBroadcast = function(arg) {
var self = this; if (arg) {
return binding.setBroadcast(this.fd, 1);
} else {
return binding.setBroadcast(this.fd, 0);
}
};
var lastArg = arguments[arguments.length - 1]; Socket.prototype.setTTL = function(arg) {
var callback = typeof lastArg === 'function' ? lastArg : null; var newttl = parseInt(arg);
if (!isPort(arguments[0])) { if (newttl > 0 && newttl < 256) {
try { return binding.setTTL(this.fd, newttl);
if (!self.fd) { } else {
self.type = 'unix_dgram'; throw new Error("New TTL must be between 1 and 255");
self.fd = socket(self.type);
} }
var bytes = sendto(self.fd, buffer, offset, length, 0, port, addr); };
} catch (e) {
if (callback) callback(e); // translate arguments from JS API into C++ API, after optional DNS lookup
return; Socket.prototype.send = function(buffer, offset, length) {
var self = this;
if (typeof offset !== "number" || typeof length !== "number") {
throw new Error("send takes offset and length as args 2 and 3");
}
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");
} }
if (callback) callback(null, bytes); 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 { } else {
dns.lookup(arguments[1], function (err, ip, addressType) { var port = arguments[3],
// DNS error callback = arguments[5];
if (err) {
if (callback) callback(err); // 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); self.emit('error', err);
return; return;
} }
self.sendto(buffer, offset, length, port, ip, callback);
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();
}); });
} }
var bytes = sendto(self.fd, buffer, offset, length, 0, port, ip); }
};
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) { } catch (err) {
// socket creation, or sendto error. if (callback) {
if (callback) callback(err); callback(err);
}
return; return;
} }
if (callback) callback(null, bytes); if (callback) {
}); callback(null, bytes);
} }
}; };
Socket.prototype.close = function () { Socket.prototype.close = function () {
var self = this; 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); close(this.fd);
self.fd = null; this.fd = null;
if (self.type === "unix_dgram") { if (this.type === "unix_dgram" && this.path) {
fs.unlink(self.path, function () { fs.unlink(this.path, function () {
self.emit("close"); self.emit("close");
}); });
} else { } else {
self.emit("close"); this.emit("close");
} }
}; };

2
lib/dns.js

@ -71,7 +71,7 @@ var channel = new dns.Channel({SOCK_STATE_CB: function (socket, read, write) {
updateTimer(); updateTimer();
}}); }});
exports.isIP = dns.isIP;
exports.resolve = function (domain, type_, callback_) { exports.resolve = function (domain, type_, callback_) {
var type, callback; var type, callback;

72
src/node_net.cc

@ -355,6 +355,7 @@ do { \
int port; \ int port; \
struct sockaddr_in *a4; \ struct sockaddr_in *a4; \
struct sockaddr_in6 *a6; \ struct sockaddr_in6 *a6; \
struct sockaddr_un *au; \
switch ((address_storage).ss_family) { \ switch ((address_storage).ss_family) { \
case AF_INET6: \ case AF_INET6: \
a6 = (struct sockaddr_in6*)&(address_storage); \ a6 = (struct sockaddr_in6*)&(address_storage); \
@ -370,6 +371,13 @@ do { \
(info)->Set(address_symbol, String::New(ip)); \ (info)->Set(address_symbol, String::New(ip)); \
(info)->Set(port_symbol, Integer::New(port)); \ (info)->Set(port_symbol, Integer::New(port)); \
break; \ break; \
case AF_UNIX: \
au = (struct sockaddr_un*)&(address_storage); \
char un_path[105]; \
strncpy(un_path, au->sun_path, au->sun_len-2); \
un_path[au->sun_len-2] = 0; \
(info)->Set(address_symbol, String::New(un_path)); \
break; \
} \ } \
} while (0) } while (0)
@ -971,22 +979,6 @@ static Handle<Value> SetNoDelay(const Arguments& args) {
return Undefined(); return Undefined();
} }
static Handle<Value> SetBroadcast(const Arguments& args) {
int flags, r;
HandleScope scope;
FD_ARG(args[0])
flags = args[1]->IsFalse() ? 0 : 1;
r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void *)&flags, sizeof(flags));
if (r < 0) {
return ThrowException(ErrnoException(errno, "setsockopt"));
}
return Undefined();
}
static Handle<Value> SetKeepAlive(const Arguments& args) { static Handle<Value> SetKeepAlive(const Arguments& args) {
int r; int r;
HandleScope scope; HandleScope scope;
@ -1018,6 +1010,53 @@ static Handle<Value> SetKeepAlive(const Arguments& args) {
return Undefined(); return Undefined();
} }
static Handle<Value> SetBroadcast(const Arguments& args) {
int flags, r;
HandleScope scope;
FD_ARG(args[0])
flags = args[1]->IsFalse() ? 0 : 1;
r = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void *)&flags, sizeof(flags));
if (r < 0) {
return ThrowException(ErrnoException(errno, "setsockopt"));
} else {
return scope.Close(Integer::New(flags));
}
}
static Handle<Value> SetTTL(const Arguments& args) {
HandleScope scope;
if (args.Length() != 2) {
return ThrowException(Exception::TypeError(
String::New("Takes exactly two arguments: fd, new TTL")));
}
FD_ARG(args[0]);
if (! args[1]->IsInt32()) {
return ThrowException(Exception::TypeError(
String::New("Argument must be a number")));
}
int newttl = args[1]->Int32Value();
if (newttl < 1 || newttl > 255) {
return ThrowException(Exception::TypeError(
String::New("new TTL must be between 1 and 255")));
}
int r = setsockopt(fd, IPPROTO_IP, IP_TTL, (void *)&newttl, sizeof(newttl));
if (r < 0) {
return ThrowException(ErrnoException(errno, "setsockopt"));
} else {
return scope.Close(Integer::New(newttl));
}
}
// //
// G E T A D D R I N F O // G E T A D D R I N F O
// //
@ -1241,6 +1280,7 @@ void InitNet(Handle<Object> target) {
NODE_SET_METHOD(target, "toRead", ToRead); NODE_SET_METHOD(target, "toRead", ToRead);
NODE_SET_METHOD(target, "setNoDelay", SetNoDelay); NODE_SET_METHOD(target, "setNoDelay", SetNoDelay);
NODE_SET_METHOD(target, "setBroadcast", SetBroadcast); NODE_SET_METHOD(target, "setBroadcast", SetBroadcast);
NODE_SET_METHOD(target, "setTTL", SetTTL);
NODE_SET_METHOD(target, "setKeepAlive", SetKeepAlive); NODE_SET_METHOD(target, "setKeepAlive", SetKeepAlive);
NODE_SET_METHOD(target, "getsockname", GetSockName); NODE_SET_METHOD(target, "getsockname", GetSockName);
NODE_SET_METHOD(target, "getpeername", GetPeerName); NODE_SET_METHOD(target, "getpeername", GetPeerName);

49
test/simple/test-dgram-pingpong.js

@ -4,85 +4,82 @@ var dgram = require("dgram");
var tests_run = 0; var tests_run = 0;
function pingPongTest (port, host) { function pingPongTest (port, host) {
var callbacks = 0; var callbacks = 0;
var N = 500; var N = 500;
var count = 0; var count = 0;
var sent_final_ping = false; var sent_final_ping = false;
var server = dgram.createSocket(function (msg, rinfo) { var server = dgram.createSocket("udp4", function (msg, rinfo) {
console.log("connection: " + rinfo.address + ":"+ rinfo.port); console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port);
console.log("server got: " + msg);
if (/PING/.exec(msg)) { if (/PING/.exec(msg)) {
var buf = new Buffer(4); var buf = new Buffer(4);
buf.write('PONG'); buf.write('PONG');
server.send(rinfo.port, rinfo.address, buf, 0, buf.length, function (err, sent) { server.send(buf, 0, buf.length, rinfo.port, rinfo.address, function (err, sent) {
callbacks++; callbacks++;
}); });
} }
}); });
server.addListener("error", function (e) { server.on("error", function (e) {
throw e; throw e;
}); });
server.bind(port, host); server.on("listening", function () {
server.addListener("listening", function () {
console.log("server listening on " + port + " " + host); console.log("server listening on " + port + " " + host);
var buf = new Buffer(4); var buf = new Buffer('PING'),
buf.write('PING'); client = dgram.createSocket("udp4");
var client = dgram.createSocket();
client.addListener("message", function (msg, rinfo) { client.addListener("message", function (msg, rinfo) {
console.log("client got: " + msg); console.log("client got: " + msg + " from " + rinfo.address + ":" + rinfo.port);
assert.equal("PONG", msg.toString('ascii')); assert.equal("PONG", msg.toString('ascii'));
count += 1; count += 1;
if (count < N) { if (count < N) {
client.send(port, host, buf, 0, buf.length); client.send(buf, 0, buf.length, port, "localhost");
} else { } else {
sent_final_ping = true; sent_final_ping = true;
client.send(port, host, buf, 0, buf.length); client.send(buf, 0, buf.length, port, "localhost");
process.nextTick(function() { process.nextTick(function() {
client.close(); client.close();
}); });
} }
}); });
client.addListener("close", function () { client.on("close", function () {
console.log('client.close'); console.log('client has closed, closing server');
assert.equal(N, count); assert.equal(N, count);
tests_run += 1; tests_run += 1;
server.close(); server.close();
assert.equal(N-1, callbacks); assert.equal(N-1, callbacks);
}); });
client.addListener("error", function (e) { client.on("error", function (e) {
throw e; throw e;
}); });
client.send(port, host, buf, 0, buf.length); console.log("Client sending to " + port + ", localhost " + buf);
client.send(buf, 0, buf.length, port, "localhost", function (err, bytes) {
if (err) {
throw err;
}
console.log("Client sent " + bytes + " bytes");
});
count += 1; count += 1;
}); });
server.bind(port, host);
} }
/* All are run at once, so run on different ports */ // All are run at once, so run on different ports
pingPongTest(20989, "localhost"); pingPongTest(20989, "localhost");
pingPongTest(20990, "localhost"); pingPongTest(20990, "localhost");
pingPongTest(20988); pingPongTest(20988);
pingPongTest(20997, "::1");
//pingPongTest("/tmp/pingpong.sock"); //pingPongTest("/tmp/pingpong.sock");
process.addListener("exit", function () { process.addListener("exit", function () {
assert.equal(4, tests_run); assert.equal(3, tests_run);
console.log('done'); console.log('done');
}); });

52
test/simple/test-dgram-udp4.js

@ -0,0 +1,52 @@
require("../common");
var Buffer = require("buffer").Buffer,
fs = require("fs"),
dgram = require("dgram"), server, client,
server_port = 20989,
message_to_send = new Buffer("A message to send"),
timer;
server = dgram.createSocket("udp4");
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port);
assert.strictEqual(rinfo.address, "127.0.0.1");
assert.strictEqual(msg.toString(), message_to_send.toString());
server.send(msg, 0, msg.length, rinfo.port, rinfo.address);
});
server.on("listening", function () {
var address = server.address();
console.log("server is listening on " + address.address + ":" + address.port);
client = dgram.createSocket("udp4");
client.on("message", function (msg, rinfo) {
console.log("client got: " + msg + " from " + rinfo.address + ":" + address.port);
assert.strictEqual(rinfo.address, "127.0.0.1");
assert.strictEqual(rinfo.port, server_port);
assert.strictEqual(msg.toString(), message_to_send.toString());
client.close();
server.close();
});
client.send(message_to_send, 0, message_to_send.length, server_port, "localhost", function (err, bytes) {
if (err) {
console.log("Caught error in client send.");
throw err;
}
console.log("client wrote " + bytes + " bytes.");
assert.strictEqual(bytes, message_to_send.length);
});
client.on("close", function () {
if (server.fd === null) {
clearTimeout(timer);
}
});
});
server.on("close", function () {
if (client.fd === null) {
clearTimeout(timer);
}
});
server.bind(server_port);
timer = setTimeout(function () {
throw new Error("Timeout");
}, 200);

56
test/simple/test-dgram-unix-anon.js

@ -0,0 +1,56 @@
require("../common");
var Buffer = require("buffer").Buffer,
fs = require("fs"),
dgram = require("dgram"), server, client,
server_path = "/tmp/dgram_server_sock",
messages_to_send = [
new Buffer("First message to send"),
new Buffer("Second message to send"),
new Buffer("Third message to send"),
new Buffer("Fourth message to send")
],
timer;
server = dgram.createSocket("unix_dgram");
server.bind(server_path);
server.messages = [];
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg);
assert.strictEqual(rinfo.address, ""); // anon client sending
server.messages.push(msg.toString());
if (server.messages.length === messages_to_send.length) {
server.messages.forEach(function (m, i) {
assert.strictEqual(m, messages_to_send[i].toString());
});
server.close();
client.close();
}
});
server.on("listening", function () {
console.log("server is listening");
client = dgram.createSocket("unix_dgram");
messages_to_send.forEach(function (m) {
client.send(m, 0, m.length, server_path, function (err, bytes) {
if (err) {
console.log("Caught error in client send.");
throw err;
}
console.log("client wrote " + bytes + " bytes.");
});
});
client.on("close", function () {
if (server.fd === null) {
clearTimeout(timer);
}
});
});
server.on("close", function () {
if (client.fd === null) {
clearTimeout(timer);
}
});
timer = setTimeout(function () {
throw new Error("Timeout");
}, 200);

55
test/simple/test-dgram-unix.js

@ -0,0 +1,55 @@
require("../common");
var Buffer = require("buffer").Buffer,
fs = require("fs"),
dgram = require("dgram"), server, client,
server_path = "/tmp/dgram_server_sock",
client_path = "/tmp/dgram_client_sock",
message_to_send = new Buffer("A message to send"),
timer;
server = dgram.createSocket("unix_dgram");
server.on("message", function (msg, rinfo) {
console.log("server got: " + msg + " from " + rinfo.address);
assert.strictEqual(rinfo.address, client_path);
assert.strictEqual(msg.toString(), message_to_send.toString());
server.send(msg, 0, msg.length, rinfo.address);
});
server.on("listening", function () {
console.log("server is listening");
client = dgram.createSocket("unix_dgram");
client.on("message", function (msg, rinfo) {
console.log("client got: " + msg + " from " + rinfo.address);
assert.strictEqual(rinfo.address, server_path);
assert.strictEqual(msg.toString(), message_to_send.toString());
client.close();
server.close();
});
client.on("listening", function () {
console.log("client is listening");
client.send(message_to_send, 0, message_to_send.length, server_path, function (err, bytes) {
if (err) {
console.log("Caught error in client send.");
throw err;
}
console.log("client wrote " + bytes + " bytes.");
assert.strictEqual(bytes, message_to_send.length);
});
});
client.on("close", function () {
if (server.fd === null) {
clearTimeout(timer);
}
});
client.bind(client_path);
});
server.on("close", function () {
if (client.fd === null) {
clearTimeout(timer);
}
});
server.bind(server_path);
timer = setTimeout(function () {
throw new Error("Timeout");
}, 200);
Loading…
Cancel
Save