Merge branch 'master' into v0.6-merge
Conflicts: src/node.cc
This commit is contained in:
commit
643f00d3f9
28
LICENSE
28
LICENSE
@ -550,3 +550,31 @@ maintained libraries. The externally maintained libraries used by Node are:
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
"""
|
||||
|
||||
- src/ngx-queue.h ngx-queue.h is taken from the nginx source tree. nginx's
|
||||
license follows
|
||||
"""
|
||||
Copyright (C) 2002-2012 Igor Sysoev
|
||||
Copyright (C) 2011,2012 Nginx, Inc.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
"""
|
||||
|
24
configure
vendored
24
configure
vendored
@ -224,18 +224,22 @@ def host_arch():
|
||||
def target_arch():
|
||||
return host_arch()
|
||||
|
||||
|
||||
def gcc_version():
|
||||
def cc_version():
|
||||
try:
|
||||
proc = subprocess.Popen([CC, '-v'], stderr=subprocess.PIPE)
|
||||
except OSError:
|
||||
return None
|
||||
# TODO parse clang output
|
||||
version = proc.communicate()[1].split('\n')[-2]
|
||||
match = re.match('gcc version (\d+)\.(\d+)\.(\d+)', version)
|
||||
if not match: return None
|
||||
return ['LLVM' in version] + map(int, match.groups())
|
||||
|
||||
lines = proc.communicate()[1].split('\n')
|
||||
version_line = None
|
||||
for i, line in enumerate(lines):
|
||||
if 'version' in line:
|
||||
version_line = line
|
||||
if not version_line:
|
||||
return None
|
||||
version = version_line.split("version")[1].strip().split()[0].split(".")
|
||||
if not version:
|
||||
return None
|
||||
return ['LLVM' in version_line] + version
|
||||
|
||||
def configure_node(o):
|
||||
# TODO add gdb
|
||||
@ -250,10 +254,10 @@ def configure_node(o):
|
||||
# see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45883
|
||||
# see http://code.google.com/p/v8/issues/detail?id=884
|
||||
o['variables']['strict_aliasing'] = b(
|
||||
'clang' in CC or gcc_version() >= [False, 4, 6, 0])
|
||||
'clang' in CC or cc_version() >= [False, 4, 6, 0])
|
||||
|
||||
# clang has always supported -fvisibility=hidden, right?
|
||||
if 'clang' not in CC and gcc_version() < [False, 4, 0, 0]:
|
||||
if 'clang' not in CC and cc_version() < [False, 4, 0, 0]:
|
||||
o['variables']['visibility'] = ''
|
||||
|
||||
# By default, enable DTrace on SunOS systems. Don't allow it on other
|
||||
|
@ -52,6 +52,14 @@ in the child. After disconnecting it is no longer possible to send messages.
|
||||
An alternative way to check if you can send messages is to see if the
|
||||
`child.connected` property is `true`.
|
||||
|
||||
### Event: 'message'
|
||||
|
||||
* `message` {Object} a parsed JSON object or primitive value
|
||||
* `sendHandle` {Handle object} a Socket or Server object
|
||||
|
||||
Messages send by `.send(message, [sendHandle])` are obtained using the
|
||||
`message` event.
|
||||
|
||||
### child.stdin
|
||||
|
||||
* {Stream object}
|
||||
@ -116,15 +124,120 @@ process may not actually kill it. `kill` really just sends a signal to a proces
|
||||
|
||||
See `kill(2)`
|
||||
|
||||
|
||||
### child.send(message, [sendHandle])
|
||||
|
||||
* `message` {Object}
|
||||
* `sendHandle` {Handle object}
|
||||
|
||||
Send a message (and, optionally, a handle object) to a child process.
|
||||
When using `child_process.fork()` you can write to the child using
|
||||
`child.send(message, [sendHandle])` and messages are received by
|
||||
a `'message'` event on the child.
|
||||
|
||||
See `child_process.fork()` for details.
|
||||
For example:
|
||||
|
||||
var cp = require('child_process');
|
||||
|
||||
var n = cp.fork(__dirname + '/sub.js');
|
||||
|
||||
n.on('message', function(m) {
|
||||
console.log('PARENT got message:', m);
|
||||
});
|
||||
|
||||
n.send({ hello: 'world' });
|
||||
|
||||
And then the child script, `'sub.js'` might look like this:
|
||||
|
||||
process.on('message', function(m) {
|
||||
console.log('CHILD got message:', m);
|
||||
});
|
||||
|
||||
process.send({ foo: 'bar' });
|
||||
|
||||
In the child the `process` object will have a `send()` method, and `process`
|
||||
will emit objects each time it receives a message on its channel.
|
||||
|
||||
There is a special case when sending a `{cmd: 'NODE_foo'}` message. All messages
|
||||
containing a `NODE_` prefix in its `cmd` property will not be emitted in
|
||||
the `message` event, since they are internal messages used by node core.
|
||||
Messages containing the prefix are emitted in the `internalMessage` event, you
|
||||
should by all means avoid using this feature, it is subject to change without notice.
|
||||
|
||||
The `sendHandle` option to `child.send()` is for sending a TCP server or
|
||||
socket object to another process. The child will receive the object as its
|
||||
second argument to the `message` event.
|
||||
|
||||
**send server object**
|
||||
|
||||
Here is an example of sending a server:
|
||||
|
||||
var child = require('child_process').fork('child.js');
|
||||
|
||||
// Open up the server object and send the handle.
|
||||
var server = require('net').createServer();
|
||||
server.on('connection', function (socket) {
|
||||
socket.end('handled by parent');
|
||||
});
|
||||
server.listen(1337, function() {
|
||||
child.send('server', server);
|
||||
});
|
||||
|
||||
And the child would the recive the server object as:
|
||||
|
||||
process.on('message', function(m, server) {
|
||||
if (m === 'server') {
|
||||
server.on('connection', function (socket) {
|
||||
socket.end('handled by child');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Note that the server is now shared between the parent and child, this means
|
||||
that some connections will be handled by the parent and some by the child.
|
||||
|
||||
**send socket object**
|
||||
|
||||
Here is an example of sending a socket. It will spawn two childs and handle
|
||||
connections with the remote address `74.125.127.100` as VIP by sending the
|
||||
socket to a "special" child process. Other sockets will go to a "normal" process.
|
||||
|
||||
var normal = require('child_process').fork('child.js', ['normal']);
|
||||
var special = require('child_process').fork('child.js', ['special']);
|
||||
|
||||
// Open up the server and send sockets to child
|
||||
var server = require('net').createServer();
|
||||
server.on('connection', function (socket) {
|
||||
|
||||
// if this is a VIP
|
||||
if (socket.remoteAddress === '74.125.127.100') {
|
||||
special.send('socket', socket);
|
||||
return;
|
||||
}
|
||||
// just the usual dudes
|
||||
normal.send('socket', socket);
|
||||
});
|
||||
server.listen(1337);
|
||||
|
||||
The `child.js` could look like this:
|
||||
|
||||
process.on('message', function(m, socket) {
|
||||
if (m === 'socket') {
|
||||
socket.end('You where handled as a ' + process.argv[2] + ' person');
|
||||
}
|
||||
});
|
||||
|
||||
Note that once a single socket has been sent to a child the parent can no
|
||||
longer keep track of when the socket is destroyed. To indicate this condition
|
||||
the `.connections` property becomes `null`.
|
||||
It is also recomended not to use `.maxConnections` in this condition.
|
||||
|
||||
### child.disconnect()
|
||||
|
||||
To close the IPC connection between parent and child use the
|
||||
`child.disconnect()` method. This allows the child to exit gracefully since
|
||||
there is no IPC channel keeping it alive. When calling this method the
|
||||
`disconnect` event will be emitted in both parent and child, and the
|
||||
`connected` flag will be set to `false`. Please note that you can also call
|
||||
`process.disconnect()` in the child process.
|
||||
|
||||
## child_process.spawn(command, [args], [options])
|
||||
|
||||
@ -333,38 +446,8 @@ leaner than `child_process.exec`. It has the same options.
|
||||
|
||||
This is a special case of the `spawn()` functionality for spawning Node
|
||||
processes. In addition to having all the methods in a normal ChildProcess
|
||||
instance, the returned object has a communication channel built-in. The
|
||||
channel is written to with `child.send(message, [sendHandle])` and messages
|
||||
are received by a `'message'` event on the child.
|
||||
|
||||
For example:
|
||||
|
||||
var cp = require('child_process');
|
||||
|
||||
var n = cp.fork(__dirname + '/sub.js');
|
||||
|
||||
n.on('message', function(m) {
|
||||
console.log('PARENT got message:', m);
|
||||
});
|
||||
|
||||
n.send({ hello: 'world' });
|
||||
|
||||
And then the child script, `'sub.js'` might look like this:
|
||||
|
||||
process.on('message', function(m) {
|
||||
console.log('CHILD got message:', m);
|
||||
});
|
||||
|
||||
process.send({ foo: 'bar' });
|
||||
|
||||
In the child the `process` object will have a `send()` method, and `process`
|
||||
will emit objects each time it receives a message on its channel.
|
||||
|
||||
There is a special case when sending a `{cmd: 'NODE_foo'}` message. All messages
|
||||
containing a `NODE_` prefix in its `cmd` property will not be emitted in
|
||||
the `message` event, since they are internal messages used by node core.
|
||||
Messages containing the prefix are emitted in the `internalMessage` event, you
|
||||
should by all means avoid using this feature, it may change without warranty.
|
||||
instance, the returned object has a communication channel built-in. See
|
||||
`child.send(message, [sendHandle])` for details.
|
||||
|
||||
By default the spawned Node process will have the stdout, stderr associated
|
||||
with the parent's. To change this behavior set the `silent` property in the
|
||||
@ -373,31 +456,3 @@ with the parent's. To change this behavior set the `silent` property in the
|
||||
These child Nodes are still whole new instances of V8. Assume at least 30ms
|
||||
startup and 10mb memory for each new Node. That is, you cannot create many
|
||||
thousands of them.
|
||||
|
||||
The `sendHandle` option to `child.send()` is for sending a handle object to
|
||||
another process. Child will receive the handle as as second argument to the
|
||||
`message` event. Here is an example of sending a handle:
|
||||
|
||||
var server = require('net').createServer();
|
||||
var child = require('child_process').fork(__dirname + '/child.js');
|
||||
// Open up the server object and send the handle.
|
||||
server.listen(1337, function() {
|
||||
child.send({ server: true }, server._handle);
|
||||
});
|
||||
|
||||
Here is an example of receiving the server handle and sharing it between
|
||||
processes:
|
||||
|
||||
process.on('message', function(m, serverHandle) {
|
||||
if (serverHandle) {
|
||||
var server = require('net').createServer();
|
||||
server.listen(serverHandle);
|
||||
}
|
||||
});
|
||||
|
||||
To close the IPC connection between parent and child use the
|
||||
`child.disconnect()` method. This allows the child to exit gracefully since
|
||||
there is no IPC channel keeping it alive. When calling this method the
|
||||
`disconnect` event will be emitted in both parent and child, and the
|
||||
`connected` flag will be set to `false`. Please note that you can also call
|
||||
`process.disconnect()` in the child process.
|
||||
|
@ -198,10 +198,14 @@ Don't call `server.address()` until the `'listening'` event has been emitted.
|
||||
Set this property to reject connections when the server's connection count gets
|
||||
high.
|
||||
|
||||
It is not recommended to use this option once a socket has been sent to a child
|
||||
with `child_process.fork()`.
|
||||
|
||||
### server.connections
|
||||
|
||||
The number of concurrent connections on the server.
|
||||
|
||||
This becomes `null` when sending a socket to a child with `child_process.fork()`.
|
||||
|
||||
`net.Server` is an `EventEmitter` with the following events:
|
||||
|
||||
|
@ -33,6 +33,10 @@ function binaryWarn() {
|
||||
|
||||
exports.INSPECT_MAX_BYTES = 50;
|
||||
|
||||
// Make SlowBuffer inherit from Buffer.
|
||||
// This is an exception to the rule that __proto__ is not allowed in core.
|
||||
SlowBuffer.prototype.__proto__ = Buffer.prototype;
|
||||
|
||||
|
||||
function toHex(n) {
|
||||
if (n < 16) return '0' + n.toString(16);
|
||||
@ -40,20 +44,6 @@ function toHex(n) {
|
||||
}
|
||||
|
||||
|
||||
SlowBuffer.prototype.inspect = function() {
|
||||
var out = [],
|
||||
len = this.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
out[i] = toHex(this[i]);
|
||||
if (i == exports.INSPECT_MAX_BYTES) {
|
||||
out[i + 1] = '...';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return '<SlowBuffer ' + out.join(' ') + '>';
|
||||
};
|
||||
|
||||
|
||||
SlowBuffer.prototype.hexSlice = function(start, end) {
|
||||
var len = this.length;
|
||||
|
||||
@ -302,24 +292,25 @@ function allocPool() {
|
||||
|
||||
// Static methods
|
||||
Buffer.isBuffer = function isBuffer(b) {
|
||||
return b instanceof Buffer || b instanceof SlowBuffer;
|
||||
return b instanceof Buffer;
|
||||
};
|
||||
|
||||
|
||||
// Inspect
|
||||
Buffer.prototype.inspect = function inspect() {
|
||||
var out = [],
|
||||
len = this.length;
|
||||
len = this.length,
|
||||
name = this.constructor.name;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
out[i] = toHex(this.parent[i + this.offset]);
|
||||
out[i] = toHex(this[i]);
|
||||
if (i == exports.INSPECT_MAX_BYTES) {
|
||||
out[i + 1] = '...';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return '<Buffer ' + out.join(' ') + '>';
|
||||
return '<' + name + ' ' + out.join(' ') + '>';
|
||||
};
|
||||
|
||||
|
||||
@ -1143,32 +1134,3 @@ Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) {
|
||||
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
|
||||
writeDouble(this, value, offset, true, noAssert);
|
||||
};
|
||||
|
||||
SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8;
|
||||
SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE;
|
||||
SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE;
|
||||
SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE;
|
||||
SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE;
|
||||
SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8;
|
||||
SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE;
|
||||
SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE;
|
||||
SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE;
|
||||
SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE;
|
||||
SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE;
|
||||
SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE;
|
||||
SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE;
|
||||
SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE;
|
||||
SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8;
|
||||
SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE;
|
||||
SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE;
|
||||
SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE;
|
||||
SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE;
|
||||
SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8;
|
||||
SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE;
|
||||
SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE;
|
||||
SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE;
|
||||
SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE;
|
||||
SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE;
|
||||
SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE;
|
||||
SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE;
|
||||
SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE;
|
||||
|
@ -54,15 +54,207 @@ function createSocket(pipe, readable) {
|
||||
}
|
||||
|
||||
|
||||
// this object contain function to convert TCP objects to native handle objects
|
||||
// and back again.
|
||||
var handleConversion = {
|
||||
'net.Native': {
|
||||
simultaneousAccepts: true,
|
||||
|
||||
send: function(message, handle) {
|
||||
return handle;
|
||||
},
|
||||
|
||||
got: function(message, handle, emit) {
|
||||
emit(handle);
|
||||
}
|
||||
},
|
||||
|
||||
'net.Server': {
|
||||
simultaneousAccepts: true,
|
||||
|
||||
send: function(message, server) {
|
||||
return server._handle;
|
||||
},
|
||||
|
||||
got: function(message, handle, emit) {
|
||||
var self = this;
|
||||
|
||||
var server = new net.Server();
|
||||
server.listen(handle, function() {
|
||||
emit(server);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'net.Socket': {
|
||||
send: function(message, socket) {
|
||||
// pause socket so no data is lost, will be resumed later
|
||||
socket.pause();
|
||||
|
||||
// if the socket wsa created by net.Server
|
||||
if (socket.server) {
|
||||
// the slave should keep track of the socket
|
||||
message.key = socket.server._connectionKey;
|
||||
|
||||
var firstTime = !this._channel.sockets.send[message.key];
|
||||
|
||||
// add socket to connections list
|
||||
var socketList = getSocketList('send', this, message.key);
|
||||
socketList.add(socket);
|
||||
|
||||
// the server should no longer expose a .connection property
|
||||
// and when asked to close it should query the socket status from slaves
|
||||
if (firstTime) {
|
||||
socket.server._setupSlave(socketList);
|
||||
}
|
||||
}
|
||||
|
||||
// remove handle from socket object, it will be closed when the socket
|
||||
// has been send
|
||||
var handle = socket._handle;
|
||||
handle.onread = function() {};
|
||||
socket._handle = null;
|
||||
|
||||
return handle;
|
||||
},
|
||||
|
||||
got: function(message, handle, emit) {
|
||||
var socket = new net.Socket({handle: handle});
|
||||
socket.readable = socket.writable = true;
|
||||
socket.pause();
|
||||
|
||||
// if the socket was created by net.Server we will track the socket
|
||||
if (message.key) {
|
||||
|
||||
// add socket to connections list
|
||||
var socketList = getSocketList('got', this, message.key);
|
||||
socketList.add(socket);
|
||||
}
|
||||
|
||||
emit(socket);
|
||||
socket.resume();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This object keep track of the socket there are sended
|
||||
function SocketListSend(slave, key) {
|
||||
var self = this;
|
||||
|
||||
this.key = key;
|
||||
this.list = [];
|
||||
this.slave = slave;
|
||||
|
||||
slave.once('disconnect', function() {
|
||||
self.flush();
|
||||
});
|
||||
|
||||
this.slave.on('internalMessage', function(msg) {
|
||||
if (msg.cmd !== 'NODE_SOCKET_CLOSED' || msg.key !== self.key) return;
|
||||
self.flush();
|
||||
});
|
||||
}
|
||||
util.inherits(SocketListSend, EventEmitter);
|
||||
|
||||
SocketListSend.prototype.add = function(socket) {
|
||||
this.list.push(socket);
|
||||
};
|
||||
|
||||
SocketListSend.prototype.flush = function() {
|
||||
var list = this.list;
|
||||
this.list = [];
|
||||
|
||||
list.forEach(function(socket) {
|
||||
socket.destroy();
|
||||
});
|
||||
};
|
||||
|
||||
SocketListSend.prototype.update = function() {
|
||||
if (this.slave.connected === false) return;
|
||||
|
||||
this.slave.send({
|
||||
cmd: 'NODE_SOCKET_FETCH',
|
||||
key: this.key
|
||||
});
|
||||
};
|
||||
|
||||
// This object keep track of the socket there are received
|
||||
function SocketListReceive(slave, key) {
|
||||
var self = this;
|
||||
|
||||
this.key = key;
|
||||
this.list = [];
|
||||
this.slave = slave;
|
||||
|
||||
slave.on('internalMessage', function(msg) {
|
||||
if (msg.cmd !== 'NODE_SOCKET_FETCH' || msg.key !== self.key) return;
|
||||
|
||||
if (self.list.length === 0) {
|
||||
self.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
self.on('itemRemoved', function removeMe() {
|
||||
if (self.list.length !== 0) return;
|
||||
self.removeListener('itemRemoved', removeMe);
|
||||
self.flush();
|
||||
});
|
||||
});
|
||||
}
|
||||
util.inherits(SocketListReceive, EventEmitter);
|
||||
|
||||
SocketListReceive.prototype.flush = function() {
|
||||
this.list = [];
|
||||
|
||||
if (this.slave.connected) {
|
||||
this.slave.send({
|
||||
cmd: 'NODE_SOCKET_CLOSED',
|
||||
key: this.key
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
SocketListReceive.prototype.add = function(socket) {
|
||||
var self = this;
|
||||
this.list.push(socket);
|
||||
|
||||
socket.on('close', function() {
|
||||
self.list.splice(self.list.indexOf(socket), 1);
|
||||
self.emit('itemRemoved');
|
||||
});
|
||||
};
|
||||
|
||||
function getSocketList(type, slave, key) {
|
||||
var sockets = slave._channel.sockets[type];
|
||||
var socketList = sockets[key];
|
||||
if (!socketList) {
|
||||
var Construct = type === 'send' ? SocketListSend : SocketListReceive;
|
||||
socketList = sockets[key] = new Construct(slave, key);
|
||||
}
|
||||
return socketList;
|
||||
}
|
||||
|
||||
function handleMessage(target, message, handle) {
|
||||
//Filter out internal messages
|
||||
//if cmd property begin with "_NODE"
|
||||
if (message !== null &&
|
||||
typeof message === 'object' &&
|
||||
typeof message.cmd === 'string' &&
|
||||
message.cmd.indexOf('NODE_') === 0) {
|
||||
target.emit('internalMessage', message, handle);
|
||||
}
|
||||
//Non-internal message
|
||||
else {
|
||||
target.emit('message', message, handle);
|
||||
}
|
||||
}
|
||||
|
||||
function setupChannel(target, channel) {
|
||||
target._channel = channel;
|
||||
|
||||
var jsonBuffer = '';
|
||||
channel.buffering = false;
|
||||
channel.onread = function(pool, offset, length, recvHandle) {
|
||||
// Update simultaneous accepts on Windows
|
||||
net._setSimultaneousAccepts(recvHandle);
|
||||
|
||||
if (pool) {
|
||||
jsonBuffer += pool.toString('ascii', offset, offset + length);
|
||||
|
||||
@ -73,18 +265,7 @@ function setupChannel(target, channel) {
|
||||
var json = jsonBuffer.slice(start, i);
|
||||
var message = JSON.parse(json);
|
||||
|
||||
//Filter out internal messages
|
||||
//if cmd property begin with "_NODE"
|
||||
if (message !== null &&
|
||||
typeof message === 'object' &&
|
||||
typeof message.cmd === 'string' &&
|
||||
message.cmd.indexOf('NODE_') === 0) {
|
||||
target.emit('internalMessage', message, recvHandle);
|
||||
}
|
||||
//Non-internal message
|
||||
else {
|
||||
target.emit('message', message, recvHandle);
|
||||
}
|
||||
handleMessage(target, message, recvHandle);
|
||||
|
||||
start = i + 1;
|
||||
}
|
||||
@ -97,7 +278,27 @@ function setupChannel(target, channel) {
|
||||
}
|
||||
};
|
||||
|
||||
target.send = function(message, sendHandle) {
|
||||
// object where socket lists will live
|
||||
channel.sockets = { got: {}, send: {} };
|
||||
|
||||
// handlers will go through this
|
||||
target.on('internalMessage', function(message, handle) {
|
||||
if (message.cmd !== 'NODE_HANDLE') return;
|
||||
|
||||
var obj = handleConversion[message.type];
|
||||
|
||||
// Update simultaneous accepts on Windows
|
||||
if (obj.simultaneousAccepts) {
|
||||
net._setSimultaneousAccepts(handle);
|
||||
}
|
||||
|
||||
// Convert handle object
|
||||
obj.got.call(this, message, handle, function(handle) {
|
||||
handleMessage(target, message.msg, handle);
|
||||
});
|
||||
});
|
||||
|
||||
target.send = function(message, handle) {
|
||||
if (typeof message === 'undefined') {
|
||||
throw new TypeError('message cannot be undefined');
|
||||
}
|
||||
@ -112,12 +313,43 @@ function setupChannel(target, channel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// package messages with a handle object
|
||||
if (handle) {
|
||||
// this message will be handled by an internalMessage event handler
|
||||
message = {
|
||||
cmd: 'NODE_HANDLE',
|
||||
type: 'net.',
|
||||
msg: message
|
||||
};
|
||||
|
||||
switch (handle.constructor.name) {
|
||||
case 'Socket':
|
||||
message.type += 'Socket'; break;
|
||||
case 'Server':
|
||||
message.type += 'Server'; break;
|
||||
case 'Pipe':
|
||||
case 'TCP':
|
||||
message.type += 'Native'; break;
|
||||
}
|
||||
|
||||
var obj = handleConversion[message.type];
|
||||
|
||||
// convert TCP object to native handle object
|
||||
handle = handleConversion[message.type].send.apply(target, arguments);
|
||||
|
||||
// Update simultaneous accepts on Windows
|
||||
if (obj.simultaneousAccepts) {
|
||||
net._setSimultaneousAccepts(handle);
|
||||
}
|
||||
}
|
||||
|
||||
var string = JSON.stringify(message) + '\n';
|
||||
var writeReq = channel.writeUtf8String(string, handle);
|
||||
|
||||
// Update simultaneous accepts on Windows
|
||||
net._setSimultaneousAccepts(sendHandle);
|
||||
|
||||
var writeReq = channel.writeUtf8String(string, sendHandle);
|
||||
// Close the Socket handle after sending it
|
||||
if (message && message.type === 'net.Socket') {
|
||||
handle.close();
|
||||
}
|
||||
|
||||
if (!writeReq) {
|
||||
var er = errnoException(errno, 'write', 'cannot write to IPC channel.');
|
||||
@ -172,10 +404,10 @@ exports.fork = function(modulePath /*, args, options*/) {
|
||||
var options, args, execArgv;
|
||||
if (Array.isArray(arguments[1])) {
|
||||
args = arguments[1];
|
||||
options = arguments[2] || {};
|
||||
options = util._extend({}, arguments[2]);
|
||||
} else {
|
||||
args = [];
|
||||
options = arguments[1] || {};
|
||||
options = util._extend({}, arguments[1]);
|
||||
}
|
||||
|
||||
// Prepare arguments for fork:
|
||||
@ -264,15 +496,12 @@ exports.execFile = function(file /* args, options, callback */) {
|
||||
|
||||
if (Array.isArray(arguments[1])) {
|
||||
args = arguments[1];
|
||||
if (typeof arguments[2] === 'object') optionArg = arguments[2];
|
||||
options = util._extend(options, arguments[2]);
|
||||
} else {
|
||||
args = [];
|
||||
if (typeof arguments[1] === 'object') optionArg = arguments[1];
|
||||
options = util._extend(options, arguments[1]);
|
||||
}
|
||||
|
||||
// Merge optionArg into options
|
||||
util._extend(options, optionArg);
|
||||
|
||||
var child = spawn(file, args, {
|
||||
cwd: options.cwd,
|
||||
env: options.env,
|
||||
@ -398,8 +627,10 @@ function ChildProcess() {
|
||||
this.exitCode = null;
|
||||
this.killed = false;
|
||||
|
||||
this._internal = new Process();
|
||||
this._internal.onexit = function(exitCode, signalCode) {
|
||||
this._handle = new Process();
|
||||
this._handle.owner = this;
|
||||
|
||||
this._handle.onexit = function(exitCode, signalCode) {
|
||||
//
|
||||
// follow 0.4.x behaviour:
|
||||
//
|
||||
@ -416,8 +647,8 @@ function ChildProcess() {
|
||||
self.stdin.destroy();
|
||||
}
|
||||
|
||||
self._internal.close();
|
||||
self._internal = null;
|
||||
self._handle.close();
|
||||
self._handle = null;
|
||||
|
||||
self.emit('exit', self.exitCode, self.signalCode);
|
||||
|
||||
@ -452,7 +683,7 @@ ChildProcess.prototype.spawn = function(options) {
|
||||
setStreamOption('stdoutStream', 1, options);
|
||||
setStreamOption('stderrStream', 2, options);
|
||||
|
||||
var r = this._internal.spawn(options);
|
||||
var r = this._handle.spawn(options);
|
||||
|
||||
if (r) {
|
||||
if (options.stdinStream) {
|
||||
@ -467,12 +698,12 @@ ChildProcess.prototype.spawn = function(options) {
|
||||
options.stderrStream.close();
|
||||
}
|
||||
|
||||
this._internal.close();
|
||||
this._internal = null;
|
||||
this._handle.close();
|
||||
this._handle = null;
|
||||
throw errnoException(errno, 'spawn');
|
||||
}
|
||||
|
||||
this.pid = this._internal.pid;
|
||||
this.pid = this._handle.pid;
|
||||
|
||||
if (options.stdinStream) {
|
||||
this.stdin = createSocket(options.stdinStream, false);
|
||||
@ -525,9 +756,9 @@ ChildProcess.prototype.kill = function(sig) {
|
||||
throw new Error('Unknown signal: ' + sig);
|
||||
}
|
||||
|
||||
if (this._internal) {
|
||||
if (this._handle) {
|
||||
this.killed = true;
|
||||
var r = this._internal.kill(signal);
|
||||
var r = this._handle.kill(signal);
|
||||
if (r === -1) {
|
||||
this.emit('error', errnoException(errno, 'kill'));
|
||||
return;
|
||||
|
@ -91,7 +91,7 @@ function Socket(type, listener) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
var handle = newHandle(type);
|
||||
handle.socket = this;
|
||||
handle.owner = this;
|
||||
|
||||
this._handle = handle;
|
||||
this._receiving = false;
|
||||
@ -200,7 +200,7 @@ Socket.prototype.send = function(buffer,
|
||||
|
||||
|
||||
function afterSend(status, handle, req, buffer) {
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
|
||||
// CHECKME socket's been closed by user, don't call callback?
|
||||
if (handle !== self._handle)
|
||||
@ -344,7 +344,7 @@ Socket.prototype._stopReceiving = function() {
|
||||
|
||||
|
||||
function onMessage(handle, slab, start, len, rinfo) {
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
if (!slab) return self.emit('error', errnoException(errno, 'recvmsg'));
|
||||
rinfo.size = len; // compatibility
|
||||
self.emit('message', slab.slice(start, start + len), rinfo);
|
||||
|
@ -737,6 +737,7 @@ function FSWatcher() {
|
||||
var self = this;
|
||||
var FSEvent = process.binding('fs_event_wrap').FSEvent;
|
||||
this._handle = new FSEvent();
|
||||
this._handle.owner = this;
|
||||
|
||||
this._handle.onchange = function(status, event, filename) {
|
||||
if (status) {
|
||||
|
@ -475,6 +475,10 @@ OutgoingMessage.prototype._send = function(data, encoding) {
|
||||
|
||||
|
||||
OutgoingMessage.prototype._writeRaw = function(data, encoding) {
|
||||
if (data.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.connection &&
|
||||
this.connection._httpMessage === this &&
|
||||
this.connection.writable) {
|
||||
|
62
lib/net.js
62
lib/net.js
@ -120,7 +120,7 @@ function initSocketHandle(self) {
|
||||
|
||||
// Handle creation may be deferred to bind() or connect() time.
|
||||
if (self._handle) {
|
||||
self._handle.socket = self;
|
||||
self._handle.owner = self;
|
||||
self._handle.onread = onread;
|
||||
}
|
||||
}
|
||||
@ -291,7 +291,7 @@ Socket.prototype.end = function(data, encoding) {
|
||||
|
||||
|
||||
function afterShutdown(status, handle, req) {
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
|
||||
assert.ok(self._flags & FLAG_SHUTDOWN);
|
||||
assert.ok(!self.writable);
|
||||
@ -352,7 +352,7 @@ Socket.prototype._destroy = function(exception, cb) {
|
||||
timers.unenroll(this);
|
||||
|
||||
if (this.server) {
|
||||
this.server.connections--;
|
||||
this.server._connections--;
|
||||
this.server._emitCloseIfDrained();
|
||||
}
|
||||
|
||||
@ -380,7 +380,7 @@ Socket.prototype.destroy = function(exception) {
|
||||
|
||||
function onread(buffer, offset, length) {
|
||||
var handle = this;
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
assert.equal(handle, self._handle);
|
||||
|
||||
timers.active(self);
|
||||
@ -583,7 +583,7 @@ Socket.prototype.__defineGetter__('bytesWritten', function() {
|
||||
|
||||
|
||||
function afterWrite(status, handle, req) {
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
|
||||
// callback may come after call to destroy.
|
||||
if (self.destroyed) {
|
||||
@ -722,7 +722,7 @@ Socket.prototype.connect = function(options, cb) {
|
||||
|
||||
|
||||
function afterConnect(status, handle, req, readable, writable) {
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
|
||||
// callback may come after call to destroy
|
||||
if (self.destroyed) {
|
||||
@ -800,7 +800,23 @@ function Server(/* [ options, ] listener */) {
|
||||
}
|
||||
}
|
||||
|
||||
this.connections = 0;
|
||||
this._connections = 0;
|
||||
|
||||
// when server is using slaves .connections is not reliable
|
||||
// so null will be return if thats the case
|
||||
Object.defineProperty(this, 'connections', {
|
||||
get: function() {
|
||||
if (self._usingSlaves) {
|
||||
return null;
|
||||
}
|
||||
return self._connections;
|
||||
},
|
||||
set: function(val) {
|
||||
return (self._connections = val);
|
||||
},
|
||||
configurable: true, enumerable: true
|
||||
});
|
||||
|
||||
this.allowHalfOpen = options.allowHalfOpen || false;
|
||||
|
||||
this._handle = null;
|
||||
@ -865,7 +881,7 @@ Server.prototype._listen2 = function(address, port, addressType, backlog) {
|
||||
}
|
||||
|
||||
self._handle.onconnection = onconnection;
|
||||
self._handle.socket = self;
|
||||
self._handle.owner = self;
|
||||
|
||||
// Use a backlog of 512 entries. We pass 511 to the listen() call because
|
||||
// the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
||||
@ -881,6 +897,9 @@ Server.prototype._listen2 = function(address, port, addressType, backlog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// generate connection key, this should be unique to the connection
|
||||
this._connectionKey = addressType + ':' + address + ':' + port;
|
||||
|
||||
process.nextTick(function() {
|
||||
self.emit('listening');
|
||||
});
|
||||
@ -961,7 +980,7 @@ Server.prototype.address = function() {
|
||||
|
||||
function onconnection(clientHandle) {
|
||||
var handle = this;
|
||||
var self = handle.socket;
|
||||
var self = handle.owner;
|
||||
|
||||
debug('onconnection');
|
||||
|
||||
@ -970,7 +989,7 @@ function onconnection(clientHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.maxConnections && self.connections >= self.maxConnections) {
|
||||
if (self.maxConnections && self._connections >= self.maxConnections) {
|
||||
clientHandle.close();
|
||||
return;
|
||||
}
|
||||
@ -983,7 +1002,7 @@ function onconnection(clientHandle) {
|
||||
|
||||
socket.resume();
|
||||
|
||||
self.connections++;
|
||||
self._connections++;
|
||||
socket.server = self;
|
||||
|
||||
DTRACE_NET_SERVER_CONNECTION(socket);
|
||||
@ -1005,13 +1024,21 @@ Server.prototype.close = function(cb) {
|
||||
this._handle = null;
|
||||
this._emitCloseIfDrained();
|
||||
|
||||
// fetch new socket lists
|
||||
if (this._usingSlaves) {
|
||||
this._slaves.forEach(function(socketList) {
|
||||
if (socketList.list.length === 0) return;
|
||||
socketList.update();
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Server.prototype._emitCloseIfDrained = function() {
|
||||
var self = this;
|
||||
|
||||
if (self._handle || self.connections) return;
|
||||
if (self._handle || self._connections) return;
|
||||
|
||||
process.nextTick(function() {
|
||||
self.emit('close');
|
||||
@ -1023,6 +1050,15 @@ Server.prototype.listenFD = function(fd, type) {
|
||||
throw new Error('This API is no longer supported. See child_process.fork');
|
||||
};
|
||||
|
||||
// when sending a socket using fork IPC this function is executed
|
||||
Server.prototype._setupSlave = function(socketList) {
|
||||
if (!this._usingSlaves) {
|
||||
this._usingSlaves = true;
|
||||
this._slaves = [];
|
||||
}
|
||||
this._slaves.push(socketList);
|
||||
};
|
||||
|
||||
|
||||
// TODO: isIP should be moved to the DNS code. Putting it here now because
|
||||
// this is what the legacy system did.
|
||||
@ -1030,7 +1066,7 @@ Server.prototype.listenFD = function(fd, type) {
|
||||
// and it does not detect more than one double : in a string.
|
||||
exports.isIP = function(input) {
|
||||
if (!input) {
|
||||
return 4;
|
||||
return 0;
|
||||
} else if (/^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/.test(input)) {
|
||||
var parts = input.split('.');
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
|
@ -189,6 +189,11 @@ QueryString.parse = QueryString.decode = function(qs, sep, eq, options) {
|
||||
kstr = x.substring(0, idx),
|
||||
vstr = x.substring(idx + 1), k, v;
|
||||
|
||||
if (kstr === '' && vstr !== '') {
|
||||
kstr = vstr;
|
||||
vstr = '';
|
||||
}
|
||||
|
||||
try {
|
||||
k = decodeURIComponent(kstr);
|
||||
v = decodeURIComponent(vstr);
|
||||
|
@ -509,7 +509,7 @@ exports.inherits = function(ctor, superCtor) {
|
||||
|
||||
exports._extend = function(origin, add) {
|
||||
// Don't do anything if add isn't an object
|
||||
if (!add) return origin;
|
||||
if (!add || typeof add !== 'object') return origin;
|
||||
|
||||
var keys = Object.keys(add);
|
||||
var i = keys.length;
|
||||
|
1
node.gyp
1
node.gyp
@ -107,6 +107,7 @@
|
||||
'src/node_script.h',
|
||||
'src/node_string.h',
|
||||
'src/node_version.h',
|
||||
'src/ngx-queue.h',
|
||||
'src/pipe_wrap.h',
|
||||
'src/req_wrap.h',
|
||||
'src/slab_allocator.h',
|
||||
|
@ -20,10 +20,12 @@
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "node.h"
|
||||
#include "ngx-queue.h"
|
||||
#include "handle_wrap.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::Array;
|
||||
using v8::Object;
|
||||
using v8::Handle;
|
||||
using v8::Local;
|
||||
@ -52,6 +54,10 @@ using v8::Integer;
|
||||
}
|
||||
|
||||
|
||||
// defined in node.cc
|
||||
extern ngx_queue_t handle_wrap_queue;
|
||||
|
||||
|
||||
void HandleWrap::Initialize(Handle<Object> target) {
|
||||
/* Doesn't do anything at the moment. */
|
||||
}
|
||||
@ -125,6 +131,7 @@ HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
|
||||
assert(object->InternalFieldCount() > 0);
|
||||
object_ = v8::Persistent<v8::Object>::New(object);
|
||||
object_->SetPointerInInternalField(0, this);
|
||||
ngx_queue_insert_tail(&handle_wrap_queue, &handle_wrap_queue_);
|
||||
}
|
||||
|
||||
|
||||
@ -136,6 +143,7 @@ void HandleWrap::SetHandle(uv_handle_t* h) {
|
||||
|
||||
HandleWrap::~HandleWrap() {
|
||||
assert(object_.IsEmpty());
|
||||
ngx_queue_remove(&handle_wrap_queue_);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef HANDLE_WRAP_H_
|
||||
#define HANDLE_WRAP_H_
|
||||
|
||||
#include "ngx-queue.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
// Rules:
|
||||
@ -61,7 +63,9 @@ class HandleWrap {
|
||||
v8::Persistent<v8::Object> object_;
|
||||
|
||||
private:
|
||||
friend v8::Handle<v8::Value> GetActiveHandles(const v8::Arguments&);
|
||||
static void OnClose(uv_handle_t* handle);
|
||||
ngx_queue_t handle_wrap_queue_;
|
||||
// Using double underscore due to handle_ member in tcp_wrap. Probably
|
||||
// tcp_wrap should rename it's member to 'handle'.
|
||||
uv_handle_t* handle__;
|
||||
|
106
src/ngx-queue.h
Normal file
106
src/ngx-queue.h
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
*/
|
||||
|
||||
|
||||
#ifndef NGX_QUEUE_H_INCLUDED_
|
||||
#define NGX_QUEUE_H_INCLUDED_
|
||||
|
||||
|
||||
typedef struct ngx_queue_s ngx_queue_t;
|
||||
|
||||
struct ngx_queue_s {
|
||||
ngx_queue_t *prev;
|
||||
ngx_queue_t *next;
|
||||
};
|
||||
|
||||
|
||||
#define ngx_queue_init(q) \
|
||||
(q)->prev = q; \
|
||||
(q)->next = q
|
||||
|
||||
|
||||
#define ngx_queue_empty(h) \
|
||||
(h == (h)->prev)
|
||||
|
||||
|
||||
#define ngx_queue_insert_head(h, x) \
|
||||
(x)->next = (h)->next; \
|
||||
(x)->next->prev = x; \
|
||||
(x)->prev = h; \
|
||||
(h)->next = x
|
||||
|
||||
|
||||
#define ngx_queue_insert_after ngx_queue_insert_head
|
||||
|
||||
|
||||
#define ngx_queue_insert_tail(h, x) \
|
||||
(x)->prev = (h)->prev; \
|
||||
(x)->prev->next = x; \
|
||||
(x)->next = h; \
|
||||
(h)->prev = x
|
||||
|
||||
|
||||
#define ngx_queue_head(h) \
|
||||
(h)->next
|
||||
|
||||
|
||||
#define ngx_queue_last(h) \
|
||||
(h)->prev
|
||||
|
||||
|
||||
#define ngx_queue_sentinel(h) \
|
||||
(h)
|
||||
|
||||
|
||||
#define ngx_queue_next(q) \
|
||||
(q)->next
|
||||
|
||||
|
||||
#define ngx_queue_prev(q) \
|
||||
(q)->prev
|
||||
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next; \
|
||||
(x)->prev = NULL; \
|
||||
(x)->next = NULL
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_queue_remove(x) \
|
||||
(x)->next->prev = (x)->prev; \
|
||||
(x)->prev->next = (x)->next
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_queue_split(h, q, n) \
|
||||
(n)->prev = (h)->prev; \
|
||||
(n)->prev->next = n; \
|
||||
(n)->next = q; \
|
||||
(h)->prev = (q)->prev; \
|
||||
(h)->prev->next = h; \
|
||||
(q)->prev = n;
|
||||
|
||||
|
||||
#define ngx_queue_add(h, n) \
|
||||
(h)->prev->next = (n)->next; \
|
||||
(n)->next->prev = (h)->prev; \
|
||||
(h)->prev = (n)->prev; \
|
||||
(h)->prev->next = h;
|
||||
|
||||
|
||||
#define ngx_queue_data(q, type, link) \
|
||||
(type *) ((unsigned char *) q - offsetof(type, link))
|
||||
|
||||
|
||||
#define ngx_queue_foreach(q, h) \
|
||||
for ((q) = ngx_queue_head(h); (q) != (h); (q) = ngx_queue_next(q))
|
||||
|
||||
|
||||
#endif /* NGX_QUEUE_H_INCLUDED_ */
|
58
src/node.cc
58
src/node.cc
@ -20,6 +20,8 @@
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "node.h"
|
||||
#include "req_wrap.h"
|
||||
#include "handle_wrap.h"
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
@ -90,6 +92,13 @@ extern char **environ;
|
||||
|
||||
namespace node {
|
||||
|
||||
ngx_queue_t handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue };
|
||||
ngx_queue_t req_wrap_queue = { &req_wrap_queue, &req_wrap_queue };
|
||||
|
||||
// declared in req_wrap.h
|
||||
Persistent<String> process_symbol;
|
||||
Persistent<String> domain_symbol;
|
||||
|
||||
static Persistent<Object> process;
|
||||
|
||||
static Persistent<String> errno_symbol;
|
||||
@ -105,7 +114,6 @@ static Persistent<String> listeners_symbol;
|
||||
static Persistent<String> uncaught_exception_symbol;
|
||||
static Persistent<String> emit_symbol;
|
||||
|
||||
static Persistent<String> domain_symbol;
|
||||
static Persistent<String> enter_symbol;
|
||||
static Persistent<String> exit_symbol;
|
||||
static Persistent<String> disposed_symbol;
|
||||
@ -1019,8 +1027,7 @@ MakeCallback(const Handle<Object> object,
|
||||
|
||||
TryCatch try_catch;
|
||||
|
||||
if (domain_symbol.IsEmpty()) {
|
||||
domain_symbol = NODE_PSYMBOL("domain");
|
||||
if (enter_symbol.IsEmpty()) {
|
||||
enter_symbol = NODE_PSYMBOL("enter");
|
||||
exit_symbol = NODE_PSYMBOL("exit");
|
||||
disposed_symbol = NODE_PSYMBOL("_disposed");
|
||||
@ -1330,6 +1337,46 @@ Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) {
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> GetActiveRequests(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
Local<Array> ary = Array::New();
|
||||
ngx_queue_t* q = NULL;
|
||||
int i = 0;
|
||||
|
||||
ngx_queue_foreach(q, &req_wrap_queue) {
|
||||
ReqWrap<uv_req_t>* w = container_of(q, ReqWrap<uv_req_t>, req_wrap_queue_);
|
||||
if (w->object_.IsEmpty()) continue;
|
||||
ary->Set(i++, w->object_);
|
||||
}
|
||||
|
||||
return scope.Close(ary);
|
||||
}
|
||||
|
||||
|
||||
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
|
||||
// implemented here for consistency with GetActiveRequests().
|
||||
Handle<Value> GetActiveHandles(const Arguments& args) {
|
||||
HandleScope scope;
|
||||
|
||||
Local<Array> ary = Array::New();
|
||||
ngx_queue_t* q = NULL;
|
||||
int i = 0;
|
||||
|
||||
Local<String> owner_sym = String::New("owner");
|
||||
|
||||
ngx_queue_foreach(q, &handle_wrap_queue) {
|
||||
HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_);
|
||||
if (w->object_.IsEmpty() || w->unref) continue;
|
||||
Local<Value> obj = w->object_->Get(owner_sym);
|
||||
if (obj->IsUndefined()) obj = *w->object_;
|
||||
ary->Set(i++, obj);
|
||||
}
|
||||
|
||||
return scope.Close(ary);
|
||||
}
|
||||
|
||||
|
||||
static Handle<Value> Abort(const Arguments& args) {
|
||||
abort();
|
||||
return Undefined();
|
||||
@ -2239,6 +2286,8 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
||||
|
||||
|
||||
// define various internal methods
|
||||
NODE_SET_METHOD(process, "_getActiveRequests", GetActiveRequests);
|
||||
NODE_SET_METHOD(process, "_getActiveHandles", GetActiveHandles);
|
||||
NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
|
||||
NODE_SET_METHOD(process, "reallyExit", Exit);
|
||||
NODE_SET_METHOD(process, "abort", Abort);
|
||||
@ -2869,6 +2918,9 @@ int Start(int argc, char *argv[]) {
|
||||
Persistent<Context> context = Context::New();
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
process_symbol = NODE_PSYMBOL("process");
|
||||
domain_symbol = NODE_PSYMBOL("domain");
|
||||
|
||||
// Use original argv, as we're just copying values out of it.
|
||||
Handle<Object> process_l = SetupProcessObject(argc, argv);
|
||||
v8_typed_array::AttachBindings(context->Global());
|
||||
|
@ -22,10 +22,14 @@
|
||||
#ifndef REQ_WRAP_H_
|
||||
#define REQ_WRAP_H_
|
||||
|
||||
#include "ngx-queue.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
static v8::Persistent<v8::String> process_symbol;
|
||||
static v8::Persistent<v8::String> domain_symbol;
|
||||
// defined in node.cc
|
||||
extern v8::Persistent<v8::String> process_symbol;
|
||||
extern v8::Persistent<v8::String> domain_symbol;
|
||||
extern ngx_queue_t req_wrap_queue;
|
||||
|
||||
template <typename T>
|
||||
class ReqWrap {
|
||||
@ -34,12 +38,6 @@ class ReqWrap {
|
||||
v8::HandleScope scope;
|
||||
object_ = v8::Persistent<v8::Object>::New(v8::Object::New());
|
||||
|
||||
// TODO: grab a handle to the current process.domain
|
||||
if (process_symbol.IsEmpty()) {
|
||||
process_symbol = NODE_PSYMBOL("process");
|
||||
domain_symbol = NODE_PSYMBOL("domain");
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> domain = v8::Context::GetCurrent()
|
||||
->Global()
|
||||
->Get(process_symbol)
|
||||
@ -50,10 +48,13 @@ class ReqWrap {
|
||||
// fprintf(stderr, "setting domain on ReqWrap\n");
|
||||
object_->Set(domain_symbol, domain);
|
||||
}
|
||||
|
||||
ngx_queue_insert_tail(&req_wrap_queue, &req_wrap_queue_);
|
||||
}
|
||||
|
||||
|
||||
~ReqWrap() {
|
||||
ngx_queue_remove(&req_wrap_queue_);
|
||||
// Assert that someone has called Dispatched()
|
||||
assert(req_.data == this);
|
||||
assert(!object_.IsEmpty());
|
||||
@ -67,8 +68,9 @@ class ReqWrap {
|
||||
}
|
||||
|
||||
v8::Persistent<v8::Object> object_;
|
||||
T req_;
|
||||
ngx_queue_t req_wrap_queue_;
|
||||
void* data_;
|
||||
T req_; // *must* be last, GetActiveRequests() in node.cc depends on it
|
||||
};
|
||||
|
||||
|
||||
|
58
test/pummel/test-net-connect-econnrefused.js
Normal file
58
test/pummel/test-net-connect-econnrefused.js
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// verify that connect reqs are properly cleaned up
|
||||
|
||||
var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var net = require('net');
|
||||
|
||||
var ROUNDS = 1024;
|
||||
var rounds = 0;
|
||||
var reqs = 0;
|
||||
|
||||
pummel();
|
||||
|
||||
function pummel() {
|
||||
net.createConnection(common.PORT).on('error', function(err) {
|
||||
assert.equal(err.code, 'ECONNREFUSED');
|
||||
if (++rounds < ROUNDS) return pummel();
|
||||
check();
|
||||
});
|
||||
reqs++;
|
||||
}
|
||||
|
||||
function check() {
|
||||
process.nextTick(function() {
|
||||
process.nextTick(function() {
|
||||
assert.equal(process._getActiveRequests().length, 0);
|
||||
assert.equal(process._getActiveHandles().length, 0);
|
||||
check_called = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
var check_called = false;
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.equal(rounds, ROUNDS);
|
||||
assert.equal(reqs, ROUNDS);
|
||||
assert(check_called);
|
||||
});
|
198
test/simple/test-child-process-fork-net.js
Normal file
198
test/simple/test-child-process-fork-net.js
Normal file
@ -0,0 +1,198 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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 assert = require('assert');
|
||||
var common = require('../common');
|
||||
var fork = require('child_process').fork;
|
||||
var net = require('net');
|
||||
|
||||
// progress tracker
|
||||
function ProgressTracker(missing, callback) {
|
||||
this.missing = missing;
|
||||
this.callback = callback;
|
||||
}
|
||||
ProgressTracker.prototype.done = function() {
|
||||
this.missing -= 1;
|
||||
this.check();
|
||||
};
|
||||
ProgressTracker.prototype.check = function() {
|
||||
if (this.missing === 0) this.callback();
|
||||
};
|
||||
|
||||
if (process.argv[2] === 'child') {
|
||||
|
||||
var serverScope;
|
||||
|
||||
process.on('message', function onServer(msg, server) {
|
||||
if (msg.what !== 'server') return;
|
||||
process.removeListener('message', onServer);
|
||||
|
||||
serverScope = server;
|
||||
|
||||
server.on('connection', function(socket) {
|
||||
console.log('CHILD: got connection');
|
||||
process.send({what: 'connection'});
|
||||
socket.destroy();
|
||||
});
|
||||
|
||||
// start making connection from parent
|
||||
console.log('CHILD: server listening');
|
||||
process.send({what: 'listening'});
|
||||
});
|
||||
|
||||
process.on('message', function onClose(msg) {
|
||||
if (msg.what !== 'close') return;
|
||||
process.removeListener('message', onClose);
|
||||
|
||||
serverScope.on('close', function() {
|
||||
process.send({what: 'close'});
|
||||
});
|
||||
serverScope.close();
|
||||
});
|
||||
|
||||
process.on('message', function onSocket(msg, socket) {
|
||||
if (msg.what !== 'socket') return;
|
||||
process.removeListener('message', onSocket);
|
||||
socket.end('echo');
|
||||
console.log('CHILD: got socket');
|
||||
});
|
||||
|
||||
process.send({what: 'ready'});
|
||||
} else {
|
||||
|
||||
var child = fork(process.argv[1], ['child']);
|
||||
|
||||
child.on('exit', function() {
|
||||
console.log('CHILD: died');
|
||||
});
|
||||
|
||||
// send net.Server to child and test by connecting
|
||||
var testServer = function(callback) {
|
||||
|
||||
// destroy server execute callback when done
|
||||
var progress = new ProgressTracker(2, function() {
|
||||
server.on('close', function() {
|
||||
console.log('PARENT: server closed');
|
||||
child.send({what: 'close'});
|
||||
});
|
||||
server.close();
|
||||
});
|
||||
|
||||
// we expect 10 connections and close events
|
||||
var connections = new ProgressTracker(10, progress.done.bind(progress));
|
||||
var closed = new ProgressTracker(10, progress.done.bind(progress));
|
||||
|
||||
// create server and send it to child
|
||||
var server = net.createServer();
|
||||
server.on('connection', function(socket) {
|
||||
console.log('PARENT: got connection');
|
||||
socket.destroy();
|
||||
connections.done();
|
||||
});
|
||||
server.on('listening', function() {
|
||||
console.log('PARENT: server listening');
|
||||
child.send({what: 'server'}, server);
|
||||
});
|
||||
server.listen(common.PORT);
|
||||
|
||||
// handle client messages
|
||||
var messageHandlers = function(msg) {
|
||||
|
||||
if (msg.what === 'listening') {
|
||||
// make connections
|
||||
var socket;
|
||||
for (var i = 0; i < 10; i++) {
|
||||
socket = net.connect(common.PORT, function() {
|
||||
console.log('CLIENT: connected');
|
||||
});
|
||||
socket.on('close', function() {
|
||||
closed.done();
|
||||
console.log('CLIENT: closed');
|
||||
});
|
||||
}
|
||||
|
||||
} else if (msg.what === 'connection') {
|
||||
// child got connection
|
||||
connections.done();
|
||||
} else if (msg.what === 'close') {
|
||||
child.removeListener('message', messageHandlers);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
child.on('message', messageHandlers);
|
||||
};
|
||||
|
||||
// send net.Socket to child
|
||||
var testSocket = function(callback) {
|
||||
|
||||
// create a new server and connect to it,
|
||||
// but the socket will be handled by the child
|
||||
var server = net.createServer();
|
||||
server.on('connection', function(socket) {
|
||||
socket.on('close', function() {
|
||||
console.log('CLIENT: socket closed');
|
||||
});
|
||||
child.send({what: 'socket'}, socket);
|
||||
});
|
||||
server.on('close', function() {
|
||||
console.log('PARENT: server closed');
|
||||
callback();
|
||||
});
|
||||
server.listen(common.PORT, function() {
|
||||
var connect = net.connect(common.PORT);
|
||||
var store = '';
|
||||
connect.on('data', function(chunk) {
|
||||
store += chunk;
|
||||
console.log('CLIENT: got data');
|
||||
});
|
||||
connect.on('close', function() {
|
||||
console.log('CLIENT: closed');
|
||||
assert.equal(store, 'echo');
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// create server and send it to child
|
||||
var serverSucess = false;
|
||||
var socketSucess = false;
|
||||
child.on('message', function onReady(msg) {
|
||||
if (msg.what !== 'ready') return;
|
||||
child.removeListener('message', onReady);
|
||||
|
||||
testServer(function() {
|
||||
serverSucess = true;
|
||||
|
||||
testSocket(function() {
|
||||
socketSucess = true;
|
||||
child.kill();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.ok(serverSucess);
|
||||
assert.ok(socketSucess);
|
||||
});
|
||||
|
||||
}
|
131
test/simple/test-child-process-fork-net2.js
Normal file
131
test/simple/test-child-process-fork-net2.js
Normal file
@ -0,0 +1,131 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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 assert = require('assert');
|
||||
var common = require('../common');
|
||||
var fork = require('child_process').fork;
|
||||
var net = require('net');
|
||||
|
||||
if (process.argv[2] === 'child') {
|
||||
|
||||
var endMe = null;
|
||||
|
||||
process.on('message', function(m, socket) {
|
||||
if (!socket) return;
|
||||
|
||||
// will call .end('end') or .write('write');
|
||||
socket[m](m);
|
||||
|
||||
// store the unfinished socket
|
||||
if (m === 'write') {
|
||||
endMe = socket;
|
||||
}
|
||||
});
|
||||
|
||||
process.on('message', function(m) {
|
||||
if (m !== 'close') return;
|
||||
endMe.end('end');
|
||||
endMe = null;
|
||||
});
|
||||
|
||||
process.on('disconnect', function() {
|
||||
endMe.end('end');
|
||||
endMe = null;
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
var child1 = fork(process.argv[1], ['child']);
|
||||
var child2 = fork(process.argv[1], ['child']);
|
||||
var child3 = fork(process.argv[1], ['child']);
|
||||
|
||||
var server = net.createServer();
|
||||
|
||||
var connected = 0;
|
||||
server.on('connection', function(socket) {
|
||||
switch (connected) {
|
||||
case 0:
|
||||
child1.send('end', socket); break;
|
||||
case 1:
|
||||
child1.send('write', socket); break;
|
||||
case 2:
|
||||
child2.send('end', socket); break;
|
||||
case 3:
|
||||
child2.send('write', socket); break;
|
||||
case 4:
|
||||
child3.send('end', socket); break;
|
||||
case 5:
|
||||
child3.send('write', socket); break;
|
||||
}
|
||||
connected += 1;
|
||||
|
||||
if (connected === 6) {
|
||||
closeServer();
|
||||
}
|
||||
});
|
||||
|
||||
var disconnected = 0;
|
||||
server.on('listening', function() {
|
||||
|
||||
var j = 6, client;
|
||||
while (j--) {
|
||||
client = net.connect(common.PORT, '127.0.0.1');
|
||||
client.on('close', function() {
|
||||
disconnected += 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var closeEmitted = false;
|
||||
server.on('close', function() {
|
||||
closeEmitted = true;
|
||||
|
||||
child1.kill();
|
||||
child2.kill();
|
||||
child3.kill();
|
||||
});
|
||||
|
||||
server.listen(common.PORT, '127.0.0.1');
|
||||
|
||||
var timeElasped = 0;
|
||||
var closeServer = function() {
|
||||
var startTime = Date.now();
|
||||
server.on('close', function() {
|
||||
timeElasped = Date.now() - startTime;
|
||||
});
|
||||
|
||||
server.close();
|
||||
|
||||
setTimeout(function() {
|
||||
child1.send('close');
|
||||
child2.send('close');
|
||||
child3.disconnect();
|
||||
}, 200);
|
||||
};
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.equal(disconnected, 6);
|
||||
assert.equal(connected, 6);
|
||||
assert.ok(closeEmitted);
|
||||
assert.ok(timeElasped >= 190 && timeElasped <= 1000,
|
||||
'timeElasped was not between 190 and 1000 ms');
|
||||
});
|
||||
}
|
@ -30,7 +30,7 @@ if (process.argv[2] === 'child') {
|
||||
|
||||
var error = {};
|
||||
child.on('exit', function() {
|
||||
child._internal = {
|
||||
child._handle = {
|
||||
kill: function() {
|
||||
global.errno = 42;
|
||||
return -1;
|
||||
|
27
test/simple/test-dgram-ref.js
Normal file
27
test/simple/test-dgram-ref.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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 common = require('../common');
|
||||
var dgram = require('dgram');
|
||||
|
||||
// should not hang, see #1282
|
||||
dgram.createSocket('udp4');
|
||||
dgram.createSocket('udp6');
|
58
test/simple/test-http-client-pipe-end.js
Normal file
58
test/simple/test-http-client-pipe-end.js
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// see https://github.com/joyent/node/issues/3257
|
||||
|
||||
var common = require('../common');
|
||||
var assert = require('assert');
|
||||
var http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
req.once('end', function() {
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(common.PIPE, function() {
|
||||
var req = http.request({
|
||||
socketPath: common.PIPE,
|
||||
headers: {'Content-Length':'1'},
|
||||
method: 'POST',
|
||||
path: '/'
|
||||
});
|
||||
|
||||
req.write('.');
|
||||
|
||||
sched(function() { req.end() }, 5);
|
||||
});
|
||||
|
||||
// schedule a callback after `ticks` event loop ticks
|
||||
function sched(cb, ticks) {
|
||||
function fn() {
|
||||
if (--ticks)
|
||||
process.nextTick(fn);
|
||||
else
|
||||
cb();
|
||||
}
|
||||
process.nextTick(fn);
|
||||
}
|
@ -36,12 +36,13 @@ assert.equal(net.isIP('::1'), 6);
|
||||
assert.equal(net.isIP('::'), 6);
|
||||
assert.equal(net.isIP('0000:0000:0000:0000:0000:0000:12345:0000'), 0);
|
||||
assert.equal(net.isIP('0'), 0);
|
||||
assert.equal(net.isIP(), 0);
|
||||
assert.equal(net.isIP(""), 0);
|
||||
|
||||
assert.equal(net.isIPv4('127.0.0.1'), true);
|
||||
assert.equal(net.isIPv4('example.com'), false);
|
||||
assert.equal(net.isIPv4('2001:252:0:1::2008:6'), false);
|
||||
|
||||
assert.equal(net.isIPv6('127.0.0.1'), false);
|
||||
assert.equal(net.isIPv4('example.com'), false);
|
||||
assert.equal(net.isIPv6('2001:252:0:1::2008:6'), true);
|
||||
|
||||
assert.equal(net.isIPv6('example.com'), false);
|
||||
assert.equal(net.isIPv6('2001:252:0:1::2008:6'), true);
|
54
test/simple/test-process-active-wraps.js
Normal file
54
test/simple/test-process-active-wraps.js
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// 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 common = require('../common');
|
||||
var assert = require('assert');
|
||||
var spawn = require('child_process').spawn;
|
||||
var net = require('net');
|
||||
|
||||
function expect(activeHandles, activeRequests) {
|
||||
assert.equal(process._getActiveHandles().length, activeHandles);
|
||||
assert.equal(process._getActiveRequests().length, activeRequests);
|
||||
}
|
||||
|
||||
(function() {
|
||||
expect(0, 0);
|
||||
var server = net.createServer().listen(common.PORT);
|
||||
expect(1, 0);
|
||||
server.close();
|
||||
expect(1, 0); // server handle doesn't shut down until next tick
|
||||
})();
|
||||
|
||||
(function() {
|
||||
expect(1, 0);
|
||||
var conn = net.createConnection(common.PORT);
|
||||
conn.on('error', function() { /* ignore */ });
|
||||
expect(2, 1);
|
||||
conn.destroy();
|
||||
expect(2, 1); // client handle doesn't shut down until next tick
|
||||
})();
|
||||
|
||||
process.nextTick(function() {
|
||||
process.nextTick(function() {
|
||||
// the handles should be gone but the connect req could still be alive
|
||||
assert.equal(process._getActiveHandles().length, 0);
|
||||
});
|
||||
});
|
@ -55,7 +55,9 @@ var qsTestCases = [
|
||||
{ hasOwnProperty: 'x',
|
||||
toString: 'foo',
|
||||
valueOf: 'bar',
|
||||
__defineGetter__: 'baz' }]
|
||||
__defineGetter__: 'baz' }],
|
||||
// See: https://github.com/joyent/node/issues/3058
|
||||
['foo&bar=baz', 'foo=&bar=baz', { foo: '', bar: 'baz' }]
|
||||
];
|
||||
|
||||
// [ wonkyQS, canonicalQS, obj ]
|
||||
|
@ -69,3 +69,12 @@ assert.equal(false, util.isError({}));
|
||||
assert.equal(false, util.isError({ name: 'Error', message: '' }));
|
||||
assert.equal(false, util.isError([]));
|
||||
assert.equal(false, util.isError(Object.create(Error.prototype)));
|
||||
|
||||
// _extend
|
||||
assert.deepEqual(util._extend({a:1}), {a:1});
|
||||
assert.deepEqual(util._extend({a:1}, []), {a:1});
|
||||
assert.deepEqual(util._extend({a:1}, null), {a:1});
|
||||
assert.deepEqual(util._extend({a:1}, true), {a:1});
|
||||
assert.deepEqual(util._extend({a:1}, false), {a:1});
|
||||
assert.deepEqual(util._extend({a:1}, {b:2}), {a:1, b:2});
|
||||
assert.deepEqual(util._extend({a:1, b:2}, {b:3}), {a:1, b:3});
|
||||
|
Loading…
x
Reference in New Issue
Block a user