macgyver 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Growl +0 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Growl +0 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/Growl.h +5 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +551 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlDefines.h +341 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Resources/Info.plist +40 -0
- data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/_CodeSignature/CodeResources +34 -0
- data/assets/MacGap.app/Contents/Info.plist +48 -0
- data/assets/MacGap.app/Contents/MacOS/MacGap +0 -0
- data/assets/MacGap.app/Contents/PkgInfo +1 -0
- data/assets/MacGap.app/Contents/Resources/_debugger.js +1718 -0
- data/assets/MacGap.app/Contents/Resources/_http_agent.js +310 -0
- data/assets/MacGap.app/Contents/Resources/_http_client.js +533 -0
- data/assets/MacGap.app/Contents/Resources/_http_common.js +222 -0
- data/assets/MacGap.app/Contents/Resources/_http_incoming.js +194 -0
- data/assets/MacGap.app/Contents/Resources/_http_outgoing.js +597 -0
- data/assets/MacGap.app/Contents/Resources/_http_server.js +510 -0
- data/assets/MacGap.app/Contents/Resources/_linklist.js +76 -0
- data/assets/MacGap.app/Contents/Resources/_stream_duplex.js +69 -0
- data/assets/MacGap.app/Contents/Resources/_stream_passthrough.js +41 -0
- data/assets/MacGap.app/Contents/Resources/_stream_readable.js +900 -0
- data/assets/MacGap.app/Contents/Resources/_stream_transform.js +204 -0
- data/assets/MacGap.app/Contents/Resources/_stream_writable.js +456 -0
- data/assets/MacGap.app/Contents/Resources/_tls_legacy.js +887 -0
- data/assets/MacGap.app/Contents/Resources/_tls_wrap.js +831 -0
- data/assets/MacGap.app/Contents/Resources/application.icns +0 -0
- data/assets/MacGap.app/Contents/Resources/assert.js +326 -0
- data/assets/MacGap.app/Contents/Resources/buffer.js +724 -0
- data/assets/MacGap.app/Contents/Resources/child_process.js +1107 -0
- data/assets/MacGap.app/Contents/Resources/cluster.js +613 -0
- data/assets/MacGap.app/Contents/Resources/console.js +108 -0
- data/assets/MacGap.app/Contents/Resources/constants.js +22 -0
- data/assets/MacGap.app/Contents/Resources/crypto.js +691 -0
- data/assets/MacGap.app/Contents/Resources/dgram.js +459 -0
- data/assets/MacGap.app/Contents/Resources/dns.js +274 -0
- data/assets/MacGap.app/Contents/Resources/domain.js +292 -0
- data/assets/MacGap.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
- data/assets/MacGap.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
- data/assets/MacGap.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
- data/assets/MacGap.app/Contents/Resources/en.lproj/Window.nib +0 -0
- data/assets/MacGap.app/Contents/Resources/events.js +312 -0
- data/assets/MacGap.app/Contents/Resources/freelist.js +43 -0
- data/assets/MacGap.app/Contents/Resources/fs.js +1732 -0
- data/assets/MacGap.app/Contents/Resources/http.js +119 -0
- data/assets/MacGap.app/Contents/Resources/https.js +134 -0
- data/assets/MacGap.app/Contents/Resources/module.js +529 -0
- data/assets/MacGap.app/Contents/Resources/net.js +1378 -0
- data/assets/MacGap.app/Contents/Resources/nodelike.js +195 -0
- data/assets/MacGap.app/Contents/Resources/os.js +64 -0
- data/assets/MacGap.app/Contents/Resources/path.js +517 -0
- data/assets/MacGap.app/Contents/Resources/public/index.html +38 -0
- data/assets/MacGap.app/Contents/Resources/punycode.js +507 -0
- data/assets/MacGap.app/Contents/Resources/querystring.js +206 -0
- data/assets/MacGap.app/Contents/Resources/readline.js +1311 -0
- data/assets/MacGap.app/Contents/Resources/repl.js +945 -0
- data/assets/MacGap.app/Contents/Resources/smalloc.js +90 -0
- data/assets/MacGap.app/Contents/Resources/stream.js +127 -0
- data/assets/MacGap.app/Contents/Resources/string_decoder.js +189 -0
- data/assets/MacGap.app/Contents/Resources/sys.js +24 -0
- data/assets/MacGap.app/Contents/Resources/timers.js +568 -0
- data/assets/MacGap.app/Contents/Resources/tls.js +220 -0
- data/assets/MacGap.app/Contents/Resources/tty.js +129 -0
- data/assets/MacGap.app/Contents/Resources/url.js +693 -0
- data/assets/MacGap.app/Contents/Resources/util.js +688 -0
- data/assets/MacGap.app/Contents/Resources/vm.js +73 -0
- data/assets/MacGap.app/Contents/Resources/zlib.js +524 -0
- data/assets/index.html +38 -0
- data/bin/macgyver +104 -0
- data/macgyver.gemspec +19 -0
- data/test/public/index.html +27 -0
- metadata +121 -0
@@ -0,0 +1,1378 @@
|
|
1
|
+
// Copyright Joyent, Inc. and other Node contributors.
|
2
|
+
//
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a
|
4
|
+
// copy of this software and associated documentation files (the
|
5
|
+
// "Software"), to deal in the Software without restriction, including
|
6
|
+
// without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
8
|
+
// persons to whom the Software is furnished to do so, subject to the
|
9
|
+
// following conditions:
|
10
|
+
//
|
11
|
+
// The above copyright notice and this permission notice shall be included
|
12
|
+
// in all copies or substantial portions of the Software.
|
13
|
+
//
|
14
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
15
|
+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
17
|
+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
18
|
+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
19
|
+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
20
|
+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
var events = require('events');
|
23
|
+
var stream = require('stream');
|
24
|
+
var timers = require('timers');
|
25
|
+
var util = require('util');
|
26
|
+
var assert = require('assert');
|
27
|
+
var cares = process.binding('cares_wrap');
|
28
|
+
var uv = process.binding('uv');
|
29
|
+
|
30
|
+
var cluster;
|
31
|
+
var errnoException = util._errnoException;
|
32
|
+
|
33
|
+
function noop() {}
|
34
|
+
|
35
|
+
// constructor for lazy loading
|
36
|
+
function createPipe() {
|
37
|
+
var Pipe = process.binding('pipe_wrap').Pipe;
|
38
|
+
return new Pipe();
|
39
|
+
}
|
40
|
+
|
41
|
+
// constructor for lazy loading
|
42
|
+
function createTCP() {
|
43
|
+
var TCP = process.binding('tcp_wrap').TCP;
|
44
|
+
return new TCP();
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
function createHandle(fd) {
|
49
|
+
var tty = process.binding('tty_wrap');
|
50
|
+
var type = tty.guessHandleType(fd);
|
51
|
+
if (type === 'PIPE') return createPipe();
|
52
|
+
if (type === 'TCP') return createTCP();
|
53
|
+
throw new TypeError('Unsupported fd type: ' + type);
|
54
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
var debug = util.debuglog('net');
|
58
|
+
|
59
|
+
function isPipeName(s) {
|
60
|
+
return util.isString(s) && toNumber(s) === false;
|
61
|
+
}
|
62
|
+
|
63
|
+
|
64
|
+
exports.createServer = function() {
|
65
|
+
return new Server(arguments[0], arguments[1]);
|
66
|
+
};
|
67
|
+
|
68
|
+
|
69
|
+
// Target API:
|
70
|
+
//
|
71
|
+
// var s = net.connect({port: 80, host: 'google.com'}, function() {
|
72
|
+
// ...
|
73
|
+
// });
|
74
|
+
//
|
75
|
+
// There are various forms:
|
76
|
+
//
|
77
|
+
// connect(options, [cb])
|
78
|
+
// connect(port, [host], [cb])
|
79
|
+
// connect(path, [cb]);
|
80
|
+
//
|
81
|
+
exports.connect = exports.createConnection = function() {
|
82
|
+
var args = normalizeConnectArgs(arguments);
|
83
|
+
debug('createConnection', args);
|
84
|
+
var s = new Socket(args[0]);
|
85
|
+
return Socket.prototype.connect.apply(s, args);
|
86
|
+
};
|
87
|
+
|
88
|
+
// Returns an array [options] or [options, cb]
|
89
|
+
// It is the same as the argument of Socket.prototype.connect().
|
90
|
+
function normalizeConnectArgs(args) {
|
91
|
+
var options = {};
|
92
|
+
|
93
|
+
if (util.isObject(args[0])) {
|
94
|
+
// connect(options, [cb])
|
95
|
+
options = args[0];
|
96
|
+
} else if (isPipeName(args[0])) {
|
97
|
+
// connect(path, [cb]);
|
98
|
+
options.path = args[0];
|
99
|
+
} else {
|
100
|
+
// connect(port, [host], [cb])
|
101
|
+
options.port = args[0];
|
102
|
+
if (util.isString(args[1])) {
|
103
|
+
options.host = args[1];
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
var cb = args[args.length - 1];
|
108
|
+
return util.isFunction(cb) ? [options, cb] : [options];
|
109
|
+
}
|
110
|
+
exports._normalizeConnectArgs = normalizeConnectArgs;
|
111
|
+
|
112
|
+
|
113
|
+
// called when creating new Socket, or when re-using a closed Socket
|
114
|
+
function initSocketHandle(self) {
|
115
|
+
self.destroyed = false;
|
116
|
+
self.errorEmitted = false;
|
117
|
+
self.bytesRead = 0;
|
118
|
+
self._bytesDispatched = 0;
|
119
|
+
|
120
|
+
// Handle creation may be deferred to bind() or connect() time.
|
121
|
+
if (self._handle) {
|
122
|
+
self._handle.owner = self;
|
123
|
+
self._handle.onread = onread;
|
124
|
+
|
125
|
+
// If handle doesn't support writev - neither do we
|
126
|
+
if (!self._handle.writev)
|
127
|
+
self._writev = null;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
function Socket(options) {
|
132
|
+
if (!(this instanceof Socket)) return new Socket(options);
|
133
|
+
|
134
|
+
this._connecting = false;
|
135
|
+
this._hadError = false;
|
136
|
+
this._handle = null;
|
137
|
+
this._host = null;
|
138
|
+
|
139
|
+
if (util.isNumber(options))
|
140
|
+
options = { fd: options }; // Legacy interface.
|
141
|
+
else if (util.isUndefined(options))
|
142
|
+
options = {};
|
143
|
+
|
144
|
+
stream.Duplex.call(this, options);
|
145
|
+
|
146
|
+
if (options.handle) {
|
147
|
+
this._handle = options.handle; // private
|
148
|
+
} else if (!util.isUndefined(options.fd)) {
|
149
|
+
this._handle = createHandle(options.fd);
|
150
|
+
this._handle.open(options.fd);
|
151
|
+
this.readable = options.readable !== false;
|
152
|
+
this.writable = options.writable !== false;
|
153
|
+
} else {
|
154
|
+
// these will be set once there is a connection
|
155
|
+
this.readable = this.writable = false;
|
156
|
+
}
|
157
|
+
|
158
|
+
// shut down the socket when we're finished with it.
|
159
|
+
this.on('finish', onSocketFinish);
|
160
|
+
this.on('_socketEnd', onSocketEnd);
|
161
|
+
|
162
|
+
initSocketHandle(this);
|
163
|
+
|
164
|
+
this._pendingData = null;
|
165
|
+
this._pendingEncoding = '';
|
166
|
+
|
167
|
+
// handle strings directly
|
168
|
+
this._writableState.decodeStrings = false;
|
169
|
+
|
170
|
+
// default to *not* allowing half open sockets
|
171
|
+
this.allowHalfOpen = options && options.allowHalfOpen || false;
|
172
|
+
|
173
|
+
// if we have a handle, then start the flow of data into the
|
174
|
+
// buffer. if not, then this will happen when we connect
|
175
|
+
if (this._handle && options.readable !== false)
|
176
|
+
this.read(0);
|
177
|
+
}
|
178
|
+
util.inherits(Socket, stream.Duplex);
|
179
|
+
|
180
|
+
// the user has called .end(), and all the bytes have been
|
181
|
+
// sent out to the other side.
|
182
|
+
// If allowHalfOpen is false, or if the readable side has
|
183
|
+
// ended already, then destroy.
|
184
|
+
// If allowHalfOpen is true, then we need to do a shutdown,
|
185
|
+
// so that only the writable side will be cleaned up.
|
186
|
+
function onSocketFinish() {
|
187
|
+
// If still connecting - defer handling 'finish' until 'connect' will happen
|
188
|
+
if (this._connecting) {
|
189
|
+
debug('osF: not yet connected');
|
190
|
+
return this.once('connect', onSocketFinish);
|
191
|
+
}
|
192
|
+
|
193
|
+
debug('onSocketFinish');
|
194
|
+
if (!this.readable || this._readableState.ended) {
|
195
|
+
debug('oSF: ended, destroy', this._readableState);
|
196
|
+
return this.destroy();
|
197
|
+
}
|
198
|
+
|
199
|
+
debug('oSF: not ended, call shutdown()');
|
200
|
+
|
201
|
+
// otherwise, just shutdown, or destroy() if not possible
|
202
|
+
if (!this._handle || !this._handle.shutdown)
|
203
|
+
return this.destroy();
|
204
|
+
|
205
|
+
var req = { oncomplete: afterShutdown };
|
206
|
+
var err = this._handle.shutdown(req);
|
207
|
+
|
208
|
+
if (err)
|
209
|
+
return this._destroy(errnoException(err, 'shutdown'));
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
function afterShutdown(status, handle, req) {
|
214
|
+
var self = handle.owner;
|
215
|
+
|
216
|
+
debug('afterShutdown destroyed=%j', self.destroyed,
|
217
|
+
self._readableState);
|
218
|
+
|
219
|
+
// callback may come after call to destroy.
|
220
|
+
if (self.destroyed)
|
221
|
+
return;
|
222
|
+
|
223
|
+
if (self._readableState.ended) {
|
224
|
+
debug('readableState ended, destroying');
|
225
|
+
self.destroy();
|
226
|
+
} else {
|
227
|
+
self.once('_socketEnd', self.destroy);
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
// the EOF has been received, and no more bytes are coming.
|
232
|
+
// if the writable side has ended already, then clean everything
|
233
|
+
// up.
|
234
|
+
function onSocketEnd() {
|
235
|
+
// XXX Should not have to do as much crap in this function.
|
236
|
+
// ended should already be true, since this is called *after*
|
237
|
+
// the EOF errno and onread has eof'ed
|
238
|
+
debug('onSocketEnd', this._readableState);
|
239
|
+
this._readableState.ended = true;
|
240
|
+
if (this._readableState.endEmitted) {
|
241
|
+
this.readable = false;
|
242
|
+
maybeDestroy(this);
|
243
|
+
} else {
|
244
|
+
this.once('end', function() {
|
245
|
+
this.readable = false;
|
246
|
+
maybeDestroy(this);
|
247
|
+
});
|
248
|
+
this.read(0);
|
249
|
+
}
|
250
|
+
|
251
|
+
if (!this.allowHalfOpen) {
|
252
|
+
this.write = writeAfterFIN;
|
253
|
+
this.destroySoon();
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
// Provide a better error message when we call end() as a result
|
258
|
+
// of the other side sending a FIN. The standard 'write after end'
|
259
|
+
// is overly vague, and makes it seem like the user's code is to blame.
|
260
|
+
function writeAfterFIN(chunk, encoding, cb) {
|
261
|
+
if (util.isFunction(encoding)) {
|
262
|
+
cb = encoding;
|
263
|
+
encoding = null;
|
264
|
+
}
|
265
|
+
|
266
|
+
var er = new Error('This socket has been ended by the other party');
|
267
|
+
er.code = 'EPIPE';
|
268
|
+
var self = this;
|
269
|
+
// TODO: defer error events consistently everywhere, not just the cb
|
270
|
+
self.emit('error', er);
|
271
|
+
if (util.isFunction(cb)) {
|
272
|
+
process.nextTick(function() {
|
273
|
+
cb(er);
|
274
|
+
});
|
275
|
+
}
|
276
|
+
}
|
277
|
+
|
278
|
+
exports.Socket = Socket;
|
279
|
+
exports.Stream = Socket; // Legacy naming.
|
280
|
+
|
281
|
+
Socket.prototype.read = function(n) {
|
282
|
+
if (n === 0)
|
283
|
+
return stream.Readable.prototype.read.call(this, n);
|
284
|
+
|
285
|
+
this.read = stream.Readable.prototype.read;
|
286
|
+
this._consuming = true;
|
287
|
+
return this.read(n);
|
288
|
+
};
|
289
|
+
|
290
|
+
|
291
|
+
Socket.prototype.listen = function() {
|
292
|
+
debug('socket.listen');
|
293
|
+
var self = this;
|
294
|
+
self.on('connection', arguments[0]);
|
295
|
+
listen(self, null, null, null);
|
296
|
+
};
|
297
|
+
|
298
|
+
|
299
|
+
Socket.prototype.setTimeout = function(msecs, callback) {
|
300
|
+
if (msecs > 0 && !isNaN(msecs) && isFinite(msecs)) {
|
301
|
+
timers.enroll(this, msecs);
|
302
|
+
timers._unrefActive(this);
|
303
|
+
if (callback) {
|
304
|
+
this.once('timeout', callback);
|
305
|
+
}
|
306
|
+
} else if (msecs === 0) {
|
307
|
+
timers.unenroll(this);
|
308
|
+
if (callback) {
|
309
|
+
this.removeListener('timeout', callback);
|
310
|
+
}
|
311
|
+
}
|
312
|
+
};
|
313
|
+
|
314
|
+
|
315
|
+
Socket.prototype._onTimeout = function() {
|
316
|
+
debug('_onTimeout');
|
317
|
+
this.emit('timeout');
|
318
|
+
};
|
319
|
+
|
320
|
+
|
321
|
+
Socket.prototype.setNoDelay = function(enable) {
|
322
|
+
// backwards compatibility: assume true when `enable` is omitted
|
323
|
+
if (this._handle && this._handle.setNoDelay)
|
324
|
+
this._handle.setNoDelay(util.isUndefined(enable) ? true : !!enable);
|
325
|
+
};
|
326
|
+
|
327
|
+
|
328
|
+
Socket.prototype.setKeepAlive = function(setting, msecs) {
|
329
|
+
if (this._handle && this._handle.setKeepAlive)
|
330
|
+
this._handle.setKeepAlive(setting, ~~(msecs / 1000));
|
331
|
+
};
|
332
|
+
|
333
|
+
|
334
|
+
Socket.prototype.address = function() {
|
335
|
+
if (this._handle && this._handle.getsockname) {
|
336
|
+
var out = {};
|
337
|
+
var err = this._handle.getsockname(out);
|
338
|
+
// TODO(bnoordhuis) Check err and throw?
|
339
|
+
return out;
|
340
|
+
}
|
341
|
+
return null;
|
342
|
+
};
|
343
|
+
|
344
|
+
|
345
|
+
Object.defineProperty(Socket.prototype, 'readyState', {
|
346
|
+
get: function() {
|
347
|
+
if (this._connecting) {
|
348
|
+
return 'opening';
|
349
|
+
} else if (this.readable && this.writable) {
|
350
|
+
return 'open';
|
351
|
+
} else if (this.readable && !this.writable) {
|
352
|
+
return 'readOnly';
|
353
|
+
} else if (!this.readable && this.writable) {
|
354
|
+
return 'writeOnly';
|
355
|
+
} else {
|
356
|
+
return 'closed';
|
357
|
+
}
|
358
|
+
}
|
359
|
+
});
|
360
|
+
|
361
|
+
|
362
|
+
Object.defineProperty(Socket.prototype, 'bufferSize', {
|
363
|
+
get: function() {
|
364
|
+
if (this._handle) {
|
365
|
+
return this._handle.writeQueueSize + this._writableState.length;
|
366
|
+
}
|
367
|
+
}
|
368
|
+
});
|
369
|
+
|
370
|
+
|
371
|
+
// Just call handle.readStart until we have enough in the buffer
|
372
|
+
Socket.prototype._read = function(n) {
|
373
|
+
debug('_read');
|
374
|
+
|
375
|
+
if (this._connecting || !this._handle) {
|
376
|
+
debug('_read wait for connection');
|
377
|
+
this.once('connect', this._read.bind(this, n));
|
378
|
+
} else if (!this._handle.reading) {
|
379
|
+
// not already reading, start the flow
|
380
|
+
debug('Socket._read readStart');
|
381
|
+
this._handle.reading = true;
|
382
|
+
var err = this._handle.readStart();
|
383
|
+
if (err)
|
384
|
+
this._destroy(errnoException(err, 'read'));
|
385
|
+
}
|
386
|
+
};
|
387
|
+
|
388
|
+
|
389
|
+
Socket.prototype.end = function(data, encoding) {
|
390
|
+
stream.Duplex.prototype.end.call(this, data, encoding);
|
391
|
+
this.writable = false;
|
392
|
+
DTRACE_NET_STREAM_END(this);
|
393
|
+
|
394
|
+
// just in case we're waiting for an EOF.
|
395
|
+
if (this.readable && !this._readableState.endEmitted)
|
396
|
+
this.read(0);
|
397
|
+
else
|
398
|
+
maybeDestroy(this);
|
399
|
+
};
|
400
|
+
|
401
|
+
|
402
|
+
// Call whenever we set writable=false or readable=false
|
403
|
+
function maybeDestroy(socket) {
|
404
|
+
if (!socket.readable &&
|
405
|
+
!socket.writable &&
|
406
|
+
!socket.destroyed &&
|
407
|
+
!socket._connecting &&
|
408
|
+
!socket._writableState.length) {
|
409
|
+
socket.destroy();
|
410
|
+
}
|
411
|
+
}
|
412
|
+
|
413
|
+
|
414
|
+
Socket.prototype.destroySoon = function() {
|
415
|
+
if (this.writable)
|
416
|
+
this.end();
|
417
|
+
|
418
|
+
if (this._writableState.finished)
|
419
|
+
this.destroy();
|
420
|
+
else
|
421
|
+
this.once('finish', this.destroy);
|
422
|
+
};
|
423
|
+
|
424
|
+
|
425
|
+
Socket.prototype._destroy = function(exception, cb) {
|
426
|
+
debug('destroy');
|
427
|
+
|
428
|
+
var self = this;
|
429
|
+
|
430
|
+
function fireErrorCallbacks() {
|
431
|
+
if (cb) cb(exception);
|
432
|
+
if (exception && !self.errorEmitted) {
|
433
|
+
process.nextTick(function() {
|
434
|
+
self.emit('error', exception);
|
435
|
+
});
|
436
|
+
self.errorEmitted = true;
|
437
|
+
}
|
438
|
+
};
|
439
|
+
|
440
|
+
if (this.destroyed) {
|
441
|
+
debug('already destroyed, fire error callbacks');
|
442
|
+
fireErrorCallbacks();
|
443
|
+
return;
|
444
|
+
}
|
445
|
+
|
446
|
+
self._connecting = false;
|
447
|
+
|
448
|
+
this.readable = this.writable = false;
|
449
|
+
|
450
|
+
timers.unenroll(this);
|
451
|
+
|
452
|
+
debug('close');
|
453
|
+
if (this._handle) {
|
454
|
+
if (this !== process.stderr)
|
455
|
+
debug('close handle');
|
456
|
+
var isException = exception ? true : false;
|
457
|
+
this._handle.close(function() {
|
458
|
+
debug('emit close');
|
459
|
+
self.emit('close', isException);
|
460
|
+
});
|
461
|
+
this._handle.onread = noop;
|
462
|
+
this._handle = null;
|
463
|
+
}
|
464
|
+
|
465
|
+
fireErrorCallbacks();
|
466
|
+
this.destroyed = true;
|
467
|
+
|
468
|
+
if (this.server) {
|
469
|
+
COUNTER_NET_SERVER_CONNECTION_CLOSE(this);
|
470
|
+
debug('has server');
|
471
|
+
this.server._connections--;
|
472
|
+
if (this.server._emitCloseIfDrained) {
|
473
|
+
this.server._emitCloseIfDrained();
|
474
|
+
}
|
475
|
+
}
|
476
|
+
};
|
477
|
+
|
478
|
+
|
479
|
+
Socket.prototype.destroy = function(exception) {
|
480
|
+
debug('destroy', exception);
|
481
|
+
this._destroy(exception);
|
482
|
+
};
|
483
|
+
|
484
|
+
|
485
|
+
// This function is called whenever the handle gets a
|
486
|
+
// buffer, or when there's an error reading.
|
487
|
+
function onread(nread, buffer) {
|
488
|
+
var handle = this;
|
489
|
+
var self = handle.owner;
|
490
|
+
assert(handle === self._handle, 'handle != self._handle');
|
491
|
+
|
492
|
+
timers._unrefActive(self);
|
493
|
+
|
494
|
+
debug('onread', nread);
|
495
|
+
|
496
|
+
if (nread > 0) {
|
497
|
+
debug('got data');
|
498
|
+
|
499
|
+
// read success.
|
500
|
+
// In theory (and in practice) calling readStop right now
|
501
|
+
// will prevent this from being called again until _read() gets
|
502
|
+
// called again.
|
503
|
+
|
504
|
+
// if it's not enough data, we'll just call handle.readStart()
|
505
|
+
// again right away.
|
506
|
+
self.bytesRead += nread;
|
507
|
+
|
508
|
+
// Optimization: emit the original buffer with end points
|
509
|
+
var ret = self.push(buffer);
|
510
|
+
|
511
|
+
if (handle.reading && !ret) {
|
512
|
+
handle.reading = false;
|
513
|
+
debug('readStop');
|
514
|
+
var err = handle.readStop();
|
515
|
+
if (err)
|
516
|
+
self._destroy(errnoException(err, 'read'));
|
517
|
+
}
|
518
|
+
return;
|
519
|
+
}
|
520
|
+
|
521
|
+
// if we didn't get any bytes, that doesn't necessarily mean EOF.
|
522
|
+
// wait for the next one.
|
523
|
+
if (nread === 0) {
|
524
|
+
debug('not any data, keep waiting');
|
525
|
+
return;
|
526
|
+
}
|
527
|
+
|
528
|
+
// Error, possibly EOF.
|
529
|
+
if (nread !== uv.UV_EOF) {
|
530
|
+
return self._destroy(errnoException(nread, 'read'));
|
531
|
+
}
|
532
|
+
|
533
|
+
debug('EOF');
|
534
|
+
|
535
|
+
if (self._readableState.length === 0) {
|
536
|
+
self.readable = false;
|
537
|
+
maybeDestroy(self);
|
538
|
+
}
|
539
|
+
|
540
|
+
// push a null to signal the end of data.
|
541
|
+
self.push(null);
|
542
|
+
|
543
|
+
// internal end event so that we know that the actual socket
|
544
|
+
// is no longer readable, and we can start the shutdown
|
545
|
+
// procedure. No need to wait for all the data to be consumed.
|
546
|
+
self.emit('_socketEnd');
|
547
|
+
}
|
548
|
+
|
549
|
+
|
550
|
+
Socket.prototype._getpeername = function() {
|
551
|
+
if (!this._handle || !this._handle.getpeername) {
|
552
|
+
return {};
|
553
|
+
}
|
554
|
+
if (!this._peername) {
|
555
|
+
var out = {};
|
556
|
+
var err = this._handle.getpeername(out);
|
557
|
+
if (err) return {}; // FIXME(bnoordhuis) Throw?
|
558
|
+
this._peername = out;
|
559
|
+
}
|
560
|
+
return this._peername;
|
561
|
+
};
|
562
|
+
|
563
|
+
|
564
|
+
Socket.prototype.__defineGetter__('remoteAddress', function() {
|
565
|
+
return this._getpeername().address;
|
566
|
+
});
|
567
|
+
|
568
|
+
|
569
|
+
Socket.prototype.__defineGetter__('remotePort', function() {
|
570
|
+
return this._getpeername().port;
|
571
|
+
});
|
572
|
+
|
573
|
+
|
574
|
+
Socket.prototype._getsockname = function() {
|
575
|
+
if (!this._handle || !this._handle.getsockname) {
|
576
|
+
return {};
|
577
|
+
}
|
578
|
+
if (!this._sockname) {
|
579
|
+
var out = {};
|
580
|
+
var err = this._handle.getsockname(out);
|
581
|
+
if (err) return {}; // FIXME(bnoordhuis) Throw?
|
582
|
+
this._sockname = out;
|
583
|
+
}
|
584
|
+
return this._sockname;
|
585
|
+
};
|
586
|
+
|
587
|
+
|
588
|
+
Socket.prototype.__defineGetter__('localAddress', function() {
|
589
|
+
return this._getsockname().address;
|
590
|
+
});
|
591
|
+
|
592
|
+
|
593
|
+
Socket.prototype.__defineGetter__('localPort', function() {
|
594
|
+
return this._getsockname().port;
|
595
|
+
});
|
596
|
+
|
597
|
+
|
598
|
+
Socket.prototype.write = function(chunk, encoding, cb) {
|
599
|
+
if (!util.isString(chunk) && !util.isBuffer(chunk))
|
600
|
+
throw new TypeError('invalid data');
|
601
|
+
return stream.Duplex.prototype.write.apply(this, arguments);
|
602
|
+
};
|
603
|
+
|
604
|
+
|
605
|
+
Socket.prototype._writeGeneric = function(writev, data, encoding, cb) {
|
606
|
+
// If we are still connecting, then buffer this for later.
|
607
|
+
// The Writable logic will buffer up any more writes while
|
608
|
+
// waiting for this one to be done.
|
609
|
+
if (this._connecting) {
|
610
|
+
this._pendingData = data;
|
611
|
+
this._pendingEncoding = encoding;
|
612
|
+
this.once('connect', function() {
|
613
|
+
this._writeGeneric(writev, data, encoding, cb);
|
614
|
+
});
|
615
|
+
return;
|
616
|
+
}
|
617
|
+
this._pendingData = null;
|
618
|
+
this._pendingEncoding = '';
|
619
|
+
|
620
|
+
timers._unrefActive(this);
|
621
|
+
|
622
|
+
if (!this._handle) {
|
623
|
+
this._destroy(new Error('This socket is closed.'), cb);
|
624
|
+
return false;
|
625
|
+
}
|
626
|
+
|
627
|
+
var req = { oncomplete: afterWrite };
|
628
|
+
var err;
|
629
|
+
|
630
|
+
if (writev) {
|
631
|
+
var chunks = new Array(data.length << 1);
|
632
|
+
for (var i = 0; i < data.length; i++) {
|
633
|
+
var entry = data[i];
|
634
|
+
var chunk = entry.chunk;
|
635
|
+
var enc = entry.encoding;
|
636
|
+
chunks[i * 2] = chunk;
|
637
|
+
chunks[i * 2 + 1] = enc;
|
638
|
+
}
|
639
|
+
err = this._handle.writev(req, chunks);
|
640
|
+
|
641
|
+
// Retain chunks
|
642
|
+
if (err === 0) req._chunks = chunks;
|
643
|
+
} else {
|
644
|
+
var enc;
|
645
|
+
if (util.isBuffer(data)) {
|
646
|
+
req.buffer = data; // Keep reference alive.
|
647
|
+
enc = 'buffer';
|
648
|
+
} else {
|
649
|
+
enc = encoding;
|
650
|
+
}
|
651
|
+
err = createWriteReq(req, this._handle, data, enc);
|
652
|
+
}
|
653
|
+
|
654
|
+
if (err)
|
655
|
+
return this._destroy(errnoException(err, 'write'), cb);
|
656
|
+
|
657
|
+
this._bytesDispatched += req.bytes;
|
658
|
+
|
659
|
+
// If it was entirely flushed, we can write some more right now.
|
660
|
+
// However, if more is left in the queue, then wait until that clears.
|
661
|
+
if (this._handle.writeQueueSize === 0)
|
662
|
+
cb();
|
663
|
+
else
|
664
|
+
req.cb = cb;
|
665
|
+
};
|
666
|
+
|
667
|
+
|
668
|
+
Socket.prototype._writev = function(chunks, cb) {
|
669
|
+
this._writeGeneric(true, chunks, '', cb);
|
670
|
+
};
|
671
|
+
|
672
|
+
|
673
|
+
Socket.prototype._write = function(data, encoding, cb) {
|
674
|
+
this._writeGeneric(false, data, encoding, cb);
|
675
|
+
};
|
676
|
+
|
677
|
+
// Important: this should have the same values as in src/stream_wrap.h
|
678
|
+
function getEncodingId(encoding) {
|
679
|
+
switch (encoding) {
|
680
|
+
case 'buffer':
|
681
|
+
return 0;
|
682
|
+
|
683
|
+
case 'utf8':
|
684
|
+
case 'utf-8':
|
685
|
+
return 1;
|
686
|
+
|
687
|
+
case 'ascii':
|
688
|
+
return 2;
|
689
|
+
|
690
|
+
case 'ucs2':
|
691
|
+
case 'ucs-2':
|
692
|
+
case 'utf16le':
|
693
|
+
case 'utf-16le':
|
694
|
+
return 3;
|
695
|
+
|
696
|
+
default:
|
697
|
+
return 0;
|
698
|
+
}
|
699
|
+
}
|
700
|
+
|
701
|
+
function createWriteReq(req, handle, data, encoding) {
|
702
|
+
switch (encoding) {
|
703
|
+
case 'buffer':
|
704
|
+
return handle.writeBuffer(req, data);
|
705
|
+
|
706
|
+
case 'utf8':
|
707
|
+
case 'utf-8':
|
708
|
+
return handle.writeUtf8String(req, data);
|
709
|
+
|
710
|
+
case 'ascii':
|
711
|
+
return handle.writeAsciiString(req, data);
|
712
|
+
|
713
|
+
case 'ucs2':
|
714
|
+
case 'ucs-2':
|
715
|
+
case 'utf16le':
|
716
|
+
case 'utf-16le':
|
717
|
+
return handle.writeUcs2String(req, data);
|
718
|
+
|
719
|
+
default:
|
720
|
+
return handle.writeBuffer(req, new Buffer(data, encoding));
|
721
|
+
}
|
722
|
+
}
|
723
|
+
|
724
|
+
|
725
|
+
Socket.prototype.__defineGetter__('bytesWritten', function() {
|
726
|
+
var bytes = this._bytesDispatched,
|
727
|
+
state = this._writableState,
|
728
|
+
data = this._pendingData,
|
729
|
+
encoding = this._pendingEncoding;
|
730
|
+
|
731
|
+
state.buffer.forEach(function(el) {
|
732
|
+
if (util.isBuffer(el.chunk))
|
733
|
+
bytes += el.chunk.length;
|
734
|
+
else
|
735
|
+
bytes += Buffer.byteLength(el.chunk, el.encoding);
|
736
|
+
});
|
737
|
+
|
738
|
+
if (data) {
|
739
|
+
if (util.isBuffer(data))
|
740
|
+
bytes += data.length;
|
741
|
+
else
|
742
|
+
bytes += Buffer.byteLength(data, encoding);
|
743
|
+
}
|
744
|
+
|
745
|
+
return bytes;
|
746
|
+
});
|
747
|
+
|
748
|
+
|
749
|
+
function afterWrite(status, handle, req) {
|
750
|
+
var self = handle.owner;
|
751
|
+
if (self !== process.stderr && self !== process.stdout)
|
752
|
+
debug('afterWrite', status);
|
753
|
+
|
754
|
+
// callback may come after call to destroy.
|
755
|
+
if (self.destroyed) {
|
756
|
+
debug('afterWrite destroyed');
|
757
|
+
return;
|
758
|
+
}
|
759
|
+
|
760
|
+
if (status < 0) {
|
761
|
+
var ex = errnoException(status, 'write');
|
762
|
+
debug('write failure', ex);
|
763
|
+
self._destroy(ex, req.cb);
|
764
|
+
return;
|
765
|
+
}
|
766
|
+
|
767
|
+
timers._unrefActive(self);
|
768
|
+
|
769
|
+
if (self !== process.stderr && self !== process.stdout)
|
770
|
+
debug('afterWrite call cb');
|
771
|
+
|
772
|
+
if (req.cb)
|
773
|
+
req.cb.call(self);
|
774
|
+
}
|
775
|
+
|
776
|
+
|
777
|
+
function connect(self, address, port, addressType, localAddress) {
|
778
|
+
// TODO return promise from Socket.prototype.connect which
|
779
|
+
// wraps _connectReq.
|
780
|
+
|
781
|
+
assert.ok(self._connecting);
|
782
|
+
|
783
|
+
var err;
|
784
|
+
if (localAddress) {
|
785
|
+
if (addressType == 6) {
|
786
|
+
err = self._handle.bind6(localAddress);
|
787
|
+
} else {
|
788
|
+
err = self._handle.bind(localAddress);
|
789
|
+
}
|
790
|
+
|
791
|
+
if (err) {
|
792
|
+
self._destroy(errnoException(err, 'bind'));
|
793
|
+
return;
|
794
|
+
}
|
795
|
+
}
|
796
|
+
|
797
|
+
var req = { oncomplete: afterConnect };
|
798
|
+
if (addressType === 6 || addressType === 4) {
|
799
|
+
port = port | 0;
|
800
|
+
if (port <= 0 || port > 65535)
|
801
|
+
throw new RangeError('Port should be > 0 and < 65536');
|
802
|
+
|
803
|
+
if (addressType === 6) {
|
804
|
+
err = self._handle.connect6(req, address, port);
|
805
|
+
} else if (addressType === 4) {
|
806
|
+
err = self._handle.connect(req, address, port);
|
807
|
+
}
|
808
|
+
} else {
|
809
|
+
err = self._handle.connect(req, address, afterConnect);
|
810
|
+
}
|
811
|
+
|
812
|
+
if (err) {
|
813
|
+
self._destroy(errnoException(err, 'connect'));
|
814
|
+
}
|
815
|
+
}
|
816
|
+
|
817
|
+
|
818
|
+
Socket.prototype.connect = function(options, cb) {
|
819
|
+
if (this.write !== Socket.prototype.write)
|
820
|
+
this.write = Socket.prototype.write;
|
821
|
+
|
822
|
+
if (!util.isObject(options)) {
|
823
|
+
// Old API:
|
824
|
+
// connect(port, [host], [cb])
|
825
|
+
// connect(path, [cb]);
|
826
|
+
var args = normalizeConnectArgs(arguments);
|
827
|
+
return Socket.prototype.connect.apply(this, args);
|
828
|
+
}
|
829
|
+
|
830
|
+
if (this.destroyed) {
|
831
|
+
this._readableState.reading = false;
|
832
|
+
this._readableState.ended = false;
|
833
|
+
this._writableState.ended = false;
|
834
|
+
this._writableState.ending = false;
|
835
|
+
this._writableState.finished = false;
|
836
|
+
this.destroyed = false;
|
837
|
+
this._handle = null;
|
838
|
+
}
|
839
|
+
|
840
|
+
var self = this;
|
841
|
+
var pipe = !!options.path;
|
842
|
+
debug('pipe', pipe, options.path);
|
843
|
+
|
844
|
+
if (!this._handle) {
|
845
|
+
this._handle = pipe ? createPipe() : createTCP();
|
846
|
+
initSocketHandle(this);
|
847
|
+
}
|
848
|
+
|
849
|
+
if (util.isFunction(cb)) {
|
850
|
+
self.once('connect', cb);
|
851
|
+
}
|
852
|
+
|
853
|
+
timers._unrefActive(this);
|
854
|
+
|
855
|
+
self._connecting = true;
|
856
|
+
self.writable = true;
|
857
|
+
|
858
|
+
if (pipe) {
|
859
|
+
connect(self, options.path);
|
860
|
+
|
861
|
+
} else if (!options.host) {
|
862
|
+
debug('connect: missing host');
|
863
|
+
self._host = '127.0.0.1';
|
864
|
+
connect(self, self._host, options.port, 4);
|
865
|
+
|
866
|
+
} else {
|
867
|
+
var host = options.host;
|
868
|
+
var family = options.family || 4;
|
869
|
+
debug('connect: find host ' + host);
|
870
|
+
self._host = host;
|
871
|
+
require('dns').lookup(host, family, function(err, ip, addressType) {
|
872
|
+
self.emit('lookup', err, ip, addressType);
|
873
|
+
|
874
|
+
// It's possible we were destroyed while looking this up.
|
875
|
+
// XXX it would be great if we could cancel the promise returned by
|
876
|
+
// the look up.
|
877
|
+
if (!self._connecting) return;
|
878
|
+
|
879
|
+
if (err) {
|
880
|
+
// net.createConnection() creates a net.Socket object and
|
881
|
+
// immediately calls net.Socket.connect() on it (that's us).
|
882
|
+
// There are no event listeners registered yet so defer the
|
883
|
+
// error event to the next tick.
|
884
|
+
process.nextTick(function() {
|
885
|
+
self.emit('error', err);
|
886
|
+
self._destroy();
|
887
|
+
});
|
888
|
+
} else {
|
889
|
+
timers._unrefActive(self);
|
890
|
+
|
891
|
+
addressType = addressType || 4;
|
892
|
+
|
893
|
+
// node_net.cc handles null host names graciously but user land
|
894
|
+
// expects remoteAddress to have a meaningful value
|
895
|
+
ip = ip || (addressType === 4 ? '127.0.0.1' : '0:0:0:0:0:0:0:1');
|
896
|
+
|
897
|
+
connect(self, ip, options.port, addressType, options.localAddress);
|
898
|
+
}
|
899
|
+
});
|
900
|
+
}
|
901
|
+
return self;
|
902
|
+
};
|
903
|
+
|
904
|
+
|
905
|
+
Socket.prototype.ref = function() {
|
906
|
+
if (this._handle)
|
907
|
+
this._handle.ref();
|
908
|
+
};
|
909
|
+
|
910
|
+
|
911
|
+
Socket.prototype.unref = function() {
|
912
|
+
if (this._handle)
|
913
|
+
this._handle.unref();
|
914
|
+
};
|
915
|
+
|
916
|
+
|
917
|
+
|
918
|
+
function afterConnect(status, handle, req, readable, writable) {
|
919
|
+
var self = handle.owner;
|
920
|
+
|
921
|
+
// callback may come after call to destroy
|
922
|
+
if (self.destroyed) {
|
923
|
+
return;
|
924
|
+
}
|
925
|
+
|
926
|
+
assert(handle === self._handle, 'handle != self._handle');
|
927
|
+
|
928
|
+
debug('afterConnect');
|
929
|
+
|
930
|
+
assert.ok(self._connecting);
|
931
|
+
self._connecting = false;
|
932
|
+
|
933
|
+
if (status == 0) {
|
934
|
+
self.readable = readable;
|
935
|
+
self.writable = writable;
|
936
|
+
timers._unrefActive(self);
|
937
|
+
|
938
|
+
self.emit('connect');
|
939
|
+
|
940
|
+
// start the first read, or get an immediate EOF.
|
941
|
+
// this doesn't actually consume any bytes, because len=0.
|
942
|
+
if (readable)
|
943
|
+
self.read(0);
|
944
|
+
|
945
|
+
} else {
|
946
|
+
self._connecting = false;
|
947
|
+
self._destroy(errnoException(status, 'connect'));
|
948
|
+
}
|
949
|
+
}
|
950
|
+
|
951
|
+
|
952
|
+
function Server(/* [ options, ] listener */) {
|
953
|
+
if (!(this instanceof Server)) return new Server(arguments[0], arguments[1]);
|
954
|
+
events.EventEmitter.call(this);
|
955
|
+
|
956
|
+
var self = this;
|
957
|
+
|
958
|
+
var options;
|
959
|
+
|
960
|
+
if (util.isFunction(arguments[0])) {
|
961
|
+
options = {};
|
962
|
+
self.on('connection', arguments[0]);
|
963
|
+
} else {
|
964
|
+
options = arguments[0] || {};
|
965
|
+
|
966
|
+
if (util.isFunction(arguments[1])) {
|
967
|
+
self.on('connection', arguments[1]);
|
968
|
+
}
|
969
|
+
}
|
970
|
+
|
971
|
+
this._connections = 0;
|
972
|
+
|
973
|
+
Object.defineProperty(this, 'connections', {
|
974
|
+
get: util.deprecate(function() {
|
975
|
+
|
976
|
+
if (self._usingSlaves) {
|
977
|
+
return null;
|
978
|
+
}
|
979
|
+
return self._connections;
|
980
|
+
}, 'connections property is deprecated. Use getConnections() method'),
|
981
|
+
set: util.deprecate(function(val) {
|
982
|
+
return (self._connections = val);
|
983
|
+
}, 'connections property is deprecated. Use getConnections() method'),
|
984
|
+
configurable: true, enumerable: true
|
985
|
+
});
|
986
|
+
|
987
|
+
this._handle = null;
|
988
|
+
this._usingSlaves = false;
|
989
|
+
this._slaves = [];
|
990
|
+
|
991
|
+
this.allowHalfOpen = options.allowHalfOpen || false;
|
992
|
+
}
|
993
|
+
util.inherits(Server, events.EventEmitter);
|
994
|
+
exports.Server = Server;
|
995
|
+
|
996
|
+
|
997
|
+
function toNumber(x) { return (x = Number(x)) >= 0 ? x : false; }
|
998
|
+
|
999
|
+
|
1000
|
+
var createServerHandle = exports._createServerHandle =
|
1001
|
+
function(address, port, addressType, fd) {
|
1002
|
+
var err = 0;
|
1003
|
+
// assign handle in listen, and clean up if bind or listen fails
|
1004
|
+
var handle;
|
1005
|
+
|
1006
|
+
if (util.isNumber(fd) && fd >= 0) {
|
1007
|
+
try {
|
1008
|
+
handle = createHandle(fd);
|
1009
|
+
}
|
1010
|
+
catch (e) {
|
1011
|
+
// Not a fd we can listen on. This will trigger an error.
|
1012
|
+
debug('listen invalid fd=' + fd + ': ' + e.message);
|
1013
|
+
return uv.UV_EINVAL;
|
1014
|
+
}
|
1015
|
+
handle.open(fd);
|
1016
|
+
handle.readable = true;
|
1017
|
+
handle.writable = true;
|
1018
|
+
return handle;
|
1019
|
+
|
1020
|
+
} else if (port == -1 && addressType == -1) {
|
1021
|
+
handle = createPipe();
|
1022
|
+
if (process.platform === 'win32') {
|
1023
|
+
var instances = parseInt(process.env.NODE_PENDING_PIPE_INSTANCES);
|
1024
|
+
if (!isNaN(instances)) {
|
1025
|
+
handle.setPendingInstances(instances);
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
} else {
|
1029
|
+
handle = createTCP();
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
if (address || port) {
|
1033
|
+
debug('bind to ' + address);
|
1034
|
+
if (addressType == 6) {
|
1035
|
+
err = handle.bind6(address, port);
|
1036
|
+
} else {
|
1037
|
+
err = handle.bind(address, port);
|
1038
|
+
}
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
if (err) {
|
1042
|
+
handle.close();
|
1043
|
+
return err;
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
return handle;
|
1047
|
+
};
|
1048
|
+
|
1049
|
+
|
1050
|
+
Server.prototype._listen2 = function(address, port, addressType, backlog, fd) {
|
1051
|
+
debug('listen2', address, port, addressType, backlog);
|
1052
|
+
var self = this;
|
1053
|
+
|
1054
|
+
// If there is not yet a handle, we need to create one and bind.
|
1055
|
+
// In the case of a server sent via IPC, we don't need to do this.
|
1056
|
+
if (!self._handle) {
|
1057
|
+
debug('_listen2: create a handle');
|
1058
|
+
var rval = createServerHandle(address, port, addressType, fd);
|
1059
|
+
if (util.isNumber(rval)) {
|
1060
|
+
var error = errnoException(rval, 'listen');
|
1061
|
+
process.nextTick(function() {
|
1062
|
+
self.emit('error', error);
|
1063
|
+
});
|
1064
|
+
return;
|
1065
|
+
}
|
1066
|
+
self._handle = rval;
|
1067
|
+
} else {
|
1068
|
+
debug('_listen2: have a handle already');
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
self._handle.onconnection = onconnection;
|
1072
|
+
self._handle.owner = self;
|
1073
|
+
|
1074
|
+
// Use a backlog of 512 entries. We pass 511 to the listen() call because
|
1075
|
+
// the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
1076
|
+
// which will thus give us a backlog of 512 entries.
|
1077
|
+
var err = self._handle.listen(backlog || 511);
|
1078
|
+
|
1079
|
+
if (err) {
|
1080
|
+
var ex = errnoException(err, 'listen');
|
1081
|
+
self._handle.close();
|
1082
|
+
self._handle = null;
|
1083
|
+
process.nextTick(function() {
|
1084
|
+
self.emit('error', ex);
|
1085
|
+
});
|
1086
|
+
return;
|
1087
|
+
}
|
1088
|
+
|
1089
|
+
// generate connection key, this should be unique to the connection
|
1090
|
+
this._connectionKey = addressType + ':' + address + ':' + port;
|
1091
|
+
|
1092
|
+
process.nextTick(function() {
|
1093
|
+
self.emit('listening');
|
1094
|
+
});
|
1095
|
+
};
|
1096
|
+
|
1097
|
+
|
1098
|
+
function listen(self, address, port, addressType, backlog, fd) {
|
1099
|
+
if (!cluster) cluster = require('cluster');
|
1100
|
+
|
1101
|
+
if (cluster.isMaster) {
|
1102
|
+
self._listen2(address, port, addressType, backlog, fd);
|
1103
|
+
return;
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
cluster._getServer(self, address, port, addressType, fd, cb);
|
1107
|
+
|
1108
|
+
function cb(err, handle) {
|
1109
|
+
// EADDRINUSE may not be reported until we call listen(). To complicate
|
1110
|
+
// matters, a failed bind() followed by listen() will implicitly bind to
|
1111
|
+
// a random port. Ergo, check that the socket is bound to the expected
|
1112
|
+
// port before calling listen().
|
1113
|
+
//
|
1114
|
+
// FIXME(bnoordhuis) Doesn't work for pipe handles, they don't have a
|
1115
|
+
// getsockname() method. Non-issue for now, the cluster module doesn't
|
1116
|
+
// really support pipes anyway.
|
1117
|
+
if (err === 0 && port > 0 && handle.getsockname) {
|
1118
|
+
var out = {};
|
1119
|
+
err = handle.getsockname(out);
|
1120
|
+
if (err === 0 && port !== out.port)
|
1121
|
+
err = uv.UV_EADDRINUSE;
|
1122
|
+
}
|
1123
|
+
|
1124
|
+
if (err)
|
1125
|
+
return self.emit('error', errnoException(err, 'bind'));
|
1126
|
+
|
1127
|
+
self._handle = handle;
|
1128
|
+
self._listen2(address, port, addressType, backlog, fd);
|
1129
|
+
}
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
|
1133
|
+
Server.prototype.listen = function() {
|
1134
|
+
var self = this;
|
1135
|
+
|
1136
|
+
var lastArg = arguments[arguments.length - 1];
|
1137
|
+
if (util.isFunction(lastArg)) {
|
1138
|
+
self.once('listening', lastArg);
|
1139
|
+
}
|
1140
|
+
|
1141
|
+
var port = toNumber(arguments[0]);
|
1142
|
+
|
1143
|
+
// The third optional argument is the backlog size.
|
1144
|
+
// When the ip is omitted it can be the second argument.
|
1145
|
+
var backlog = toNumber(arguments[1]) || toNumber(arguments[2]);
|
1146
|
+
|
1147
|
+
var TCP = process.binding('tcp_wrap').TCP;
|
1148
|
+
|
1149
|
+
if (arguments.length == 0 || util.isFunction(arguments[0])) {
|
1150
|
+
// Bind to a random port.
|
1151
|
+
listen(self, '0.0.0.0', 0, null, backlog);
|
1152
|
+
|
1153
|
+
} else if (arguments[0] && util.isObject(arguments[0])) {
|
1154
|
+
var h = arguments[0];
|
1155
|
+
if (h._handle) {
|
1156
|
+
h = h._handle;
|
1157
|
+
} else if (h.handle) {
|
1158
|
+
h = h.handle;
|
1159
|
+
}
|
1160
|
+
if (h instanceof TCP) {
|
1161
|
+
self._handle = h;
|
1162
|
+
listen(self, null, -1, -1, backlog);
|
1163
|
+
} else if (util.isNumber(h.fd) && h.fd >= 0) {
|
1164
|
+
listen(self, null, null, null, backlog, h.fd);
|
1165
|
+
} else {
|
1166
|
+
throw new Error('Invalid listen argument: ' + h);
|
1167
|
+
}
|
1168
|
+
} else if (isPipeName(arguments[0])) {
|
1169
|
+
// UNIX socket or Windows pipe.
|
1170
|
+
var pipeName = self._pipeName = arguments[0];
|
1171
|
+
listen(self, pipeName, -1, -1, backlog);
|
1172
|
+
|
1173
|
+
} else if (util.isUndefined(arguments[1]) ||
|
1174
|
+
util.isFunction(arguments[1]) ||
|
1175
|
+
util.isNumber(arguments[1])) {
|
1176
|
+
// The first argument is the port, no IP given.
|
1177
|
+
listen(self, '0.0.0.0', port, 4, backlog);
|
1178
|
+
|
1179
|
+
} else {
|
1180
|
+
// The first argument is the port, the second an IP.
|
1181
|
+
require('dns').lookup(arguments[1], function(err, ip, addressType) {
|
1182
|
+
if (err) {
|
1183
|
+
self.emit('error', err);
|
1184
|
+
} else {
|
1185
|
+
listen(self, ip || '0.0.0.0', port, ip ? addressType : 4, backlog);
|
1186
|
+
}
|
1187
|
+
});
|
1188
|
+
}
|
1189
|
+
return self;
|
1190
|
+
};
|
1191
|
+
|
1192
|
+
Server.prototype.address = function() {
|
1193
|
+
if (this._handle && this._handle.getsockname) {
|
1194
|
+
var out = {};
|
1195
|
+
var err = this._handle.getsockname(out);
|
1196
|
+
// TODO(bnoordhuis) Check err and throw?
|
1197
|
+
return out;
|
1198
|
+
} else if (this._pipeName) {
|
1199
|
+
return this._pipeName;
|
1200
|
+
} else {
|
1201
|
+
return null;
|
1202
|
+
}
|
1203
|
+
};
|
1204
|
+
|
1205
|
+
function onconnection(err, clientHandle) {
|
1206
|
+
var handle = this;
|
1207
|
+
var self = handle.owner;
|
1208
|
+
|
1209
|
+
debug('onconnection');
|
1210
|
+
|
1211
|
+
if (err) {
|
1212
|
+
self.emit('error', errnoException(err, 'accept'));
|
1213
|
+
return;
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
if (self.maxConnections && self._connections >= self.maxConnections) {
|
1217
|
+
clientHandle.close();
|
1218
|
+
return;
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
var socket = new Socket({
|
1222
|
+
handle: clientHandle,
|
1223
|
+
allowHalfOpen: self.allowHalfOpen
|
1224
|
+
});
|
1225
|
+
socket.readable = socket.writable = true;
|
1226
|
+
|
1227
|
+
|
1228
|
+
self._connections++;
|
1229
|
+
socket.server = self;
|
1230
|
+
|
1231
|
+
DTRACE_NET_SERVER_CONNECTION(socket);
|
1232
|
+
COUNTER_NET_SERVER_CONNECTION(socket);
|
1233
|
+
self.emit('connection', socket);
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
|
1237
|
+
Server.prototype.getConnections = function(cb) {
|
1238
|
+
function end(err, connections) {
|
1239
|
+
process.nextTick(function() {
|
1240
|
+
cb(err, connections);
|
1241
|
+
});
|
1242
|
+
}
|
1243
|
+
|
1244
|
+
if (!this._usingSlaves) {
|
1245
|
+
return end(null, this._connections);
|
1246
|
+
}
|
1247
|
+
|
1248
|
+
// Poll slaves
|
1249
|
+
var left = this._slaves.length,
|
1250
|
+
total = this._connections;
|
1251
|
+
|
1252
|
+
function oncount(err, count) {
|
1253
|
+
if (err) {
|
1254
|
+
left = -1;
|
1255
|
+
return end(err);
|
1256
|
+
}
|
1257
|
+
|
1258
|
+
total += count;
|
1259
|
+
if (--left === 0) return end(null, total);
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
this._slaves.forEach(function(slave) {
|
1263
|
+
slave.getConnections(oncount);
|
1264
|
+
});
|
1265
|
+
};
|
1266
|
+
|
1267
|
+
|
1268
|
+
Server.prototype.close = function(cb) {
|
1269
|
+
function onSlaveClose() {
|
1270
|
+
if (--left !== 0) return;
|
1271
|
+
|
1272
|
+
self._connections = 0;
|
1273
|
+
self._emitCloseIfDrained();
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
if (!this._handle) {
|
1277
|
+
// Throw error. Follows net_legacy behaviour.
|
1278
|
+
throw new Error('Not running');
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
if (cb) {
|
1282
|
+
this.once('close', cb);
|
1283
|
+
}
|
1284
|
+
this._handle.close();
|
1285
|
+
this._handle = null;
|
1286
|
+
|
1287
|
+
if (this._usingSlaves) {
|
1288
|
+
var self = this,
|
1289
|
+
left = this._slaves.length;
|
1290
|
+
|
1291
|
+
// Increment connections to be sure that, even if all sockets will be closed
|
1292
|
+
// during polling of slaves, `close` event will be emitted only once.
|
1293
|
+
this._connections++;
|
1294
|
+
|
1295
|
+
// Poll slaves
|
1296
|
+
this._slaves.forEach(function(slave) {
|
1297
|
+
slave.close(onSlaveClose);
|
1298
|
+
});
|
1299
|
+
} else {
|
1300
|
+
this._emitCloseIfDrained();
|
1301
|
+
}
|
1302
|
+
|
1303
|
+
return this;
|
1304
|
+
};
|
1305
|
+
|
1306
|
+
Server.prototype._emitCloseIfDrained = function() {
|
1307
|
+
debug('SERVER _emitCloseIfDrained');
|
1308
|
+
var self = this;
|
1309
|
+
|
1310
|
+
if (self._handle || self._connections) {
|
1311
|
+
debug('SERVER handle? %j connections? %d',
|
1312
|
+
!!self._handle, self._connections);
|
1313
|
+
return;
|
1314
|
+
}
|
1315
|
+
|
1316
|
+
process.nextTick(function() {
|
1317
|
+
debug('SERVER: emit close');
|
1318
|
+
self.emit('close');
|
1319
|
+
});
|
1320
|
+
};
|
1321
|
+
|
1322
|
+
|
1323
|
+
Server.prototype.listenFD = util.deprecate(function(fd, type) {
|
1324
|
+
return this.listen({ fd: fd });
|
1325
|
+
}, 'listenFD is deprecated. Use listen({fd: <number>}).');
|
1326
|
+
|
1327
|
+
Server.prototype._setupSlave = function(socketList) {
|
1328
|
+
this._usingSlaves = true;
|
1329
|
+
this._slaves.push(socketList);
|
1330
|
+
};
|
1331
|
+
|
1332
|
+
Server.prototype.ref = function() {
|
1333
|
+
if (this._handle)
|
1334
|
+
this._handle.ref();
|
1335
|
+
};
|
1336
|
+
|
1337
|
+
Server.prototype.unref = function() {
|
1338
|
+
if (this._handle)
|
1339
|
+
this._handle.unref();
|
1340
|
+
};
|
1341
|
+
|
1342
|
+
|
1343
|
+
// TODO: isIP should be moved to the DNS code. Putting it here now because
|
1344
|
+
// this is what the legacy system did.
|
1345
|
+
exports.isIP = cares.isIP;
|
1346
|
+
|
1347
|
+
|
1348
|
+
exports.isIPv4 = function(input) {
|
1349
|
+
return exports.isIP(input) === 4;
|
1350
|
+
};
|
1351
|
+
|
1352
|
+
|
1353
|
+
exports.isIPv6 = function(input) {
|
1354
|
+
return exports.isIP(input) === 6;
|
1355
|
+
};
|
1356
|
+
|
1357
|
+
|
1358
|
+
if (process.platform === 'win32') {
|
1359
|
+
var simultaneousAccepts;
|
1360
|
+
|
1361
|
+
exports._setSimultaneousAccepts = function(handle) {
|
1362
|
+
if (util.isUndefined(handle)) {
|
1363
|
+
return;
|
1364
|
+
}
|
1365
|
+
|
1366
|
+
if (util.isUndefined(simultaneousAccepts)) {
|
1367
|
+
simultaneousAccepts = (process.env.NODE_MANY_ACCEPTS &&
|
1368
|
+
process.env.NODE_MANY_ACCEPTS !== '0');
|
1369
|
+
}
|
1370
|
+
|
1371
|
+
if (handle._simultaneousAccepts !== simultaneousAccepts) {
|
1372
|
+
handle.setSimultaneousAccepts(simultaneousAccepts);
|
1373
|
+
handle._simultaneousAccepts = simultaneousAccepts;
|
1374
|
+
}
|
1375
|
+
};
|
1376
|
+
} else {
|
1377
|
+
exports._setSimultaneousAccepts = function(handle) {};
|
1378
|
+
}
|