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
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.
## 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
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 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");
}
} else {
if (!r.isFile()) {
throw new Error("Non-file exists at " + path);
} else {
fs.unlink(path, function (err) {
if (err) {
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 {
bind(self.fd, path);
process.nextTick(function() {
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 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 {
// the first argument is the port, the second an IP
var port = arguments[0];
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.type = addressType == 4 ? 'udp4' : 'udp6';
self.fd = socket(self.type);
bind(self.fd, port, ip);
process.nextTick(function() {
self._startWatcher();
});
self.ip = ip;
binding.bind(self.fd, self.port, ip);
self.emit("listening");
}
});
}
}
}
};
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.emit("listening");
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 (!isPort(arguments[0])) {
try {
if (!self.fd) {
self.type = 'unix_dgram';
self.fd = socket(self.type);
if (newttl > 0 && newttl < 256) {
return binding.setTTL(this.fd, newttl);
} else {
throw new Error("New TTL must be between 1 and 255");
}
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 (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 {
dns.lookup(arguments[1], function (err, ip, addressType) {
// DNS error
if (err) {
if (callback) callback(err);
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;
}
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, port, ip, callback);
});
}
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) {
// socket creation, or sendto error.
if (callback) callback(err);
if (callback) {
callback(err);
}
return;
}
if (callback) callback(null, bytes);
});
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");
}
};

2
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;

72
src/node_net.cc

@ -355,6 +355,7 @@ do { \
int port; \
struct sockaddr_in *a4; \
struct sockaddr_in6 *a6; \
struct sockaddr_un *au; \
switch ((address_storage).ss_family) { \
case AF_INET6: \
a6 = (struct sockaddr_in6*)&(address_storage); \
@ -370,6 +371,13 @@ do { \
(info)->Set(address_symbol, String::New(ip)); \
(info)->Set(port_symbol, Integer::New(port)); \
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)
@ -971,22 +979,6 @@ static Handle<Value> SetNoDelay(const Arguments& args) {
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) {
int r;
HandleScope scope;
@ -1018,6 +1010,53 @@ static Handle<Value> SetKeepAlive(const Arguments& args) {
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
//
@ -1241,6 +1280,7 @@ void InitNet(Handle<Object> target) {
NODE_SET_METHOD(target, "toRead", ToRead);
NODE_SET_METHOD(target, "setNoDelay", SetNoDelay);
NODE_SET_METHOD(target, "setBroadcast", SetBroadcast);
NODE_SET_METHOD(target, "setTTL", SetTTL);
NODE_SET_METHOD(target, "setKeepAlive", SetKeepAlive);
NODE_SET_METHOD(target, "getsockname", GetSockName);
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;
function pingPongTest (port, host) {
var callbacks = 0;
var N = 500;
var count = 0;
var sent_final_ping = false;
var server = dgram.createSocket(function (msg, rinfo) {
console.log("connection: " + rinfo.address + ":"+ rinfo.port);
console.log("server got: " + msg);
var server = dgram.createSocket("udp4", function (msg, rinfo) {
console.log("server got: " + msg + " from " + rinfo.address + ":" + rinfo.port);
if (/PING/.exec(msg)) {
var buf = new Buffer(4);
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++;
});
}
});
server.addListener("error", function (e) {
server.on("error", function (e) {
throw e;
});
server.bind(port, host);
server.addListener("listening", function () {
server.on("listening", function () {
console.log("server listening on " + port + " " + host);
var buf = new Buffer(4);
buf.write('PING');
var client = dgram.createSocket();
var buf = new Buffer('PING'),
client = dgram.createSocket("udp4");
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'));
count += 1;
if (count < N) {
client.send(port, host, buf, 0, buf.length);
client.send(buf, 0, buf.length, port, "localhost");
} else {
sent_final_ping = true;
client.send(port, host, buf, 0, buf.length);
client.send(buf, 0, buf.length, port, "localhost");
process.nextTick(function() {
client.close();
});
}
});
client.addListener("close", function () {
console.log('client.close');
client.on("close", function () {
console.log('client has closed, closing server');
assert.equal(N, count);
tests_run += 1;
server.close();
assert.equal(N-1, callbacks);
});
client.addListener("error", function (e) {
client.on("error", function (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;
});
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(20990, "localhost");
pingPongTest(20988);
pingPongTest(20997, "::1");
//pingPongTest("/tmp/pingpong.sock");
process.addListener("exit", function () {
assert.equal(4, tests_run);
assert.equal(3, tests_run);
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