macgyver 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/README.md +45 -0
  6. data/Rakefile +1 -0
  7. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Growl +0 -0
  8. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Growl +0 -0
  9. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/Growl.h +5 -0
  10. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +551 -0
  11. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Headers/GrowlDefines.h +341 -0
  12. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/Resources/Info.plist +40 -0
  13. data/assets/MacGap.app/Contents/Frameworks/Growl.framework/Versions/A/_CodeSignature/CodeResources +34 -0
  14. data/assets/MacGap.app/Contents/Info.plist +48 -0
  15. data/assets/MacGap.app/Contents/MacOS/MacGap +0 -0
  16. data/assets/MacGap.app/Contents/PkgInfo +1 -0
  17. data/assets/MacGap.app/Contents/Resources/_debugger.js +1718 -0
  18. data/assets/MacGap.app/Contents/Resources/_http_agent.js +310 -0
  19. data/assets/MacGap.app/Contents/Resources/_http_client.js +533 -0
  20. data/assets/MacGap.app/Contents/Resources/_http_common.js +222 -0
  21. data/assets/MacGap.app/Contents/Resources/_http_incoming.js +194 -0
  22. data/assets/MacGap.app/Contents/Resources/_http_outgoing.js +597 -0
  23. data/assets/MacGap.app/Contents/Resources/_http_server.js +510 -0
  24. data/assets/MacGap.app/Contents/Resources/_linklist.js +76 -0
  25. data/assets/MacGap.app/Contents/Resources/_stream_duplex.js +69 -0
  26. data/assets/MacGap.app/Contents/Resources/_stream_passthrough.js +41 -0
  27. data/assets/MacGap.app/Contents/Resources/_stream_readable.js +900 -0
  28. data/assets/MacGap.app/Contents/Resources/_stream_transform.js +204 -0
  29. data/assets/MacGap.app/Contents/Resources/_stream_writable.js +456 -0
  30. data/assets/MacGap.app/Contents/Resources/_tls_legacy.js +887 -0
  31. data/assets/MacGap.app/Contents/Resources/_tls_wrap.js +831 -0
  32. data/assets/MacGap.app/Contents/Resources/application.icns +0 -0
  33. data/assets/MacGap.app/Contents/Resources/assert.js +326 -0
  34. data/assets/MacGap.app/Contents/Resources/buffer.js +724 -0
  35. data/assets/MacGap.app/Contents/Resources/child_process.js +1107 -0
  36. data/assets/MacGap.app/Contents/Resources/cluster.js +613 -0
  37. data/assets/MacGap.app/Contents/Resources/console.js +108 -0
  38. data/assets/MacGap.app/Contents/Resources/constants.js +22 -0
  39. data/assets/MacGap.app/Contents/Resources/crypto.js +691 -0
  40. data/assets/MacGap.app/Contents/Resources/dgram.js +459 -0
  41. data/assets/MacGap.app/Contents/Resources/dns.js +274 -0
  42. data/assets/MacGap.app/Contents/Resources/domain.js +292 -0
  43. data/assets/MacGap.app/Contents/Resources/en.lproj/Credits.rtf +29 -0
  44. data/assets/MacGap.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -0
  45. data/assets/MacGap.app/Contents/Resources/en.lproj/MainMenu.nib +0 -0
  46. data/assets/MacGap.app/Contents/Resources/en.lproj/Window.nib +0 -0
  47. data/assets/MacGap.app/Contents/Resources/events.js +312 -0
  48. data/assets/MacGap.app/Contents/Resources/freelist.js +43 -0
  49. data/assets/MacGap.app/Contents/Resources/fs.js +1732 -0
  50. data/assets/MacGap.app/Contents/Resources/http.js +119 -0
  51. data/assets/MacGap.app/Contents/Resources/https.js +134 -0
  52. data/assets/MacGap.app/Contents/Resources/module.js +529 -0
  53. data/assets/MacGap.app/Contents/Resources/net.js +1378 -0
  54. data/assets/MacGap.app/Contents/Resources/nodelike.js +195 -0
  55. data/assets/MacGap.app/Contents/Resources/os.js +64 -0
  56. data/assets/MacGap.app/Contents/Resources/path.js +517 -0
  57. data/assets/MacGap.app/Contents/Resources/public/index.html +38 -0
  58. data/assets/MacGap.app/Contents/Resources/punycode.js +507 -0
  59. data/assets/MacGap.app/Contents/Resources/querystring.js +206 -0
  60. data/assets/MacGap.app/Contents/Resources/readline.js +1311 -0
  61. data/assets/MacGap.app/Contents/Resources/repl.js +945 -0
  62. data/assets/MacGap.app/Contents/Resources/smalloc.js +90 -0
  63. data/assets/MacGap.app/Contents/Resources/stream.js +127 -0
  64. data/assets/MacGap.app/Contents/Resources/string_decoder.js +189 -0
  65. data/assets/MacGap.app/Contents/Resources/sys.js +24 -0
  66. data/assets/MacGap.app/Contents/Resources/timers.js +568 -0
  67. data/assets/MacGap.app/Contents/Resources/tls.js +220 -0
  68. data/assets/MacGap.app/Contents/Resources/tty.js +129 -0
  69. data/assets/MacGap.app/Contents/Resources/url.js +693 -0
  70. data/assets/MacGap.app/Contents/Resources/util.js +688 -0
  71. data/assets/MacGap.app/Contents/Resources/vm.js +73 -0
  72. data/assets/MacGap.app/Contents/Resources/zlib.js +524 -0
  73. data/assets/index.html +38 -0
  74. data/bin/macgyver +104 -0
  75. data/macgyver.gemspec +19 -0
  76. data/test/public/index.html +27 -0
  77. metadata +121 -0
@@ -0,0 +1,613 @@
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 EventEmitter = require('events').EventEmitter;
23
+ var assert = require('assert');
24
+ var dgram = require('dgram');
25
+ var fork = require('child_process').fork;
26
+ var net = require('net');
27
+ var util = require('util');
28
+ var SCHED_NONE = 1;
29
+ var SCHED_RR = 2;
30
+
31
+ var cluster = new EventEmitter;
32
+ module.exports = cluster;
33
+ cluster.Worker = Worker;
34
+ cluster.isWorker = ('NODE_UNIQUE_ID' in process.env);
35
+ cluster.isMaster = (cluster.isWorker === false);
36
+
37
+
38
+ function Worker() {
39
+ if (!(this instanceof Worker)) return new Worker;
40
+ EventEmitter.call(this);
41
+ this.suicide = undefined;
42
+ this.state = 'none';
43
+ this.id = 0;
44
+ }
45
+ util.inherits(Worker, EventEmitter);
46
+
47
+ Worker.prototype.kill = function() {
48
+ this.destroy.apply(this, arguments);
49
+ };
50
+
51
+ Worker.prototype.send = function() {
52
+ this.process.send.apply(this.process, arguments);
53
+ };
54
+
55
+ // Master/worker specific methods are defined in the *Init() functions.
56
+
57
+ function SharedHandle(key, address, port, addressType, backlog, fd) {
58
+ this.key = key;
59
+ this.workers = [];
60
+ this.handle = null;
61
+ this.errno = 0;
62
+
63
+ // FIXME(bnoordhuis) Polymorphic return type for lack of a better solution.
64
+ var rval;
65
+ if (addressType === 'udp4' || addressType === 'udp6')
66
+ rval = dgram._createSocketHandle(address, port, addressType, fd);
67
+ else
68
+ rval = net._createServerHandle(address, port, addressType, fd);
69
+
70
+ if (util.isNumber(rval))
71
+ this.errno = rval;
72
+ else
73
+ this.handle = rval;
74
+ }
75
+
76
+ SharedHandle.prototype.add = function(worker, send) {
77
+ assert(this.workers.indexOf(worker) === -1);
78
+ this.workers.push(worker);
79
+ send(this.errno, null, this.handle);
80
+ };
81
+
82
+ SharedHandle.prototype.remove = function(worker) {
83
+ var index = this.workers.indexOf(worker);
84
+ assert(index !== -1);
85
+ this.workers.splice(index, 1);
86
+ if (this.workers.length !== 0) return false;
87
+ this.handle.close();
88
+ this.handle = null;
89
+ return true;
90
+ };
91
+
92
+
93
+ // Start a round-robin server. Master accepts connections and distributes
94
+ // them over the workers.
95
+ function RoundRobinHandle(key, address, port, addressType, backlog, fd) {
96
+ this.key = key;
97
+ this.all = {};
98
+ this.free = [];
99
+ this.handles = [];
100
+ this.handle = null;
101
+ this.server = net.createServer(assert.fail);
102
+
103
+ if (fd >= 0)
104
+ this.server.listen({ fd: fd });
105
+ else if (port >= 0)
106
+ this.server.listen(port, address);
107
+ else
108
+ this.server.listen(address); // UNIX socket path.
109
+
110
+ var self = this;
111
+ this.server.once('listening', function() {
112
+ self.handle = self.server._handle;
113
+ self.handle.onconnection = self.distribute.bind(self);
114
+ self.server._handle = null;
115
+ self.server = null;
116
+ });
117
+ }
118
+
119
+ RoundRobinHandle.prototype.add = function(worker, send) {
120
+ assert(worker.id in this.all === false);
121
+ this.all[worker.id] = worker;
122
+
123
+ var self = this;
124
+ function done() {
125
+ if (self.handle.getsockname) {
126
+ var out = {};
127
+ var err = self.handle.getsockname(out);
128
+ // TODO(bnoordhuis) Check err.
129
+ send(null, { sockname: out }, null);
130
+ }
131
+ else {
132
+ send(null, null, null); // UNIX socket.
133
+ }
134
+ self.handoff(worker); // In case there are connections pending.
135
+ }
136
+
137
+ if (util.isNull(this.server)) return done();
138
+ // Still busy binding.
139
+ this.server.once('listening', done);
140
+ this.server.once('error', function(err) {
141
+ // Hack: translate 'EADDRINUSE' error string back to numeric error code.
142
+ // It works but ideally we'd have some backchannel between the net and
143
+ // cluster modules for stuff like this.
144
+ var errno = process.binding('uv')['UV_' + err.errno];
145
+ send(errno, null);
146
+ });
147
+ };
148
+
149
+ RoundRobinHandle.prototype.remove = function(worker) {
150
+ if (worker.id in this.all === false) return false;
151
+ delete this.all[worker.id];
152
+ var index = this.free.indexOf(worker);
153
+ if (index !== -1) this.free.splice(index, 1);
154
+ if (Object.getOwnPropertyNames(this.all).length !== 0) return false;
155
+ for (var handle; handle = this.handles.shift(); handle.close());
156
+ this.handle.close();
157
+ this.handle = null;
158
+ return true;
159
+ };
160
+
161
+ RoundRobinHandle.prototype.distribute = function(err, handle) {
162
+ this.handles.push(handle);
163
+ var worker = this.free.shift();
164
+ if (worker) this.handoff(worker);
165
+ };
166
+
167
+ RoundRobinHandle.prototype.handoff = function(worker) {
168
+ if (worker.id in this.all === false) {
169
+ return; // Worker is closing (or has closed) the server.
170
+ }
171
+ var handle = this.handles.shift();
172
+ if (util.isUndefined(handle)) {
173
+ this.free.push(worker); // Add to ready queue again.
174
+ return;
175
+ }
176
+ var message = { act: 'newconn', key: this.key };
177
+ var self = this;
178
+ sendHelper(worker.process, message, handle, function(reply) {
179
+ if (reply.accepted)
180
+ handle.close();
181
+ else
182
+ self.distribute(0, handle); // Worker is shutting down. Send to another.
183
+ self.handoff(worker);
184
+ });
185
+ };
186
+
187
+
188
+ if (cluster.isMaster)
189
+ masterInit();
190
+ else
191
+ workerInit();
192
+
193
+
194
+ function createWorkerExecArgv(masterExecArgv, worker) {
195
+ var args = masterExecArgv.slice();
196
+ var debugPort = process.debugPort + worker.id;
197
+ var hasDebugArg = false;
198
+
199
+ for (var i = 0; i < args.length; i++) {
200
+ var match = args[i].match(/^(--debug|--debug-brk)(=\d+)?$/);
201
+ if (!match) continue;
202
+ args[i] = match[1] + '=' + debugPort;
203
+ hasDebugArg = true;
204
+ }
205
+
206
+ if (!hasDebugArg)
207
+ args = ['--debug-port=' + debugPort].concat(args);
208
+
209
+ return args;
210
+ }
211
+
212
+
213
+ function masterInit() {
214
+ cluster.workers = {};
215
+
216
+ var intercom = new EventEmitter;
217
+ var settings = {
218
+ args: process.argv.slice(2),
219
+ exec: process.argv[1],
220
+ execArgv: process.execArgv,
221
+ silent: false
222
+ };
223
+ cluster.settings = settings;
224
+
225
+ // XXX(bnoordhuis) Fold cluster.schedulingPolicy into cluster.settings?
226
+ var schedulingPolicy = {
227
+ 'none': SCHED_NONE,
228
+ 'rr': SCHED_RR
229
+ }[process.env.NODE_CLUSTER_SCHED_POLICY];
230
+
231
+ if (util.isUndefined(schedulingPolicy)) {
232
+ // FIXME Round-robin doesn't perform well on Windows right now due to the
233
+ // way IOCP is wired up. Bert is going to fix that, eventually.
234
+ schedulingPolicy = (process.platform === 'win32') ? SCHED_NONE : SCHED_RR;
235
+ }
236
+
237
+ cluster.schedulingPolicy = schedulingPolicy;
238
+ cluster.SCHED_NONE = SCHED_NONE; // Leave it to the operating system.
239
+ cluster.SCHED_RR = SCHED_RR; // Master distributes connections.
240
+
241
+ // Keyed on address:port:etc. When a worker dies, we walk over the handles
242
+ // and remove() the worker from each one. remove() may do a linear scan
243
+ // itself so we might end up with an O(n*m) operation. Ergo, FIXME.
244
+ var handles = {};
245
+
246
+ var initialized = false;
247
+ cluster.setupMaster = function(options) {
248
+ if (initialized === true) return;
249
+ initialized = true;
250
+ settings = util._extend(settings, options || {});
251
+ // Tell V8 to write profile data for each process to a separate file.
252
+ // Without --logfile=v8-%p.log, everything ends up in a single, unusable
253
+ // file. (Unusable because what V8 logs are memory addresses and each
254
+ // process has its own memory mappings.)
255
+ if (settings.execArgv.some(function(s) { return /^--prof/.test(s); }) &&
256
+ !settings.execArgv.some(function(s) { return /^--logfile=/.test(s); }))
257
+ {
258
+ settings.execArgv = settings.execArgv.concat(['--logfile=v8-%p.log']);
259
+ }
260
+ schedulingPolicy = cluster.schedulingPolicy; // Freeze policy.
261
+ assert(schedulingPolicy === SCHED_NONE || schedulingPolicy === SCHED_RR,
262
+ 'Bad cluster.schedulingPolicy: ' + schedulingPolicy);
263
+ cluster.settings = settings;
264
+
265
+ process.on('internalMessage', function(message) {
266
+ if (message.cmd !== 'NODE_DEBUG_ENABLED') return;
267
+ var key;
268
+ for (key in cluster.workers)
269
+ process._debugProcess(cluster.workers[key].process.pid);
270
+ });
271
+
272
+ process.nextTick(function() {
273
+ cluster.emit('setup');
274
+ });
275
+ };
276
+
277
+ var ids = 0;
278
+ cluster.fork = function(env) {
279
+ cluster.setupMaster();
280
+ var worker = new Worker;
281
+ worker.id = ++ids;
282
+ var workerEnv = util._extend({}, process.env);
283
+ workerEnv = util._extend(workerEnv, env);
284
+ workerEnv.NODE_UNIQUE_ID = '' + worker.id;
285
+ worker.process = fork(settings.exec, settings.args, {
286
+ env: workerEnv,
287
+ silent: settings.silent,
288
+ execArgv: createWorkerExecArgv(settings.execArgv, worker)
289
+ });
290
+ worker.process.once('exit', function(exitCode, signalCode) {
291
+ worker.suicide = !!worker.suicide;
292
+ worker.state = 'dead';
293
+ worker.emit('exit', exitCode, signalCode);
294
+ cluster.emit('exit', worker, exitCode, signalCode);
295
+ delete cluster.workers[worker.id];
296
+ });
297
+ worker.process.once('disconnect', function() {
298
+ worker.suicide = !!worker.suicide;
299
+ worker.state = 'disconnected';
300
+ worker.emit('disconnect');
301
+ cluster.emit('disconnect', worker);
302
+ delete cluster.workers[worker.id];
303
+ });
304
+ worker.process.on('error', worker.emit.bind(worker, 'error'));
305
+ worker.process.on('message', worker.emit.bind(worker, 'message'));
306
+ worker.process.on('internalMessage', internal(worker, onmessage));
307
+ process.nextTick(function() {
308
+ cluster.emit('fork', worker);
309
+ });
310
+ cluster.workers[worker.id] = worker;
311
+ return worker;
312
+ };
313
+
314
+ cluster.disconnect = function(cb) {
315
+ var workers = Object.keys(cluster.workers);
316
+ if (workers.length === 0) {
317
+ process.nextTick(intercom.emit.bind(intercom, 'disconnect'));
318
+ } else {
319
+ for (var key in workers) {
320
+ key = workers[key];
321
+ cluster.workers[key].disconnect();
322
+ }
323
+ }
324
+ if (cb) intercom.once('disconnect', cb);
325
+ };
326
+
327
+ cluster.on('disconnect', function(worker) {
328
+ delete cluster.workers[worker.id];
329
+ for (var key in handles) {
330
+ var handle = handles[key];
331
+ if (handle.remove(worker)) delete handles[key];
332
+ }
333
+ if (Object.keys(cluster.workers).length === 0) {
334
+ assert(Object.keys(handles).length === 0, 'Resource leak detected.');
335
+ intercom.emit('disconnect');
336
+ }
337
+ });
338
+
339
+ Worker.prototype.disconnect = function() {
340
+ this.suicide = true;
341
+ send(this, { act: 'disconnect' });
342
+ };
343
+
344
+ Worker.prototype.destroy = function(signo) {
345
+ signo = signo || 'SIGTERM';
346
+ var proc = this.process;
347
+ if (proc.connected) {
348
+ this.once('disconnect', proc.kill.bind(proc, signo));
349
+ this.disconnect();
350
+ return;
351
+ }
352
+ proc.kill(signo);
353
+ };
354
+
355
+ function onmessage(message, handle) {
356
+ var worker = this;
357
+ if (message.act === 'online')
358
+ online(worker);
359
+ else if (message.act === 'queryServer')
360
+ queryServer(worker, message);
361
+ else if (message.act === 'listening')
362
+ listening(worker, message);
363
+ else if (message.act === 'suicide')
364
+ worker.suicide = true;
365
+ else if (message.act === 'close')
366
+ close(worker, message);
367
+ }
368
+
369
+ function online(worker) {
370
+ worker.state = 'online';
371
+ worker.emit('online');
372
+ cluster.emit('online', worker);
373
+ }
374
+
375
+ function queryServer(worker, message) {
376
+ var args = [message.address,
377
+ message.port,
378
+ message.addressType,
379
+ message.fd];
380
+ var key = args.join(':');
381
+ var handle = handles[key];
382
+ if (util.isUndefined(handle)) {
383
+ var constructor = RoundRobinHandle;
384
+ // UDP is exempt from round-robin connection balancing for what should
385
+ // be obvious reasons: it's connectionless. There is nothing to send to
386
+ // the workers except raw datagrams and that's pointless.
387
+ if (schedulingPolicy !== SCHED_RR ||
388
+ message.addressType === 'udp4' ||
389
+ message.addressType === 'udp6') {
390
+ constructor = SharedHandle;
391
+ }
392
+ handles[key] = handle = new constructor(key,
393
+ message.address,
394
+ message.port,
395
+ message.addressType,
396
+ message.backlog,
397
+ message.fd);
398
+ }
399
+ if (!handle.data) handle.data = message.data;
400
+
401
+ // Set custom server data
402
+ handle.add(worker, function(errno, reply, handle) {
403
+ reply = util._extend({
404
+ errno: errno,
405
+ key: key,
406
+ ack: message.seq,
407
+ data: handles[key].data
408
+ }, reply);
409
+ if (errno) delete handles[key]; // Gives other workers a chance to retry.
410
+ send(worker, reply, handle);
411
+ });
412
+ }
413
+
414
+ function listening(worker, message) {
415
+ var info = {
416
+ addressType: message.addressType,
417
+ address: message.address,
418
+ port: message.port,
419
+ fd: message.fd
420
+ };
421
+ worker.state = 'listening';
422
+ worker.emit('listening', info);
423
+ cluster.emit('listening', worker, info);
424
+ }
425
+
426
+ // Round-robin only. Server in worker is closing, remove from list.
427
+ function close(worker, message) {
428
+ var key = message.key;
429
+ var handle = handles[key];
430
+ if (handle.remove(worker)) delete handles[key];
431
+ }
432
+
433
+ function send(worker, message, handle, cb) {
434
+ sendHelper(worker.process, message, handle, cb);
435
+ }
436
+ }
437
+
438
+
439
+ function workerInit() {
440
+ var handles = {};
441
+
442
+ // Called from src/node.js
443
+ cluster._setupWorker = function() {
444
+ var worker = new Worker;
445
+ cluster.worker = worker;
446
+ worker.id = +process.env.NODE_UNIQUE_ID | 0;
447
+ worker.state = 'online';
448
+ worker.process = process;
449
+ process.once('disconnect', function() {
450
+ if (!worker.suicide) {
451
+ // Unexpected disconnect, master exited, or some such nastiness, so
452
+ // worker exits immediately.
453
+ process.exit(0);
454
+ }
455
+ });
456
+ process.on('internalMessage', internal(worker, onmessage));
457
+ send({ act: 'online' });
458
+ function onmessage(message, handle) {
459
+ if (message.act === 'newconn')
460
+ onconnection(message, handle);
461
+ else if (message.act === 'disconnect')
462
+ worker.disconnect();
463
+ }
464
+ };
465
+
466
+ // obj is a net#Server or a dgram#Socket object.
467
+ cluster._getServer = function(obj, address, port, addressType, fd, cb) {
468
+ var message = {
469
+ addressType: addressType,
470
+ address: address,
471
+ port: port,
472
+ act: 'queryServer',
473
+ fd: fd,
474
+ data: null
475
+ };
476
+ // Set custom data on handle (i.e. tls tickets key)
477
+ if (obj._getServerData) message.data = obj._getServerData();
478
+ send(message, function(reply, handle) {
479
+ if (obj._setServerData) obj._setServerData(reply.data);
480
+
481
+ if (handle)
482
+ shared(reply, handle, cb); // Shared listen socket.
483
+ else
484
+ rr(reply, cb); // Round-robin.
485
+ });
486
+ obj.once('listening', function() {
487
+ cluster.worker.state = 'listening';
488
+ var address = obj.address();
489
+ message.act = 'listening';
490
+ message.port = address && address.port || port;
491
+ send(message);
492
+ });
493
+ };
494
+
495
+ // Shared listen socket.
496
+ function shared(message, handle, cb) {
497
+ var key = message.key;
498
+ // Monkey-patch the close() method so we can keep track of when it's
499
+ // closed. Avoids resource leaks when the handle is short-lived.
500
+ var close = handle.close;
501
+ handle.close = function() {
502
+ delete handles[key];
503
+ return close.apply(this, arguments);
504
+ };
505
+ assert(util.isUndefined(handles[key]));
506
+ handles[key] = handle;
507
+ cb(message.errno, handle);
508
+ }
509
+
510
+ // Round-robin. Master distributes handles across workers.
511
+ function rr(message, cb) {
512
+ if (message.errno)
513
+ return cb(message.errno, null);
514
+
515
+ var key = message.key;
516
+ function listen(backlog) {
517
+ // TODO(bnoordhuis) Send a message to the master that tells it to
518
+ // update the backlog size. The actual backlog should probably be
519
+ // the largest requested size by any worker.
520
+ return 0;
521
+ }
522
+
523
+ function close() {
524
+ // lib/net.js treats server._handle.close() as effectively synchronous.
525
+ // That means there is a time window between the call to close() and
526
+ // the ack by the master process in which we can still receive handles.
527
+ // onconnection() below handles that by sending those handles back to
528
+ // the master.
529
+ if (util.isUndefined(key)) return;
530
+ send({ act: 'close', key: key });
531
+ delete handles[key];
532
+ key = undefined;
533
+ }
534
+
535
+ function getsockname(out) {
536
+ if (key) util._extend(out, message.sockname);
537
+ return 0;
538
+ }
539
+
540
+ // Faux handle. Mimics a TCPWrap with just enough fidelity to get away
541
+ // with it. Fools net.Server into thinking that it's backed by a real
542
+ // handle.
543
+ var handle = {
544
+ close: close,
545
+ listen: listen
546
+ };
547
+ if (message.sockname) {
548
+ handle.getsockname = getsockname; // TCP handles only.
549
+ }
550
+ assert(util.isUndefined(handles[key]));
551
+ handles[key] = handle;
552
+ cb(0, handle);
553
+ }
554
+
555
+ // Round-robin connection.
556
+ function onconnection(message, handle) {
557
+ var key = message.key;
558
+ var server = handles[key];
559
+ var accepted = !util.isUndefined(server);
560
+ send({ ack: message.seq, accepted: accepted });
561
+ if (accepted) server.onconnection(0, handle);
562
+ }
563
+
564
+ Worker.prototype.disconnect = function() {
565
+ this.suicide = true;
566
+ for (var key in handles) {
567
+ var handle = handles[key];
568
+ delete handles[key];
569
+ handle.close();
570
+ }
571
+ process.disconnect();
572
+ };
573
+
574
+ Worker.prototype.destroy = function() {
575
+ this.suicide = true;
576
+ if (!process.connected) process.exit(0);
577
+ var exit = process.exit.bind(null, 0);
578
+ send({ act: 'suicide' }, exit);
579
+ process.once('disconnect', exit);
580
+ process.disconnect();
581
+ };
582
+
583
+ function send(message, cb) {
584
+ sendHelper(process, message, null, cb);
585
+ }
586
+ }
587
+
588
+
589
+ var seq = 0;
590
+ var callbacks = {};
591
+ function sendHelper(proc, message, handle, cb) {
592
+ // Mark message as internal. See INTERNAL_PREFIX in lib/child_process.js
593
+ message = util._extend({ cmd: 'NODE_CLUSTER' }, message);
594
+ if (cb) callbacks[seq] = cb;
595
+ message.seq = seq;
596
+ seq += 1;
597
+ proc.send(message, handle);
598
+ }
599
+
600
+
601
+ // Returns an internalMessage listener that hands off normal messages
602
+ // to the callback but intercepts and redirects ACK messages.
603
+ function internal(worker, cb) {
604
+ return function(message, handle) {
605
+ if (message.cmd !== 'NODE_CLUSTER') return;
606
+ var fn = cb;
607
+ if (!util.isUndefined(message.ack)) {
608
+ fn = callbacks[message.ack];
609
+ delete callbacks[message.ack];
610
+ }
611
+ fn.apply(worker, arguments);
612
+ };
613
+ }