#include "node.h" #include "v8.h" #include "env.h" #include "env-inl.h" #include #include #ifdef __MINGW32__ # include #endif // __MINGW32__ #ifdef __POSIX__ # include // MAXHOSTNAMELEN on Solaris. # include // gethostname, sysconf # include // MAXHOSTNAMELEN on Linux and the BSDs. # include #endif // __MINGW32__ // Add Windows fallback. #ifndef MAXHOSTNAMELEN # define MAXHOSTNAMELEN 256 #endif // MAXHOSTNAMELEN namespace node { namespace os { using v8::Array; using v8::Boolean; using v8::Context; using v8::FunctionCallbackInfo; using v8::Handle; using v8::Integer; using v8::Local; using v8::Number; using v8::Object; using v8::String; using v8::Value; static void GetHostname(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); char buf[MAXHOSTNAMELEN + 1]; if (gethostname(buf, sizeof(buf))) { #ifdef __POSIX__ int errorno = errno; #else // __MINGW32__ int errorno = WSAGetLastError(); #endif // __POSIX__ return env->ThrowErrnoException(errorno, "gethostname"); } buf[sizeof(buf) - 1] = '\0'; args.GetReturnValue().Set(OneByteString(env->isolate(), buf)); } static void GetOSType(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); const char* rval; #ifdef __POSIX__ struct utsname info; if (uname(&info) < 0) { return env->ThrowErrnoException(errno, "uname"); } rval = info.sysname; #else // __MINGW32__ rval ="Windows_NT"; #endif // __POSIX__ args.GetReturnValue().Set(OneByteString(env->isolate(), rval)); } static void GetOSRelease(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); const char* rval; #ifdef __POSIX__ struct utsname info; if (uname(&info) < 0) { return env->ThrowErrnoException(errno, "uname"); } rval = info.release; #else // Windows char release[256]; OSVERSIONINFOW info; info.dwOSVersionInfoSize = sizeof(info); // Don't complain that GetVersionEx is deprecated; there is no alternative. #pragma warning(suppress : 4996) if (GetVersionExW(&info) == 0) return; snprintf(release, sizeof(release), "%d.%d.%d", static_cast(info.dwMajorVersion), static_cast(info.dwMinorVersion), static_cast(info.dwBuildNumber)); rval = release; #endif // __POSIX__ args.GetReturnValue().Set(OneByteString(env->isolate(), rval)); } static void GetCPUInfo(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); uv_cpu_info_t* cpu_infos; int count, i; int err = uv_cpu_info(&cpu_infos, &count); if (err) return; Local cpus = Array::New(env->isolate()); for (i = 0; i < count; i++) { uv_cpu_info_t* ci = cpu_infos + i; Local times_info = Object::New(env->isolate()); times_info->Set(env->user_string(), Number::New(env->isolate(), ci->cpu_times.user)); times_info->Set(env->nice_string(), Number::New(env->isolate(), ci->cpu_times.nice)); times_info->Set(env->sys_string(), Number::New(env->isolate(), ci->cpu_times.sys)); times_info->Set(env->idle_string(), Number::New(env->isolate(), ci->cpu_times.idle)); times_info->Set(env->irq_string(), Number::New(env->isolate(), ci->cpu_times.irq)); Local cpu_info = Object::New(env->isolate()); cpu_info->Set(env->model_string(), OneByteString(env->isolate(), ci->model)); cpu_info->Set(env->speed_string(), Number::New(env->isolate(), ci->speed)); cpu_info->Set(env->times_string(), times_info); (*cpus)->Set(i, cpu_info); } uv_free_cpu_info(cpu_infos, count); args.GetReturnValue().Set(cpus); } static void GetFreeMemory(const FunctionCallbackInfo& args) { double amount = uv_get_free_memory(); if (amount < 0) return; args.GetReturnValue().Set(amount); } static void GetTotalMemory(const FunctionCallbackInfo& args) { double amount = uv_get_total_memory(); if (amount < 0) return; args.GetReturnValue().Set(amount); } static void GetUptime(const FunctionCallbackInfo& args) { double uptime; int err = uv_uptime(&uptime); if (err == 0) args.GetReturnValue().Set(uptime); } static void GetLoadAvg(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); double loadavg[3]; uv_loadavg(loadavg); Local loads = Array::New(env->isolate(), 3); loads->Set(0, Number::New(env->isolate(), loadavg[0])); loads->Set(1, Number::New(env->isolate(), loadavg[1])); loads->Set(2, Number::New(env->isolate(), loadavg[2])); args.GetReturnValue().Set(loads); } static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); uv_interface_address_t* interfaces; int count, i; char ip[INET6_ADDRSTRLEN]; char netmask[INET6_ADDRSTRLEN]; char mac[18]; Local ret, o; Local name, family; Local ifarr; int err = uv_interface_addresses(&interfaces, &count); ret = Object::New(env->isolate()); if (err == UV_ENOSYS) { args.GetReturnValue().Set(ret); } else if (err) { return env->ThrowUVException(err, "uv_interface_addresses"); } for (i = 0; i < count; i++) { const char* const raw_name = interfaces[i].name; // On Windows, the interface name is the UTF8-encoded friendly name and may // contain non-ASCII characters. On UNIX, it's just a binary string with // no particular encoding but we treat it as a one-byte Latin-1 string. #ifdef _WIN32 name = String::NewFromUtf8(env->isolate(), raw_name); #else name = OneByteString(env->isolate(), raw_name); #endif if (ret->Has(name)) { ifarr = Local::Cast(ret->Get(name)); } else { ifarr = Array::New(env->isolate()); ret->Set(name, ifarr); } snprintf(mac, 18, "%02x:%02x:%02x:%02x:%02x:%02x", static_cast(interfaces[i].phys_addr[0]), static_cast(interfaces[i].phys_addr[1]), static_cast(interfaces[i].phys_addr[2]), static_cast(interfaces[i].phys_addr[3]), static_cast(interfaces[i].phys_addr[4]), static_cast(interfaces[i].phys_addr[5])); if (interfaces[i].address.address4.sin_family == AF_INET) { uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip)); uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask)); family = env->ipv4_string(); } else if (interfaces[i].address.address4.sin_family == AF_INET6) { uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip)); uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask)); family = env->ipv6_string(); } else { strncpy(ip, "", INET6_ADDRSTRLEN); family = env->unknown_string(); } o = Object::New(env->isolate()); o->Set(env->address_string(), OneByteString(env->isolate(), ip)); o->Set(env->netmask_string(), OneByteString(env->isolate(), netmask)); o->Set(env->family_string(), family); o->Set(env->mac_string(), FIXED_ONE_BYTE_STRING(env->isolate(), mac)); if (interfaces[i].address.address4.sin_family == AF_INET6) { uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id; o->Set(env->scopeid_string(), Integer::NewFromUnsigned(env->isolate(), scopeid)); } const bool internal = interfaces[i].is_internal; o->Set(env->internal_string(), internal ? True(env->isolate()) : False(env->isolate())); ifarr->Set(ifarr->Length(), o); } uv_free_interface_addresses(interfaces, count); args.GetReturnValue().Set(ret); } void Initialize(Handle target, Handle unused, Handle context) { Environment* env = Environment::GetCurrent(context); env->SetMethod(target, "getHostname", GetHostname); env->SetMethod(target, "getLoadAvg", GetLoadAvg); env->SetMethod(target, "getUptime", GetUptime); env->SetMethod(target, "getTotalMem", GetTotalMemory); env->SetMethod(target, "getFreeMem", GetFreeMemory); env->SetMethod(target, "getCPUs", GetCPUInfo); env->SetMethod(target, "getOSType", GetOSType); env->SetMethod(target, "getOSRelease", GetOSRelease); env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"), Boolean::New(env->isolate(), IsBigEndian())); } } // namespace os } // namespace node NODE_MODULE_CONTEXT_AWARE_BUILTIN(os, node::os::Initialize)