// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node.h"
#include "node_buffer.h"
#include "node_constants.h"
#include "node_file.h"
#include "node_http_parser.h"
#include "node_javascript.h"
#include "node_version.h"
#if defined HAVE_PERFCTR
#include "node_counters.h"
#endif
#if HAVE_OPENSSL
#include "node_crypto.h"
#endif
#if defined(NODE_HAVE_I18N_SUPPORT)
#include "node_i18n.h"
#endif
#if defined HAVE_DTRACE || defined HAVE_ETW
#include "node_dtrace.h"
#endif
#include "ares.h"
#include "async-wrap.h"
#include "async-wrap-inl.h"
#include "env.h"
#include "env-inl.h"
#include "handle_wrap.h"
#include "req_wrap.h"
#include "string_bytes.h"
#include "util.h"
#include "uv.h"
#include "v8-debug.h"
#include "v8-profiler.h"
#include "zlib.h"
#include
#include
#include // PATH_MAX
#include
#include
#include
#include
#include
#include
#if defined(_MSC_VER)
#include
#include
#include
#define strcasecmp _stricmp
#define getpid _getpid
#define umask _umask
typedef int mode_t;
#else
#include // getrlimit, setrlimit
#include // setuid, getuid
#endif
#if defined(__POSIX__) && !defined(__ANDROID__)
#include // getpwnam()
#include // getgrnam()
#endif
#ifdef __APPLE__
#include
#define environ (*_NSGetEnviron())
#elif !defined(_MSC_VER)
extern char **environ;
#endif
namespace node {
using v8::Array;
using v8::ArrayBuffer;
using v8::Boolean;
using v8::Context;
using v8::EscapableHandleScope;
using v8::Exception;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Handle;
using v8::HandleScope;
using v8::HeapStatistics;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Locker;
using v8::Message;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
using v8::PropertyCallbackInfo;
using v8::SealHandleScope;
using v8::String;
using v8::TryCatch;
using v8::Uint32;
using v8::V8;
using v8::Value;
using v8::kExternalUint32Array;
static bool print_eval = false;
static bool force_repl = false;
static bool trace_deprecation = false;
static bool throw_deprecation = false;
static const char* eval_string = NULL;
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static int debug_port = 5858;
static bool v8_is_profiling = false;
static bool node_is_initialized = false;
static node_module* modpending;
static node_module* modlist_builtin;
static node_module* modlist_linked;
static node_module* modlist_addon;
#if defined(NODE_HAVE_I18N_SUPPORT)
// Path to ICU data (for i18n / Intl)
static const char* icu_data_dir = NULL;
#endif
// used by C++ modules as well
bool no_deprecation = false;
// process-relative uptime base, initialized at start-up
static double prog_start_time;
static bool debugger_running;
static uv_async_t dispatch_debug_messages_async;
static Isolate* node_isolate = NULL;
int WRITE_UTF8_FLAGS = v8::String::HINT_MANY_WRITES_EXPECTED |
v8::String::NO_NULL_TERMINATION;
class ArrayBufferAllocator : public ArrayBuffer::Allocator {
public:
// Impose an upper limit to avoid out of memory errors that bring down
// the process.
static const size_t kMaxLength = 0x3fffffff;
static ArrayBufferAllocator the_singleton;
virtual ~ArrayBufferAllocator() {}
virtual void* Allocate(size_t length);
virtual void* AllocateUninitialized(size_t length);
virtual void Free(void* data, size_t length);
private:
ArrayBufferAllocator() {}
ArrayBufferAllocator(const ArrayBufferAllocator&);
void operator=(const ArrayBufferAllocator&);
};
ArrayBufferAllocator ArrayBufferAllocator::the_singleton;
void* ArrayBufferAllocator::Allocate(size_t length) {
if (length > kMaxLength)
return NULL;
char* data = new char[length];
memset(data, 0, length);
return data;
}
void* ArrayBufferAllocator::AllocateUninitialized(size_t length) {
if (length > kMaxLength)
return NULL;
return new char[length];
}
void ArrayBufferAllocator::Free(void* data, size_t length) {
delete[] static_cast(data);
}
static void CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle);
HandleScope scope(env->isolate());
Context::Scope context_scope(env->context());
MakeCallback(env, env->process_object(), env->immediate_callback_string());
}
static void IdleImmediateDummy(uv_idle_t* handle) {
// Do nothing. Only for maintaining event loop.
// TODO(bnoordhuis) Maybe make libuv accept NULL idle callbacks.
}
static inline const char *errno_string(int errorno) {
#define ERRNO_CASE(e) case e: return #e;
switch (errorno) {
#ifdef EACCES
ERRNO_CASE(EACCES);
#endif
#ifdef EADDRINUSE
ERRNO_CASE(EADDRINUSE);
#endif
#ifdef EADDRNOTAVAIL
ERRNO_CASE(EADDRNOTAVAIL);
#endif
#ifdef EAFNOSUPPORT
ERRNO_CASE(EAFNOSUPPORT);
#endif
#ifdef EAGAIN
ERRNO_CASE(EAGAIN);
#endif
#ifdef EWOULDBLOCK
# if EAGAIN != EWOULDBLOCK
ERRNO_CASE(EWOULDBLOCK);
# endif
#endif
#ifdef EALREADY
ERRNO_CASE(EALREADY);
#endif
#ifdef EBADF
ERRNO_CASE(EBADF);
#endif
#ifdef EBADMSG
ERRNO_CASE(EBADMSG);
#endif
#ifdef EBUSY
ERRNO_CASE(EBUSY);
#endif
#ifdef ECANCELED
ERRNO_CASE(ECANCELED);
#endif
#ifdef ECHILD
ERRNO_CASE(ECHILD);
#endif
#ifdef ECONNABORTED
ERRNO_CASE(ECONNABORTED);
#endif
#ifdef ECONNREFUSED
ERRNO_CASE(ECONNREFUSED);
#endif
#ifdef ECONNRESET
ERRNO_CASE(ECONNRESET);
#endif
#ifdef EDEADLK
ERRNO_CASE(EDEADLK);
#endif
#ifdef EDESTADDRREQ
ERRNO_CASE(EDESTADDRREQ);
#endif
#ifdef EDOM
ERRNO_CASE(EDOM);
#endif
#ifdef EDQUOT
ERRNO_CASE(EDQUOT);
#endif
#ifdef EEXIST
ERRNO_CASE(EEXIST);
#endif
#ifdef EFAULT
ERRNO_CASE(EFAULT);
#endif
#ifdef EFBIG
ERRNO_CASE(EFBIG);
#endif
#ifdef EHOSTUNREACH
ERRNO_CASE(EHOSTUNREACH);
#endif
#ifdef EIDRM
ERRNO_CASE(EIDRM);
#endif
#ifdef EILSEQ
ERRNO_CASE(EILSEQ);
#endif
#ifdef EINPROGRESS
ERRNO_CASE(EINPROGRESS);
#endif
#ifdef EINTR
ERRNO_CASE(EINTR);
#endif
#ifdef EINVAL
ERRNO_CASE(EINVAL);
#endif
#ifdef EIO
ERRNO_CASE(EIO);
#endif
#ifdef EISCONN
ERRNO_CASE(EISCONN);
#endif
#ifdef EISDIR
ERRNO_CASE(EISDIR);
#endif
#ifdef ELOOP
ERRNO_CASE(ELOOP);
#endif
#ifdef EMFILE
ERRNO_CASE(EMFILE);
#endif
#ifdef EMLINK
ERRNO_CASE(EMLINK);
#endif
#ifdef EMSGSIZE
ERRNO_CASE(EMSGSIZE);
#endif
#ifdef EMULTIHOP
ERRNO_CASE(EMULTIHOP);
#endif
#ifdef ENAMETOOLONG
ERRNO_CASE(ENAMETOOLONG);
#endif
#ifdef ENETDOWN
ERRNO_CASE(ENETDOWN);
#endif
#ifdef ENETRESET
ERRNO_CASE(ENETRESET);
#endif
#ifdef ENETUNREACH
ERRNO_CASE(ENETUNREACH);
#endif
#ifdef ENFILE
ERRNO_CASE(ENFILE);
#endif
#ifdef ENOBUFS
ERRNO_CASE(ENOBUFS);
#endif
#ifdef ENODATA
ERRNO_CASE(ENODATA);
#endif
#ifdef ENODEV
ERRNO_CASE(ENODEV);
#endif
#ifdef ENOENT
ERRNO_CASE(ENOENT);
#endif
#ifdef ENOEXEC
ERRNO_CASE(ENOEXEC);
#endif
#ifdef ENOLINK
ERRNO_CASE(ENOLINK);
#endif
#ifdef ENOLCK
# if ENOLINK != ENOLCK
ERRNO_CASE(ENOLCK);
# endif
#endif
#ifdef ENOMEM
ERRNO_CASE(ENOMEM);
#endif
#ifdef ENOMSG
ERRNO_CASE(ENOMSG);
#endif
#ifdef ENOPROTOOPT
ERRNO_CASE(ENOPROTOOPT);
#endif
#ifdef ENOSPC
ERRNO_CASE(ENOSPC);
#endif
#ifdef ENOSR
ERRNO_CASE(ENOSR);
#endif
#ifdef ENOSTR
ERRNO_CASE(ENOSTR);
#endif
#ifdef ENOSYS
ERRNO_CASE(ENOSYS);
#endif
#ifdef ENOTCONN
ERRNO_CASE(ENOTCONN);
#endif
#ifdef ENOTDIR
ERRNO_CASE(ENOTDIR);
#endif
#ifdef ENOTEMPTY
ERRNO_CASE(ENOTEMPTY);
#endif
#ifdef ENOTSOCK
ERRNO_CASE(ENOTSOCK);
#endif
#ifdef ENOTSUP
ERRNO_CASE(ENOTSUP);
#else
# ifdef EOPNOTSUPP
ERRNO_CASE(EOPNOTSUPP);
# endif
#endif
#ifdef ENOTTY
ERRNO_CASE(ENOTTY);
#endif
#ifdef ENXIO
ERRNO_CASE(ENXIO);
#endif
#ifdef EOVERFLOW
ERRNO_CASE(EOVERFLOW);
#endif
#ifdef EPERM
ERRNO_CASE(EPERM);
#endif
#ifdef EPIPE
ERRNO_CASE(EPIPE);
#endif
#ifdef EPROTO
ERRNO_CASE(EPROTO);
#endif
#ifdef EPROTONOSUPPORT
ERRNO_CASE(EPROTONOSUPPORT);
#endif
#ifdef EPROTOTYPE
ERRNO_CASE(EPROTOTYPE);
#endif
#ifdef ERANGE
ERRNO_CASE(ERANGE);
#endif
#ifdef EROFS
ERRNO_CASE(EROFS);
#endif
#ifdef ESPIPE
ERRNO_CASE(ESPIPE);
#endif
#ifdef ESRCH
ERRNO_CASE(ESRCH);
#endif
#ifdef ESTALE
ERRNO_CASE(ESTALE);
#endif
#ifdef ETIME
ERRNO_CASE(ETIME);
#endif
#ifdef ETIMEDOUT
ERRNO_CASE(ETIMEDOUT);
#endif
#ifdef ETXTBSY
ERRNO_CASE(ETXTBSY);
#endif
#ifdef EXDEV
ERRNO_CASE(EXDEV);
#endif
default: return "";
}
}
const char *signo_string(int signo) {
#define SIGNO_CASE(e) case e: return #e;
switch (signo) {
#ifdef SIGHUP
SIGNO_CASE(SIGHUP);
#endif
#ifdef SIGINT
SIGNO_CASE(SIGINT);
#endif
#ifdef SIGQUIT
SIGNO_CASE(SIGQUIT);
#endif
#ifdef SIGILL
SIGNO_CASE(SIGILL);
#endif
#ifdef SIGTRAP
SIGNO_CASE(SIGTRAP);
#endif
#ifdef SIGABRT
SIGNO_CASE(SIGABRT);
#endif
#ifdef SIGIOT
# if SIGABRT != SIGIOT
SIGNO_CASE(SIGIOT);
# endif
#endif
#ifdef SIGBUS
SIGNO_CASE(SIGBUS);
#endif
#ifdef SIGFPE
SIGNO_CASE(SIGFPE);
#endif
#ifdef SIGKILL
SIGNO_CASE(SIGKILL);
#endif
#ifdef SIGUSR1
SIGNO_CASE(SIGUSR1);
#endif
#ifdef SIGSEGV
SIGNO_CASE(SIGSEGV);
#endif
#ifdef SIGUSR2
SIGNO_CASE(SIGUSR2);
#endif
#ifdef SIGPIPE
SIGNO_CASE(SIGPIPE);
#endif
#ifdef SIGALRM
SIGNO_CASE(SIGALRM);
#endif
SIGNO_CASE(SIGTERM);
#ifdef SIGCHLD
SIGNO_CASE(SIGCHLD);
#endif
#ifdef SIGSTKFLT
SIGNO_CASE(SIGSTKFLT);
#endif
#ifdef SIGCONT
SIGNO_CASE(SIGCONT);
#endif
#ifdef SIGSTOP
SIGNO_CASE(SIGSTOP);
#endif
#ifdef SIGTSTP
SIGNO_CASE(SIGTSTP);
#endif
#ifdef SIGBREAK
SIGNO_CASE(SIGBREAK);
#endif
#ifdef SIGTTIN
SIGNO_CASE(SIGTTIN);
#endif
#ifdef SIGTTOU
SIGNO_CASE(SIGTTOU);
#endif
#ifdef SIGURG
SIGNO_CASE(SIGURG);
#endif
#ifdef SIGXCPU
SIGNO_CASE(SIGXCPU);
#endif
#ifdef SIGXFSZ
SIGNO_CASE(SIGXFSZ);
#endif
#ifdef SIGVTALRM
SIGNO_CASE(SIGVTALRM);
#endif
#ifdef SIGPROF
SIGNO_CASE(SIGPROF);
#endif
#ifdef SIGWINCH
SIGNO_CASE(SIGWINCH);
#endif
#ifdef SIGIO
SIGNO_CASE(SIGIO);
#endif
#ifdef SIGPOLL
# if SIGPOLL != SIGIO
SIGNO_CASE(SIGPOLL);
# endif
#endif
#ifdef SIGLOST
SIGNO_CASE(SIGLOST);
#endif
#ifdef SIGPWR
# if SIGPWR != SIGLOST
SIGNO_CASE(SIGPWR);
# endif
#endif
#ifdef SIGSYS
SIGNO_CASE(SIGSYS);
#endif
default: return "";
}
}
// Convenience methods
void ThrowError(v8::Isolate* isolate, const char* errmsg) {
Environment::GetCurrent(isolate)->ThrowError(errmsg);
}
void ThrowTypeError(v8::Isolate* isolate, const char* errmsg) {
Environment::GetCurrent(isolate)->ThrowTypeError(errmsg);
}
void ThrowRangeError(v8::Isolate* isolate, const char* errmsg) {
Environment::GetCurrent(isolate)->ThrowRangeError(errmsg);
}
void ThrowErrnoException(v8::Isolate* isolate,
int errorno,
const char* syscall,
const char* message,
const char* path) {
Environment::GetCurrent(isolate)->ThrowErrnoException(errorno,
syscall,
message,
path);
}
void ThrowUVException(v8::Isolate* isolate,
int errorno,
const char* syscall,
const char* message,
const char* path) {
Environment::GetCurrent(isolate)->ThrowErrnoException(errorno,
syscall,
message,
path);
}
Local ErrnoException(Isolate* isolate,
int errorno,
const char *syscall,
const char *msg,
const char *path) {
Environment* env = Environment::GetCurrent(isolate);
Local e;
Local estring = OneByteString(env->isolate(), errno_string(errorno));
if (msg == NULL || msg[0] == '\0') {
msg = strerror(errorno);
}
Local message = OneByteString(env->isolate(), msg);
Local cons1 =
String::Concat(estring, FIXED_ONE_BYTE_STRING(env->isolate(), ", "));
Local cons2 = String::Concat(cons1, message);
if (path) {
Local cons3 =
String::Concat(cons2, FIXED_ONE_BYTE_STRING(env->isolate(), " '"));
Local cons4 =
String::Concat(cons3, String::NewFromUtf8(env->isolate(), path));
Local cons5 =
String::Concat(cons4, FIXED_ONE_BYTE_STRING(env->isolate(), "'"));
e = Exception::Error(cons5);
} else {
e = Exception::Error(cons2);
}
Local