blob: 4a42a052c8e6e43b0fee4bd9f0b77098a4698433 [file] [log] [blame]
Ryan Dahl55048cd2011-03-10 08:54:521// 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.
Bert Beldere0f47be2011-01-17 23:22:3621
Ben Noordhuisff4a9d32012-03-09 23:11:1122#include "node.h"
Ben Noordhuis5f040652012-04-28 16:45:1023#include "req_wrap.h"
24#include "handle_wrap.h"
Ryan63a9cd32009-04-15 08:08:2825
Ben Noordhuisff4a9d32012-03-09 23:11:1126#include "uv.h"
Ryan Dahlefca3342011-05-13 02:16:4027
Ben Noordhuisff4a9d32012-03-09 23:11:1128#include "v8-debug.h"
Ryan Dahlb3ddb892011-10-26 18:31:1229#ifdef HAVE_DTRACE
Ben Noordhuisff4a9d32012-03-09 23:11:1130# include "node_dtrace.h"
Ryan Dahlb3ddb892011-10-26 18:31:1231#endif
Ryan Dahl4635ed72010-03-11 20:40:1932
Bert Beldere0f47be2011-01-17 23:22:3633#include <locale.h>
Bert Belder9cec08e2011-05-23 23:42:2234#include <signal.h>
Ryan19478ed2009-03-03 00:56:1535#include <stdio.h>
Ryan34a6f102009-05-28 12:47:1636#include <stdlib.h>
Ryan Dahlc90e44e2010-05-10 23:38:4737#include <string.h>
Peter Bright13d6a1f2011-08-06 04:23:2538#if !defined(_MSC_VER)
39#include <strings.h>
40#else
41#define strcasecmp _stricmp
42#endif
Ryan82d986d2009-09-02 18:18:5043#include <limits.h> /* PATH_MAX */
Ryan19478ed2009-03-03 00:56:1544#include <assert.h>
Peter Bright13d6a1f2011-08-06 04:23:2545#if !defined(_MSC_VER)
46#include <unistd.h> /* setuid, getuid */
47#else
48#include <direct.h>
Peter Bright13d6a1f2011-08-06 04:23:2549#include <process.h>
50#define getpid _getpid
Peter Brightb9d77772011-08-11 01:45:5651#include <io.h>
52#define umask _umask
53typedef int mode_t;
Peter Bright13d6a1f2011-08-06 04:23:2554#endif
Michael Carter8ea6adc2009-09-01 09:39:3055#include <errno.h>
Michael Cartera3860762010-02-08 06:13:1056#include <sys/types.h>
Nathan Rajlich9701f1c2012-03-08 18:56:5957#include "zlib.h"
Ryane02b71e2009-03-03 23:31:3758
Bert Beldere0f47be2011-01-17 23:22:3659#ifdef __POSIX__
Bert Beldera177d602010-11-25 00:02:5560# include <pwd.h> /* getpwnam() */
61# include <grp.h> /* getgrnam() */
62#endif
63
Ben Noordhuisff4a9d32012-03-09 23:11:1164#include "node_buffer.h"
Igor Zinkovskyf35a3962011-10-28 22:34:2465#ifdef __POSIX__
Ben Noordhuisff4a9d32012-03-09 23:11:1166# include "node_io_watcher.h"
Igor Zinkovskyf35a3962011-10-28 22:34:2467#endif
Ben Noordhuisff4a9d32012-03-09 23:11:1168#include "node_file.h"
69#include "node_http_parser.h"
Bert Belder406f44a2011-06-08 02:41:2870#ifdef __POSIX__
Ben Noordhuisff4a9d32012-03-09 23:11:1171# include "node_signal_watcher.h"
72# include "node_stat_watcher.h"
Bert Belder406f44a2011-06-08 02:41:2873#endif
Ben Noordhuisff4a9d32012-03-09 23:11:1174#include "node_constants.h"
75#include "node_javascript.h"
76#include "node_version.h"
77#include "node_string.h"
Peter Bright13d6a1f2011-08-06 04:23:2578#if HAVE_OPENSSL
Ben Noordhuisff4a9d32012-03-09 23:11:1179# include "node_crypto.h"
Rhys Jonesfb3a9cd2010-04-02 23:11:5380#endif
Ben Noordhuisff4a9d32012-03-09 23:11:1181#include "node_script.h"
82#include "v8_typed_array.h"
Ryan6dd850a2009-09-08 12:59:4383
Ryan19478ed2009-03-03 00:56:1584using namespace v8;
Ryan19478ed2009-03-03 00:56:1585
Rasmus Andersson50443f02010-10-11 15:19:1186# ifdef __APPLE__
87# include <crt_externs.h>
88# define environ (*_NSGetEnviron())
Peter Bright13d6a1f2011-08-06 04:23:2589# elif !defined(_MSC_VER)
Ryan3e4fc9f2009-09-10 14:48:3890extern char **environ;
Rasmus Andersson50443f02010-10-11 15:19:1191# endif
Ryan3e4fc9f2009-09-10 14:48:3892
Ryand6c9d312009-09-11 14:02:2993namespace node {
94
Ben Noordhuis5f040652012-04-28 16:45:1095ngx_queue_t handle_wrap_queue = { &handle_wrap_queue, &handle_wrap_queue };
96ngx_queue_t req_wrap_queue = { &req_wrap_queue, &req_wrap_queue };
97
Ben Noordhuis636add22012-04-27 16:58:3098// declared in req_wrap.h
99Persistent<String> process_symbol;
100Persistent<String> domain_symbol;
Ben Noordhuis809fdf22011-12-09 20:49:10101
Ben Noordhuis74a82152012-02-03 15:32:00102static Persistent<Object> process;
103
104static Persistent<String> errno_symbol;
105static Persistent<String> syscall_symbol;
106static Persistent<String> errpath_symbol;
107static Persistent<String> code_symbol;
108
109static Persistent<String> rss_symbol;
110static Persistent<String> heap_total_symbol;
111static Persistent<String> heap_used_symbol;
112
113static Persistent<String> listeners_symbol;
114static Persistent<String> uncaught_exception_symbol;
115static Persistent<String> emit_symbol;
116
isaacs10ce3d12012-04-13 23:27:23117static Persistent<String> enter_symbol;
118static Persistent<String> exit_symbol;
119static Persistent<String> disposed_symbol;
120
Ben Noordhuis74a82152012-02-03 15:32:00121
122static bool print_eval = false;
Nathan Rajlichfeaa8a42012-03-21 07:05:25123static bool force_repl = false;
Ben Noordhuis74a82152012-02-03 15:32:00124static char *eval_string = NULL;
125static int option_end_index = 0;
126static bool use_debug_agent = false;
127static bool debug_wait_connect = false;
128static int debug_port=5858;
129static int max_stack_size = 0;
130
131static uv_check_t check_tick_watcher;
132static uv_prepare_t prepare_tick_watcher;
133static uv_idle_t tick_spinner;
134static bool need_tick_cb;
135static Persistent<String> tick_callback_sym;
136
137
138#ifdef OPENSSL_NPN_NEGOTIATED
139static bool use_npn = true;
140#else
141static bool use_npn = false;
142#endif
143
144#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
145static bool use_sni = true;
146#else
147static bool use_sni = false;
148#endif
149
150#ifdef __POSIX__
151// Buffer for getpwnam_r(), getgrpam_r() and other misc callers; keep this
152// scoped at file-level rather than method-level to avoid excess stack usage.
153static char getbuf[PATH_MAX + 1];
154#endif
155
156// We need to notify V8 when we're idle so that it can run the garbage
157// collector. The interface to this is V8::IdleNotification(). It returns
158// true if the heap hasn't be fully compacted, and needs to be run again.
159// Returning false means that it doesn't have anymore work to do.
160//
161// A rather convoluted algorithm has been devised to determine when Node is
162// idle. You'll have to figure it out for yourself.
163static uv_check_t gc_check;
164static uv_idle_t gc_idle;
165static uv_timer_t gc_timer;
166bool need_gc;
167
168// process-relative uptime base, initialized at start-up
169static double prog_start_time;
170
171#define FAST_TICK 700.
172#define GC_WAIT_TIME 5000.
173#define RPM_SAMPLES 100
174#define TICK_TIME(n) tick_times[(tick_time_head - (n)) % RPM_SAMPLES]
175static int64_t tick_times[RPM_SAMPLES];
176static int tick_time_head;
Ben Noordhuis2df81c52011-12-09 17:49:17177
Ryan Dahlf657d582011-06-22 12:06:26178static void CheckStatus(uv_timer_t* watcher, int status);
Ben Noordhuis809fdf22011-12-09 20:49:10179
Ryan Dahl3ac6dee2010-05-08 02:05:59180static void StartGCTimer () {
Ryan Dahl7a5977b2011-06-07 16:37:27181 if (!uv_is_active((uv_handle_t*) &gc_timer)) {
Ryan Dahl7547c7d2011-12-07 01:00:33182 uv_timer_start(&gc_timer, node::CheckStatus, 5000, 5000);
Ryan Dahlac3bc2e2010-04-15 08:29:39183 }
184}
185
Ryan Dahl3ac6dee2010-05-08 02:05:59186static void StopGCTimer () {
Ryan Dahl7a5977b2011-06-07 16:37:27187 if (uv_is_active((uv_handle_t*) &gc_timer)) {
Bert Belder9cec08e2011-05-23 23:42:22188 uv_timer_stop(&gc_timer);
Ryan Dahlac3bc2e2010-04-15 08:29:39189 }
190}
Ryan Dahldaacb812010-02-21 02:23:21191
Ryan Dahlf657d582011-06-22 12:06:26192static void Idle(uv_idle_t* watcher, int status) {
Ryan Dahl7a5977b2011-06-07 16:37:27193 assert((uv_idle_t*) watcher == &gc_idle);
Ryan Dahl801fb8a2010-04-05 20:51:32194
Ryan Dahl801fb8a2010-04-05 20:51:32195 if (V8::IdleNotification()) {
Ryan Dahl7a5977b2011-06-07 16:37:27196 uv_idle_stop(&gc_idle);
Ryan Dahl3ac6dee2010-05-08 02:05:59197 StopGCTimer();
Ryan Dahl801fb8a2010-04-05 20:51:32198 }
Ryan Dahl801fb8a2010-04-05 20:51:32199}
200
201
Ryan Dahl3ac6dee2010-05-08 02:05:59202// Called directly after every call to select() (or epoll, or whatever)
Ryan Dahlf657d582011-06-22 12:06:26203static void Check(uv_check_t* watcher, int status) {
204 assert(watcher == &gc_check);
Ryan Dahl801fb8a2010-04-05 20:51:32205
Ben Noordhuis74a82152012-02-03 15:32:00206 tick_times[tick_time_head] = uv_now(uv_default_loop());
Ryan Dahl3ac6dee2010-05-08 02:05:59207 tick_time_head = (tick_time_head + 1) % RPM_SAMPLES;
Ryan Dahl801fb8a2010-04-05 20:51:32208
Ryan Dahl3ac6dee2010-05-08 02:05:59209 StartGCTimer();
Ryan Dahl801fb8a2010-04-05 20:51:32210
Ryan Dahl3ac6dee2010-05-08 02:05:59211 for (int i = 0; i < (int)(GC_WAIT_TIME/FAST_TICK); i++) {
212 double d = TICK_TIME(i+1) - TICK_TIME(i+2);
213 //printf("d = %f\n", d);
214 // If in the last 5 ticks the difference between
215 // ticks was less than 0.7 seconds, then continue.
216 if (d < FAST_TICK) {
217 //printf("---\n");
218 return;
219 }
Ryan Dahl801fb8a2010-04-05 20:51:32220 }
Ryan Dahl3ac6dee2010-05-08 02:05:59221
222 // Otherwise start the gc!
223
224 //fprintf(stderr, "start idle 2\n");
Ryan Dahl7547c7d2011-12-07 01:00:33225 uv_idle_start(&gc_idle, node::Idle);
Ryan Dahldaacb812010-02-21 02:23:21226}
227
Ryan Dahlf80cc692010-01-06 09:17:58228
Ryan Dahl17f3ffa2010-09-09 17:30:37229static void Tick(void) {
Ryan Dahl4e7e2f82010-04-13 22:39:15230 // Avoid entering a V8 scope.
231 if (!need_tick_cb) return;
232
233 need_tick_cb = false;
Ryan Dahl7a5977b2011-06-07 16:37:27234 if (uv_is_active((uv_handle_t*) &tick_spinner)) {
Ryan Dahl207901e2011-05-23 22:38:54235 uv_idle_stop(&tick_spinner);
Ben Noordhuis74a82152012-02-03 15:32:00236 uv_unref(uv_default_loop());
Ryan Dahl207901e2011-05-23 22:38:54237 }
Ryan Dahl4e7e2f82010-04-13 22:39:15238
239 HandleScope scope;
240
241 if (tick_callback_sym.IsEmpty()) {
242 // Lazily set the symbol
isaacsa26bee82012-04-12 23:03:47243 tick_callback_sym = NODE_PSYMBOL("_tickCallback");
Ryan Dahl4e7e2f82010-04-13 22:39:15244 }
245
246 Local<Value> cb_v = process->Get(tick_callback_sym);
247 if (!cb_v->IsFunction()) return;
248 Local<Function> cb = Local<Function>::Cast(cb_v);
249
250 TryCatch try_catch;
251
252 cb->Call(process, 0, NULL);
253
254 if (try_catch.HasCaught()) {
255 FatalException(try_catch);
256 }
257}
258
259
Ryan Dahlf657d582011-06-22 12:06:26260static void Spin(uv_idle_t* handle, int status) {
Bert Belder09ac99f2011-06-08 01:46:29261 assert((uv_idle_t*) handle == &tick_spinner);
262 assert(status == 0);
263 Tick();
264}
265
Felix Geisendörfer81403332012-05-08 14:07:14266static void StartTickSpinner() {
Bert Belder09ac99f2011-06-08 01:46:29267 need_tick_cb = true;
268 // TODO: this tick_spinner shouldn't be necessary. An ev_prepare should be
269 // sufficent, the problem is only in the case of the very last "tick" -
270 // there is nothing left to do in the event loop and libev will exit. The
271 // ev_prepare callback isn't called before exiting. Thus we start this
272 // tick_spinner to keep the event loop alive long enough to handle it.
273 if (!uv_is_active((uv_handle_t*) &tick_spinner)) {
274 uv_idle_start(&tick_spinner, Spin);
Ben Noordhuis74a82152012-02-03 15:32:00275 uv_ref(uv_default_loop());
Bert Belder09ac99f2011-06-08 01:46:29276 }
Bert Belder09ac99f2011-06-08 01:46:29277}
278
Felix Geisendörfer81403332012-05-08 14:07:14279static Handle<Value> NeedTickCallback(const Arguments& args) {
280 StartTickSpinner();
281 return Undefined();
282}
Bert Belder09ac99f2011-06-08 01:46:29283
Ryan Dahlf657d582011-06-22 12:06:26284static void PrepareTick(uv_prepare_t* handle, int status) {
285 assert(handle == &prepare_tick_watcher);
Ryan Dahla46c63b2011-05-13 14:06:20286 assert(status == 0);
Ryan Dahl17f3ffa2010-09-09 17:30:37287 Tick();
288}
289
290
Ryan Dahlf657d582011-06-22 12:06:26291static void CheckTick(uv_check_t* handle, int status) {
292 assert(handle == &check_tick_watcher);
Ryan Dahl91bd1442011-05-13 14:09:28293 assert(status == 0);
Ryan Dahl17f3ffa2010-09-09 17:30:37294 Tick();
295}
296
Ryan Dahlc9e27b12010-04-23 00:53:45297static inline const char *errno_string(int errorno) {
298#define ERRNO_CASE(e) case e: return #e;
299 switch (errorno) {
300
301#ifdef EACCES
302 ERRNO_CASE(EACCES);
303#endif
304
305#ifdef EADDRINUSE
306 ERRNO_CASE(EADDRINUSE);
307#endif
308
309#ifdef EADDRNOTAVAIL
310 ERRNO_CASE(EADDRNOTAVAIL);
311#endif
312
313#ifdef EAFNOSUPPORT
314 ERRNO_CASE(EAFNOSUPPORT);
315#endif
316
317#ifdef EAGAIN
318 ERRNO_CASE(EAGAIN);
Ryan Dahl9b2aac62010-04-28 19:58:00319#endif
320
321#ifdef EWOULDBLOCK
322# if EAGAIN != EWOULDBLOCK
Ryan Dahlc9e27b12010-04-23 00:53:45323 ERRNO_CASE(EWOULDBLOCK);
324# endif
325#endif
326
327#ifdef EALREADY
328 ERRNO_CASE(EALREADY);
329#endif
330
331#ifdef EBADF
332 ERRNO_CASE(EBADF);
333#endif
334
335#ifdef EBADMSG
336 ERRNO_CASE(EBADMSG);
337#endif
338
339#ifdef EBUSY
340 ERRNO_CASE(EBUSY);
341#endif
342
343#ifdef ECANCELED
344 ERRNO_CASE(ECANCELED);
345#endif
346
347#ifdef ECHILD
348 ERRNO_CASE(ECHILD);
349#endif
350
351#ifdef ECONNABORTED
352 ERRNO_CASE(ECONNABORTED);
353#endif
354
355#ifdef ECONNREFUSED
356 ERRNO_CASE(ECONNREFUSED);
357#endif
358
359#ifdef ECONNRESET
360 ERRNO_CASE(ECONNRESET);
361#endif
362
363#ifdef EDEADLK
364 ERRNO_CASE(EDEADLK);
365#endif
366
367#ifdef EDESTADDRREQ
368 ERRNO_CASE(EDESTADDRREQ);
369#endif
370
371#ifdef EDOM
372 ERRNO_CASE(EDOM);
373#endif
374
375#ifdef EDQUOT
376 ERRNO_CASE(EDQUOT);
377#endif
378
379#ifdef EEXIST
380 ERRNO_CASE(EEXIST);
381#endif
382
383#ifdef EFAULT
384 ERRNO_CASE(EFAULT);
385#endif
386
387#ifdef EFBIG
388 ERRNO_CASE(EFBIG);
389#endif
390
391#ifdef EHOSTUNREACH
392 ERRNO_CASE(EHOSTUNREACH);
393#endif
394
395#ifdef EIDRM
396 ERRNO_CASE(EIDRM);
397#endif
398
399#ifdef EILSEQ
400 ERRNO_CASE(EILSEQ);
401#endif
402
403#ifdef EINPROGRESS
404 ERRNO_CASE(EINPROGRESS);
405#endif
406
407#ifdef EINTR
408 ERRNO_CASE(EINTR);
409#endif
410
411#ifdef EINVAL
412 ERRNO_CASE(EINVAL);
413#endif
414
415#ifdef EIO
416 ERRNO_CASE(EIO);
417#endif
418
419#ifdef EISCONN
420 ERRNO_CASE(EISCONN);
421#endif
422
423#ifdef EISDIR
424 ERRNO_CASE(EISDIR);
425#endif
426
427#ifdef ELOOP
428 ERRNO_CASE(ELOOP);
429#endif
430
431#ifdef EMFILE
432 ERRNO_CASE(EMFILE);
433#endif
434
435#ifdef EMLINK
436 ERRNO_CASE(EMLINK);
437#endif
438
439#ifdef EMSGSIZE
440 ERRNO_CASE(EMSGSIZE);
441#endif
442
443#ifdef EMULTIHOP
444 ERRNO_CASE(EMULTIHOP);
445#endif
446
447#ifdef ENAMETOOLONG
448 ERRNO_CASE(ENAMETOOLONG);
449#endif
450
451#ifdef ENETDOWN
452 ERRNO_CASE(ENETDOWN);
453#endif
454
455#ifdef ENETRESET
456 ERRNO_CASE(ENETRESET);
457#endif
458
459#ifdef ENETUNREACH
460 ERRNO_CASE(ENETUNREACH);
461#endif
462
463#ifdef ENFILE
464 ERRNO_CASE(ENFILE);
465#endif
466
467#ifdef ENOBUFS
468 ERRNO_CASE(ENOBUFS);
469#endif
470
471#ifdef ENODATA
472 ERRNO_CASE(ENODATA);
473#endif
474
475#ifdef ENODEV
476 ERRNO_CASE(ENODEV);
477#endif
478
479#ifdef ENOENT
480 ERRNO_CASE(ENOENT);
481#endif
482
483#ifdef ENOEXEC
484 ERRNO_CASE(ENOEXEC);
485#endif
486
Ryan Dahlc9e27b12010-04-23 00:53:45487#ifdef ENOLINK
488 ERRNO_CASE(ENOLINK);
489#endif
490
Ryan Dahl3bb21b52010-04-28 22:07:15491#ifdef ENOLCK
492# if ENOLINK != ENOLCK
493 ERRNO_CASE(ENOLCK);
494# endif
495#endif
496
Ryan Dahlc9e27b12010-04-23 00:53:45497#ifdef ENOMEM
498 ERRNO_CASE(ENOMEM);
499#endif
500
501#ifdef ENOMSG
502 ERRNO_CASE(ENOMSG);
503#endif
504
505#ifdef ENOPROTOOPT
506 ERRNO_CASE(ENOPROTOOPT);
507#endif
508
509#ifdef ENOSPC
510 ERRNO_CASE(ENOSPC);
511#endif
512
513#ifdef ENOSR
514 ERRNO_CASE(ENOSR);
515#endif
516
517#ifdef ENOSTR
518 ERRNO_CASE(ENOSTR);
519#endif
520
521#ifdef ENOSYS
522 ERRNO_CASE(ENOSYS);
523#endif
524
525#ifdef ENOTCONN
526 ERRNO_CASE(ENOTCONN);
527#endif
528
529#ifdef ENOTDIR
530 ERRNO_CASE(ENOTDIR);
531#endif
532
533#ifdef ENOTEMPTY
534 ERRNO_CASE(ENOTEMPTY);
535#endif
536
537#ifdef ENOTSOCK
538 ERRNO_CASE(ENOTSOCK);
539#endif
540
541#ifdef ENOTSUP
542 ERRNO_CASE(ENOTSUP);
543#else
544# ifdef EOPNOTSUPP
545 ERRNO_CASE(EOPNOTSUPP);
546# endif
547#endif
548
549#ifdef ENOTTY
550 ERRNO_CASE(ENOTTY);
551#endif
552
553#ifdef ENXIO
554 ERRNO_CASE(ENXIO);
555#endif
556
557
558#ifdef EOVERFLOW
559 ERRNO_CASE(EOVERFLOW);
560#endif
561
562#ifdef EPERM
563 ERRNO_CASE(EPERM);
564#endif
565
566#ifdef EPIPE
567 ERRNO_CASE(EPIPE);
568#endif
569
570#ifdef EPROTO
571 ERRNO_CASE(EPROTO);
572#endif
573
574#ifdef EPROTONOSUPPORT
575 ERRNO_CASE(EPROTONOSUPPORT);
576#endif
577
578#ifdef EPROTOTYPE
579 ERRNO_CASE(EPROTOTYPE);
580#endif
581
582#ifdef ERANGE
583 ERRNO_CASE(ERANGE);
584#endif
585
586#ifdef EROFS
587 ERRNO_CASE(EROFS);
588#endif
589
590#ifdef ESPIPE
591 ERRNO_CASE(ESPIPE);
592#endif
593
594#ifdef ESRCH
595 ERRNO_CASE(ESRCH);
596#endif
597
598#ifdef ESTALE
599 ERRNO_CASE(ESTALE);
600#endif
601
602#ifdef ETIME
603 ERRNO_CASE(ETIME);
604#endif
605
606#ifdef ETIMEDOUT
607 ERRNO_CASE(ETIMEDOUT);
608#endif
609
610#ifdef ETXTBSY
611 ERRNO_CASE(ETXTBSY);
612#endif
613
614#ifdef EXDEV
615 ERRNO_CASE(EXDEV);
616#endif
617
618 default: return "";
619 }
620}
621
Felix Geisendörferf8a3cf92010-04-28 13:04:08622const char *signo_string(int signo) {
623#define SIGNO_CASE(e) case e: return #e;
624 switch (signo) {
625
626#ifdef SIGHUP
627 SIGNO_CASE(SIGHUP);
628#endif
629
630#ifdef SIGINT
631 SIGNO_CASE(SIGINT);
632#endif
633
634#ifdef SIGQUIT
635 SIGNO_CASE(SIGQUIT);
636#endif
637
638#ifdef SIGILL
639 SIGNO_CASE(SIGILL);
640#endif
641
642#ifdef SIGTRAP
643 SIGNO_CASE(SIGTRAP);
644#endif
645
646#ifdef SIGABRT
647 SIGNO_CASE(SIGABRT);
648#endif
649
650#ifdef SIGIOT
651# if SIGABRT != SIGIOT
652 SIGNO_CASE(SIGIOT);
653# endif
654#endif
655
656#ifdef SIGBUS
657 SIGNO_CASE(SIGBUS);
658#endif
659
660#ifdef SIGFPE
661 SIGNO_CASE(SIGFPE);
662#endif
663
664#ifdef SIGKILL
665 SIGNO_CASE(SIGKILL);
666#endif
667
668#ifdef SIGUSR1
669 SIGNO_CASE(SIGUSR1);
670#endif
671
672#ifdef SIGSEGV
673 SIGNO_CASE(SIGSEGV);
674#endif
675
676#ifdef SIGUSR2
677 SIGNO_CASE(SIGUSR2);
678#endif
679
680#ifdef SIGPIPE
681 SIGNO_CASE(SIGPIPE);
682#endif
683
684#ifdef SIGALRM
685 SIGNO_CASE(SIGALRM);
686#endif
687
688 SIGNO_CASE(SIGTERM);
Bert Belderdcc35082010-11-25 00:04:31689
690#ifdef SIGCHLD
Felix Geisendörferf8a3cf92010-04-28 13:04:08691 SIGNO_CASE(SIGCHLD);
Bert Belderdcc35082010-11-25 00:04:31692#endif
Felix Geisendörferf8a3cf92010-04-28 13:04:08693
694#ifdef SIGSTKFLT
695 SIGNO_CASE(SIGSTKFLT);
696#endif
697
698
699#ifdef SIGCONT
700 SIGNO_CASE(SIGCONT);
701#endif
702
703#ifdef SIGSTOP
704 SIGNO_CASE(SIGSTOP);
705#endif
706
707#ifdef SIGTSTP
708 SIGNO_CASE(SIGTSTP);
709#endif
710
711#ifdef SIGTTIN
712 SIGNO_CASE(SIGTTIN);
713#endif
714
715#ifdef SIGTTOU
716 SIGNO_CASE(SIGTTOU);
717#endif
718
719#ifdef SIGURG
720 SIGNO_CASE(SIGURG);
721#endif
722
723#ifdef SIGXCPU
724 SIGNO_CASE(SIGXCPU);
725#endif
726
727#ifdef SIGXFSZ
728 SIGNO_CASE(SIGXFSZ);
729#endif
730
731#ifdef SIGVTALRM
732 SIGNO_CASE(SIGVTALRM);
733#endif
734
735#ifdef SIGPROF
736 SIGNO_CASE(SIGPROF);
737#endif
738
739#ifdef SIGWINCH
740 SIGNO_CASE(SIGWINCH);
741#endif
742
743#ifdef SIGIO
744 SIGNO_CASE(SIGIO);
745#endif
746
747#ifdef SIGPOLL
Ryan Dahl3bb21b52010-04-28 22:07:15748# if SIGPOLL != SIGIO
Felix Geisendörferf8a3cf92010-04-28 13:04:08749 SIGNO_CASE(SIGPOLL);
Ryan Dahl3bb21b52010-04-28 22:07:15750# endif
Felix Geisendörferf8a3cf92010-04-28 13:04:08751#endif
752
753#ifdef SIGLOST
754 SIGNO_CASE(SIGLOST);
755#endif
756
757#ifdef SIGPWR
Raffaele Senab3b81d62010-06-09 04:08:05758# if SIGPWR != SIGLOST
Felix Geisendörferf8a3cf92010-04-28 13:04:08759 SIGNO_CASE(SIGPWR);
Raffaele Senab3b81d62010-06-09 04:08:05760# endif
Felix Geisendörferf8a3cf92010-04-28 13:04:08761#endif
762
763#ifdef SIGSYS
764 SIGNO_CASE(SIGSYS);
765#endif
766
Felix Geisendörferf8a3cf92010-04-28 13:04:08767 default: return "";
768 }
769}
770
Ryan Dahlc9e27b12010-04-23 00:53:45771
772Local<Value> ErrnoException(int errorno,
773 const char *syscall,
visionmedia45948e02010-05-14 14:52:49774 const char *msg,
775 const char *path) {
776 Local<Value> e;
Ryan Dahlc9e27b12010-04-23 00:53:45777 Local<String> estring = String::NewSymbol(errno_string(errorno));
Bert Belder2ce09612011-01-17 21:47:59778 if (!msg[0]) {
Bert Belder2ce09612011-01-17 21:47:59779 msg = strerror(errorno);
Bert Belder2ce09612011-01-17 21:47:59780 }
Ryan Dahlc9e27b12010-04-23 00:53:45781 Local<String> message = String::NewSymbol(msg);
782
783 Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
784 Local<String> cons2 = String::Concat(cons1, message);
785
Ryan Dahl6cc42922011-10-19 23:53:07786 if (syscall_symbol.IsEmpty()) {
Ryan Dahlc9e27b12010-04-23 00:53:45787 syscall_symbol = NODE_PSYMBOL("syscall");
788 errno_symbol = NODE_PSYMBOL("errno");
visionmedia45948e02010-05-14 14:52:49789 errpath_symbol = NODE_PSYMBOL("path");
Ryan Dahlaa95e572011-02-04 22:35:14790 code_symbol = NODE_PSYMBOL("code");
Ryan Dahlc9e27b12010-04-23 00:53:45791 }
792
visionmedia45948e02010-05-14 14:52:49793 if (path) {
794 Local<String> cons3 = String::Concat(cons2, String::NewSymbol(" '"));
795 Local<String> cons4 = String::Concat(cons3, String::New(path));
796 Local<String> cons5 = String::Concat(cons4, String::NewSymbol("'"));
797 e = Exception::Error(cons5);
798 } else {
799 e = Exception::Error(cons2);
800 }
801
802 Local<Object> obj = e->ToObject();
803
Ryan Dahlc9e27b12010-04-23 00:53:45804 obj->Set(errno_symbol, Integer::New(errorno));
Ryan Dahlaa95e572011-02-04 22:35:14805 obj->Set(code_symbol, estring);
visionmedia45948e02010-05-14 14:52:49806 if (path) obj->Set(errpath_symbol, String::New(path));
Ryan Dahlc9e27b12010-04-23 00:53:45807 if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
808 return e;
809}
810
811
Bert Belder823a4432011-12-01 23:02:51812static const char* get_uv_errno_string(int errorno) {
813 uv_err_t err;
814 memset(&err, 0, sizeof err);
815 err.code = (uv_err_code)errorno;
816 return uv_err_name(err);
817}
818
819
820static const char* get_uv_errno_message(int errorno) {
821 uv_err_t err;
822 memset(&err, 0, sizeof err);
823 err.code = (uv_err_code)errorno;
824 return uv_strerror(err);
825}
826
827
Shigeki Ohtsu59c39232012-02-26 12:26:09828static bool get_uv_dlerror_message(uv_lib_t lib, char* error_msg, int size) {
829 int r;
830 const char *msg;
831 if ((msg = uv_dlerror(lib)) == NULL) {
832 r = snprintf(error_msg, size, "%s", "Unable to load shared library ");
833 } else {
834 r = snprintf(error_msg, size, "%s", msg);
835 uv_dlerror_free(lib, msg);
836 }
837 // return bool if the error message be written correctly
838 return (0 < r && r < size);
839}
840
841
Bert Belder823a4432011-12-01 23:02:51842// hack alert! copy of ErrnoException, tuned for uv errors
843Local<Value> UVException(int errorno,
844 const char *syscall,
845 const char *msg,
846 const char *path) {
Bert Belder823a4432011-12-01 23:02:51847 if (syscall_symbol.IsEmpty()) {
848 syscall_symbol = NODE_PSYMBOL("syscall");
849 errno_symbol = NODE_PSYMBOL("errno");
850 errpath_symbol = NODE_PSYMBOL("path");
851 code_symbol = NODE_PSYMBOL("code");
852 }
853
854 if (!msg || !msg[0])
855 msg = get_uv_errno_message(errorno);
856
Bert Belder641f2be2011-12-02 01:14:04857 Local<String> estring = String::NewSymbol(get_uv_errno_string(errorno));
Bert Belder823a4432011-12-01 23:02:51858 Local<String> message = String::NewSymbol(msg);
859 Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
860 Local<String> cons2 = String::Concat(cons1, message);
861
862 Local<Value> e;
863
864 Local<String> path_str;
865
866 if (path) {
867#ifdef _WIN32
868 if (strncmp(path, "\\\\?\\UNC\\", 8) == 0) {
869 path_str = String::Concat(String::New("\\\\"), String::New(path + 8));
870 } else if (strncmp(path, "\\\\?\\", 4) == 0) {
871 path_str = String::New(path + 4);
872 } else {
873 path_str = String::New(path);
874 }
875#else
876 path_str = String::New(path);
877#endif
878
879 Local<String> cons3 = String::Concat(cons2, String::NewSymbol(" '"));
880 Local<String> cons4 = String::Concat(cons3, path_str);
881 Local<String> cons5 = String::Concat(cons4, String::NewSymbol("'"));
882 e = Exception::Error(cons5);
883 } else {
884 e = Exception::Error(cons2);
885 }
886
887 Local<Object> obj = e->ToObject();
888
889 // TODO errno should probably go
890 obj->Set(errno_symbol, Integer::New(errorno));
891 obj->Set(code_symbol, estring);
892 if (path) obj->Set(errpath_symbol, path_str);
893 if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
894 return e;
895}
896
897
Bert Belder6ee73a22011-11-04 15:10:48898#ifdef _WIN32
Igor Zinkovsky500c8f42011-12-15 20:36:05899// Does about the same as strerror(),
900// but supports all windows error messages
901static const char *winapi_strerror(const int errorno) {
902 char *errmsg = NULL;
903
904 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
905 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
906 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errmsg, 0, NULL);
907
908 if (errmsg) {
909 // Remove trailing newlines
910 for (int i = strlen(errmsg) - 1;
911 i >= 0 && (errmsg[i] == '\n' || errmsg[i] == '\r'); i--) {
912 errmsg[i] = '\0';
913 }
914
915 return errmsg;
916 } else {
917 // FormatMessage failed
918 return "Unknown error";
919 }
920}
921
922
Bert Belder6ee73a22011-11-04 15:10:48923Local<Value> WinapiErrnoException(int errorno,
Bert Belder829735e2011-11-04 15:23:02924 const char* syscall,
925 const char* msg,
926 const char* path) {
Bert Belder6ee73a22011-11-04 15:10:48927 Local<Value> e;
Bert Belder829735e2011-11-04 15:23:02928 if (!msg || !msg[0]) {
Bert Belder6ee73a22011-11-04 15:10:48929 msg = winapi_strerror(errorno);
930 }
931 Local<String> message = String::NewSymbol(msg);
932
933 if (syscall_symbol.IsEmpty()) {
934 syscall_symbol = NODE_PSYMBOL("syscall");
935 errno_symbol = NODE_PSYMBOL("errno");
936 errpath_symbol = NODE_PSYMBOL("path");
937 code_symbol = NODE_PSYMBOL("code");
938 }
939
940 if (path) {
941 Local<String> cons1 = String::Concat(message, String::NewSymbol(" '"));
942 Local<String> cons2 = String::Concat(cons1, String::New(path));
943 Local<String> cons3 = String::Concat(cons2, String::NewSymbol("'"));
944 e = Exception::Error(cons3);
945 } else {
946 e = Exception::Error(message);
947 }
948
949 Local<Object> obj = e->ToObject();
950
951 obj->Set(errno_symbol, Integer::New(errorno));
952 if (path) obj->Set(errpath_symbol, String::New(path));
953 if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
954 return e;
955}
956#endif
957
958
Ben Noordhuis55c65cc2010-09-24 15:02:08959Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate>& t,
960 const Arguments& args) {
961 HandleScope scope;
962
963 const int argc = args.Length();
Ryan Dahl5dd08c62010-10-09 21:21:26964 Local<Value>* argv = new Local<Value>[argc];
Ben Noordhuis55c65cc2010-09-24 15:02:08965
966 for (int i = 0; i < argc; ++i) {
967 argv[i] = args[i];
968 }
969
970 Local<Object> instance = t->GetFunction()->NewInstance(argc, argv);
Ryan Dahl5dd08c62010-10-09 21:21:26971
972 delete[] argv;
973
Ben Noordhuis55c65cc2010-09-24 15:02:08974 return scope.Close(instance);
975}
976
977
Ryan Dahl650a3082011-05-28 20:44:03978// MakeCallback may only be made directly off the event loop.
979// That is there can be no JavaScript stack frames underneath it.
980// (Is there any way to assert that?)
981//
982// Maybe make this a method of a node::Handle super class
983//
isaacsac1aadd2012-04-13 23:34:48984Handle<Value>
isaacs7407be82012-04-13 23:33:09985MakeCallback(const Handle<Object> object,
986 const char* method,
987 int argc,
988 Handle<Value> argv[]) {
989 HandleScope scope;
isaacsa26bee82012-04-12 23:03:47990
991 Handle<Value> ret =
992 MakeCallback(object, String::NewSymbol(method), argc, argv);
993
994 return scope.Close(ret);
isaacs7407be82012-04-13 23:33:09995}
996
isaacsac1aadd2012-04-13 23:34:48997Handle<Value>
isaacs7407be82012-04-13 23:33:09998MakeCallback(const Handle<Object> object,
999 const Handle<String> symbol,
1000 int argc,
1001 Handle<Value> argv[]) {
Ryan Dahl650a3082011-05-28 20:44:031002 HandleScope scope;
1003
isaacs7407be82012-04-13 23:33:091004 Local<Value> callback_v = object->Get(symbol);
Ryan Dahl26c59052011-10-07 07:57:371005 if (!callback_v->IsFunction()) {
isaacs7407be82012-04-13 23:33:091006 String::Utf8Value method(symbol);
isaacs88f94fa2012-04-17 04:27:121007 // XXX: If the object has a domain attached, handle it there?
1008 // At least, would be good to get *some* sort of indication
1009 // of how we got here, even if it's not catchable.
1010 fprintf(stderr, "Non-function in MakeCallback. method = %s\n", *method);
1011 abort();
Ryan Dahl26c59052011-10-07 07:57:371012 }
isaacs88f94fa2012-04-17 04:27:121013
Ryan Dahl650a3082011-05-28 20:44:031014 Local<Function> callback = Local<Function>::Cast(callback_v);
1015
isaacsac1aadd2012-04-13 23:34:481016 return scope.Close(MakeCallback(object, callback, argc, argv));
isaacs7407be82012-04-13 23:33:091017}
1018
isaacsac1aadd2012-04-13 23:34:481019Handle<Value>
isaacs7407be82012-04-13 23:33:091020MakeCallback(const Handle<Object> object,
1021 const Handle<Function> callback,
1022 int argc,
1023 Handle<Value> argv[]) {
1024 HandleScope scope;
1025
Ryan Dahl650a3082011-05-28 20:44:031026 // TODO Hook for long stack traces to be made here.
1027
1028 TryCatch try_catch;
1029
Ben Noordhuis636add22012-04-27 16:58:301030 if (enter_symbol.IsEmpty()) {
isaacs10ce3d12012-04-13 23:27:231031 enter_symbol = NODE_PSYMBOL("enter");
1032 exit_symbol = NODE_PSYMBOL("exit");
1033 disposed_symbol = NODE_PSYMBOL("_disposed");
1034 }
1035
1036 Local<Value> domain_v = object->Get(domain_symbol);
1037 Local<Object> domain;
1038 Local<Function> enter;
1039 Local<Function> exit;
1040 if (!domain_v->IsUndefined()) {
1041 domain = domain_v->ToObject();
1042 if (domain->Get(disposed_symbol)->BooleanValue()) {
1043 // domain has been disposed of.
1044 return Undefined();
1045 }
1046 enter = Local<Function>::Cast(domain->Get(enter_symbol));
1047 enter->Call(domain, 0, NULL);
1048 }
1049
1050 if (try_catch.HasCaught()) {
1051 FatalException(try_catch);
1052 return Undefined();
1053 }
1054
isaacsac1aadd2012-04-13 23:34:481055 Local<Value> ret = callback->Call(object, argc, argv);
Ryan Dahl650a3082011-05-28 20:44:031056
1057 if (try_catch.HasCaught()) {
1058 FatalException(try_catch);
isaacs10ce3d12012-04-13 23:27:231059 return Undefined();
1060 }
1061
1062 if (!domain_v->IsUndefined()) {
1063 exit = Local<Function>::Cast(domain->Get(exit_symbol));
1064 exit->Call(domain, 0, NULL);
1065 }
1066
1067 if (try_catch.HasCaught()) {
1068 FatalException(try_catch);
1069 return Undefined();
Ryan Dahl650a3082011-05-28 20:44:031070 }
isaacsac1aadd2012-04-13 23:34:481071
1072 return scope.Close(ret);
Ryan Dahl650a3082011-05-28 20:44:031073}
1074
1075
Ryan Dahl6cc42922011-10-19 23:53:071076void SetErrno(uv_err_t err) {
1077 HandleScope scope;
1078
1079 if (errno_symbol.IsEmpty()) {
1080 errno_symbol = NODE_PSYMBOL("errno");
1081 }
1082
1083 if (err.code == UV_UNKNOWN) {
1084 char errno_buf[100];
1085 snprintf(errno_buf, 100, "Unknown system errno %d", err.sys_errno_);
1086 Context::GetCurrent()->Global()->Set(errno_symbol, String::New(errno_buf));
1087 } else {
1088 Context::GetCurrent()->Global()->Set(errno_symbol,
1089 String::NewSymbol(uv_err_name(err)));
1090 }
Ryan Dahl650a3082011-05-28 20:44:031091}
1092
1093
Ryan Dahl07792af2009-09-21 10:27:221094enum encoding ParseEncoding(Handle<Value> encoding_v, enum encoding _default) {
1095 HandleScope scope;
1096
1097 if (!encoding_v->IsString()) return _default;
1098
ssuda249c3c12012-03-21 16:47:161099 String::Utf8Value encoding(encoding_v);
Ryan Dahl07792af2009-09-21 10:27:221100
1101 if (strcasecmp(*encoding, "utf8") == 0) {
1102 return UTF8;
Ryan Dahl2b994d92009-10-06 08:45:181103 } else if (strcasecmp(*encoding, "utf-8") == 0) {
1104 return UTF8;
Ryan Dahl07792af2009-09-21 10:27:221105 } else if (strcasecmp(*encoding, "ascii") == 0) {
1106 return ASCII;
Ben Noordhuis95638c92010-07-28 12:20:231107 } else if (strcasecmp(*encoding, "base64") == 0) {
1108 return BASE64;
Konstantin Käfer9e101f22011-02-06 20:49:521109 } else if (strcasecmp(*encoding, "ucs2") == 0) {
1110 return UCS2;
1111 } else if (strcasecmp(*encoding, "ucs-2") == 0) {
1112 return UCS2;
Ryan Dahl07792af2009-09-21 10:27:221113 } else if (strcasecmp(*encoding, "binary") == 0) {
1114 return BINARY;
isaacs0aa1a8a2011-02-20 01:29:011115 } else if (strcasecmp(*encoding, "hex") == 0) {
1116 return HEX;
Ryan Dahl07792af2009-09-21 10:27:221117 } else if (strcasecmp(*encoding, "raw") == 0) {
1118 fprintf(stderr, "'raw' (array of integers) has been removed. "
isaacsa3753b42012-05-16 23:32:371119 "Use 'binary'.\n");
Ryan Dahl07792af2009-09-21 10:27:221120 return BINARY;
1121 } else if (strcasecmp(*encoding, "raws") == 0) {
isaacsa3753b42012-05-16 23:32:371122 fprintf(stderr, "'raws' encoding has been renamed to 'binary'. "
1123 "Please update your code.\n");
Ryan Dahl07792af2009-09-21 10:27:221124 return BINARY;
1125 } else {
1126 return _default;
1127 }
1128}
1129
Ryand6c9d312009-09-11 14:02:291130Local<Value> Encode(const void *buf, size_t len, enum encoding encoding) {
Ryan21a1b042009-09-09 13:51:491131 HandleScope scope;
1132
Ryan Dahl46ebaa02010-02-22 20:07:071133 if (!len) return scope.Close(String::Empty());
Ryan21a1b042009-09-09 13:51:491134
Ryan Dahl07792af2009-09-21 10:27:221135 if (encoding == BINARY) {
Ryan88900702009-09-09 15:22:201136 const unsigned char *cbuf = static_cast<const unsigned char*>(buf);
Ryand6c9d312009-09-11 14:02:291137 uint16_t * twobytebuf = new uint16_t[len];
Ryan88900702009-09-09 15:22:201138 for (size_t i = 0; i < len; i++) {
Ryand6c9d312009-09-11 14:02:291139 // XXX is the following line platform independent?
Ryan88900702009-09-09 15:22:201140 twobytebuf[i] = cbuf[i];
1141 }
1142 Local<String> chunk = String::New(twobytebuf, len);
Ryan Dahl663deb32009-09-22 16:35:151143 delete [] twobytebuf; // TODO use ExternalTwoByteString?
Ryan88900702009-09-09 15:22:201144 return scope.Close(chunk);
1145 }
1146
Ryan21a1b042009-09-09 13:51:491147 // utf8 or ascii encoding
1148 Local<String> chunk = String::New((const char*)buf, len);
1149 return scope.Close(chunk);
1150}
1151
Ryand6c9d312009-09-11 14:02:291152// Returns -1 if the handle was not valid for decoding
1153ssize_t DecodeBytes(v8::Handle<v8::Value> val, enum encoding encoding) {
Ryan21a1b042009-09-09 13:51:491154 HandleScope scope;
1155
1156 if (val->IsArray()) {
isaacsa3753b42012-05-16 23:32:371157 fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
1158 "Use 'binary'.\n");
Ryan Dahl07792af2009-09-21 10:27:221159 assert(0);
1160 return -1;
Ryan21a1b042009-09-09 13:51:491161 }
1162
Ben Noordhuis9a79bb62012-01-08 23:45:191163 if (encoding == BINARY && Buffer::HasInstance(val)) {
1164 return Buffer::Length(val->ToObject());
1165 }
1166
Ryan Dahl07792af2009-09-21 10:27:221167 Local<String> str = val->ToString();
Ryan21a1b042009-09-09 13:51:491168
Ryand6c9d312009-09-11 14:02:291169 if (encoding == UTF8) return str->Utf8Length();
Konstantin Käfer9e101f22011-02-06 20:49:521170 else if (encoding == UCS2) return str->Length() * 2;
isaacs0aa1a8a2011-02-20 01:29:011171 else if (encoding == HEX) return str->Length() / 2;
Ryan21a1b042009-09-09 13:51:491172
Ryand6c9d312009-09-11 14:02:291173 return str->Length();
Ryan21a1b042009-09-09 13:51:491174}
1175
1176#ifndef MIN
Ryand6c9d312009-09-11 14:02:291177# define MIN(a, b) ((a) < (b) ? (a) : (b))
Ryan21a1b042009-09-09 13:51:491178#endif
1179
1180// Returns number of bytes written.
Ryan Dahl53530e92010-04-02 21:55:281181ssize_t DecodeWrite(char *buf,
1182 size_t buflen,
Ryand6c9d312009-09-11 14:02:291183 v8::Handle<v8::Value> val,
1184 enum encoding encoding) {
Ryan21a1b042009-09-09 13:51:491185 HandleScope scope;
1186
1187 // XXX
1188 // A lot of improvement can be made here. See:
1189 // http://code.google.com/p/v8/issues/detail?id=270
1190 // http://groups.google.com/group/v8-dev/browse_thread/thread/dba28a81d9215291/ece2b50a3b4022c
1191 // http://groups.google.com/group/v8-users/browse_thread/thread/1f83b0ba1f0a611
1192
1193 if (val->IsArray()) {
isaacsa3753b42012-05-16 23:32:371194 fprintf(stderr, "'raw' encoding (array of integers) has been removed. "
1195 "Use 'binary'.\n");
Ryan Dahl07792af2009-09-21 10:27:221196 assert(0);
1197 return -1;
Ryan21a1b042009-09-09 13:51:491198 }
1199
Ryan Dahl07792af2009-09-21 10:27:221200 Local<String> str = val->ToString();
Ryan21a1b042009-09-09 13:51:491201
1202 if (encoding == UTF8) {
Ryan Dahl41ef1712010-04-14 17:34:171203 str->WriteUtf8(buf, buflen, NULL, String::HINT_MANY_WRITES_EXPECTED);
Ryan21a1b042009-09-09 13:51:491204 return buflen;
1205 }
1206
Ryan88900702009-09-09 15:22:201207 if (encoding == ASCII) {
Ryan Dahl41ef1712010-04-14 17:34:171208 str->WriteAscii(buf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
Ryan88900702009-09-09 15:22:201209 return buflen;
1210 }
1211
1212 // THIS IS AWFUL!!! FIXME
1213
Ryan Dahl07792af2009-09-21 10:27:221214 assert(encoding == BINARY);
1215
Ryand6c9d312009-09-11 14:02:291216 uint16_t * twobytebuf = new uint16_t[buflen];
Ryan88900702009-09-09 15:22:201217
Ryan Dahl41ef1712010-04-14 17:34:171218 str->Write(twobytebuf, 0, buflen, String::HINT_MANY_WRITES_EXPECTED);
Ryan88900702009-09-09 15:22:201219
1220 for (size_t i = 0; i < buflen; i++) {
1221 unsigned char *b = reinterpret_cast<unsigned char*>(&twobytebuf[i]);
Ryan88900702009-09-09 15:22:201222 buf[i] = b[0];
1223 }
1224
Ryan Dahl663deb32009-09-22 16:35:151225 delete [] twobytebuf;
Ryand6c9d312009-09-11 14:02:291226
Ryan21a1b042009-09-09 13:51:491227 return buflen;
1228}
1229
Ryan5131e0a2009-03-09 00:23:411230
Ryan Dahlb57c1f52010-11-24 02:46:131231void DisplayExceptionLine (TryCatch &try_catch) {
1232 HandleScope scope;
1233
Ryan Dahlb20c3432010-02-12 05:55:081234 Handle<Message> message = try_catch.Message();
Ryan Dahlef300d12009-09-13 15:43:191235
Ryan Dahlcdf5d912011-10-11 20:41:331236 uv_tty_reset_mode();
1237
Ryan Dahlb3c03592010-07-27 02:08:211238 fprintf(stderr, "\n");
Ryan Dahl41f213b2010-05-31 18:50:351239
Ryan Dahlb57c1f52010-11-24 02:46:131240 if (!message.IsEmpty()) {
Ryan Dahl53a841d2009-12-29 19:20:511241 // Print (filename):(line number): (message).
1242 String::Utf8Value filename(message->GetScriptResourceName());
Ryan Dahlb57c1f52010-11-24 02:46:131243 const char* filename_string = *filename;
Ryan Dahl53a841d2009-12-29 19:20:511244 int linenum = message->GetLineNumber();
1245 fprintf(stderr, "%s:%i\n", filename_string, linenum);
1246 // Print line of source code.
1247 String::Utf8Value sourceline(message->GetSourceLine());
Ryan Dahlb57c1f52010-11-24 02:46:131248 const char* sourceline_string = *sourceline;
Ryan Dahlab068db2010-05-09 20:54:581249
1250 // HACK HACK HACK
1251 //
1252 // FIXME
1253 //
1254 // Because of how CommonJS modules work, all scripts are wrapped with a
1255 // "function (function (exports, __filename, ...) {"
1256 // to provide script local variables.
1257 //
1258 // When reporting errors on the first line of a script, this wrapper
1259 // function is leaked to the user. This HACK is to remove it. The length
isaacs703a1ff2011-07-29 18:56:051260 // of the wrapper is 62. That wrapper is defined in src/node.js
Ryan Dahlab068db2010-05-09 20:54:581261 //
1262 // If that wrapper is ever changed, then this number also has to be
1263 // updated. Or - someone could clean this up so that the two peices
1264 // don't need to be changed.
1265 //
1266 // Even better would be to get support into V8 for wrappers that
1267 // shouldn't be reported to users.
isaacs703a1ff2011-07-29 18:56:051268 int offset = linenum == 1 ? 62 : 0;
Ryan Dahlab068db2010-05-09 20:54:581269
1270 fprintf(stderr, "%s\n", sourceline_string + offset);
Ryan Dahl53a841d2009-12-29 19:20:511271 // Print wavy underline (GetUnderline is deprecated).
1272 int start = message->GetStartColumn();
Ryan Dahlab068db2010-05-09 20:54:581273 for (int i = offset; i < start; i++) {
Ryan Dahl53a841d2009-12-29 19:20:511274 fprintf(stderr, " ");
1275 }
1276 int end = message->GetEndColumn();
1277 for (int i = start; i < end; i++) {
1278 fprintf(stderr, "^");
1279 }
1280 fprintf(stderr, "\n");
Ryan Dahl8e6dd522010-01-15 18:45:041281 }
Ryan Dahlb57c1f52010-11-24 02:46:131282}
1283
1284
1285static void ReportException(TryCatch &try_catch, bool show_line) {
1286 HandleScope scope;
Ryan Dahlb57c1f52010-11-24 02:46:131287
1288 if (show_line) DisplayExceptionLine(try_catch);
Ryan Dahl53a841d2009-12-29 19:20:511289
Ryan Dahlda932302010-05-14 18:48:141290 String::Utf8Value trace(try_catch.StackTrace());
1291
isaacs8df6f9e2011-04-25 19:22:181292 // range errors have a trace member set to undefined
1293 if (trace.length() > 0 && !try_catch.StackTrace()->IsUndefined()) {
Ryanafd9e712009-08-31 16:22:091294 fprintf(stderr, "%s\n", *trace);
isaacse9b6b0b2010-10-02 06:22:341295 } else {
1296 // this really only happens for RangeErrors, since they're the only
isaacs8df6f9e2011-04-25 19:22:181297 // kind that won't have all this info in the trace, or when non-Error
1298 // objects are thrown manually.
isaacse9b6b0b2010-10-02 06:22:341299 Local<Value> er = try_catch.Exception();
isaacs8df6f9e2011-04-25 19:22:181300 bool isErrorObject = er->IsObject() &&
1301 !(er->ToObject()->Get(String::New("message"))->IsUndefined()) &&
1302 !(er->ToObject()->Get(String::New("name"))->IsUndefined());
1303
1304 if (isErrorObject) {
1305 String::Utf8Value name(er->ToObject()->Get(String::New("name")));
1306 fprintf(stderr, "%s: ", *name);
1307 }
1308
ssuda249c3c12012-03-21 16:47:161309 String::Utf8Value msg(!isErrorObject ? er
1310 : er->ToObject()->Get(String::New("message")));
isaacse9b6b0b2010-10-02 06:22:341311 fprintf(stderr, "%s\n", *msg);
Ryan5131e0a2009-03-09 00:23:411312 }
isaacse9b6b0b2010-10-02 06:22:341313
Ryand7e220c2009-09-09 20:35:401314 fflush(stderr);
Ryan5131e0a2009-03-09 00:23:411315}
1316
Ryand6c9d312009-09-11 14:02:291317// Executes a str within the current v8 context.
Tom Hughes74954ce2011-03-08 06:00:511318Local<Value> ExecuteString(Handle<String> source, Handle<Value> filename) {
Ryan63a9cd32009-04-15 08:08:281319 HandleScope scope;
Ryan408526a2009-04-21 11:52:211320 TryCatch try_catch;
1321
Herbert Vojcikc2a06722010-04-17 15:18:151322 Local<v8::Script> script = v8::Script::Compile(source, filename);
Ryan63a9cd32009-04-15 08:08:281323 if (script.IsEmpty()) {
Ryan Dahlab068db2010-05-09 20:54:581324 ReportException(try_catch, true);
Ryan34a6f102009-05-28 12:47:161325 exit(1);
Ryan63a9cd32009-04-15 08:08:281326 }
1327
Ryan Dahl9f5643f2010-01-31 07:22:341328 Local<Value> result = script->Run();
Ryan63a9cd32009-04-15 08:08:281329 if (result.IsEmpty()) {
Ryan Dahlab068db2010-05-09 20:54:581330 ReportException(try_catch, true);
Ryan34a6f102009-05-28 12:47:161331 exit(1);
Ryan63a9cd32009-04-15 08:08:281332 }
1333
1334 return scope.Close(result);
1335}
1336
Felix Geisendörfer7371fcb2009-11-11 17:10:581337
Ben Noordhuis5f040652012-04-28 16:45:101338static Handle<Value> GetActiveRequests(const Arguments& args) {
1339 HandleScope scope;
1340
1341 Local<Array> ary = Array::New();
1342 ngx_queue_t* q = NULL;
1343 int i = 0;
1344
1345 ngx_queue_foreach(q, &req_wrap_queue) {
1346 ReqWrap<uv_req_t>* w = container_of(q, ReqWrap<uv_req_t>, req_wrap_queue_);
1347 if (w->object_.IsEmpty()) continue;
1348 ary->Set(i++, w->object_);
1349 }
1350
1351 return scope.Close(ary);
1352}
1353
1354
1355// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
1356// implemented here for consistency with GetActiveRequests().
1357Handle<Value> GetActiveHandles(const Arguments& args) {
1358 HandleScope scope;
1359
1360 Local<Array> ary = Array::New();
1361 ngx_queue_t* q = NULL;
1362 int i = 0;
1363
Ben Noordhuise813e342012-05-15 15:24:061364 Local<String> owner_sym = String::New("owner");
1365
Ben Noordhuis5f040652012-04-28 16:45:101366 ngx_queue_foreach(q, &handle_wrap_queue) {
1367 HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_);
1368 if (w->object_.IsEmpty() || w->unref) continue;
Ben Noordhuise813e342012-05-15 15:24:061369 Local<Value> obj = w->object_->Get(owner_sym);
1370 if (obj->IsUndefined()) obj = *w->object_;
1371 ary->Set(i++, obj);
Ben Noordhuis5f040652012-04-28 16:45:101372 }
1373
1374 return scope.Close(ary);
1375}
1376
1377
Robert Mustacchi22404862011-12-15 01:02:151378static Handle<Value> Abort(const Arguments& args) {
1379 abort();
Igor Zinkovsky88cc6882011-12-16 01:18:281380 return Undefined();
Robert Mustacchi22404862011-12-15 01:02:151381}
1382
1383
Brandon Beacher47fcf782009-11-03 18:13:381384static Handle<Value> Chdir(const Arguments& args) {
1385 HandleScope scope;
Ryan Dahlb20c3432010-02-12 05:55:081386
Brandon Beacher47fcf782009-11-03 18:13:381387 if (args.Length() != 1 || !args[0]->IsString()) {
1388 return ThrowException(Exception::Error(String::New("Bad argument.")));
1389 }
Ryan Dahlb20c3432010-02-12 05:55:081390
ssuda249c3c12012-03-21 16:47:161391 String::Utf8Value path(args[0]);
Ryan Dahlb20c3432010-02-12 05:55:081392
Bert Beldere84edd22011-12-01 23:24:441393 uv_err_t r = uv_chdir(*path);
Ryan Dahlb20c3432010-02-12 05:55:081394
Bert Beldere84edd22011-12-01 23:24:441395 if (r.code != UV_OK) {
1396 return ThrowException(UVException(r.code, "uv_chdir"));
Brandon Beacher47fcf782009-11-03 18:13:381397 }
1398
1399 return Undefined();
1400}
1401
Bert Beldercbcf4fe2011-11-24 01:19:541402
Ryand6c9d312009-09-11 14:02:291403static Handle<Value> Cwd(const Arguments& args) {
Michael Carter8ea6adc2009-09-01 09:39:301404 HandleScope scope;
Bert Beldere84edd22011-12-01 23:24:441405#ifdef _WIN32
1406 /* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
1407 char buf[MAX_PATH * 4 + 1];
1408#else
1409 char buf[PATH_MAX + 1];
1410#endif
Michael Carter8ea6adc2009-09-01 09:39:301411
Bert Beldere84edd22011-12-01 23:24:441412 uv_err_t r = uv_cwd(buf, ARRAY_SIZE(buf) - 1);
1413 if (r.code != UV_OK) {
1414 return ThrowException(UVException(r.code, "uv_cwd"));
Michael Carter8ea6adc2009-09-01 09:39:301415 }
Peter Griess4e3c5d82010-07-12 15:47:451416
Bert Beldere84edd22011-12-01 23:24:441417 buf[ARRAY_SIZE(buf) - 1] = '\0';
1418 Local<String> cwd = String::New(buf);
Michael Carter8ea6adc2009-09-01 09:39:301419
1420 return scope.Close(cwd);
1421}
1422
Bert Beldere84edd22011-12-01 23:24:441423
Ryan Dahlacc120a2011-08-09 20:53:561424static Handle<Value> Umask(const Arguments& args) {
Friedemann Altrock0433d822009-11-22 18:52:521425 HandleScope scope;
Rasmus Andersson374300c2010-02-27 17:18:411426 unsigned int old;
isaacs5f2e9092011-01-25 18:40:121427
Ryan Dahlacc120a2011-08-09 20:53:561428 if (args.Length() < 1 || args[0]->IsUndefined()) {
Rasmus Andersson374300c2010-02-27 17:18:411429 old = umask(0);
1430 umask((mode_t)old);
isaacs5f2e9092011-01-25 18:40:121431
1432 } else if(!args[0]->IsInt32() && !args[0]->IsString()) {
Friedemann Altrock0433d822009-11-22 18:52:521433 return ThrowException(Exception::TypeError(
isaacs5f2e9092011-01-25 18:40:121434 String::New("argument must be an integer or octal string.")));
1435
1436 } else {
1437 int oct;
1438 if(args[0]->IsInt32()) {
1439 oct = args[0]->Uint32Value();
1440 } else {
1441 oct = 0;
1442 String::Utf8Value str(args[0]);
1443
1444 // Parse the octal string.
1445 for (int i = 0; i < str.length(); i++) {
1446 char c = (*str)[i];
1447 if (c > '7' || c < '0') {
1448 return ThrowException(Exception::TypeError(
1449 String::New("invalid octal string")));
1450 }
1451 oct *= 8;
1452 oct += c - '0';
1453 }
1454 }
1455 old = umask(static_cast<mode_t>(oct));
Friedemann Altrock0433d822009-11-22 18:52:521456 }
isaacs5f2e9092011-01-25 18:40:121457
Friedemann Altrock0433d822009-11-22 18:52:521458 return scope.Close(Uint32::New(old));
1459}
1460
Michael Cartera3860762010-02-08 06:13:101461
Ryan Dahlacc120a2011-08-09 20:53:561462#ifdef __POSIX__
1463
Michael Cartera3860762010-02-08 06:13:101464static Handle<Value> GetUid(const Arguments& args) {
1465 HandleScope scope;
1466 int uid = getuid();
1467 return scope.Close(Integer::New(uid));
1468}
1469
Ryan Dahlacc120a2011-08-09 20:53:561470
James Duncandf1c1e52010-02-23 22:45:021471static Handle<Value> GetGid(const Arguments& args) {
1472 HandleScope scope;
1473 int gid = getgid();
1474 return scope.Close(Integer::New(gid));
1475}
1476
1477
1478static Handle<Value> SetGid(const Arguments& args) {
1479 HandleScope scope;
Ryan Dahl39943402010-03-15 19:49:401480
James Duncandf1c1e52010-02-23 22:45:021481 if (args.Length() < 1) {
1482 return ThrowException(Exception::Error(
Ryan Dahl39943402010-03-15 19:49:401483 String::New("setgid requires 1 argument")));
James Duncandf1c1e52010-02-23 22:45:021484 }
1485
Peter Griess2420f072010-05-19 00:40:441486 int gid;
Blake Mizerany8c853402010-06-30 06:12:461487
Peter Griess2420f072010-05-19 00:40:441488 if (args[0]->IsNumber()) {
1489 gid = args[0]->Int32Value();
1490 } else if (args[0]->IsString()) {
ssuda249c3c12012-03-21 16:47:161491 String::Utf8Value grpnam(args[0]);
Peter Griess2420f072010-05-19 00:40:441492 struct group grp, *grpp = NULL;
1493 int err;
1494
Peter Griess4e3c5d82010-07-12 15:47:451495 if ((err = getgrnam_r(*grpnam, &grp, getbuf, ARRAY_SIZE(getbuf), &grpp)) ||
Peter Griess2420f072010-05-19 00:40:441496 grpp == NULL) {
Brian White52b9ede2011-03-18 05:39:391497 if (errno == 0)
1498 return ThrowException(Exception::Error(
1499 String::New("setgid group id does not exist")));
1500 else
1501 return ThrowException(ErrnoException(errno, "getgrnam_r"));
Peter Griess2420f072010-05-19 00:40:441502 }
1503
1504 gid = grpp->gr_gid;
1505 } else {
1506 return ThrowException(Exception::Error(
1507 String::New("setgid argument must be a number or a string")));
1508 }
1509
James Duncandf1c1e52010-02-23 22:45:021510 int result;
isaacs0dba38e2010-03-03 09:11:471511 if ((result = setgid(gid)) != 0) {
Peter Griess2420f072010-05-19 00:40:441512 return ThrowException(ErrnoException(errno, "setgid"));
James Duncandf1c1e52010-02-23 22:45:021513 }
1514 return Undefined();
1515}
Michael Cartera3860762010-02-08 06:13:101516
Ryan Dahlacc120a2011-08-09 20:53:561517
Michael Cartera3860762010-02-08 06:13:101518static Handle<Value> SetUid(const Arguments& args) {
1519 HandleScope scope;
1520
1521 if (args.Length() < 1) {
1522 return ThrowException(Exception::Error(
1523 String::New("setuid requires 1 argument")));
1524 }
1525
Peter Griess2420f072010-05-19 00:40:441526 int uid;
1527
1528 if (args[0]->IsNumber()) {
1529 uid = args[0]->Int32Value();
1530 } else if (args[0]->IsString()) {
ssuda249c3c12012-03-21 16:47:161531 String::Utf8Value pwnam(args[0]);
Peter Griess2420f072010-05-19 00:40:441532 struct passwd pwd, *pwdp = NULL;
1533 int err;
1534
Peter Griess4e3c5d82010-07-12 15:47:451535 if ((err = getpwnam_r(*pwnam, &pwd, getbuf, ARRAY_SIZE(getbuf), &pwdp)) ||
Peter Griess2420f072010-05-19 00:40:441536 pwdp == NULL) {
Brian White52b9ede2011-03-18 05:39:391537 if (errno == 0)
1538 return ThrowException(Exception::Error(
1539 String::New("setuid user id does not exist")));
1540 else
1541 return ThrowException(ErrnoException(errno, "getpwnam_r"));
Peter Griess2420f072010-05-19 00:40:441542 }
1543
1544 uid = pwdp->pw_uid;
1545 } else {
1546 return ThrowException(Exception::Error(
1547 String::New("setuid argument must be a number or a string")));
1548 }
1549
Michael Cartera3860762010-02-08 06:13:101550 int result;
1551 if ((result = setuid(uid)) != 0) {
Peter Griess2420f072010-05-19 00:40:441552 return ThrowException(ErrnoException(errno, "setuid"));
Michael Cartera3860762010-02-08 06:13:101553 }
1554 return Undefined();
1555}
1556
Ryan Dahlacc120a2011-08-09 20:53:561557
Bert Belder30bab522010-11-25 00:09:061558#endif // __POSIX__
1559
Michael Cartera3860762010-02-08 06:13:101560
Ryand6c9d312009-09-11 14:02:291561v8::Handle<v8::Value> Exit(const v8::Arguments& args) {
Ryan Dahl6f92d8f2010-02-08 05:59:561562 HandleScope scope;
Ryan Dahl6f92d8f2010-02-08 05:59:561563 exit(args[0]->IntegerValue());
Ryan116f4de2009-08-26 20:03:191564 return Undefined();
Ryan0f517032009-04-29 09:09:321565}
1566
Ryan Dahl3ac6dee2010-05-08 02:05:591567
Ryan Dahlf657d582011-06-22 12:06:261568static void CheckStatus(uv_timer_t* watcher, int status) {
1569 assert(watcher == &gc_timer);
Ryan Dahl3ac6dee2010-05-08 02:05:591570
Ryan Dahl3ac6dee2010-05-08 02:05:591571 // check memory
Ryan Dahl7a5977b2011-06-07 16:37:271572 if (!uv_is_active((uv_handle_t*) &gc_idle)) {
Ryan Dahlaeed9662011-03-18 18:39:441573 HeapStatistics stats;
1574 V8::GetHeapStatistics(&stats);
1575 if (stats.total_heap_size() > 1024 * 1024 * 128) {
Ryan Dahl3ac6dee2010-05-08 02:05:591576 // larger than 128 megs, just start the idle watcher
Ryan Dahl7547c7d2011-12-07 01:00:331577 uv_idle_start(&gc_idle, node::Idle);
Ryan Dahl3ac6dee2010-05-08 02:05:591578 return;
1579 }
1580 }
Ryan Dahl3ac6dee2010-05-08 02:05:591581
Ben Noordhuis74a82152012-02-03 15:32:001582 double d = uv_now(uv_default_loop()) - TICK_TIME(3);
Ryan Dahl3ac6dee2010-05-08 02:05:591583
1584 //printfb("timer d = %f\n", d);
1585
1586 if (d >= GC_WAIT_TIME - 1.) {
1587 //fprintf(stderr, "start idle\n");
Ryan Dahl7547c7d2011-12-07 01:00:331588 uv_idle_start(&gc_idle, node::Idle);
Ryan Dahl3ac6dee2010-05-08 02:05:591589 }
1590}
1591
Igor Zinkovsky500c8f42011-12-15 20:36:051592
Tom Hughescf78ce52011-03-04 23:57:541593static Handle<Value> Uptime(const Arguments& args) {
1594 HandleScope scope;
Igor Zinkovsky500c8f42011-12-15 20:36:051595 double uptime;
Tom Hughescf78ce52011-03-04 23:57:541596
Igor Zinkovsky500c8f42011-12-15 20:36:051597 uv_err_t err = uv_uptime(&uptime);
Tom Hughescf78ce52011-03-04 23:57:541598
Igor Zinkovsky500c8f42011-12-15 20:36:051599 if (err.code != UV_OK) {
Tom Hughescf78ce52011-03-04 23:57:541600 return Undefined();
1601 }
1602
Igor Zinkovsky500c8f42011-12-15 20:36:051603 return scope.Close(Number::New(uptime - prog_start_time));
Tom Hughescf78ce52011-03-04 23:57:541604}
Ryan Dahl3ac6dee2010-05-08 02:05:591605
Ryan Dahlc344fbc2011-10-06 21:59:381606
1607v8::Handle<v8::Value> UVCounters(const v8::Arguments& args) {
1608 HandleScope scope;
1609
Ben Noordhuis74a82152012-02-03 15:32:001610 uv_counters_t* c = &uv_default_loop()->counters;
Ryan Dahlc344fbc2011-10-06 21:59:381611
1612 Local<Object> obj = Object::New();
1613
Bert Belder889620d2011-10-28 09:34:531614#define setc(name) \
1615 obj->Set(String::New(#name), Integer::New(static_cast<int32_t>(c->name)));
Ryan Dahlc344fbc2011-10-06 21:59:381616
1617 setc(eio_init)
1618 setc(req_init)
1619 setc(handle_init)
1620 setc(stream_init)
1621 setc(tcp_init)
1622 setc(udp_init)
1623 setc(pipe_init)
1624 setc(tty_init)
1625 setc(prepare_init)
1626 setc(check_init)
1627 setc(idle_init)
1628 setc(async_init)
1629 setc(timer_init)
1630 setc(process_init)
1631 setc(fs_event_init)
1632
1633#undef setc
1634
1635 return scope.Close(obj);
1636}
1637
1638
Ryan Dahlb3b3cfe2009-11-03 12:00:421639v8::Handle<v8::Value> MemoryUsage(const v8::Arguments& args) {
1640 HandleScope scope;
1641
Ryan Dahl5783a522011-10-18 21:30:311642 size_t rss;
Ryan Dahlb3b3cfe2009-11-03 12:00:421643
Igor Zinkovsky500c8f42011-12-15 20:36:051644 uv_err_t err = uv_resident_set_memory(&rss);
Ryan Dahlb3b3cfe2009-11-03 12:00:421645
Igor Zinkovsky500c8f42011-12-15 20:36:051646 if (err.code != UV_OK) {
1647 return ThrowException(UVException(err.code, "uv_resident_set_memory"));
Ryan Dahl3a701292009-11-03 00:30:011648 }
1649
Ryan Dahl3a701292009-11-03 00:30:011650 Local<Object> info = Object::New();
1651
Ryan Dahl45a806a2009-12-09 08:02:211652 if (rss_symbol.IsEmpty()) {
1653 rss_symbol = NODE_PSYMBOL("rss");
Ryan Dahl45a806a2009-12-09 08:02:211654 heap_total_symbol = NODE_PSYMBOL("heapTotal");
1655 heap_used_symbol = NODE_PSYMBOL("heapUsed");
1656 }
1657
Russ Bradberry754e23d2011-11-29 22:28:221658 info->Set(rss_symbol, Number::New(rss));
Ryan Dahl3a701292009-11-03 00:30:011659
Ryan Dahl38e425d2009-11-28 15:31:291660 // V8 memory usage
1661 HeapStatistics v8_heap_stats;
1662 V8::GetHeapStatistics(&v8_heap_stats);
Ryan Dahl45a806a2009-12-09 08:02:211663 info->Set(heap_total_symbol,
Ryan Dahl38e425d2009-11-28 15:31:291664 Integer::NewFromUnsigned(v8_heap_stats.total_heap_size()));
Ryan Dahl45a806a2009-12-09 08:02:211665 info->Set(heap_used_symbol,
Ryan Dahl38e425d2009-11-28 15:31:291666 Integer::NewFromUnsigned(v8_heap_stats.used_heap_size()));
1667
Ryan Dahl3a701292009-11-03 00:30:011668 return scope.Close(info);
1669}
Ryan Dahlb3b3cfe2009-11-03 12:00:421670
Bert Belder4a2cb072010-11-29 17:40:141671
Ryan Dahl6eca9482010-09-17 06:13:031672Handle<Value> Kill(const Arguments& args) {
Brandon Beacher334d56d2009-10-14 21:56:121673 HandleScope scope;
Ryan Dahlb20c3432010-02-12 05:55:081674
Ryan Dahl4227e9d2010-12-21 23:40:101675 if (args.Length() != 2) {
Brandon Beacher334d56d2009-10-14 21:56:121676 return ThrowException(Exception::Error(String::New("Bad argument.")));
1677 }
Ryan Dahlb20c3432010-02-12 05:55:081678
Igor Zinkovsky24a69d22011-11-02 22:06:481679 int pid = args[0]->IntegerValue();
Ryan Dahl6eca9482010-09-17 06:13:031680 int sig = args[1]->Int32Value();
Igor Zinkovsky24a69d22011-11-02 22:06:481681 uv_err_t err = uv_kill(pid, sig);
Brandon Beacher334d56d2009-10-14 21:56:121682
Igor Zinkovsky24a69d22011-11-02 22:06:481683 if (err.code != UV_OK) {
1684 SetErrno(err);
1685 return scope.Close(Integer::New(-1));
1686 }
Brandon Beacher334d56d2009-10-14 21:56:121687
1688 return Undefined();
1689}
1690
Nathan Rajlich07c886f2012-03-05 16:51:581691// used in Hrtime() below
1692#define NANOS_PER_SEC 1000000000
1693
1694// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
1695// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
1696// so this function instead returns an Array with 2 entries representing seconds
1697// and nanoseconds, to avoid any integer overflow possibility.
1698// Pass in an Array from a previous hrtime() call to instead get a time diff.
1699Handle<Value> Hrtime(const v8::Arguments& args) {
1700 HandleScope scope;
1701
1702 uint64_t t = uv_hrtime();
1703
1704 if (args.Length() > 0) {
1705 // return a time diff tuple
1706 Local<Array> inArray = Local<Array>::Cast(args[0]);
1707 uint64_t seconds = inArray->Get(0)->Uint32Value();
1708 uint64_t nanos = inArray->Get(1)->Uint32Value();
1709 t -= (seconds * NANOS_PER_SEC) + nanos;
1710 }
1711
1712 Local<Array> tuple = Array::New(2);
1713 tuple->Set(0, Integer::NewFromUnsigned(t / NANOS_PER_SEC));
1714 tuple->Set(1, Integer::NewFromUnsigned(t % NANOS_PER_SEC));
1715
1716 return scope.Close(tuple);
1717}
1718
Bert Belderdd93c532011-10-28 10:05:091719
1720typedef void (UV_DYNAMIC* extInit)(Handle<Object> exports);
Ryan2b6d7242009-06-20 13:07:101721
Ryan Dahl38814552009-10-09 15:15:471722// DLOpen is node.dlopen(). Used to load 'module.node' dynamically shared
1723// objects.
Ryand6c9d312009-09-11 14:02:291724Handle<Value> DLOpen(const v8::Arguments& args) {
Ryan2b6d7242009-06-20 13:07:101725 HandleScope scope;
Bert Belderdd93c532011-10-28 10:05:091726 char symbol[1024], *base, *pos;
1727 uv_lib_t lib;
1728 node_module_struct compat_mod;
1729 uv_err_t err;
1730 int r;
Ryan2b6d7242009-06-20 13:07:101731
Bert Belderdd93c532011-10-28 10:05:091732 if (args.Length() < 2) {
Bert Belder35f41822011-11-04 15:11:391733 Local<Value> exception = Exception::Error(
1734 String::New("process.dlopen takes exactly 2 arguments."));
1735 return ThrowException(exception);
Bert Belderdd93c532011-10-28 10:05:091736 }
Ryana97dce72009-08-31 09:14:341737
ssuda249c3c12012-03-21 16:47:161738 String::Utf8Value filename(args[0]); // Cast
Ryan Dahl38814552009-10-09 15:15:471739 Local<Object> target = args[1]->ToObject(); // Cast
Ryan2b6d7242009-06-20 13:07:101740
Bert Belderdd93c532011-10-28 10:05:091741 err = uv_dlopen(*filename, &lib);
1742 if (err.code != UV_OK) {
Shigeki Ohtsu59c39232012-02-26 12:26:091743 // Retrieve uv_dlerror() message and throw exception with it
1744 char dlerror_msg[1024];
1745 if (!get_uv_dlerror_message(lib, dlerror_msg, sizeof dlerror_msg)) {
1746 Local<Value> exception = Exception::Error(
1747 String::New("Cannot retrieve an error message in process.dlopen"));
1748 return ThrowException(exception);
1749 }
1750#ifdef __POSIX__
1751 Local<Value> exception = Exception::Error(String::New(dlerror_msg));
1752#else // Windows needs to add the filename into the error message
Bert Belder35f41822011-11-04 15:11:391753 Local<Value> exception = Exception::Error(
Shigeki Ohtsu59c39232012-02-26 12:26:091754 String::Concat(String::New(dlerror_msg), args[0]->ToString()));
1755#endif
Bert Belder35f41822011-11-04 15:11:391756 return ThrowException(exception);
Ryan2b6d7242009-06-20 13:07:101757 }
1758
ssuda249c3c12012-03-21 16:47:161759 String::Utf8Value path(args[0]);
Bert Belderdd93c532011-10-28 10:05:091760 base = *path;
Paul Querna367b87d2010-07-13 08:33:511761
Bert Belderdd93c532011-10-28 10:05:091762 /* Find the shared library filename within the full path. */
1763#ifdef __POSIX__
1764 pos = strrchr(base, '/');
1765 if (pos != NULL) {
Ben Noordhuisa1fa3ef2011-10-30 16:33:421766 base = pos + 1;
Bert Belderdd93c532011-10-28 10:05:091767 }
1768#else // Windows
1769 for (;;) {
1770 pos = strpbrk(base, "\\/:");
1771 if (pos == NULL) {
1772 break;
Paul Querna367b87d2010-07-13 08:33:511773 }
Bert Belderdd93c532011-10-28 10:05:091774 base = pos + 1;
1775 }
1776#endif
Paul Querna367b87d2010-07-13 08:33:511777
Bert Belderdd93c532011-10-28 10:05:091778 /* Strip the .node extension. */
1779 pos = strrchr(base, '.');
1780 if (pos != NULL) {
1781 *pos = '\0';
1782 }
1783
1784 /* Add the `_module` suffix to the extension name. */
1785 r = snprintf(symbol, sizeof symbol, "%s_module", base);
Ben Noordhuis8c97ad42012-03-30 12:41:431786 if (r <= 0 || static_cast<size_t>(r) >= sizeof symbol) {
Bert Belder35f41822011-11-04 15:11:391787 Local<Value> exception =
1788 Exception::Error(String::New("Out of memory."));
1789 return ThrowException(exception);
Paul Querna367b87d2010-07-13 08:33:511790 }
1791
Ryan Dahl38814552009-10-09 15:15:471792 // Get the init() function from the dynamically shared object.
Bert Belderdd93c532011-10-28 10:05:091793 node_module_struct *mod;
1794 err = uv_dlsym(lib, symbol, reinterpret_cast<void**>(&mod));
Ben Noordhuiseaac8812011-08-13 23:25:391795
Bert Belderdd93c532011-10-28 10:05:091796 if (err.code != UV_OK) {
Paul Querna367b87d2010-07-13 08:33:511797 /* Start Compatibility hack: Remove once everyone is using NODE_MODULE macro */
Ben Noordhuiseaac8812011-08-13 23:25:391798 memset(&compat_mod, 0, sizeof compat_mod);
1799
Paul Querna367b87d2010-07-13 08:33:511800 mod = &compat_mod;
1801 mod->version = NODE_MODULE_VERSION;
1802
Bert Belderdd93c532011-10-28 10:05:091803 err = uv_dlsym(lib, "init", reinterpret_cast<void**>(&mod->register_func));
1804 if (err.code != UV_OK) {
1805 uv_dlclose(lib);
Ben Noordhuis216019b2011-11-27 21:38:541806
1807 const char* message;
1808 if (err.code == UV_ENOENT)
1809 message = "Module entry point not found.";
1810 else
Ben Noordhuis4b455ba2011-12-18 21:27:211811 message = uv_strerror(err);
Ben Noordhuis216019b2011-11-27 21:38:541812
1813 return ThrowException(Exception::Error(String::New(message)));
Paul Querna367b87d2010-07-13 08:33:511814 }
Paul Querna367b87d2010-07-13 08:33:511815 /* End Compatibility hack */
1816 }
1817
1818 if (mod->version != NODE_MODULE_VERSION) {
Bert Belder35f41822011-11-04 15:11:391819 Local<Value> exception = Exception::Error(
1820 String::New("Module version mismatch, refusing to load."));
Ryan3862fda2009-08-31 16:48:471821 return ThrowException(exception);
Ryan2b6d7242009-06-20 13:07:101822 }
Ryan2b6d7242009-06-20 13:07:101823
Ryan Dahl38814552009-10-09 15:15:471824 // Execute the C++ module
Paul Querna367b87d2010-07-13 08:33:511825 mod->register_func(target);
Ryan2b6d7242009-06-20 13:07:101826
Peter Griess4e3c5d82010-07-12 15:47:451827 // Tell coverity that 'handle' should not be freed when we return.
1828 // coverity[leaked_storage]
Ryan2b6d7242009-06-20 13:07:101829 return Undefined();
1830}
1831
Tim-Smartae10a482010-03-12 08:36:001832
Ryand6c9d312009-09-11 14:02:291833static void OnFatalError(const char* location, const char* message) {
Ryan Dahl53a841d2009-12-29 19:20:511834 if (location) {
1835 fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
1836 } else {
1837 fprintf(stderr, "FATAL ERROR: %s\n", message);
1838 }
Ryan34a6f102009-05-28 12:47:161839 exit(1);
Ryan63a9cd32009-04-15 08:08:281840}
1841
Ryand6c9d312009-09-11 14:02:291842void FatalException(TryCatch &try_catch) {
Felix Geisendörfer2b252ac2009-11-14 22:07:541843 HandleScope scope;
1844
Ryan Dahl45a806a2009-12-09 08:02:211845 if (listeners_symbol.IsEmpty()) {
1846 listeners_symbol = NODE_PSYMBOL("listeners");
1847 uncaught_exception_symbol = NODE_PSYMBOL("uncaughtException");
1848 emit_symbol = NODE_PSYMBOL("emit");
1849 }
1850
1851 Local<Value> listeners_v = process->Get(listeners_symbol);
Felix Geisendörfer2b252ac2009-11-14 22:07:541852 assert(listeners_v->IsFunction());
1853
1854 Local<Function> listeners = Local<Function>::Cast(listeners_v);
1855
Ryan Dahl45a806a2009-12-09 08:02:211856 Local<String> uncaught_exception_symbol_l = Local<String>::New(uncaught_exception_symbol);
1857 Local<Value> argv[1] = { uncaught_exception_symbol_l };
Felix Geisendörfer2b252ac2009-11-14 22:07:541858 Local<Value> ret = listeners->Call(process, 1, argv);
1859
1860 assert(ret->IsArray());
1861
1862 Local<Array> listener_array = Local<Array>::Cast(ret);
1863
1864 uint32_t length = listener_array->Length();
1865 // Report and exit if process has no "uncaughtException" listener
1866 if (length == 0) {
Ryan Dahlab068db2010-05-09 20:54:581867 ReportException(try_catch, true);
Felix Geisendörfer2b252ac2009-11-14 22:07:541868 exit(1);
1869 }
1870
1871 // Otherwise fire the process "uncaughtException" event
Ryan Dahl45a806a2009-12-09 08:02:211872 Local<Value> emit_v = process->Get(emit_symbol);
Felix Geisendörfer2b252ac2009-11-14 22:07:541873 assert(emit_v->IsFunction());
1874
1875 Local<Function> emit = Local<Function>::Cast(emit_v);
1876
1877 Local<Value> error = try_catch.Exception();
Ryan Dahl45a806a2009-12-09 08:02:211878 Local<Value> event_argv[2] = { uncaught_exception_symbol_l, error };
Felix Geisendörfer2b252ac2009-11-14 22:07:541879
isaacs80a55e92012-04-07 02:23:161880 TryCatch event_try_catch;
Felix Geisendörfer2b252ac2009-11-14 22:07:541881 emit->Call(process, 2, event_argv);
isaacs07be9fc2012-05-09 22:12:131882
isaacs80a55e92012-04-07 02:23:161883 if (event_try_catch.HasCaught()) {
1884 // the uncaught exception event threw, so we must exit.
1885 ReportException(event_try_catch, true);
1886 exit(1);
1887 }
Felix Geisendörfer81403332012-05-08 14:07:141888
1889 // This makes sure uncaught exceptions don't interfere with process.nextTick
1890 StartTickSpinner();
Ryane78917b2009-03-09 13:08:311891}
1892
Ryan0e9e9272009-04-04 14:53:431893
Ben Noordhuis74a82152012-02-03 15:32:001894Persistent<Object> binding_cache;
1895Persistent<Array> module_load_list;
1896
Ryan Dahl627fb5a2010-03-15 20:48:031897static Handle<Value> Binding(const Arguments& args) {
1898 HandleScope scope;
1899
1900 Local<String> module = args[0]->ToString();
1901 String::Utf8Value module_v(module);
Paul Querna30dadfc2010-07-14 06:22:411902 node_module_struct* modp;
Ryan Dahl627fb5a2010-03-15 20:48:031903
1904 if (binding_cache.IsEmpty()) {
1905 binding_cache = Persistent<Object>::New(Object::New());
1906 }
1907
1908 Local<Object> exports;
1909
Paul Querna30dadfc2010-07-14 06:22:411910 if (binding_cache->Has(module)) {
1911 exports = binding_cache->Get(module)->ToObject();
Ryan Dahlea9ee1f2011-07-28 02:30:321912 return scope.Close(exports);
1913 }
Ryan Dahl6eca9482010-09-17 06:13:031914
Ryan Dahlea9ee1f2011-07-28 02:30:321915 // Append a string to process.moduleLoadList
1916 char buf[1024];
1917 snprintf(buf, 1024, "Binding %s", *module_v);
1918 uint32_t l = module_load_list->Length();
1919 module_load_list->Set(l, String::New(buf));
1920
1921 if ((modp = get_builtin_module(*module_v)) != NULL) {
Paul Querna30dadfc2010-07-14 06:22:411922 exports = Object::New();
1923 modp->register_func(exports);
1924 binding_cache->Set(module, exports);
Ryan Dahl6eca9482010-09-17 06:13:031925
1926 } else if (!strcmp(*module_v, "constants")) {
1927 exports = Object::New();
1928 DefineConstants(exports);
1929 binding_cache->Set(module, exports);
1930
Igor Zinkovskyf35a3962011-10-28 22:34:241931#ifdef __POSIX__
1932 } else if (!strcmp(*module_v, "io_watcher")) {
1933 exports = Object::New();
1934 IOWatcher::Initialize(exports);
1935 binding_cache->Set(module, exports);
1936#endif
1937
Ryan Dahlc90546f2010-03-15 21:22:501938 } else if (!strcmp(*module_v, "natives")) {
Paul Querna8dbfe5e2010-07-14 06:32:381939 exports = Object::New();
Ryan Dahlc4636a52010-10-12 18:49:411940 DefineJavaScript(exports);
Paul Querna8dbfe5e2010-07-14 06:32:381941 binding_cache->Set(module, exports);
Ryan Dahlc4636a52010-10-12 18:49:411942
Ryan Dahl627fb5a2010-03-15 20:48:031943 } else {
Ryan Dahl6eca9482010-09-17 06:13:031944
Ryan Dahl627fb5a2010-03-15 20:48:031945 return ThrowException(Exception::Error(String::New("No such module")));
1946 }
1947
1948 return scope.Close(exports);
1949}
1950
Ryan Dahle742d072009-10-09 11:25:041951
Ryan Dahl5185c152010-06-18 07:26:491952static Handle<Value> ProcessTitleGetter(Local<String> property,
1953 const AccessorInfo& info) {
1954 HandleScope scope;
Igor Zinkovsky500c8f42011-12-15 20:36:051955 char buffer[512];
1956 uv_get_process_title(buffer, sizeof(buffer));
1957 return scope.Close(String::New(buffer));
Ryan Dahl5185c152010-06-18 07:26:491958}
1959
1960
1961static void ProcessTitleSetter(Local<String> property,
1962 Local<Value> value,
1963 const AccessorInfo& info) {
1964 HandleScope scope;
ssuda249c3c12012-03-21 16:47:161965 String::Utf8Value title(value);
Igor Zinkovsky500c8f42011-12-15 20:36:051966 // TODO: protect with a lock
1967 uv_set_process_title(*title);
Ryan Dahl5185c152010-06-18 07:26:491968}
1969
1970
Ben Noordhuisb4def482010-10-15 13:48:341971static Handle<Value> EnvGetter(Local<String> property,
1972 const AccessorInfo& info) {
Bert Belder077f9d72012-02-15 22:34:181973 HandleScope scope;
1974#ifdef __POSIX__
Ben Noordhuisb4def482010-10-15 13:48:341975 String::Utf8Value key(property);
1976 const char* val = getenv(*key);
1977 if (val) {
Ben Noordhuisb4def482010-10-15 13:48:341978 return scope.Close(String::New(val));
1979 }
Bert Belder077f9d72012-02-15 22:34:181980#else // _WIN32
1981 String::Value key(property);
1982 WCHAR buffer[32767]; // The maximum size allowed for environment variables.
1983 DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
1984 buffer,
1985 ARRAY_SIZE(buffer));
1986 // If result >= sizeof buffer the buffer was too small. That should never
1987 // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
1988 // not found.
1989 if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
1990 result < ARRAY_SIZE(buffer)) {
1991 return scope.Close(String::New(reinterpret_cast<uint16_t*>(buffer), result));
1992 }
1993#endif
1994 // Not found
Ben Noordhuisb4def482010-10-15 13:48:341995 return Undefined();
1996}
1997
1998
1999static Handle<Value> EnvSetter(Local<String> property,
2000 Local<Value> value,
2001 const AccessorInfo& info) {
Ryan Dahle6b06bc2011-08-11 00:14:232002 HandleScope scope;
Bert Belder077f9d72012-02-15 22:34:182003#ifdef __POSIX__
Ben Noordhuisb4def482010-10-15 13:48:342004 String::Utf8Value key(property);
2005 String::Utf8Value val(value);
2006 setenv(*key, *val, 1);
Bert Belder077f9d72012-02-15 22:34:182007#else // _WIN32
2008 String::Value key(property);
2009 String::Value val(value);
2010 WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
2011 // Environment variables that start with '=' are read-only.
2012 if (key_ptr[0] != L'=') {
2013 SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
Ryan Dahle6b06bc2011-08-11 00:14:232014 }
Bert Belder30bab522010-11-25 00:09:062015#endif
Bert Belder077f9d72012-02-15 22:34:182016 // Whether it worked or not, always return rval.
2017 return scope.Close(value);
Ben Noordhuisb4def482010-10-15 13:48:342018}
2019
2020
2021static Handle<Integer> EnvQuery(Local<String> property,
2022 const AccessorInfo& info) {
Bert Belder077f9d72012-02-15 22:34:182023 HandleScope scope;
2024#ifdef __POSIX__
Ben Noordhuisb4def482010-10-15 13:48:342025 String::Utf8Value key(property);
2026 if (getenv(*key)) {
Ben Noordhuisb4def482010-10-15 13:48:342027 return scope.Close(Integer::New(None));
2028 }
Bert Belder077f9d72012-02-15 22:34:182029#else // _WIN32
2030 String::Value key(property);
2031 WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
2032 if (GetEnvironmentVariableW(key_ptr, NULL, 0) > 0 ||
2033 GetLastError() == ERROR_SUCCESS) {
2034 if (key_ptr[0] == L'=') {
2035 // Environment variables that start with '=' are hidden and read-only.
2036 return scope.Close(Integer::New(v8::ReadOnly ||
2037 v8::DontDelete ||
2038 v8::DontEnum));
2039 } else {
2040 return scope.Close(Integer::New(None));
2041 }
2042 }
2043#endif
2044 // Not found
2045 return scope.Close(Handle<Integer>());
Ben Noordhuisb4def482010-10-15 13:48:342046}
2047
2048
2049static Handle<Boolean> EnvDeleter(Local<String> property,
2050 const AccessorInfo& info) {
Ryan Dahle6b06bc2011-08-11 00:14:232051 HandleScope scope;
Bert Belder30bab522010-11-25 00:09:062052#ifdef __POSIX__
Bert Belder077f9d72012-02-15 22:34:182053 String::Utf8Value key(property);
Ben Noordhuisdee8c512012-03-31 21:23:462054 if (!getenv(*key)) return False();
2055 unsetenv(*key); // can't check return value, it's void on some platforms
2056 return True();
Bert Belder30bab522010-11-25 00:09:062057#else
Bert Belder077f9d72012-02-15 22:34:182058 String::Value key(property);
2059 WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
2060 if (key_ptr[0] == L'=' || !SetEnvironmentVariableW(key_ptr, NULL)) {
2061 // Deletion failed. Return true if the key wasn't there in the first place,
2062 // false if it is still there.
2063 bool rv = GetEnvironmentVariableW(key_ptr, NULL, NULL) == 0 &&
2064 GetLastError() != ERROR_SUCCESS;
2065 return scope.Close(Boolean::New(rv));
Ben Noordhuisb4def482010-10-15 13:48:342066 }
Ben Noordhuisdee8c512012-03-31 21:23:462067 return True();
Bert Belder077f9d72012-02-15 22:34:182068#endif
Ben Noordhuisb4def482010-10-15 13:48:342069}
2070
2071
2072static Handle<Array> EnvEnumerator(const AccessorInfo& info) {
2073 HandleScope scope;
Bert Belder077f9d72012-02-15 22:34:182074#ifdef __POSIX__
Ben Noordhuisb4def482010-10-15 13:48:342075 int size = 0;
2076 while (environ[size]) size++;
2077
2078 Local<Array> env = Array::New(size);
2079
2080 for (int i = 0; i < size; ++i) {
2081 const char* var = environ[i];
2082 const char* s = strchr(var, '=');
2083 const int length = s ? s - var : strlen(var);
2084 env->Set(i, String::New(var, length));
2085 }
Bert Belder077f9d72012-02-15 22:34:182086#else // _WIN32
2087 WCHAR* environment = GetEnvironmentStringsW();
2088 if (environment == NULL) {
2089 // This should not happen.
2090 return scope.Close(Handle<Array>());
2091 }
2092 Local<Array> env = Array::New();
2093 WCHAR* p = environment;
2094 int i = 0;
2095 while (*p != NULL) {
2096 WCHAR *s;
2097 if (*p == L'=') {
2098 // If the key starts with '=' it is a hidden environment variable.
2099 p += wcslen(p) + 1;
2100 continue;
2101 } else {
2102 s = wcschr(p, L'=');
2103 }
2104 if (!s) {
2105 s = p + wcslen(p);
2106 }
2107 env->Set(i++, String::New(reinterpret_cast<uint16_t*>(p), s - p));
2108 p = s + wcslen(s) + 1;
2109 }
2110 FreeEnvironmentStringsW(environment);
2111#endif
Ben Noordhuisb4def482010-10-15 13:48:342112 return scope.Close(env);
2113}
2114
2115
Ben Noordhuisaa0308d2011-07-23 21:16:482116static Handle<Object> GetFeatures() {
2117 HandleScope scope;
2118
2119 Local<Object> obj = Object::New();
Ryan Dahl52a40e02011-08-24 21:16:352120 obj->Set(String::NewSymbol("debug"),
2121#if defined(DEBUG) && DEBUG
2122 True()
2123#else
2124 False()
2125#endif
2126 );
2127
Ryan Dahlc8dbaf52011-10-11 21:38:382128 obj->Set(String::NewSymbol("uv"), True());
Ben Noordhuisaa0308d2011-07-23 21:16:482129 obj->Set(String::NewSymbol("ipv6"), True()); // TODO ping libuv
Fedor Indutny9010f5f2011-07-28 15:52:042130 obj->Set(String::NewSymbol("tls_npn"), Boolean::New(use_npn));
2131 obj->Set(String::NewSymbol("tls_sni"), Boolean::New(use_sni));
Ben Noordhuisaa0308d2011-07-23 21:16:482132 obj->Set(String::NewSymbol("tls"),
2133 Boolean::New(get_builtin_module("crypto") != NULL));
2134
2135 return scope.Close(obj);
2136}
2137
2138
Fedor Indutny3f43b1c2012-02-12 15:53:432139static Handle<Value> DebugPortGetter(Local<String> property,
2140 const AccessorInfo& info) {
2141 HandleScope scope;
2142 return scope.Close(Integer::NewFromUnsigned(debug_port));
2143}
2144
2145
2146static void DebugPortSetter(Local<String> property,
2147 Local<Value> value,
2148 const AccessorInfo& info) {
2149 HandleScope scope;
2150 debug_port = value->NumberValue();
2151}
2152
2153
Bert Belder829735e2011-11-04 15:23:022154static Handle<Value> DebugProcess(const Arguments& args);
Fedor Indutnyb0388cc2011-12-10 16:52:072155static Handle<Value> DebugPause(const Arguments& args);
Fedor Indutny3f43b1c2012-02-12 15:53:432156static Handle<Value> DebugEnd(const Arguments& args);
Bert Belder829735e2011-11-04 15:23:022157
Dean McNameef67e8f22011-03-15 22:39:162158Handle<Object> SetupProcessObject(int argc, char *argv[]) {
Ryan27b268b2009-06-17 13:05:442159 HandleScope scope;
2160
Ryan Dahlcd1ec272011-01-02 09:44:422161 int i, j;
2162
Ryan Dahlad0a4ce2009-10-29 22:34:102163 Local<FunctionTemplate> process_template = FunctionTemplate::New();
Ryan27b268b2009-06-17 13:05:442164
Ryan Dahlad0a4ce2009-10-29 22:34:102165 process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
2166
Ben Noordhuis74a82152012-02-03 15:32:002167
Ryan Dahl5185c152010-06-18 07:26:492168 process->SetAccessor(String::New("title"),
2169 ProcessTitleGetter,
2170 ProcessTitleSetter);
2171
Ryan Dahlf4811832009-11-02 23:21:002172 // process.version
Ryan Dahlad0a4ce2009-10-29 22:34:102173 process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
Ryan Dahl39b432e2010-08-17 18:24:102174
Ryan Dahla979ab92011-08-04 23:40:072175#ifdef NODE_PREFIX
Ryan Dahlf4811832009-11-02 23:21:002176 // process.installPrefix
Ryan Dahlad0a4ce2009-10-29 22:34:102177 process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
Ryan Dahla979ab92011-08-04 23:40:072178#endif
Ryan1bf9be62009-08-03 15:51:352179
Ryan Dahlea9ee1f2011-07-28 02:30:322180 // process.moduleLoadList
2181 module_load_list = Persistent<Array>::New(Array::New());
2182 process->Set(String::NewSymbol("moduleLoadList"), module_load_list);
2183
Nathan Rajlich35043ad2012-03-13 23:04:172184 // process.versions
Ryan Dahl39b432e2010-08-17 18:24:102185 Local<Object> versions = Object::New();
Ryan Dahl39b432e2010-08-17 18:24:102186 process->Set(String::NewSymbol("versions"), versions);
Nathan Rajlich36761b22012-03-08 20:25:402187 versions->Set(String::NewSymbol("http_parser"), String::New(
2188 NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) "."
2189 NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR)));
Ryan Dahl39b432e2010-08-17 18:24:102190 // +1 to get rid of the leading 'v'
2191 versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
2192 versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
2193 versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
Nathan Rajlich35043ad2012-03-13 23:04:172194 versions->Set(String::NewSymbol("uv"), String::New(
2195 NODE_STRINGIFY(UV_VERSION_MAJOR) "."
2196 NODE_STRINGIFY(UV_VERSION_MINOR)));
Nathan Rajlich9701f1c2012-03-08 18:56:592197 versions->Set(String::NewSymbol("zlib"), String::New(ZLIB_VERSION));
Peter Bright13d6a1f2011-08-06 04:23:252198#if HAVE_OPENSSL
Ryan Dahlcd1ec272011-01-02 09:44:422199 // Stupid code to slice out the version string.
2200 int c, l = strlen(OPENSSL_VERSION_TEXT);
Ben Noordhuise0297ca2011-10-14 15:05:022201 for (i = j = 0; i < l; i++) {
Ryan Dahlcd1ec272011-01-02 09:44:422202 c = OPENSSL_VERSION_TEXT[i];
2203 if ('0' <= c && c <= '9') {
2204 for (j = i + 1; j < l; j++) {
2205 c = OPENSSL_VERSION_TEXT[j];
2206 if (c == ' ') break;
2207 }
2208 break;
2209 }
2210 }
2211 versions->Set(String::NewSymbol("openssl"),
2212 String::New(OPENSSL_VERSION_TEXT + i, j - i));
2213#endif
Ryan Dahl39b432e2010-08-17 18:24:102214
2215
2216
Nathan Rajlichb1be5402011-04-26 03:24:512217 // process.arch
2218 process->Set(String::NewSymbol("arch"), String::New(ARCH));
2219
Ryan Dahlf4811832009-11-02 23:21:002220 // process.platform
Ryan Dahl37704622011-01-06 03:05:592221 process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
Ryan Dahlf4811832009-11-02 23:21:002222
Ryan Dahlf3ad6352010-02-03 20:19:082223 // process.argv
Jeremy Ashkenas2916a2a2010-02-21 06:41:272224 Local<Array> arguments = Array::New(argc - option_end_index + 1);
Ryan1910c112009-09-11 18:05:222225 arguments->Set(Integer::New(0), String::New(argv[0]));
Peter Griess78d33f42010-06-04 15:29:102226 for (j = 1, i = option_end_index; i < argc; j++, i++) {
Ryan27b268b2009-06-17 13:05:442227 Local<String> arg = String::New(argv[i]);
Ryan1910c112009-09-11 18:05:222228 arguments->Set(Integer::New(j), arg);
Ryan27b268b2009-06-17 13:05:442229 }
Ryan Dahl38814552009-10-09 15:15:472230 // assign it
Ryan Dahlf3ad6352010-02-03 20:19:082231 process->Set(String::NewSymbol("argv"), arguments);
Ryan27b268b2009-06-17 13:05:442232
Micheil Smith19fd5302012-03-05 17:53:152233 // process.execArgv
2234 Local<Array> execArgv = Array::New(option_end_index - 1);
2235 for (j = 1, i = 0; j < option_end_index; j++, i++) {
2236 execArgv->Set(Integer::New(i), String::New(argv[j]));
2237 }
2238 // assign it
2239 process->Set(String::NewSymbol("execArgv"), execArgv);
2240
2241
Ryan Dahlf3ad6352010-02-03 20:19:082242 // create process.env
Ben Noordhuisb4def482010-10-15 13:48:342243 Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
Ryan Dahlea9006a2010-12-02 23:59:352244 envTemplate->SetNamedPropertyHandler(EnvGetter,
2245 EnvSetter,
2246 EnvQuery,
2247 EnvDeleter,
2248 EnvEnumerator,
2249 Undefined());
Ben Noordhuisb4def482010-10-15 13:48:342250 Local<Object> env = envTemplate->NewInstance();
Ryan Dahlf3ad6352010-02-03 20:19:082251 process->Set(String::NewSymbol("env"), env);
2252
Brandon Beacher334d56d2009-10-14 21:56:122253 process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
Ben Noordhuisaa0308d2011-07-23 21:16:482254 process->Set(String::NewSymbol("features"), GetFeatures());
Ryandc39e822009-09-10 12:07:352255
TJ Holowaychuk9481bc12010-10-07 02:05:012256 // -e, --eval
2257 if (eval_string) {
2258 process->Set(String::NewSymbol("_eval"), String::New(eval_string));
Nathan Rajlichef3a8742012-04-24 08:24:132259 }
2260
2261 // -p, --print
2262 if (print_eval) {
2263 process->Set(String::NewSymbol("_print_eval"), True());
TJ Holowaychuk9481bc12010-10-07 02:05:012264 }
2265
Nathan Rajlich6292df62012-04-24 08:32:332266 // -i, --interactive
Nathan Rajlichfeaa8a42012-03-21 07:05:252267 if (force_repl) {
2268 process->Set(String::NewSymbol("_forceRepl"), True());
2269 }
2270
Marshall Culpepperca35ba62010-06-22 06:31:192271 size_t size = 2*PATH_MAX;
Peter Bright13d6a1f2011-08-06 04:23:252272 char* execPath = new char[size];
Ryan Dahl48f65b32011-07-15 17:46:112273 if (uv_exepath(execPath, &size) != 0) {
Marshall Culpepperca35ba62010-06-22 06:31:192274 // as a last ditch effort, fallback on argv[0] ?
2275 process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
2276 } else {
Ryan Dahl00a1d612010-11-16 03:06:182277 process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
Marshall Culpepperca35ba62010-06-22 06:31:192278 }
Peter Bright13d6a1f2011-08-06 04:23:252279 delete [] execPath;
Marshall Culpepperca35ba62010-06-22 06:31:192280
Maciej Małecki977e2112012-02-17 18:35:052281 process->SetAccessor(String::New("debugPort"),
Fedor Indutny3f43b1c2012-02-12 15:53:432282 DebugPortGetter,
2283 DebugPortSetter);
2284
Marshall Culpepperca35ba62010-06-22 06:31:192285
Ryan Dahl38814552009-10-09 15:15:472286 // define various internal methods
Ben Noordhuis5f040652012-04-28 16:45:102287 NODE_SET_METHOD(process, "_getActiveRequests", GetActiveRequests);
2288 NODE_SET_METHOD(process, "_getActiveHandles", GetActiveHandles);
Ryan Dahl4e7e2f82010-04-13 22:39:152289 NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
Ryan Dahlad0a4ce2009-10-29 22:34:102290 NODE_SET_METHOD(process, "reallyExit", Exit);
Robert Mustacchi22404862011-12-15 01:02:152291 NODE_SET_METHOD(process, "abort", Abort);
Brandon Beacher47fcf782009-11-03 18:13:382292 NODE_SET_METHOD(process, "chdir", Chdir);
Ryan Dahlad0a4ce2009-10-29 22:34:102293 NODE_SET_METHOD(process, "cwd", Cwd);
Bert Belder30bab522010-11-25 00:09:062294
Ryan Dahlacc120a2011-08-09 20:53:562295 NODE_SET_METHOD(process, "umask", Umask);
2296
Bert Belder30bab522010-11-25 00:09:062297#ifdef __POSIX__
Michael Cartera3860762010-02-08 06:13:102298 NODE_SET_METHOD(process, "getuid", GetUid);
2299 NODE_SET_METHOD(process, "setuid", SetUid);
James Duncandf1c1e52010-02-23 22:45:022300
2301 NODE_SET_METHOD(process, "setgid", SetGid);
2302 NODE_SET_METHOD(process, "getgid", GetGid);
Igor Zinkovsky24a69d22011-11-02 22:06:482303#endif // __POSIX__
James Duncandf1c1e52010-02-23 22:45:022304
Ryan Dahl6eca9482010-09-17 06:13:032305 NODE_SET_METHOD(process, "_kill", Kill);
Bert Belder30bab522010-11-25 00:09:062306
Bert Belder829735e2011-11-04 15:23:022307 NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
Fedor Indutnyb0388cc2011-12-10 16:52:072308 NODE_SET_METHOD(process, "_debugPause", DebugPause);
Fedor Indutny3f43b1c2012-02-12 15:53:432309 NODE_SET_METHOD(process, "_debugEnd", DebugEnd);
Bert Belder829735e2011-11-04 15:23:022310
Nathan Rajlich07c886f2012-03-05 16:51:582311 NODE_SET_METHOD(process, "hrtime", Hrtime);
2312
Bert Belderdd93c532011-10-28 10:05:092313 NODE_SET_METHOD(process, "dlopen", DLOpen);
2314
Tom Hughescf78ce52011-03-04 23:57:542315 NODE_SET_METHOD(process, "uptime", Uptime);
Ryan Dahlb3b3cfe2009-11-03 12:00:422316 NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
Ryan Dahlc344fbc2011-10-06 21:59:382317 NODE_SET_METHOD(process, "uvCounters", UVCounters);
Ryan27b268b2009-06-17 13:05:442318
Ryan Dahl627fb5a2010-03-15 20:48:032319 NODE_SET_METHOD(process, "binding", Binding);
2320
Dean McNameef67e8f22011-03-15 22:39:162321 return process;
2322}
2323
2324
2325static void AtExit() {
Ryan Dahl4e43afd2011-09-30 20:11:472326 uv_tty_reset_mode();
Dean McNameef67e8f22011-03-15 22:39:162327}
2328
2329
2330static void SignalExit(int signal) {
Ryan Dahl4e43afd2011-09-30 20:11:472331 uv_tty_reset_mode();
Dean McNameef67e8f22011-03-15 22:39:162332 _exit(1);
2333}
2334
2335
Ryan Dahl7547c7d2011-12-07 01:00:332336void Load(Handle<Object> process_l) {
Ryan Dahl9f5643f2010-01-31 07:22:342337 // Compile, execute the src/node.js file. (Which was included as static C
2338 // string in node_natives.h. 'natve_node' is the string containing that
2339 // source code.)
Ryan Dahlb20c3432010-02-12 05:55:082340
Ryan Dahl9f5643f2010-01-31 07:22:342341 // The node.js file returns a function 'f'
Dean McNameef67e8f22011-03-15 22:39:162342 atexit(AtExit);
2343
Ryan Dahl9f5643f2010-01-31 07:22:342344 TryCatch try_catch;
Ryan Dahl9f5643f2010-01-31 07:22:342345
Tom Hughes74954ce2011-03-08 06:00:512346 Local<Value> f_value = ExecuteString(MainSource(),
2347 IMMUTABLE_STRING("node.js"));
Ryan Dahl9f5643f2010-01-31 07:22:342348 if (try_catch.HasCaught()) {
Ryan Dahlab068db2010-05-09 20:54:582349 ReportException(try_catch, true);
Ryan Dahl9f5643f2010-01-31 07:22:342350 exit(10);
2351 }
Ryan Dahl9f5643f2010-01-31 07:22:342352 assert(f_value->IsFunction());
2353 Local<Function> f = Local<Function>::Cast(f_value);
2354
2355 // Now we call 'f' with the 'process' variable that we've built up with
2356 // all our bindings. Inside node.js we'll take care of assigning things to
2357 // their places.
Ryan Dahlb20c3432010-02-12 05:55:082358
Ryan Dahl9f5643f2010-01-31 07:22:342359 // We start the process this way in order to be more modular. Developers
2360 // who do not like how 'src/node.js' setups the module system but do like
2361 // Node's I/O bindings may want to replace 'f' with their own function.
2362
Ryan Dahlf8ce8482010-09-17 07:01:072363 // Add a reference to the global object
2364 Local<Object> global = v8::Context::GetCurrent()->Global();
Ryan Dahl7547c7d2011-12-07 01:00:332365 Local<Value> args[1] = { Local<Value>::New(process_l) };
Zoran Tomicicd98ea702010-02-22 05:15:442366
Ryan Dahle9257b82011-02-10 02:50:262367#ifdef HAVE_DTRACE
Ryan Dahl068b7332011-01-25 01:50:102368 InitDTrace(global);
Ryan Dahle9257b82011-02-10 02:50:262369#endif
Ryan Dahl068b7332011-01-25 01:50:102370
Ryan Dahlb20c3432010-02-12 05:55:082371 f->Call(global, 1, args);
Ryan Dahl9f5643f2010-01-31 07:22:342372
Ryan Dahl8a52fb72010-07-01 18:10:222373 if (try_catch.HasCaught()) {
2374 ReportException(try_catch, true);
2375 exit(11);
Ryan Dahl9f5643f2010-01-31 07:22:342376 }
Ryan27b268b2009-06-17 13:05:442377}
2378
Zoran Tomicicd98ea702010-02-22 05:15:442379static void PrintHelp();
2380
2381static void ParseDebugOpt(const char* arg) {
2382 const char *p = 0;
2383
2384 use_debug_agent = true;
2385 if (!strcmp (arg, "--debug-brk")) {
2386 debug_wait_connect = true;
2387 return;
2388 } else if (!strcmp(arg, "--debug")) {
2389 return;
2390 } else if (strstr(arg, "--debug-brk=") == arg) {
2391 debug_wait_connect = true;
2392 p = 1 + strchr(arg, '=');
2393 debug_port = atoi(p);
2394 } else if (strstr(arg, "--debug=") == arg) {
2395 p = 1 + strchr(arg, '=');
2396 debug_port = atoi(p);
2397 }
2398 if (p && debug_port > 1024 && debug_port < 65536)
2399 return;
2400
2401 fprintf(stderr, "Bad debug option.\n");
2402 if (p) fprintf(stderr, "Debug port must be in range 1025 to 65535.\n");
2403
2404 PrintHelp();
2405 exit(1);
2406}
2407
Ryand6c9d312009-09-11 14:02:292408static void PrintHelp() {
Steve Engledow292345f2011-07-05 11:07:082409 printf("Usage: node [options] [ -e script | script.js ] [arguments] \n"
Ryan Dahl87339a22011-10-12 09:56:292410 " node debug script.js [arguments] \n"
Ryan Dahl4fa712c2011-01-13 23:28:162411 "\n"
Ryan Dahl209b2192010-03-08 16:33:102412 "Options:\n"
Tom Hughes78da9cb2010-10-18 22:50:562413 " -v, --version print node's version\n"
Steve Engledow292345f2011-07-05 11:07:082414 " -e, --eval script evaluate script\n"
Ben Noordhuis3d22dbf2011-12-01 16:21:002415 " -p, --print print result of --eval\n"
Nathan Rajlichfeaa8a42012-03-21 07:05:252416 " -i, --interactive always enter the REPL even if stdin\n"
2417 " does not appear to be a terminal\n"
Tom Hughes78da9cb2010-10-18 22:50:562418 " --v8-options print v8 command line options\n"
2419 " --vars print various compiled-in variables\n"
2420 " --max-stack-size=val set max v8 stack size (bytes)\n"
Ryan Dahl209b2192010-03-08 16:33:102421 "\n"
Ben Noordhuisfdf180f2011-12-05 07:42:112422 "Environment variables:\n"
2423#ifdef _WIN32
2424 "NODE_PATH ';'-separated list of directories\n"
2425#else
Tom Hughes78da9cb2010-10-18 22:50:562426 "NODE_PATH ':'-separated list of directories\n"
Ben Noordhuisfdf180f2011-12-05 07:42:112427#endif
isaacsc050d0f2011-07-25 01:04:452428 " prefixed to the module search path.\n"
Tom Hughes78da9cb2010-10-18 22:50:562429 "NODE_MODULE_CONTEXTS Set to 1 to load modules in their own\n"
2430 " global contexts.\n"
Ryan Dahl4fa712c2011-01-13 23:28:162431 "NODE_DISABLE_COLORS Set to 1 to disable colors in the REPL\n"
Ryan Dahl209b2192010-03-08 16:33:102432 "\n"
Ryan Dahl4fa712c2011-01-13 23:28:162433 "Documentation can be found at http://nodejs.org/\n");
Ryan11df2522009-08-03 16:19:402434}
2435
Ryan Dahl38814552009-10-09 15:15:472436// Parse node command line arguments.
Dean McNameef67e8f22011-03-15 22:39:162437static void ParseArgs(int argc, char **argv) {
Peter Griess78d33f42010-06-04 15:29:102438 int i;
2439
Ryan Dahle742d072009-10-09 11:25:042440 // TODO use parse opts
Dean McNameef67e8f22011-03-15 22:39:162441 for (i = 1; i < argc; i++) {
Ryan11df2522009-08-03 16:19:402442 const char *arg = argv[i];
Zoran Tomicicd98ea702010-02-22 05:15:442443 if (strstr(arg, "--debug") == arg) {
2444 ParseDebugOpt(arg);
Jonas Pfenniger8f59ccc2010-02-24 21:11:082445 argv[i] = const_cast<char*>("");
Ryan1910c112009-09-11 18:05:222446 } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
Ryan11df2522009-08-03 16:19:402447 printf("%s\n", NODE_VERSION);
2448 exit(0);
Ryan Dahl40e42e82010-03-08 17:10:242449 } else if (strcmp(arg, "--vars") == 0) {
Ryan Dahla979ab92011-08-04 23:40:072450#ifdef NODE_PREFIX
Ryan Dahl40e42e82010-03-08 17:10:242451 printf("NODE_PREFIX: %s\n", NODE_PREFIX);
Ryan Dahla979ab92011-08-04 23:40:072452#endif
2453#ifdef NODE_CFLAGS
Ryan Dahl40e42e82010-03-08 17:10:242454 printf("NODE_CFLAGS: %s\n", NODE_CFLAGS);
Ryan Dahla979ab92011-08-04 23:40:072455#endif
Ryaned9c3362009-09-01 13:28:102456 exit(0);
Tom Hughes78da9cb2010-10-18 22:50:562457 } else if (strstr(arg, "--max-stack-size=") == arg) {
2458 const char *p = 0;
2459 p = 1 + strchr(arg, '=');
2460 max_stack_size = atoi(p);
2461 argv[i] = const_cast<char*>("");
Ryan11df2522009-08-03 16:19:402462 } else if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
2463 PrintHelp();
2464 exit(0);
Ben Noordhuis3d22dbf2011-12-01 16:21:002465 } else if (strcmp(arg, "--eval") == 0 || strcmp(arg, "-e") == 0 ||
2466 strcmp(arg, "-pe") == 0) {
Dean McNameef67e8f22011-03-15 22:39:162467 if (argc <= i + 1) {
TJ Holowaychuk9481bc12010-10-07 02:05:012468 fprintf(stderr, "Error: --eval requires an argument\n");
2469 exit(1);
2470 }
Ben Noordhuis3d22dbf2011-12-01 16:21:002471 if (arg[1] == 'p') {
2472 print_eval = true;
2473 }
TJ Holowaychuk9481bc12010-10-07 02:05:012474 argv[i] = const_cast<char*>("");
2475 eval_string = argv[++i];
Ben Noordhuis3d22dbf2011-12-01 16:21:002476 } else if (strcmp(arg, "--print") == 0 || strcmp(arg, "-p") == 0) {
2477 print_eval = true;
2478 argv[i] = const_cast<char*>("");
Nathan Rajlichfeaa8a42012-03-21 07:05:252479 } else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) {
2480 force_repl = true;
2481 argv[i] = const_cast<char*>("");
Ryan11df2522009-08-03 16:19:402482 } else if (strcmp(arg, "--v8-options") == 0) {
Jonas Pfenniger8f59ccc2010-02-24 21:11:082483 argv[i] = const_cast<char*>("--help");
Jeremy Ashkenas2916a2a2010-02-21 06:41:272484 } else if (argv[i][0] != '-') {
Jeremy Ashkenas2916a2a2010-02-21 06:41:272485 break;
Ryan11df2522009-08-03 16:19:402486 }
2487 }
Peter Griess78d33f42010-06-04 15:29:102488
2489 option_end_index = i;
Ryan11df2522009-08-03 16:19:402490}
2491
Bert Belder829735e2011-11-04 15:23:022492
Ben Noordhuis74a82152012-02-03 15:32:002493static Isolate* node_isolate = NULL;
2494static volatile bool debugger_running = false;
2495
Ryan Dahl2a7e7b12010-12-18 19:17:292496static void EnableDebug(bool wait_connect) {
Bert Belder829735e2011-11-04 15:23:022497 // If we're called from another thread, make sure to enter the right
2498 // v8 isolate.
2499 node_isolate->Enter();
2500
Ryan Dahl2a7e7b12010-12-18 19:17:292501 // Start the debug thread and it's associated TCP server on port 5858.
Fedor Indutny5e8c2b02012-03-27 18:37:542502 bool r = v8::Debug::EnableAgent("node " NODE_VERSION,
2503 debug_port,
2504 wait_connect);
Ryan Dahl2a7e7b12010-12-18 19:17:292505
2506 // Crappy check that everything went well. FIXME
2507 assert(r);
2508
2509 // Print out some information.
Fedor Indutny26aab0d2011-09-24 07:28:272510 fprintf(stderr, "debugger listening on port %d\n", debug_port);
Bert Belder829735e2011-11-04 15:23:022511 fflush(stderr);
Fedor Indutny9e09fc02011-09-24 05:44:082512
2513 debugger_running = true;
Bert Belder829735e2011-11-04 15:23:022514
2515 node_isolate->Exit();
Ryan Dahl2a7e7b12010-12-18 19:17:292516}
2517
2518
Fedor Indutny82d0ac72011-09-24 13:51:592519#ifdef __POSIX__
Fedor Indutny26aab0d2011-09-24 07:28:272520static void EnableDebugSignalHandler(int signal) {
2521 // Break once process will return execution to v8
Bert Belder829735e2011-11-04 15:23:022522 v8::Debug::DebugBreak(node_isolate);
Ryan Dahl4ab54762011-03-01 17:59:172523
Fedor Indutny26aab0d2011-09-24 07:28:272524 if (!debugger_running) {
Ryan Dahl4ab54762011-03-01 17:59:172525 fprintf(stderr, "Hit SIGUSR1 - starting debugger agent.\n");
2526 EnableDebug(false);
2527 }
Ryan Dahl2a7e7b12010-12-18 19:17:292528}
2529
2530
Bert Belder829735e2011-11-04 15:23:022531static void RegisterSignalHandler(int signal, void (*handler)(int)) {
Tom Hughesf61b1102010-10-12 21:01:582532 struct sigaction sa;
2533
2534 memset(&sa, 0, sizeof(sa));
2535 sa.sa_handler = handler;
2536 sigfillset(&sa.sa_mask);
Bert Belder829735e2011-11-04 15:23:022537 sigaction(signal, &sa, NULL);
2538}
2539
2540
2541Handle<Value> DebugProcess(const Arguments& args) {
2542 HandleScope scope;
2543
2544 if (args.Length() != 1) {
2545 return ThrowException(Exception::Error(
2546 String::New("Invalid number of arguments.")));
2547 }
2548
2549 pid_t pid;
2550 int r;
2551
2552 pid = args[0]->IntegerValue();
2553 r = kill(pid, SIGUSR1);
2554 if (r != 0) {
2555 return ThrowException(ErrnoException(errno, "kill"));
2556 }
2557
2558 return Undefined();
Tom Hughesf61b1102010-10-12 21:01:582559}
Bert Belder30bab522010-11-25 00:09:062560#endif // __POSIX__
Tom Hughesf61b1102010-10-12 21:01:582561
2562
Bert Belder829735e2011-11-04 15:23:022563#ifdef _WIN32
2564DWORD WINAPI EnableDebugThreadProc(void* arg) {
2565 // Break once process will return execution to v8
2566 if (!debugger_running) {
2567 for (int i = 0; i < 1; i++) {
2568 fprintf(stderr, "Starting debugger agent.\r\n");
2569 fflush(stderr);
2570 EnableDebug(false);
2571 }
2572 }
2573
2574 v8::Debug::DebugBreak();
2575
2576 return 0;
2577}
2578
2579
Bert Belder8f2694b2012-02-16 21:19:482580static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf,
2581 size_t buf_len) {
2582 return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
Bert Belder829735e2011-11-04 15:23:022583}
2584
2585
2586static int RegisterDebugSignalHandler() {
Bert Belder8f2694b2012-02-16 21:19:482587 wchar_t mapping_name[32];
Bert Belder829735e2011-11-04 15:23:022588 HANDLE mapping_handle;
2589 DWORD pid;
2590 LPTHREAD_START_ROUTINE* handler;
2591
2592 pid = GetCurrentProcessId();
2593
2594 if (GetDebugSignalHandlerMappingName(pid,
2595 mapping_name,
Bert Belder8f2694b2012-02-16 21:19:482596 ARRAY_SIZE(mapping_name)) < 0) {
Bert Belder829735e2011-11-04 15:23:022597 return -1;
2598 }
2599
Bert Belder8f2694b2012-02-16 21:19:482600 mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE,
Bert Belder829735e2011-11-04 15:23:022601 NULL,
2602 PAGE_READWRITE,
2603 0,
2604 sizeof *handler,
2605 mapping_name);
2606 if (mapping_handle == NULL) {
2607 return -1;
2608 }
2609
Bert Belder8f2694b2012-02-16 21:19:482610 handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
2611 MapViewOfFile(mapping_handle,
2612 FILE_MAP_ALL_ACCESS,
2613 0,
2614 0,
2615 sizeof *handler));
Bert Belder829735e2011-11-04 15:23:022616 if (handler == NULL) {
2617 CloseHandle(mapping_handle);
2618 return -1;
2619 }
2620
2621 *handler = EnableDebugThreadProc;
2622
2623 UnmapViewOfFile((void*) handler);
2624
2625 return 0;
2626}
2627
2628
2629static Handle<Value> DebugProcess(const Arguments& args) {
2630 HandleScope scope;
2631 Handle<Value> rv = Undefined();
2632 DWORD pid;
Bert Belder68db2062012-02-03 14:37:462633 HANDLE process = NULL;
Bert Belder829735e2011-11-04 15:23:022634 HANDLE thread = NULL;
2635 HANDLE mapping = NULL;
Bert Belder8f2694b2012-02-16 21:19:482636 wchar_t mapping_name[32];
Bert Belder829735e2011-11-04 15:23:022637 LPTHREAD_START_ROUTINE* handler = NULL;
2638
2639 if (args.Length() != 1) {
2640 rv = ThrowException(Exception::Error(String::New("Invalid number of arguments.")));
2641 goto out;
2642 }
2643
2644 pid = (DWORD) args[0]->IntegerValue();
2645
Bert Belder68db2062012-02-03 14:37:462646 process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
Bert Belder829735e2011-11-04 15:23:022647 PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
2648 PROCESS_VM_READ,
2649 FALSE,
2650 pid);
Bert Belder68db2062012-02-03 14:37:462651 if (process == NULL) {
Bert Belder829735e2011-11-04 15:23:022652 rv = ThrowException(WinapiErrnoException(GetLastError(), "OpenProcess"));
2653 goto out;
2654 }
2655
2656 if (GetDebugSignalHandlerMappingName(pid,
2657 mapping_name,
Bert Belder8f2694b2012-02-16 21:19:482658 ARRAY_SIZE(mapping_name)) < 0) {
Bert Belder829735e2011-11-04 15:23:022659 rv = ThrowException(ErrnoException(errno, "sprintf"));
2660 goto out;
2661 }
2662
Bert Belder8f2694b2012-02-16 21:19:482663 mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
Bert Belder829735e2011-11-04 15:23:022664 if (mapping == NULL) {
Bert Belder8f2694b2012-02-16 21:19:482665 rv = ThrowException(WinapiErrnoException(GetLastError(),
2666 "OpenFileMappingW"));
Bert Belder829735e2011-11-04 15:23:022667 goto out;
2668 }
2669
Bert Belder8f2694b2012-02-16 21:19:482670 handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
2671 MapViewOfFile(mapping,
2672 FILE_MAP_READ,
2673 0,
2674 0,
2675 sizeof *handler));
Bert Belder829735e2011-11-04 15:23:022676 if (handler == NULL || *handler == NULL) {
2677 rv = ThrowException(WinapiErrnoException(GetLastError(), "MapViewOfFile"));
2678 goto out;
2679 }
2680
Bert Belder68db2062012-02-03 14:37:462681 thread = CreateRemoteThread(process,
Bert Belder829735e2011-11-04 15:23:022682 NULL,
2683 0,
2684 *handler,
2685 NULL,
2686 0,
2687 NULL);
2688 if (thread == NULL) {
2689 rv = ThrowException(WinapiErrnoException(GetLastError(),
2690 "CreateRemoteThread"));
2691 goto out;
2692 }
2693
2694 // Wait for the thread to terminate
2695 if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
2696 rv = ThrowException(WinapiErrnoException(GetLastError(),
2697 "WaitForSingleObject"));
2698 goto out;
2699 }
2700
2701 out:
Bert Belder68db2062012-02-03 14:37:462702 if (process != NULL) {
2703 CloseHandle(process);
Bert Belder829735e2011-11-04 15:23:022704 }
2705 if (thread != NULL) {
2706 CloseHandle(thread);
2707 }
2708 if (handler != NULL) {
2709 UnmapViewOfFile(handler);
2710 }
2711 if (mapping != NULL) {
2712 CloseHandle(mapping);
2713 }
2714
2715 return Undefined();
2716}
2717#endif // _WIN32
2718
2719
Fedor Indutnyb0388cc2011-12-10 16:52:072720static Handle<Value> DebugPause(const Arguments& args) {
2721 v8::Debug::DebugBreak(node_isolate);
Ben Noordhuisaac717d2011-12-19 23:30:412722 return Undefined();
Fedor Indutnyb0388cc2011-12-10 16:52:072723}
2724
2725
Fedor Indutny3f43b1c2012-02-12 15:53:432726static Handle<Value> DebugEnd(const Arguments& args) {
2727 if (debugger_running) {
2728 v8::Debug::DisableAgent();
2729 debugger_running = false;
2730 }
2731
2732 return Undefined();
2733}
2734
2735
Ben Noordhuis74a82152012-02-03 15:32:002736char** Init(int argc, char *argv[]) {
2737 // Initialize prog_start_time to get relative uptime.
2738 uv_uptime(&prog_start_time);
2739
Ryan Dahl38814552009-10-09 15:15:472740 // Parse a few arguments which are specific to Node.
Dean McNameef67e8f22011-03-15 22:39:162741 node::ParseArgs(argc, argv);
Jeremy Ashkenas2916a2a2010-02-21 06:41:272742 // Parse the rest of the args (up to the 'option_end_index' (where '--' was
Ryan Dahl38814552009-10-09 15:15:472743 // in the command line))
Ryan Dahl7547c7d2011-12-07 01:00:332744 int v8argc = option_end_index;
Danny Coatesdc8c0792010-08-01 22:46:482745 char **v8argv = argv;
2746
Ryan Dahl7547c7d2011-12-07 01:00:332747 if (debug_wait_connect) {
Ryan Dahladec5442010-08-04 17:38:192748 // v8argv is a copy of argv up to the script file argument +2 if --debug-brk
Ryan Dahld408de82010-08-06 19:31:412749 // to expose the v8 debugger js object so that node.js can set
Ryan Dahladec5442010-08-04 17:38:192750 // a breakpoint on the first line of the startup script
2751 v8argc += 2;
2752 v8argv = new char*[v8argc];
Ryan Dahl7547c7d2011-12-07 01:00:332753 memcpy(v8argv, argv, sizeof(argv) * option_end_index);
2754 v8argv[option_end_index] = const_cast<char*>("--expose_debug_as");
2755 v8argv[option_end_index + 1] = const_cast<char*>("v8debug");
Ryan Dahladec5442010-08-04 17:38:192756 }
Tom Hughes78da9cb2010-10-18 22:50:562757
2758 // For the normal stack which moves from high to low addresses when frames
2759 // are pushed, we can compute the limit as stack_size bytes below the
2760 // the address of a stack variable (e.g. &stack_var) as an approximation
2761 // of the start of the stack (we're assuming that we haven't pushed a lot
2762 // of frames yet).
Ryan Dahl7547c7d2011-12-07 01:00:332763 if (max_stack_size != 0) {
Tom Hughes78da9cb2010-10-18 22:50:562764 uint32_t stack_var;
2765 ResourceConstraints constraints;
2766
Ryan Dahl7547c7d2011-12-07 01:00:332767 uint32_t *stack_limit = &stack_var - (max_stack_size / sizeof(uint32_t));
Tom Hughes78da9cb2010-10-18 22:50:562768 constraints.set_stack_limit(stack_limit);
2769 SetResourceConstraints(&constraints); // Must be done before V8::Initialize
2770 }
Danny Coatesdc8c0792010-08-01 22:46:482771 V8::SetFlagsFromCommandLine(&v8argc, v8argv, false);
Ryan23376302009-09-10 10:34:292772
Bert Belder30bab522010-11-25 00:09:062773#ifdef __POSIX__
Ryan Dahlb6c5cf62010-05-04 17:41:562774 // Ignore SIGPIPE
Tom Hughesf61b1102010-10-12 21:01:582775 RegisterSignalHandler(SIGPIPE, SIG_IGN);
2776 RegisterSignalHandler(SIGINT, SignalExit);
2777 RegisterSignalHandler(SIGTERM, SignalExit);
Bert Belder30bab522010-11-25 00:09:062778#endif // __POSIX__
Ryan Dahlb6c5cf62010-05-04 17:41:562779
Ben Noordhuis74a82152012-02-03 15:32:002780 uv_prepare_init(uv_default_loop(), &prepare_tick_watcher);
2781 uv_prepare_start(&prepare_tick_watcher, PrepareTick);
2782 uv_unref(uv_default_loop());
2783
2784 uv_check_init(uv_default_loop(), &check_tick_watcher);
2785 uv_check_start(&check_tick_watcher, node::CheckTick);
2786 uv_unref(uv_default_loop());
2787
2788 uv_idle_init(uv_default_loop(), &tick_spinner);
2789 uv_unref(uv_default_loop());
2790
2791 uv_check_init(uv_default_loop(), &gc_check);
2792 uv_check_start(&gc_check, node::Check);
2793 uv_unref(uv_default_loop());
2794
2795 uv_idle_init(uv_default_loop(), &gc_idle);
2796 uv_unref(uv_default_loop());
2797
2798 uv_timer_init(uv_default_loop(), &gc_timer);
2799 uv_unref(uv_default_loop());
2800
2801 V8::SetFatalErrorHandler(node::OnFatalError);
2802
2803 // Fetch a reference to the main isolate, so we have a reference to it
2804 // even when we need it to access it from another (debugger) thread.
2805 node_isolate = Isolate::GetCurrent();
2806
2807 // If the --debug flag was specified then initialize the debug thread.
2808 if (use_debug_agent) {
2809 EnableDebug(debug_wait_connect);
2810 } else {
2811#ifdef _WIN32
2812 RegisterDebugSignalHandler();
2813#else // Posix
2814 RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
2815#endif // __POSIX__
2816 }
2817
Ben Noordhuis5866f1a2011-12-09 18:02:332818 return argv;
2819}
Ben Noordhuis356992f2011-11-22 16:10:092820
Ben Noordhuis5866f1a2011-12-09 18:02:332821
Ben Noordhuise4a8d262012-04-21 05:13:252822struct AtExitCallback {
2823 AtExitCallback* next_;
2824 void (*cb_)(void* arg);
2825 void* arg_;
2826};
2827
2828static AtExitCallback* at_exit_functions_;
2829
2830
2831void RunAtExit() {
2832 AtExitCallback* p = at_exit_functions_;
2833 at_exit_functions_ = NULL;
2834
2835 while (p) {
2836 AtExitCallback* q = p->next_;
2837 p->cb_(p->arg_);
2838 delete p;
2839 p = q;
2840 }
2841}
2842
2843
2844void AtExit(void (*cb)(void* arg), void* arg) {
2845 AtExitCallback* p = new AtExitCallback;
2846 p->cb_ = cb;
2847 p->arg_ = arg;
2848 p->next_ = at_exit_functions_;
2849 at_exit_functions_ = p;
2850}
2851
2852
Ben Noordhuis5866f1a2011-12-09 18:02:332853void EmitExit(v8::Handle<v8::Object> process_l) {
2854 // process.emit('exit')
Nathan Rajlichb8945212012-05-01 20:53:302855 process_l->Set(String::NewSymbol("_exiting"), True());
Ben Noordhuis5866f1a2011-12-09 18:02:332856 Local<Value> emit_v = process_l->Get(String::New("emit"));
2857 assert(emit_v->IsFunction());
2858 Local<Function> emit = Local<Function>::Cast(emit_v);
Nathan Rajlich248f5522012-04-30 01:53:412859 Local<Value> args[] = { String::New("exit"), Integer::New(0) };
Ben Noordhuis5866f1a2011-12-09 18:02:332860 TryCatch try_catch;
Nathan Rajlich248f5522012-04-30 01:53:412861 emit->Call(process_l, 2, args);
Ben Noordhuis5866f1a2011-12-09 18:02:332862 if (try_catch.HasCaught()) {
2863 FatalException(try_catch);
2864 }
2865}
2866
Micheil Smith19fd5302012-03-05 17:53:152867static char **copy_argv(int argc, char **argv) {
2868 size_t strlen_sum;
2869 char **argv_copy;
2870 char *argv_data;
2871 size_t len;
2872 int i;
2873
2874 strlen_sum = 0;
2875 for(i = 0; i < argc; i++) {
2876 strlen_sum += strlen(argv[i]) + 1;
2877 }
2878
2879 argv_copy = (char **) malloc(sizeof(char *) * (argc + 1) + strlen_sum);
2880 if (!argv_copy) {
2881 return NULL;
2882 }
2883
2884 argv_data = (char *) argv_copy + sizeof(char *) * (argc + 1);
2885
2886 for(i = 0; i < argc; i++) {
2887 argv_copy[i] = argv_data;
2888 len = strlen(argv[i]) + 1;
2889 memcpy(argv_data, argv[i], len);
2890 argv_data += len;
2891 }
2892
2893 argv_copy[argc] = NULL;
2894
2895 return argv_copy;
2896}
Ben Noordhuis5866f1a2011-12-09 18:02:332897
Ben Noordhuis74a82152012-02-03 15:32:002898int Start(int argc, char *argv[]) {
Ben Noordhuis1a979982012-03-15 22:10:322899 // Hack aroung with the argv pointer. Used for process.title = "blah".
2900 argv = uv_setup_args(argc, argv);
2901
Micheil Smith19fd5302012-03-05 17:53:152902 // Logic to duplicate argv as Init() modifies arguments
2903 // that are passed into it.
2904 char **argv_copy = copy_argv(argc, argv);
2905
Ben Noordhuis74a82152012-02-03 15:32:002906 // This needs to run *before* V8::Initialize()
Micheil Smith19fd5302012-03-05 17:53:152907 // Use copy here as to not modify the original argv:
2908 Init(argc, argv_copy);
Ben Noordhuis5866f1a2011-12-09 18:02:332909
Marcel Laverdetc33d3172012-05-04 22:29:422910 V8::Initialize();
2911 {
2912 Locker locker;
2913 HandleScope handle_scope;
Ben Noordhuis809fdf22011-12-09 20:49:102914
Marcel Laverdetc33d3172012-05-04 22:29:422915 // Create the one and only Context.
2916 Persistent<Context> context = Context::New();
2917 Context::Scope context_scope(context);
Ryan Dahle742d072009-10-09 11:25:042918
Ben Noordhuis636add22012-04-27 16:58:302919 process_symbol = NODE_PSYMBOL("process");
2920 domain_symbol = NODE_PSYMBOL("domain");
2921
Marcel Laverdetc33d3172012-05-04 22:29:422922 // Use original argv, as we're just copying values out of it.
2923 Handle<Object> process_l = SetupProcessObject(argc, argv);
2924 v8_typed_array::AttachBindings(context->Global());
Ryan Dahl4d02e772011-12-17 07:23:342925
Marcel Laverdetc33d3172012-05-04 22:29:422926 // Create all the objects, load modules, do everything.
2927 // so your next reading stop should be node::Load()!
2928 Load(process_l);
Ryan19478ed2009-03-03 00:56:152929
Marcel Laverdetc33d3172012-05-04 22:29:422930 // All our arguments are loaded. We've evaluated all of the scripts. We
2931 // might even have created TCP servers. Now we enter the main eventloop. If
2932 // there are no watchers on the loop (except for the ones that were
2933 // uv_unref'd) then this function exits. As long as there are active
2934 // watchers, it blocks.
2935 uv_run(uv_default_loop());
Ryan Dahlc7b24ef2010-11-12 00:33:212936
Marcel Laverdetc33d3172012-05-04 22:29:422937 EmitExit(process_l);
2938 RunAtExit();
Ben Noordhuis66116922011-11-23 19:50:282939
Ryan Dahl38814552009-10-09 15:15:472940#ifndef NDEBUG
Marcel Laverdetc33d3172012-05-04 22:29:422941 context.Dispose();
2942#endif
2943 }
2944
2945#ifndef NDEBUG
2946 // Clean up. Not strictly necessary.
Ryan27b268b2009-06-17 13:05:442947 V8::Dispose();
Ryan Dahl38814552009-10-09 15:15:472948#endif // NDEBUG
Igor Zinkovskya58b6432011-07-07 20:54:302949
Micheil Smith19fd5302012-03-05 17:53:152950 // Clean up the copy:
2951 free(argv_copy);
2952
Ryanf6a7fe22009-06-08 14:17:332953 return 0;
Ryan19478ed2009-03-03 00:56:152954}
Ryan Dahl124fbed2010-09-19 20:13:572955
2956
2957} // namespace node