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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
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():
|
def target_arch():
|
||||||
return host_arch()
|
return host_arch()
|
||||||
|
|
||||||
|
def cc_version():
|
||||||
def gcc_version():
|
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen([CC, '-v'], stderr=subprocess.PIPE)
|
proc = subprocess.Popen([CC, '-v'], stderr=subprocess.PIPE)
|
||||||
except OSError:
|
except OSError:
|
||||||
return None
|
return None
|
||||||
# TODO parse clang output
|
lines = proc.communicate()[1].split('\n')
|
||||||
version = proc.communicate()[1].split('\n')[-2]
|
version_line = None
|
||||||
match = re.match('gcc version (\d+)\.(\d+)\.(\d+)', version)
|
for i, line in enumerate(lines):
|
||||||
if not match: return None
|
if 'version' in line:
|
||||||
return ['LLVM' in version] + map(int, match.groups())
|
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):
|
def configure_node(o):
|
||||||
# TODO add gdb
|
# TODO add gdb
|
||||||
@ -250,10 +254,10 @@ def configure_node(o):
|
|||||||
# see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45883
|
# see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45883
|
||||||
# see http://code.google.com/p/v8/issues/detail?id=884
|
# see http://code.google.com/p/v8/issues/detail?id=884
|
||||||
o['variables']['strict_aliasing'] = b(
|
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?
|
# 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'] = ''
|
o['variables']['visibility'] = ''
|
||||||
|
|
||||||
# By default, enable DTrace on SunOS systems. Don't allow it on other
|
# 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
|
An alternative way to check if you can send messages is to see if the
|
||||||
`child.connected` property is `true`.
|
`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
|
### child.stdin
|
||||||
|
|
||||||
* {Stream object}
|
* {Stream object}
|
||||||
@ -116,15 +124,120 @@ process may not actually kill it. `kill` really just sends a signal to a proces
|
|||||||
|
|
||||||
See `kill(2)`
|
See `kill(2)`
|
||||||
|
|
||||||
|
|
||||||
### child.send(message, [sendHandle])
|
### child.send(message, [sendHandle])
|
||||||
|
|
||||||
* `message` {Object}
|
* `message` {Object}
|
||||||
* `sendHandle` {Handle 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])
|
## 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
|
This is a special case of the `spawn()` functionality for spawning Node
|
||||||
processes. In addition to having all the methods in a normal ChildProcess
|
processes. In addition to having all the methods in a normal ChildProcess
|
||||||
instance, the returned object has a communication channel built-in. The
|
instance, the returned object has a communication channel built-in. See
|
||||||
channel is written to with `child.send(message, [sendHandle])` and messages
|
`child.send(message, [sendHandle])` for details.
|
||||||
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.
|
|
||||||
|
|
||||||
By default the spawned Node process will have the stdout, stderr associated
|
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
|
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
|
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
|
startup and 10mb memory for each new Node. That is, you cannot create many
|
||||||
thousands of them.
|
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
|
Set this property to reject connections when the server's connection count gets
|
||||||
high.
|
high.
|
||||||
|
|
||||||
|
It is not recommended to use this option once a socket has been sent to a child
|
||||||
|
with `child_process.fork()`.
|
||||||
|
|
||||||
### server.connections
|
### server.connections
|
||||||
|
|
||||||
The number of concurrent connections on the server.
|
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:
|
`net.Server` is an `EventEmitter` with the following events:
|
||||||
|
|
||||||
|
@ -33,6 +33,10 @@ function binaryWarn() {
|
|||||||
|
|
||||||
exports.INSPECT_MAX_BYTES = 50;
|
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) {
|
function toHex(n) {
|
||||||
if (n < 16) return '0' + n.toString(16);
|
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) {
|
SlowBuffer.prototype.hexSlice = function(start, end) {
|
||||||
var len = this.length;
|
var len = this.length;
|
||||||
|
|
||||||
@ -302,24 +292,25 @@ function allocPool() {
|
|||||||
|
|
||||||
// Static methods
|
// Static methods
|
||||||
Buffer.isBuffer = function isBuffer(b) {
|
Buffer.isBuffer = function isBuffer(b) {
|
||||||
return b instanceof Buffer || b instanceof SlowBuffer;
|
return b instanceof Buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Inspect
|
// Inspect
|
||||||
Buffer.prototype.inspect = function inspect() {
|
Buffer.prototype.inspect = function inspect() {
|
||||||
var out = [],
|
var out = [],
|
||||||
len = this.length;
|
len = this.length,
|
||||||
|
name = this.constructor.name;
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
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) {
|
if (i == exports.INSPECT_MAX_BYTES) {
|
||||||
out[i + 1] = '...';
|
out[i + 1] = '...';
|
||||||
break;
|
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) {
|
Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) {
|
||||||
writeDouble(this, value, offset, true, 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) {
|
function setupChannel(target, channel) {
|
||||||
target._channel = channel;
|
target._channel = channel;
|
||||||
|
|
||||||
var jsonBuffer = '';
|
var jsonBuffer = '';
|
||||||
channel.buffering = false;
|
channel.buffering = false;
|
||||||
channel.onread = function(pool, offset, length, recvHandle) {
|
channel.onread = function(pool, offset, length, recvHandle) {
|
||||||
// Update simultaneous accepts on Windows
|
|
||||||
net._setSimultaneousAccepts(recvHandle);
|
|
||||||
|
|
||||||
if (pool) {
|
if (pool) {
|
||||||
jsonBuffer += pool.toString('ascii', offset, offset + length);
|
jsonBuffer += pool.toString('ascii', offset, offset + length);
|
||||||
|
|
||||||
@ -73,18 +265,7 @@ function setupChannel(target, channel) {
|
|||||||
var json = jsonBuffer.slice(start, i);
|
var json = jsonBuffer.slice(start, i);
|
||||||
var message = JSON.parse(json);
|
var message = JSON.parse(json);
|
||||||
|
|
||||||
//Filter out internal messages
|
handleMessage(target, message, recvHandle);
|
||||||
//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);
|
|
||||||
}
|
|
||||||
|
|
||||||
start = i + 1;
|
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') {
|
if (typeof message === 'undefined') {
|
||||||
throw new TypeError('message cannot be undefined');
|
throw new TypeError('message cannot be undefined');
|
||||||
}
|
}
|
||||||
@ -112,12 +313,43 @@ function setupChannel(target, channel) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var string = JSON.stringify(message) + '\n';
|
// 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
|
// Update simultaneous accepts on Windows
|
||||||
net._setSimultaneousAccepts(sendHandle);
|
if (obj.simultaneousAccepts) {
|
||||||
|
net._setSimultaneousAccepts(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var writeReq = channel.writeUtf8String(string, sendHandle);
|
var string = JSON.stringify(message) + '\n';
|
||||||
|
var writeReq = channel.writeUtf8String(string, handle);
|
||||||
|
|
||||||
|
// Close the Socket handle after sending it
|
||||||
|
if (message && message.type === 'net.Socket') {
|
||||||
|
handle.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (!writeReq) {
|
if (!writeReq) {
|
||||||
var er = errnoException(errno, 'write', 'cannot write to IPC channel.');
|
var er = errnoException(errno, 'write', 'cannot write to IPC channel.');
|
||||||
@ -172,10 +404,10 @@ exports.fork = function(modulePath /*, args, options*/) {
|
|||||||
var options, args, execArgv;
|
var options, args, execArgv;
|
||||||
if (Array.isArray(arguments[1])) {
|
if (Array.isArray(arguments[1])) {
|
||||||
args = arguments[1];
|
args = arguments[1];
|
||||||
options = arguments[2] || {};
|
options = util._extend({}, arguments[2]);
|
||||||
} else {
|
} else {
|
||||||
args = [];
|
args = [];
|
||||||
options = arguments[1] || {};
|
options = util._extend({}, arguments[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare arguments for fork:
|
// Prepare arguments for fork:
|
||||||
@ -264,15 +496,12 @@ exports.execFile = function(file /* args, options, callback */) {
|
|||||||
|
|
||||||
if (Array.isArray(arguments[1])) {
|
if (Array.isArray(arguments[1])) {
|
||||||
args = arguments[1];
|
args = arguments[1];
|
||||||
if (typeof arguments[2] === 'object') optionArg = arguments[2];
|
options = util._extend(options, arguments[2]);
|
||||||
} else {
|
} else {
|
||||||
args = [];
|
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, {
|
var child = spawn(file, args, {
|
||||||
cwd: options.cwd,
|
cwd: options.cwd,
|
||||||
env: options.env,
|
env: options.env,
|
||||||
@ -398,8 +627,10 @@ function ChildProcess() {
|
|||||||
this.exitCode = null;
|
this.exitCode = null;
|
||||||
this.killed = false;
|
this.killed = false;
|
||||||
|
|
||||||
this._internal = new Process();
|
this._handle = new Process();
|
||||||
this._internal.onexit = function(exitCode, signalCode) {
|
this._handle.owner = this;
|
||||||
|
|
||||||
|
this._handle.onexit = function(exitCode, signalCode) {
|
||||||
//
|
//
|
||||||
// follow 0.4.x behaviour:
|
// follow 0.4.x behaviour:
|
||||||
//
|
//
|
||||||
@ -416,8 +647,8 @@ function ChildProcess() {
|
|||||||
self.stdin.destroy();
|
self.stdin.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
self._internal.close();
|
self._handle.close();
|
||||||
self._internal = null;
|
self._handle = null;
|
||||||
|
|
||||||
self.emit('exit', self.exitCode, self.signalCode);
|
self.emit('exit', self.exitCode, self.signalCode);
|
||||||
|
|
||||||
@ -452,7 +683,7 @@ ChildProcess.prototype.spawn = function(options) {
|
|||||||
setStreamOption('stdoutStream', 1, options);
|
setStreamOption('stdoutStream', 1, options);
|
||||||
setStreamOption('stderrStream', 2, options);
|
setStreamOption('stderrStream', 2, options);
|
||||||
|
|
||||||
var r = this._internal.spawn(options);
|
var r = this._handle.spawn(options);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
if (options.stdinStream) {
|
if (options.stdinStream) {
|
||||||
@ -467,12 +698,12 @@ ChildProcess.prototype.spawn = function(options) {
|
|||||||
options.stderrStream.close();
|
options.stderrStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._internal.close();
|
this._handle.close();
|
||||||
this._internal = null;
|
this._handle = null;
|
||||||
throw errnoException(errno, 'spawn');
|
throw errnoException(errno, 'spawn');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pid = this._internal.pid;
|
this.pid = this._handle.pid;
|
||||||
|
|
||||||
if (options.stdinStream) {
|
if (options.stdinStream) {
|
||||||
this.stdin = createSocket(options.stdinStream, false);
|
this.stdin = createSocket(options.stdinStream, false);
|
||||||
@ -525,9 +756,9 @@ ChildProcess.prototype.kill = function(sig) {
|
|||||||
throw new Error('Unknown signal: ' + sig);
|
throw new Error('Unknown signal: ' + sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._internal) {
|
if (this._handle) {
|
||||||
this.killed = true;
|
this.killed = true;
|
||||||
var r = this._internal.kill(signal);
|
var r = this._handle.kill(signal);
|
||||||
if (r === -1) {
|
if (r === -1) {
|
||||||
this.emit('error', errnoException(errno, 'kill'));
|
this.emit('error', errnoException(errno, 'kill'));
|
||||||
return;
|
return;
|
||||||
|
@ -91,7 +91,7 @@ function Socket(type, listener) {
|
|||||||
events.EventEmitter.call(this);
|
events.EventEmitter.call(this);
|
||||||
|
|
||||||
var handle = newHandle(type);
|
var handle = newHandle(type);
|
||||||
handle.socket = this;
|
handle.owner = this;
|
||||||
|
|
||||||
this._handle = handle;
|
this._handle = handle;
|
||||||
this._receiving = false;
|
this._receiving = false;
|
||||||
@ -200,7 +200,7 @@ Socket.prototype.send = function(buffer,
|
|||||||
|
|
||||||
|
|
||||||
function afterSend(status, handle, req, 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?
|
// CHECKME socket's been closed by user, don't call callback?
|
||||||
if (handle !== self._handle)
|
if (handle !== self._handle)
|
||||||
@ -344,7 +344,7 @@ Socket.prototype._stopReceiving = function() {
|
|||||||
|
|
||||||
|
|
||||||
function onMessage(handle, slab, start, len, rinfo) {
|
function onMessage(handle, slab, start, len, rinfo) {
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
if (!slab) return self.emit('error', errnoException(errno, 'recvmsg'));
|
if (!slab) return self.emit('error', errnoException(errno, 'recvmsg'));
|
||||||
rinfo.size = len; // compatibility
|
rinfo.size = len; // compatibility
|
||||||
self.emit('message', slab.slice(start, start + len), rinfo);
|
self.emit('message', slab.slice(start, start + len), rinfo);
|
||||||
|
@ -737,6 +737,7 @@ function FSWatcher() {
|
|||||||
var self = this;
|
var self = this;
|
||||||
var FSEvent = process.binding('fs_event_wrap').FSEvent;
|
var FSEvent = process.binding('fs_event_wrap').FSEvent;
|
||||||
this._handle = new FSEvent();
|
this._handle = new FSEvent();
|
||||||
|
this._handle.owner = this;
|
||||||
|
|
||||||
this._handle.onchange = function(status, event, filename) {
|
this._handle.onchange = function(status, event, filename) {
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -475,6 +475,10 @@ OutgoingMessage.prototype._send = function(data, encoding) {
|
|||||||
|
|
||||||
|
|
||||||
OutgoingMessage.prototype._writeRaw = function(data, encoding) {
|
OutgoingMessage.prototype._writeRaw = function(data, encoding) {
|
||||||
|
if (data.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.connection &&
|
if (this.connection &&
|
||||||
this.connection._httpMessage === this &&
|
this.connection._httpMessage === this &&
|
||||||
this.connection.writable) {
|
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.
|
// Handle creation may be deferred to bind() or connect() time.
|
||||||
if (self._handle) {
|
if (self._handle) {
|
||||||
self._handle.socket = self;
|
self._handle.owner = self;
|
||||||
self._handle.onread = onread;
|
self._handle.onread = onread;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ Socket.prototype.end = function(data, encoding) {
|
|||||||
|
|
||||||
|
|
||||||
function afterShutdown(status, handle, req) {
|
function afterShutdown(status, handle, req) {
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
|
|
||||||
assert.ok(self._flags & FLAG_SHUTDOWN);
|
assert.ok(self._flags & FLAG_SHUTDOWN);
|
||||||
assert.ok(!self.writable);
|
assert.ok(!self.writable);
|
||||||
@ -352,7 +352,7 @@ Socket.prototype._destroy = function(exception, cb) {
|
|||||||
timers.unenroll(this);
|
timers.unenroll(this);
|
||||||
|
|
||||||
if (this.server) {
|
if (this.server) {
|
||||||
this.server.connections--;
|
this.server._connections--;
|
||||||
this.server._emitCloseIfDrained();
|
this.server._emitCloseIfDrained();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ Socket.prototype.destroy = function(exception) {
|
|||||||
|
|
||||||
function onread(buffer, offset, length) {
|
function onread(buffer, offset, length) {
|
||||||
var handle = this;
|
var handle = this;
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
assert.equal(handle, self._handle);
|
assert.equal(handle, self._handle);
|
||||||
|
|
||||||
timers.active(self);
|
timers.active(self);
|
||||||
@ -583,7 +583,7 @@ Socket.prototype.__defineGetter__('bytesWritten', function() {
|
|||||||
|
|
||||||
|
|
||||||
function afterWrite(status, handle, req) {
|
function afterWrite(status, handle, req) {
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
|
|
||||||
// callback may come after call to destroy.
|
// callback may come after call to destroy.
|
||||||
if (self.destroyed) {
|
if (self.destroyed) {
|
||||||
@ -722,7 +722,7 @@ Socket.prototype.connect = function(options, cb) {
|
|||||||
|
|
||||||
|
|
||||||
function afterConnect(status, handle, req, readable, writable) {
|
function afterConnect(status, handle, req, readable, writable) {
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
|
|
||||||
// callback may come after call to destroy
|
// callback may come after call to destroy
|
||||||
if (self.destroyed) {
|
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.allowHalfOpen = options.allowHalfOpen || false;
|
||||||
|
|
||||||
this._handle = null;
|
this._handle = null;
|
||||||
@ -865,7 +881,7 @@ Server.prototype._listen2 = function(address, port, addressType, backlog) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self._handle.onconnection = onconnection;
|
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
|
// Use a backlog of 512 entries. We pass 511 to the listen() call because
|
||||||
// the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
// the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
||||||
@ -881,6 +897,9 @@ Server.prototype._listen2 = function(address, port, addressType, backlog) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate connection key, this should be unique to the connection
|
||||||
|
this._connectionKey = addressType + ':' + address + ':' + port;
|
||||||
|
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
self.emit('listening');
|
self.emit('listening');
|
||||||
});
|
});
|
||||||
@ -961,7 +980,7 @@ Server.prototype.address = function() {
|
|||||||
|
|
||||||
function onconnection(clientHandle) {
|
function onconnection(clientHandle) {
|
||||||
var handle = this;
|
var handle = this;
|
||||||
var self = handle.socket;
|
var self = handle.owner;
|
||||||
|
|
||||||
debug('onconnection');
|
debug('onconnection');
|
||||||
|
|
||||||
@ -970,7 +989,7 @@ function onconnection(clientHandle) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.maxConnections && self.connections >= self.maxConnections) {
|
if (self.maxConnections && self._connections >= self.maxConnections) {
|
||||||
clientHandle.close();
|
clientHandle.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -983,7 +1002,7 @@ function onconnection(clientHandle) {
|
|||||||
|
|
||||||
socket.resume();
|
socket.resume();
|
||||||
|
|
||||||
self.connections++;
|
self._connections++;
|
||||||
socket.server = self;
|
socket.server = self;
|
||||||
|
|
||||||
DTRACE_NET_SERVER_CONNECTION(socket);
|
DTRACE_NET_SERVER_CONNECTION(socket);
|
||||||
@ -1005,13 +1024,21 @@ Server.prototype.close = function(cb) {
|
|||||||
this._handle = null;
|
this._handle = null;
|
||||||
this._emitCloseIfDrained();
|
this._emitCloseIfDrained();
|
||||||
|
|
||||||
|
// fetch new socket lists
|
||||||
|
if (this._usingSlaves) {
|
||||||
|
this._slaves.forEach(function(socketList) {
|
||||||
|
if (socketList.list.length === 0) return;
|
||||||
|
socketList.update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Server.prototype._emitCloseIfDrained = function() {
|
Server.prototype._emitCloseIfDrained = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
if (self._handle || self.connections) return;
|
if (self._handle || self._connections) return;
|
||||||
|
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
self.emit('close');
|
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');
|
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
|
// TODO: isIP should be moved to the DNS code. Putting it here now because
|
||||||
// this is what the legacy system did.
|
// 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.
|
// and it does not detect more than one double : in a string.
|
||||||
exports.isIP = function(input) {
|
exports.isIP = function(input) {
|
||||||
if (!input) {
|
if (!input) {
|
||||||
return 4;
|
return 0;
|
||||||
} else if (/^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/.test(input)) {
|
} else if (/^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/.test(input)) {
|
||||||
var parts = input.split('.');
|
var parts = input.split('.');
|
||||||
for (var i = 0; i < parts.length; i++) {
|
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),
|
kstr = x.substring(0, idx),
|
||||||
vstr = x.substring(idx + 1), k, v;
|
vstr = x.substring(idx + 1), k, v;
|
||||||
|
|
||||||
|
if (kstr === '' && vstr !== '') {
|
||||||
|
kstr = vstr;
|
||||||
|
vstr = '';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
k = decodeURIComponent(kstr);
|
k = decodeURIComponent(kstr);
|
||||||
v = decodeURIComponent(vstr);
|
v = decodeURIComponent(vstr);
|
||||||
|
@ -509,7 +509,7 @@ exports.inherits = function(ctor, superCtor) {
|
|||||||
|
|
||||||
exports._extend = function(origin, add) {
|
exports._extend = function(origin, add) {
|
||||||
// Don't do anything if add isn't an object
|
// 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 keys = Object.keys(add);
|
||||||
var i = keys.length;
|
var i = keys.length;
|
||||||
|
1
node.gyp
1
node.gyp
@ -107,6 +107,7 @@
|
|||||||
'src/node_script.h',
|
'src/node_script.h',
|
||||||
'src/node_string.h',
|
'src/node_string.h',
|
||||||
'src/node_version.h',
|
'src/node_version.h',
|
||||||
|
'src/ngx-queue.h',
|
||||||
'src/pipe_wrap.h',
|
'src/pipe_wrap.h',
|
||||||
'src/req_wrap.h',
|
'src/req_wrap.h',
|
||||||
'src/slab_allocator.h',
|
'src/slab_allocator.h',
|
||||||
|
@ -20,10 +20,12 @@
|
|||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "ngx-queue.h"
|
||||||
#include "handle_wrap.h"
|
#include "handle_wrap.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
|
using v8::Array;
|
||||||
using v8::Object;
|
using v8::Object;
|
||||||
using v8::Handle;
|
using v8::Handle;
|
||||||
using v8::Local;
|
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) {
|
void HandleWrap::Initialize(Handle<Object> target) {
|
||||||
/* Doesn't do anything at the moment. */
|
/* Doesn't do anything at the moment. */
|
||||||
}
|
}
|
||||||
@ -125,6 +131,7 @@ HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
|
|||||||
assert(object->InternalFieldCount() > 0);
|
assert(object->InternalFieldCount() > 0);
|
||||||
object_ = v8::Persistent<v8::Object>::New(object);
|
object_ = v8::Persistent<v8::Object>::New(object);
|
||||||
object_->SetPointerInInternalField(0, this);
|
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() {
|
HandleWrap::~HandleWrap() {
|
||||||
assert(object_.IsEmpty());
|
assert(object_.IsEmpty());
|
||||||
|
ngx_queue_remove(&handle_wrap_queue_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#ifndef HANDLE_WRAP_H_
|
#ifndef HANDLE_WRAP_H_
|
||||||
#define HANDLE_WRAP_H_
|
#define HANDLE_WRAP_H_
|
||||||
|
|
||||||
|
#include "ngx-queue.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
// Rules:
|
// Rules:
|
||||||
@ -61,7 +63,9 @@ class HandleWrap {
|
|||||||
v8::Persistent<v8::Object> object_;
|
v8::Persistent<v8::Object> object_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend v8::Handle<v8::Value> GetActiveHandles(const v8::Arguments&);
|
||||||
static void OnClose(uv_handle_t* handle);
|
static void OnClose(uv_handle_t* handle);
|
||||||
|
ngx_queue_t handle_wrap_queue_;
|
||||||
// Using double underscore due to handle_ member in tcp_wrap. Probably
|
// Using double underscore due to handle_ member in tcp_wrap. Probably
|
||||||
// tcp_wrap should rename it's member to 'handle'.
|
// tcp_wrap should rename it's member to 'handle'.
|
||||||
uv_handle_t* 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.
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "req_wrap.h"
|
||||||
|
#include "handle_wrap.h"
|
||||||
|
|
||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
|
|
||||||
@ -90,6 +92,13 @@ extern char **environ;
|
|||||||
|
|
||||||
namespace node {
|
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<Object> process;
|
||||||
|
|
||||||
static Persistent<String> errno_symbol;
|
static Persistent<String> errno_symbol;
|
||||||
@ -105,7 +114,6 @@ static Persistent<String> listeners_symbol;
|
|||||||
static Persistent<String> uncaught_exception_symbol;
|
static Persistent<String> uncaught_exception_symbol;
|
||||||
static Persistent<String> emit_symbol;
|
static Persistent<String> emit_symbol;
|
||||||
|
|
||||||
static Persistent<String> domain_symbol;
|
|
||||||
static Persistent<String> enter_symbol;
|
static Persistent<String> enter_symbol;
|
||||||
static Persistent<String> exit_symbol;
|
static Persistent<String> exit_symbol;
|
||||||
static Persistent<String> disposed_symbol;
|
static Persistent<String> disposed_symbol;
|
||||||
@ -1019,8 +1027,7 @@ MakeCallback(const Handle<Object> object,
|
|||||||
|
|
||||||
TryCatch try_catch;
|
TryCatch try_catch;
|
||||||
|
|
||||||
if (domain_symbol.IsEmpty()) {
|
if (enter_symbol.IsEmpty()) {
|
||||||
domain_symbol = NODE_PSYMBOL("domain");
|
|
||||||
enter_symbol = NODE_PSYMBOL("enter");
|
enter_symbol = NODE_PSYMBOL("enter");
|
||||||
exit_symbol = NODE_PSYMBOL("exit");
|
exit_symbol = NODE_PSYMBOL("exit");
|
||||||
disposed_symbol = NODE_PSYMBOL("_disposed");
|
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) {
|
static Handle<Value> Abort(const Arguments& args) {
|
||||||
abort();
|
abort();
|
||||||
return Undefined();
|
return Undefined();
|
||||||
@ -2239,6 +2286,8 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {
|
|||||||
|
|
||||||
|
|
||||||
// define various internal methods
|
// 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, "_needTickCallback", NeedTickCallback);
|
||||||
NODE_SET_METHOD(process, "reallyExit", Exit);
|
NODE_SET_METHOD(process, "reallyExit", Exit);
|
||||||
NODE_SET_METHOD(process, "abort", Abort);
|
NODE_SET_METHOD(process, "abort", Abort);
|
||||||
@ -2869,6 +2918,9 @@ int Start(int argc, char *argv[]) {
|
|||||||
Persistent<Context> context = Context::New();
|
Persistent<Context> context = Context::New();
|
||||||
Context::Scope context_scope(context);
|
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.
|
// Use original argv, as we're just copying values out of it.
|
||||||
Handle<Object> process_l = SetupProcessObject(argc, argv);
|
Handle<Object> process_l = SetupProcessObject(argc, argv);
|
||||||
v8_typed_array::AttachBindings(context->Global());
|
v8_typed_array::AttachBindings(context->Global());
|
||||||
|
@ -22,10 +22,14 @@
|
|||||||
#ifndef REQ_WRAP_H_
|
#ifndef REQ_WRAP_H_
|
||||||
#define REQ_WRAP_H_
|
#define REQ_WRAP_H_
|
||||||
|
|
||||||
|
#include "ngx-queue.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
static v8::Persistent<v8::String> process_symbol;
|
// defined in node.cc
|
||||||
static v8::Persistent<v8::String> domain_symbol;
|
extern v8::Persistent<v8::String> process_symbol;
|
||||||
|
extern v8::Persistent<v8::String> domain_symbol;
|
||||||
|
extern ngx_queue_t req_wrap_queue;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ReqWrap {
|
class ReqWrap {
|
||||||
@ -34,12 +38,6 @@ class ReqWrap {
|
|||||||
v8::HandleScope scope;
|
v8::HandleScope scope;
|
||||||
object_ = v8::Persistent<v8::Object>::New(v8::Object::New());
|
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()
|
v8::Local<v8::Value> domain = v8::Context::GetCurrent()
|
||||||
->Global()
|
->Global()
|
||||||
->Get(process_symbol)
|
->Get(process_symbol)
|
||||||
@ -50,10 +48,13 @@ class ReqWrap {
|
|||||||
// fprintf(stderr, "setting domain on ReqWrap\n");
|
// fprintf(stderr, "setting domain on ReqWrap\n");
|
||||||
object_->Set(domain_symbol, domain);
|
object_->Set(domain_symbol, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngx_queue_insert_tail(&req_wrap_queue, &req_wrap_queue_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
~ReqWrap() {
|
~ReqWrap() {
|
||||||
|
ngx_queue_remove(&req_wrap_queue_);
|
||||||
// Assert that someone has called Dispatched()
|
// Assert that someone has called Dispatched()
|
||||||
assert(req_.data == this);
|
assert(req_.data == this);
|
||||||
assert(!object_.IsEmpty());
|
assert(!object_.IsEmpty());
|
||||||
@ -67,8 +68,9 @@ class ReqWrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
v8::Persistent<v8::Object> object_;
|
v8::Persistent<v8::Object> object_;
|
||||||
T req_;
|
ngx_queue_t req_wrap_queue_;
|
||||||
void* data_;
|
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 = {};
|
var error = {};
|
||||||
child.on('exit', function() {
|
child.on('exit', function() {
|
||||||
child._internal = {
|
child._handle = {
|
||||||
kill: function() {
|
kill: function() {
|
||||||
global.errno = 42;
|
global.errno = 42;
|
||||||
return -1;
|
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('::'), 6);
|
||||||
assert.equal(net.isIP('0000:0000:0000:0000:0000:0000:12345:0000'), 0);
|
assert.equal(net.isIP('0000:0000:0000:0000:0000:0000:12345:0000'), 0);
|
||||||
assert.equal(net.isIP('0'), 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('127.0.0.1'), true);
|
||||||
assert.equal(net.isIPv4('example.com'), false);
|
assert.equal(net.isIPv4('example.com'), false);
|
||||||
assert.equal(net.isIPv4('2001:252:0:1::2008:6'), false);
|
assert.equal(net.isIPv4('2001:252:0:1::2008:6'), false);
|
||||||
|
|
||||||
assert.equal(net.isIPv6('127.0.0.1'), false);
|
assert.equal(net.isIPv6('127.0.0.1'), false);
|
||||||
assert.equal(net.isIPv4('example.com'), false);
|
assert.equal(net.isIPv6('example.com'), false);
|
||||||
assert.equal(net.isIPv6('2001:252:0:1::2008:6'), true);
|
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',
|
{ hasOwnProperty: 'x',
|
||||||
toString: 'foo',
|
toString: 'foo',
|
||||||
valueOf: 'bar',
|
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 ]
|
// [ 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({ name: 'Error', message: '' }));
|
||||||
assert.equal(false, util.isError([]));
|
assert.equal(false, util.isError([]));
|
||||||
assert.equal(false, util.isError(Object.create(Error.prototype)));
|
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