1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-06 00:13:33 +00:00
Files
MeshAgent/microscript/ILibDuktape_ScriptContainer.c
Bryan Roe 7ea36ae572 1. Added -import
2. Added ability to set uid on agent start
2023-01-20 13:06:15 -08:00

4320 lines
156 KiB
C

/*
Copyright 2006 - 2022 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <ws2tcpip.h>
#include <IPHlpApi.h>
#include <Windows.h>
#include <WinBase.h>
#include <signal.h>
#include <direct.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#ifndef NO_IFADDR
#include <ifaddrs.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#elif !defined(_FREEBSD)
#include <netpacket/packet.h>
#endif
#include <sys/utsname.h>
#endif
#if defined(_POSIX) && !defined(__APPLE__) && !defined(_FREEBSD)
#include <sys/prctl.h>
#endif
#include "duktape.h"
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#ifndef WIN32
#include <sys/resource.h>
#endif
#ifdef _OPENBSD
extern char __agentExecPath[];
#endif
#include "ILibDuktape_ScriptContainer.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_EventEmitter.h"
#include "ILibDuktape_Helpers.h"
#include "../microstack/ILibParsers.h"
#include "../microstack/ILibRemoteLogging.h"
#include "../microstack/ILibCrypto.h"
#include "ILibDuktape_net.h"
#include "ILibDuktape_WebRTC.h"
#include "ILibDuktape_Dgram.h"
#include "ILibDuktape_GenericMarshal.h"
#include "ILibDuktape_fs.h"
#include "ILibDuktape_Polyfills.h"
#include "ILibDuktape_SimpleDataStore.h"
#include "ILibDuktape_NetworkMonitor.h"
#include "ILibDuktape_ReadableStream.h"
#include "ILibDuktape_WritableStream.h"
#include "ILibDuktape_CompressedStream.h"
#include "ILibDuktape_SHA256.h"
#include "ILibDuktape_EncryptionStream.h"
#include "ILibDuktape_ChildProcess.h"
#include "ILibDuktape_Debugger.h"
#include "ILibDuktape_Commit.h"
#ifdef _POSIX
extern char **environ;
int SignalDescriptors[2] = { 0, 0 };
#endif
#define SCRIPT_ENGINE_PIPE_BUFFER_SIZE 65535
char exeJavaScriptGuid[] = "B996015880544A19B7F7E9BE44914C18";
#define ILibDuktape_ScriptContainer_MasterPtr "\xFF_ScriptContainer_MasterPtr"
#define ILibDuktape_ScriptContainer_SlavePtr "\xFF_ScriptContainer_SlavePtr"
#define ILibDuktape_ScriptContainer_ExePath "\xFF_ScriptContainer_ExePath"
#define ILibDuktape_ScriptContainer_PipeManager "\xFF_ScriptContainer_PipeManager"
#define ILibDuktape_ScriptContainer_PtrTable "\xFF_ScriptContainer_PtrTable"
#define ILibDuktape_ScriptContainer_PtrTable_Idx "\xFF_ScriptContainer_PtrTableIdx"
#define ILibDuktape_ScriptContainer_ProcessIsolated "\xFF_ScriptContainer_ProcessIsolated"
#define ILibDuktape_ScriptContainer_PeerThread "\xFF_ScriptContainer_PeerThread"
#define ILibDuktape_ScriptContainer_Command_Execute_Status "ScriptContainer_Command_Execute_Status"
#define ILibDuktape_ScriptContainer_Command_Log "ScriptContainer_Command_Log"
#define ILibDuktape_ScriptContainer_Settings_ExecutionTimeout "\xFF_ScriptContainerSettings_ExecutionTimeout"
#define ILibDuktape_ScriptContainer_Settings_SecurityFlags "\xFF_ScriptContainerSettings_SecurityFlags"
#define ILibDuktape_ScriptContainer_Settings_DB "\xFF_ScriptContainerSettings_DB"
#define ILibDuktape_ScriptContainer_Settings_ExitHandler "\xFF_ScriptContainerSettings_ExitHandler"
#define ILibDuktape_ScriptContainer_Settings_ExitUser "\xFF_ScriptContainerSettings_ExitUser"
#define ILibDuktape_ScriptContainer_Process_CoreDumpPath "\xFF_coreDumpPath"
#define ILibDuktape_ScriptContainer_Process_Restart "\xFF_ScriptContainer_Process_Restart"
#define ILibDuktape_ScriptContainer_Process_stdin "\xFF_stdin"
#define ILibDuktape_ScriptContainer_Process_stdout "\xFF_stdout"
#define ILibDuktape_ScriptContainer_Process_stderr "\xFF_stderr"
#define ILibDuktape_ScriptContainer_Signal_ListenerPtr "\xFF_signalListener"
#define ILibDuktape_ScriptContainer_ExitCode "\xFF_ExitCode"
#define ILibDuktape_ScriptContainer_Exitting "\xFF_Exiting"
#ifdef MESH_AGENTID
char *ARCHNAME[] =
{
NULL,
"x86", // ARCHID = 1 # Windows Console x86 32 bit
"x64", // ARCHID = 2 # Windows Console x86 64 bit
"x86", // ARCHID = 3 # Windows Service x86 32 bit
"x64", // ARCHID = 4 # Windows Service x86 64 bit
"x86", // ARCHID = 5 # Linux x86 32 bit
"x64", // ARCHID = 6 # Linux x86 64 bit
"mips", // ARCHID = 7 # Linux MIPS
NULL,
"arm", // ARCHID = 9 # Linux ARM 32 bit
NULL,NULL,NULL,
"arm", // ARCHID = 13 # Linux ARM 32 bit PogoPlug
NULL,
"x86", // ARCHID = 15 # Linux x86 32 bit POKY
NULL, NULL,
"x64", // ARCHARCHID = 18 # Linux x86 64 bit POKY
"x86", // ARCHARCHID = 19 # Linux x86 32 bit NOKVM
"x64", // ARCHARCHID = 20 # Linux x86 64 bit NOKVM
NULL, NULL, NULL, NULL,
"arm" // ARCHARCHID = 25 # Linux ARM 32 bit HardFloat
};
#endif
char *SIGTABLE[] =
{
"INVALID" ,
"SIGHUP" ,
"SIGINT" ,
"SIGQUIT" ,
"SIGILL" ,
"SIGTRAP" ,
"SIGIOT" ,
"SIGBUS" ,
"SIGFPE" ,
"SIGKILL" ,
"SIGUSR1" ,
"SIGSEGV" ,
"SIGUSR2" ,
"SIGPIPE" ,
"SIGALRM" ,
"SIGTERM" ,
"SIGSTKFLT" ,
"SIGCHLD" ,
"SIGCONTv" ,
"SIGSTOP" ,
"SIGTSTP" ,
"SIGTTIN" ,
"SIGTTOU" ,
"SIGURG" ,
"SIGXCPU" ,
"SIGXFSZ" ,
"SIGVTALRM" ,
"SIGPROF" ,
"SIGWINCH" ,
"SIGIO" ,
"SIGPWR"
};
extern void ILibDuktape_MemoryStream_Init(duk_context *ctx);
extern void ILibDuktape_NetworkMonitor_Init(duk_context *ctx);
extern int GenerateSHA384FileHash(char *filePath, char *fileHash);
char g_AgentCrashID[280];
char g_AgentCrashID_HASH[17] = { 0 };
typedef enum SCRIPT_ENGINE_COMMAND
{
SCRIPT_ENGINE_COMMAND_UNKNOWN = 0x00,
SCRIPT_ENGINE_COMMAND_INIT = 0x01,
SCRIPT_ENGINE_COMMAND_EXEC = 0x02,
SCRIPT_ENGINE_COMMAND_ADD_MODULE = 0x04,
SCRIPT_ENGINE_COMMAND_SEND_JSON = 0x10,
SCRIPT_ENGINE_COMMAND_QUERY = 0x20,
SCRIPT_ENGINE_COMMAND_SET = 0x21,
SCRIPT_ENGINE_COMMAND_ERROR = 0x40,
SCRIPT_ENGINE_COMMAND_EXIT = 0x80,
SCRIPT_ENGINE_COMMAND_LOG = 0xFF
}SCRIPT_ENGINE_COMMAND;
typedef struct ILibDuktape_ScriptContainer_Master
{
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
ILibProcessPipe_Process child;
void *chain;
void *PeerThread, *PeerChain;
duk_context *PeerCTX;
unsigned int ChildSecurityFlags;
}ILibDuktape_ScriptContainer_Master;
typedef struct ILibDuktape_ScriptContainer_Slave
{
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
void *chain;
int exitCode;
int noRespond;
}ILibDuktape_ScriptContainer_Slave;
typedef struct ILibDuktape_ScriptContainer_NonIsolated_Command
{
union { ILibDuktape_ScriptContainer_Master * master; ILibDuktape_ScriptContainer_Slave *slave; }container;
char json[];
}ILibDuktape_ScriptContainer_NonIsolated_Command;
void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave(void *chain, void *user);
void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster(void *chain, void *user);
#ifdef _REMOTELOGGING
void ILibDuktape_ScriptContainer_Slave_LogForwarder(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *buffer, int bufferLen)
{
char tmp[4096];
int len;
buffer[bufferLen] = 0;
len = sprintf_s(tmp + 4, sizeof(tmp) - 4, "{\"command\":255,\"module\":%d,\"flags\":%d,\"message\":\"%s\"}", module, flags, buffer);
((int*)tmp)[0] = 4 + len;
#ifdef WIN32
DWORD arg;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), (void*)tmp, 4 + len, &arg, NULL);
#else
ignore_result(write(STDERR_FILENO, (void*)tmp, 4 + len));
#endif
}
#endif
void ILibDuktape_ScriptContainer_PUSH_MASTER(duk_context *ctx, void *chain);
void ILibDuktape_ScriptContainer_PUSH_SLAVE(duk_context *ctx, void *chain);
void ILibDuktape_ScriptContainer_Slave_SendJSON(duk_context *ctx)
{
duk_size_t jsonLen;
char *json = (char*)duk_json_encode(ctx, -1);
duk_get_lstring(ctx, -1, &jsonLen);
duk_push_heap_stash(ctx);
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr);
duk_pop(ctx);
if (master != NULL)
{
ILibDuktape_ScriptContainer_NonIsolated_Command* cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(1+(int)jsonLen + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.master = master;
memcpy_s(cmd->json, jsonLen, json, jsonLen);
cmd->json[jsonLen] = 0;
Duktape_RunOnEventLoopEx(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd, 1);
return;
}
char *scratch = ILibMemory_Allocate((int)jsonLen + 4, 0, NULL, NULL);
((int*)scratch)[0] = (int)jsonLen+4;
memcpy_s(scratch + 4, jsonLen, json, jsonLen);
#ifdef WIN32
DWORD tmpLen;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), scratch, 4+(DWORD)jsonLen, &tmpLen, NULL);
#else
ignore_result(write(STDERR_FILENO, scratch, 4 + jsonLen));
#endif
duk_pop(ctx);
free(scratch);
}
void ILibDuktape_ScriptContainer_Slave_OnBrokenPipe(ILibProcessPipe_Pipe sender)
{
if (ILibMemory_CanaryOK(sender))
{
ILibStopChain(((ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_Extra(sender))[0])->chain);
}
}
void ILibDuktape_ScriptContainer_CheckEmbeddedEx(char *exePath, char **script, int *scriptLen)
{
int i;
FILE *tmpFile;
char *integratedJavaScript = NULL;
int integratedJavaScriptLen = 0;
#ifdef WIN32
if (ILibString_EndsWith(exePath, -1, ".exe", 4) == 0)
{
i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s_", exePath);
sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "%s.exe", exePath);
_wfopen_s(&tmpFile, ILibUTF8ToWide(ILibScratchPad, -1), L"rb");
}
else
{
i = ILibString_LastIndexOf(exePath, -1, "\\", 1);
if (i > 0)
{
i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s", exePath + i + 1);
g_AgentCrashID[i - 4] = '_';
i -= 3;
}
else
{
i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s", exePath);
g_AgentCrashID[i - 4] = '_';
i -= 3;
}
}
#else
i = sprintf_s(g_AgentCrashID, sizeof(g_AgentCrashID), "%s_", exePath);
#endif
char hashValue[1 + UTIL_SHA384_HASHSIZE];
if (GenerateSHA384FileHash(exePath, hashValue) == 0)
{
util_tohex(hashValue, UTIL_SHA384_HASHSIZE, g_AgentCrashID + i);
#ifdef WIN32
memcpy_s(g_AgentCrashID + i + 16, 5, ".exe", 5);
#else
g_AgentCrashID[i + 16] = 0;
#endif
}
#ifdef WIN32
_wfopen_s(&tmpFile, ILibUTF8ToWide(exePath, -1), L"rb");
#else
tmpFile = fopen(exePath, "rb");
#endif
if (tmpFile != NULL)
{
g_ILibCrashID = g_AgentCrashID;
g_ILibCrashID_HASH = g_AgentCrashID_HASH;
memcpy_s(g_AgentCrashID_HASH, sizeof(g_AgentCrashID_HASH), g_AgentCrashID + i, sizeof(g_AgentCrashID_HASH) - 1);
#ifdef WIN32
// Read the PE Headers, to determine where to look for the Embedded JS
char *optHeader = NULL;
fseek(tmpFile, 0, SEEK_SET);
ignore_result(fread(ILibScratchPad, 1, 2, tmpFile));
if (ntohs(((unsigned int*)ILibScratchPad)[0]) == 19802) // 5A4D
{
fseek(tmpFile, 60, SEEK_SET);
ignore_result(fread(ILibScratchPad, 1, 4, tmpFile));
fseek(tmpFile, ((unsigned *)ILibScratchPad)[0], SEEK_SET);
ignore_result(fread(ILibScratchPad, 1, 24, tmpFile));
if (((unsigned int*)ILibScratchPad)[0] == 17744)
{
// PE Image
optHeader = ILibMemory_AllocateA(((unsigned short*)ILibScratchPad)[10]);
if (ILibMemory_AllocateA_Size(optHeader) < 4) { fclose(tmpFile); return; }
ignore_result(fread(optHeader, 1, ILibMemory_AllocateA_Size(optHeader), tmpFile));
switch (((unsigned short*)optHeader)[0])
{
case 0x10B:
if (ILibMemory_AllocateA_Size(optHeader) < 132) { fclose(tmpFile); return; }
if (((unsigned int*)(optHeader + 128))[0] != 0)
{
fseek(tmpFile, ((unsigned int*)(optHeader + 128))[0] - 16, SEEK_SET);
}
else
{
fseek(tmpFile, -16, SEEK_END);
}
break;
case 0x20B:
if (ILibMemory_AllocateA_Size(optHeader) < 148) { fclose(tmpFile); return; }
if (((unsigned int*)(optHeader + 144))[0] != 0)
{
fseek(tmpFile, ((unsigned int*)(optHeader + 144))[0] - 16, SEEK_SET);
}
else
{
fseek(tmpFile, -16, SEEK_END);
}
break;
default:
fclose(tmpFile);
return;
}
ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
util_hexToBuf(exeJavaScriptGuid, 32, ILibScratchPad2);
if (memcmp(ILibScratchPad, ILibScratchPad2, 16) == 0)
{
// Found an Embedded JS
fseek(tmpFile, -20, SEEK_CUR);
ignore_result(fread((void*)&integratedJavaScriptLen, 1, 4, tmpFile));
integratedJavaScriptLen = (int)ntohl(integratedJavaScriptLen);
fseek(tmpFile, -4 - integratedJavaScriptLen, SEEK_CUR);
integratedJavaScript = ILibMemory_Allocate(integratedJavaScriptLen + 1, 0, NULL, NULL);
ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile));
integratedJavaScript[integratedJavaScriptLen] = 0;
}
}
}
#else
fseek(tmpFile, -16, SEEK_END);
ignore_result(fread(ILibScratchPad, 1, 16, tmpFile));
util_hexToBuf(exeJavaScriptGuid, 32, ILibScratchPad2);
if (memcmp(ILibScratchPad, ILibScratchPad2, 16) == 0)
{
// Found an Embedded JS
fseek(tmpFile, -20, SEEK_CUR);
ignore_result(fread((void*)&integratedJavaScriptLen, 1, 4, tmpFile));
integratedJavaScriptLen = (int)ntohl(integratedJavaScriptLen);
fseek(tmpFile, -4 - integratedJavaScriptLen, SEEK_CUR);
integratedJavaScript = ILibMemory_Allocate(integratedJavaScriptLen + 1, 0, NULL, NULL);
ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile));
integratedJavaScript[integratedJavaScriptLen] = 0;
}
#endif
fclose(tmpFile);
}
*script = integratedJavaScript;
*scriptLen = integratedJavaScriptLen;
}
void ILibDuktape_ScriptContainer_CheckEmbedded(char **script, int *scriptLen)
{
// Check if .JS file is integrated with executable
#ifndef __APPLE__
char exePath[_MAX_PATH*2];
#else
char exePath[PATH_MAX+1] = {0};
#endif
#ifdef WIN32
WCHAR tmpExePath[_MAX_PATH];
GetModuleFileNameW(NULL, tmpExePath, sizeof(tmpExePath)/2);
WideCharToMultiByte(CP_UTF8, 0, tmpExePath, -1, exePath, sizeof(exePath), NULL, NULL);
#elif defined(__APPLE__)
uint32_t len = sizeof(exePath);
if (_NSGetExecutablePath(exePath, &len) != 0) ILIBCRITICALEXIT(247);
#elif defined(NACL)
#elif defined(_FREEBSD)
int x = readlink("/proc/curproc/file", exePath, sizeof(exePath));
if (x < 0 || x >= sizeof(exePath))
{
#ifdef _OPENBSD
strcpy_s(exePath, sizeof(exePath), __agentExecPath);
#else
printf("\nYou'll need to mount procfs, which isn't mounted by default on FreeBSD.\n");
printf("Add the following line to /etc/fstab\n");
printf(" proc /proc procfs rw 0 0\n\n");
printf("If you don't reboot after, then you can manually mount with the command:\n");
printf(" mount -t procfs proc /proc\n\n");
ILIBCRITICALEXIT(246);
#endif
}
exePath[x] = 0;
#else
int x = readlink("/proc/self/exe", exePath, sizeof(exePath));
if (x < 0 || x >= sizeof(exePath)) ILIBCRITICALEXIT(246);
exePath[x] = 0;
#endif
ILibDuktape_ScriptContainer_CheckEmbeddedEx(exePath, script, scriptLen);
}
// Polyfill process object:
void ILibDuktape_ScriptContainer_Process_ExitCallback(void *obj)
{
if (ILibMemory_CanaryOK(obj))
{
duk_context *ctx = ((void**)obj)[0];
Duktape_SafeDestroyHeap(ctx);
}
}
duk_ret_t ILibDuktape_ScriptContainer_Process_ExitEx(duk_context *ctx)
{
if (duk_is_number(ctx, 0))
{
exit(duk_require_int(ctx, 0));
}
else
{
exit(0);
}
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_Exit(duk_context *ctx)
{
void **tmp;
int nargs = duk_get_top(ctx);
if (duk_peval_string(ctx, "require('MeshAgent').agentMode") == 0 && duk_get_boolean(ctx, -1))
{
// Running in Agent Mode, so exiting process is not allowed
return(ILibDuktape_Error(ctx, "Process.exit() not allowed when running in Agent Mode"));
}
else
{
duk_push_this(ctx); // [process]
if (nargs == 1)
{
duk_push_int(ctx, duk_require_int(ctx, 0)); // [process][code]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ExitCode); // [process]
}
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Exitting)) { return(ILibDuktape_Error(ctx, "Process.exit() forced script termination")); }
duk_push_int(ctx, 1);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Exitting); // [process]
// Execute this later, so that this stack can unwind first, before we destroy the heap
tmp = (void**)Duktape_PushBuffer(ctx, sizeof(void*)); // [process][buffer]
duk_put_prop_string(ctx, -2, "\xFF_JUNK"); // [process]
tmp[0] = ctx;
ILibLifeTime_Add(ILibGetBaseTimer(Duktape_GetChain(ctx)), tmp, 0, ILibDuktape_ScriptContainer_Process_ExitCallback, NULL);
}
return(ILibDuktape_Error(ctx, "Process.exit() forced script termination"));
}
// Polyfill process object:
duk_ret_t ILibDuktape_ScriptContainer_Process_Argv0(duk_context *ctx)
{
duk_push_this(ctx); // [process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray); // [process][array]
duk_get_prop_index(ctx, -1, 0); // [process][array][val]
}
else
{
duk_push_string(ctx, ""); // [process][array][val]
}
return 1;
}
// Polyfill process object:
duk_ret_t ILibDuktape_ScriptContainer_Process_Argv(duk_context *ctx)
{
duk_push_current_function(ctx);
int readOnly = Duktape_GetIntPropertyValue(ctx, -1, "readOnly", 0);
duk_push_this(ctx); // [process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray); // [process][array]
if (readOnly != 0) { duk_array_clone(ctx, -1); } // [process][array][array]
}
else
{
duk_push_array(ctx); // [process][array]
if (readOnly == 0)
{
duk_dup(ctx, -1); // [process][array][array]
duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_Process_ArgArray); // [process][array]
}
}
return 1;
}
duk_ret_t ILibDuktape_ScriptContainer_Process_env(duk_context *ctx)
{
duk_push_object(ctx); // [env]
#ifdef WIN32
int i;
char *envStrings = GetEnvironmentStringsA();
int envStringsLen = ILibString_IndexOf(envStrings, INT_MAX, "\0\0", 2);
if (envStringsLen > 0)
{
parser_result *r = ILibParseString(envStrings, 0, envStringsLen, "\0", 1);
parser_result_field *f = r->FirstResult;
while (f != NULL)
{
i = ILibString_IndexOf(f->data, f->datalength, "=", 1);
if (i > 0)
{ // [env]
duk_push_lstring(ctx, f->data, i); // [env][key]
duk_push_string(ctx, f->data + i + 1); // [env][key][val]
duk_put_prop(ctx, -3); // [env]
}
f = f->NextResult;
}
ILibDestructParserResults(r);
}
FreeEnvironmentStringsA(envStrings);
#elif defined(_POSIX)
for (char **env = environ; *env; ++env)
{
int envLen = (int)strnlen_s(*env, INT_MAX);
int i = ILibString_IndexOf(*env, envLen, "=", 1);
if (i > 0)
{
duk_push_lstring(ctx, *env, i);
duk_push_string(ctx, *env + i + 1);
duk_put_prop(ctx, -3);
}
}
#endif
return(1);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_Finalizer(duk_context *ctx)
{
// We need to dispatch the 'exit' event
duk_push_this(ctx); // [process]
ILibChain_Link *link = (ILibChain_Link*)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Signal_ListenerPtr);
#ifdef _POSIX
struct sigaction action;
// Unhook SIGCHLD
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = SIG_DFL;
if (sigaction(SIGCHLD, NULL, &action) == 0 && action.sa_handler != SIG_DFL)
{
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = SIG_DFL;
ignore_result(sigaction(SIGCHLD, &action, NULL));
}
// Unhook SIGTERM
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = SIG_DFL;
if (sigaction(SIGTERM, NULL, &action) == 0 && action.sa_handler != SIG_DFL)
{
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = SIG_DFL;
ignore_result(sigaction(SIGTERM, &action, NULL));
}
// Close the Pipes if they exist
if (SignalDescriptors[0] != 0)
{
close(SignalDescriptors[0]);
}
if (SignalDescriptors[1] != 0)
{
close(SignalDescriptors[1]);
}
SignalDescriptors[0] = SignalDescriptors[1] = 0;
#endif
if (link != NULL)
{
((void**)link->ExtraMemoryPtr)[0] = NULL;
((void**)link->ExtraMemoryPtr)[1] = NULL;
ILibChain_SafeRemove(Duktape_GetChain(ctx), link);
}
return(0);
}
typedef struct ILibDuktape_Process_StdIn_Data
{
ILibDuktape_readableStream *rs;
#ifdef WIN32
HANDLE workerThread;
HANDLE resumeEvent;
int exit;
#endif
int wasUnshifted;
int endPointer;
int bufferSize;
char buffer[];
}ILibDuktape_Process_StdIn_Data;
#ifdef WIN32
void __stdcall ILibDuktape_Process_stdin_readSink(ULONG_PTR obj)
{
ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)obj;
int endPointer;
do
{
endPointer = data->endPointer;
data->wasUnshifted = 0;
ILibDuktape_readableStream_WriteData(data->rs, data->buffer, data->endPointer);
} while (!data->rs->paused && data->wasUnshifted > 0 && data->wasUnshifted != endPointer);
data->endPointer = data->wasUnshifted;
if (!data->rs->paused) { SetEvent(data->resumeEvent); }
}
#endif
void ILibDuktape_Process_stdin_pauseSink(struct ILibDuktape_readableStream *sender, void *user)
{
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(user);
// NO-OP, because stream state flag will be paused, which will cause the processing loop to exit
}
void ILibDuktape_Process_stdin_resumeSink(struct ILibDuktape_readableStream *sender, void *user)
{
#ifdef WIN32
ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)user;
SetEvent(data->resumeEvent);
#endif
}
int ILibDuktape_Process_stdin_unshiftSink(struct ILibDuktape_readableStream *sender, int unshiftBytes, void *user)
{
ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)user;
data->wasUnshifted = unshiftBytes <= data->endPointer ? unshiftBytes : data->endPointer;
if (unshiftBytes > 0 && unshiftBytes < data->endPointer)
{
memmove_s(data->buffer, data->bufferSize, data->buffer + (data->endPointer - unshiftBytes), unshiftBytes);
data->endPointer = unshiftBytes;
}
return(data->wasUnshifted);
}
#ifdef WIN32
void ILibDuktape_Process_stdin_WindowsRunLoop(void *arg)
{
ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)arg;
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
DWORD bytesRead, waitResult;
while (((waitResult = WaitForSingleObjectEx(data->resumeEvent, INFINITE, TRUE)) == WAIT_OBJECT_0 || waitResult == WAIT_IO_COMPLETION) && !data->exit)
{
if (!ReadFile(h, data->buffer + data->endPointer, data->bufferSize - data->endPointer, &bytesRead, NULL))
{
break;
}
else
{
ResetEvent(data->resumeEvent); // Reset, becuase we'll need to pause and context switch to Duktape thread
data->endPointer += (int)bytesRead;
QueueUserAPC((PAPCFUNC)ILibDuktape_Process_stdin_readSink, ILibChain_GetMicrostackThreadHandle(data->rs->chain), (ULONG_PTR)data);
}
}
}
#endif
duk_ret_t ILibDuktape_Process_stdin_finalizer(duk_context *ctx)
{
duk_get_prop_string(ctx, 0, ILibDuktape_readableStream_RSPTRS);
ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)Duktape_GetBuffer(ctx, -1, NULL);
ILibDuktape_Process_StdIn_Data *data = (ILibDuktape_Process_StdIn_Data*)rs->user;
#ifdef WIN32
data->exit = 1;
SetEvent(data->resumeEvent);
CancelSynchronousIo(data->workerThread);
WaitForSingleObject(data->workerThread, 10000);
CloseHandle(data->resumeEvent);
#endif
free(data);
return(0);
}
#ifdef _POSIX
duk_ret_t ILibDuktape_Process_stdin_readset(duk_context *ctx)
{
ILibDuktape_readableStream *rs;
duk_push_this(ctx); // [descriptorevents]
duk_get_prop_string(ctx, -1, "stdin"); // [descriptorevents][stdin]
rs = (ILibDuktape_readableStream*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_readableStream_RSPTRS);
char buffer[1024];
int bufferLen;
duk_push_this(ctx); // [descriptorevents]
duk_get_prop_string(ctx, -1, "stdin"); // [descriptorevents][stdin]
bufferLen = read(0, buffer, sizeof(buffer));
if (bufferLen > 0)
{
ILibDuktape_readableStream_WriteData(rs, buffer, bufferLen);
}
return(0);
}
#endif
duk_ret_t ILibDuktape_Process_stdin_get(duk_context *ctx)
{
duk_push_this(ctx); // [process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdin))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdin);
return(1);
}
duk_push_object(ctx); // [process][stdin]
duk_dup(ctx, -1); // [process][stdin][dup]
duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_Process_stdin); // [process][stdin]
ILibDuktape_WriteID(ctx, "process.stdin");
ILibDuktape_readableStream *rs = ILibDuktape_ReadableStream_InitEx(ctx, ILibDuktape_Process_stdin_pauseSink, ILibDuktape_Process_stdin_resumeSink, ILibDuktape_Process_stdin_unshiftSink, NULL);
rs->user = ILibMemory_Allocate(sizeof(ILibDuktape_Process_StdIn_Data) + 4096, 0, NULL, NULL);
((ILibDuktape_Process_StdIn_Data*)rs->user)->rs = rs;
((ILibDuktape_Process_StdIn_Data*)rs->user)->bufferSize = 4096;
#ifdef WIN32
((ILibDuktape_Process_StdIn_Data*)rs->user)->resumeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
((ILibDuktape_Process_StdIn_Data*)rs->user)->workerThread = ILibSpawnNormalThread(ILibDuktape_Process_stdin_WindowsRunLoop, rs->user);
#else
duk_push_heap_stash(ctx); // [stash]
duk_eval_string(ctx, "require('DescriptorEvents').addDescriptor(0, { readset: true });"); // [stash][descriptorevents]
duk_dup(ctx, -3);
duk_put_prop_string(ctx, -2, "stdin");
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "readset", ILibDuktape_Process_stdin_readset);
duk_put_prop_string(ctx, -2, "FD_STDIN"); // [stash]
duk_pop(ctx); // ...
#endif
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "~", ILibDuktape_Process_stdin_finalizer);
return(1);
}
ILibTransport_DoneState ILibDuktape_Process_stdout_WriteSink(struct ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user)
{
#ifdef WIN32
DWORD writeLen;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), (void*)buffer, bufferLen, &writeLen, NULL);
#else
ignore_result(write(STDOUT_FILENO, buffer, bufferLen));
#endif
return(ILibTransport_DoneState_COMPLETE);
}
void ILibDuktape_Process_stdout_EndSink(struct ILibDuktape_WritableStream *stream, void *user)
{
UNREFERENCED_PARAMETER(stream);
UNREFERENCED_PARAMETER(user);
}
duk_ret_t ILibDuktape_Process_stdout_get(duk_context *ctx)
{
duk_push_this(ctx); // [process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdout))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stdout);
return(1);
}
duk_push_object(ctx); // [process][stdout]
duk_dup(ctx, -1); // [process][stdout][dup]
duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_Process_stdout); // [process][stdout]
ILibDuktape_WriteID(ctx, "process.stdout");
ILibDuktape_WritableStream_Init(ctx, ILibDuktape_Process_stdout_WriteSink, ILibDuktape_Process_stdout_EndSink, NULL);
return(1);
}
ILibTransport_DoneState ILibDuktape_Process_stderr_WriteSink(struct ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user)
{
#ifdef WIN32
DWORD writeLen;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), (void*)buffer, bufferLen, &writeLen, NULL);
#else
ignore_result(write(STDERR_FILENO, buffer, bufferLen));
#endif
return(ILibTransport_DoneState_COMPLETE);
}
duk_ret_t ILibDuktape_Process_stderr_get(duk_context *ctx)
{
duk_push_this(ctx); // [process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stderr))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_stderr);
return(1);
}
duk_push_object(ctx); // [process][stderr]
duk_dup(ctx, -1); // [process][stderr][dup]
duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_Process_stderr); // [process][stderr]
ILibDuktape_WriteID(ctx, "process.stderr");
ILibDuktape_WritableStream_Init(ctx, ILibDuktape_Process_stderr_WriteSink, ILibDuktape_Process_stdout_EndSink, NULL);
return(1);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_Kill(duk_context *ctx)
{
int pid = duk_require_int(ctx, 0);
#ifdef WIN32
HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD)pid);
if (NULL != handle)
{
TerminateProcess(handle, 0);
CloseHandle(handle);
}
#else
int s = SIGTERM;
if (duk_is_string(ctx, 1))
{
duk_push_this(ctx); // [process]
duk_get_prop_string(ctx, -1, "SIGTABLE"); // [process][table]
duk_dup(ctx, 1); // [process][table][key]
if (duk_get_prop(ctx, -2) != 0) // [process][table][value]
{
s = duk_get_int(ctx, -1);
}
}
else if (duk_is_number(ctx, 1))
{
s = duk_require_int(ctx, 1);
}
kill((pid_t)pid, s);
#endif
return(0);
}
duk_ret_t ILibDuktape_Process_cwd(duk_context *ctx)
{
#ifdef WIN32
GetCurrentDirectoryW((DWORD)sizeof(ILibScratchPad)/2, (LPWSTR)ILibScratchPad);
ILibDuktape_String_PushWideString(ctx, ILibScratchPad, 0);
#else
ignore_result((uintptr_t)getcwd(ILibScratchPad, sizeof(ILibScratchPad)));
duk_push_string(ctx, ILibScratchPad);
#endif
duk_get_prop_string(ctx, -1, "concat"); // [string][concat]
duk_swap_top(ctx, -2); // [concat][this]
#ifdef WIN32
duk_string_endsWith(ctx, -1, "\\"); // [concat][this][bool]
if (!duk_get_boolean(ctx, -1))
{
duk_push_string(ctx, "\\"); // [concat][this][bool][/]
}
else
{
duk_push_string(ctx, "");
}
duk_remove(ctx, -2); // [concat][this][/]
#else
duk_push_string(ctx, "/");
#endif
duk_call_method(ctx, 1);
return(1);
}
#ifdef _POSIX
duk_ret_t ILibDuktape_ScriptContainer_Process_SignalListener_Immediate(duk_context *ctx)
{
duk_size_t bufferLen;
char *sigbuffer = Duktape_GetBuffer(ctx, 0, &bufferLen);
void *h = ILibDuktape_GetProcessObject(ctx);
int s = 0;
switch (((int*)sigbuffer)[1])
{
case SIGCHLD:
s = 0;
waitpid(((pid_t*)sigbuffer)[2], &s, 0);
ILibDuktape_EventEmitter_SetupEmit(ctx, h, "SIGCHLD"); // [emit][this][SIGCHLD]
duk_push_string(ctx, SIGTABLE[((int*)sigbuffer)[1]]); // [emit][this][SIGTERM][name]
duk_push_int(ctx, s); // [emit][this][SIGCHLD][name][code]
duk_push_int(ctx, ((pid_t*)sigbuffer)[2]); // [emit][this][SIGCHLD][name][code][pid]
duk_push_uint(ctx, ((uid_t*)sigbuffer)[3]); // [emit][this][SIGCHLD][name][code][pid][uid]
if (duk_pcall_method(ctx, 5) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting SIGCHLD: "); }
duk_pop(ctx);
break;
default:
ILibDuktape_EventEmitter_SetupEmit(ctx, h, SIGTABLE[((int*)sigbuffer)[1]]); // [emit][this][SIGTERM]
duk_push_string(ctx, SIGTABLE[((int*)sigbuffer)[1]]); // [emit][this][SIGTERM][name]
if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "Error Emitting %s: ", SIGTABLE[((int*)sigbuffer)[1]]); }
duk_pop(ctx);
break;
}
return(0);
}
void ILibDuktape_ScriptContainer_Process_SignalListener_PreSelect(void* object, fd_set *readset, fd_set *writeset, fd_set *errorset, int* blocktime)
{
if (SignalDescriptors[0] != 0)
{
FD_SET(SignalDescriptors[0], readset);
}
}
void ILibDuktape_ScriptContainer_Process_SignalListener_PostSelect(void* object, int slct, fd_set *readset, fd_set *writeset, fd_set *errorset)
{
int bytesRead = 0;
char sigbuffer[255];
ILibChain_Link *link = (ILibChain_Link*)object;
duk_context *ctx = (duk_context*)((void**)link->ExtraMemoryPtr)[0];
char *tmp;
if (FD_ISSET(SignalDescriptors[0], readset))
{
if((bytesRead = read(SignalDescriptors[0], sigbuffer, sizeof(int))) == sizeof(int) && ((int*)sigbuffer)[0] < sizeof(sigbuffer) &&
(bytesRead += read(SignalDescriptors[0], sigbuffer + sizeof(int), ((int*)sigbuffer)[0])) == ((int*)sigbuffer)[0])
{
duk_push_global_object(ctx); //[g]
duk_get_prop_string(ctx, -1, "setImmediate"); //[g][immediate]
duk_swap_top(ctx, -2); //[immediate][this]
duk_push_c_function(ctx, ILibDuktape_ScriptContainer_Process_SignalListener_Immediate, DUK_VARARGS);
tmp = duk_push_fixed_buffer(ctx, ((int*)sigbuffer)[0]); //[immediate][this][func][buffer]
memcpy_s(tmp, ((int*)sigbuffer)[0], sigbuffer, ((int*)sigbuffer)[0]);
duk_pcall_method(ctx, 2); duk_pop(ctx); // ...
}
else if(bytesRead == 0 || (errno != EAGAIN && errno != EWOULDBLOCK))
{
close(SignalDescriptors[0]);
close(SignalDescriptors[1]);
if (pipe(SignalDescriptors) == 0)
{
fcntl(SignalDescriptors[0], F_SETFL, O_NONBLOCK);
fcntl(SignalDescriptors[1], F_SETFL, O_NONBLOCK);
}
}
}
}
void ILibDuktape_ScriptContainer_Process_SignalListener(int signum, siginfo_t *info, void *context)
{
if (SignalDescriptors[1] != 0)
{
char tmp[255];
switch (signum)
{
case SIGCHLD:
((int*)tmp)[0] = (sizeof(int) * 4);
((int*)tmp)[1] = signum;
((pid_t*)tmp)[2] = info->si_pid;
((uid_t*)tmp)[3] = info->si_uid;
break;
case SIGTERM:
default:
((int*)tmp)[0] = sizeof(int) * 2;
((int*)tmp)[1] = signum;
break;
}
ignore_result(write(SignalDescriptors[1], tmp, ((int*)tmp)[0]));
}
}
#endif
duk_ret_t ILibDuktape_Process_setenv(duk_context *ctx)
{
char *name = (char*)duk_require_string(ctx, 0);
char *value = Duktape_GetBuffer(ctx, 1, NULL);
#ifdef WIN32
SetEnvironmentVariableA((LPCSTR)name, (LPCTSTR)value);
#else
if (value != NULL)
{
setenv(name, value, 1);
}
else
{
unsetenv(name);
}
#endif
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_coreDumpLocation_getter(duk_context *ctx)
{
if (g_ILibCrashDump_path == NULL)
{
duk_push_null(ctx);
}
else
{
#ifdef WIN32
ILibDuktape_String_PushWideString(ctx, g_ILibCrashDump_path, 0);
#else
duk_push_string(ctx, g_ILibCrashDump_path);
#endif
}
return(1);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_coreDumpLocation_setter(duk_context *ctx)
{
if (duk_is_null(ctx, 0))
{
g_ILibCrashDump_path = NULL;
duk_push_this(ctx); // [process]
duk_del_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_CoreDumpPath); // [process]
duk_pop(ctx); // ...
#ifndef WIN32
duk_eval_string_noresult(ctx, "process.rlimit.set(process.RLIMITS.CORE, {soft: 0, hard: 0});");
#endif
}
else
{
duk_push_this(ctx); // [process]
ILibDuktape_String_UTF8ToWideEx(ctx, (char*)duk_require_string(ctx, 0)); // [process][path]
g_ILibCrashDump_path = Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Process_CoreDumpPath); // [process]
duk_pop(ctx); // ...
#ifndef WIN32
#if defined(_POSIX) && !defined(__APPLE__) && !defined(_FREEBSD)
prctl(PR_SET_DUMPABLE, 1);
#endif
duk_eval_string_noresult(ctx, "process.rlimit.set(process.RLIMITS.CORE, {soft: -1, hard: -1});");
#endif
}
return(0);
}
#ifndef WIN32
duk_ret_t ILibDuktape_ScriptContainer_Process_rlimit_getterFunc(duk_context *ctx)
{
int resource = duk_require_int(ctx, 0);
struct rlimit r;
if (getrlimit(resource, &r) == 0)
{
duk_push_object(ctx);
duk_push_int(ctx, (duk_int_t)r.rlim_cur); duk_put_prop_string(ctx, -2, "soft");
duk_push_int(ctx, (duk_int_t)r.rlim_max); duk_put_prop_string(ctx, -2, "hard");
return(1);
}
return(ILibDuktape_Error(ctx, "Error Occured fetching limits"));
}
duk_ret_t ILibDuktape_ScriptContainer_Process_rlimit_setterFunc(duk_context *ctx)
{
int resource = duk_require_int(ctx, 0);
struct rlimit r;
r.rlim_cur = Duktape_GetIntPropertyValue(ctx, 1, "soft", -1);
r.rlim_max = Duktape_GetIntPropertyValue(ctx, 1, "hard", -1);
if (setrlimit(resource, &r) == 0)
{
return(0);
}
return(ILibDuktape_Error(ctx, "Error Occured settings limits"));
}
duk_ret_t ILibDuktape_ScriptContainer_Process_rlimit_getter(duk_context *ctx)
{
duk_push_object(ctx);
duk_push_c_function(ctx, ILibDuktape_ScriptContainer_Process_rlimit_getterFunc, 1); duk_put_prop_string(ctx, -2, "get");
duk_push_c_function(ctx, ILibDuktape_ScriptContainer_Process_rlimit_setterFunc, 2); duk_put_prop_string(ctx, -2, "set");
return(1);
}
#endif
duk_ret_t ILibDuktape_ScriptContainer_removeListenerSink(duk_context *ctx)
{
#ifdef _POSIX
int i;
struct sigaction action;
char *name = (char*)duk_require_string(ctx, 0);
duk_push_this(ctx); // [process]
for (i = 1; i < (sizeof(SIGTABLE) / sizeof(char*)); ++i)
{
if (strcmp(name, SIGTABLE[i]) == 0)
{
if (ILibDuktape_EventEmitter_HasListenersEx(ctx, -1, SIGTABLE[i]) == 0)
{
// No more listeners, so we can unhook the sighandler
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = SIG_DFL;
if (sigaction(i, &action, NULL) == 0) {}
}
}
}
#endif
return(0);
}
duk_ret_t ILibDuktape_Process_Exitting(duk_context *ctx)
{
duk_push_boolean(ctx, (duk_bool_t)duk_ctx_shutting_down(ctx));
return(1);
}
void ILibDuktape_Process_SemaphoreTracking_sink(char *source, void *user, int init)
{
duk_context *ctx = user;
if (ctx != NULL && duk_ctx_is_alive(ctx) != 0 && duk_ctx_shutting_down(ctx) == 0)
{
duk_push_heap_stash(ctx); // [stash]
int v = Duktape_GetIntPropertyValue(ctx, -1, "_SemTrack", 0);
duk_push_int(ctx, init ? (++v) : (--v)); // [stash][int]
duk_put_prop_string(ctx, -2, "_SemTrack"); // [stash]
duk_pop(ctx); // ...
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "console"); // [g][console]
duk_prepare_method_call(ctx, -1, "log"); // [g][console][log][this]
duk_push_sprintf(ctx, "[%d] Semaphore <<%s>> (%s)", v, source, init ? "INIT" : "DESTROY"); // [g][console][log][this][string]
duk_pcall_method(ctx, 1); // [g][console][val]
duk_pop_3(ctx); // ...
}
else
{
ILibSemaphoreTrack_user = NULL;
ILibSemaphoreTrack_func = NULL;
}
}
duk_ret_t ILibDuktape_Process_SemaphoreTracking(duk_context *ctx)
{
if (duk_require_boolean(ctx, 0) != 0)
{
duk_push_heap_stash(ctx); // [stash]
duk_push_int(ctx, 0); // [stash][int]
duk_put_prop_string(ctx, -2, "_SemTrack"); // [stash]
duk_pop(ctx); // ...
ILibSemaphoreTrack_user = ctx;
ILibSemaphoreTrack_func = ILibDuktape_Process_SemaphoreTracking_sink;
}
else
{
ILibSemaphoreTrack_user = NULL;
ILibSemaphoreTrack_func = NULL;
}
return(0);
}
duk_ret_t ILibDuktape_Process_SignalHooks(duk_context *ctx)
{
#ifdef _POSIX
int i;
char *eventname = (char*)duk_require_string(ctx, 0);
ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_GetEmitter_fromThis(ctx);
for (i = 1; i < (sizeof(SIGTABLE) / sizeof(char*)); ++i)
{
if (strcmp(eventname, SIGTABLE[i]) == 0)
{
if (ILibDuktape_EventEmitter_HasListeners2(emitter, eventname, 0) == 0)
{
// We are the first listener, so we need to set the signal handler
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = ILibDuktape_ScriptContainer_Process_SignalListener;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
if (sigaction(i, &action, NULL) == 0) {}
}
break;
}
}
#endif
return(0);
}
duk_ret_t ILibDuktape_Process_chdir(duk_context *ctx)
{
char *path = (char*)duk_require_string(ctx, 0);
#ifdef WIN32
if (_wchdir(ILibUTF8ToWide(path, -1)) != 0) { return(ILibDuktape_Error(ctx, "chdir() failed")); }
#else
if (chdir(path) != 0) { return(ILibDuktape_Error(ctx, "chdir() failed")); }
#endif
return(0);
}
void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList)
{
int i = 0;
ILibDuktape_EventEmitter *emitter;
#ifndef MICROSTACK_NOTLS
char *sslv = (char*)SSLeay_version(SSLEAY_VERSION);
char *sslvS = strstr(sslv, " ") + 1;
#endif
duk_push_global_object(ctx); // [g]
duk_push_object(ctx); // [g][process]
ILibDuktape_WriteID(ctx, "process");
ILibDuktape_CreateEventWithGetter(ctx, "env", ILibDuktape_ScriptContainer_Process_env);
ILibDuktape_CreateInstanceMethod(ctx, "cwd", ILibDuktape_Process_cwd, 0);
ILibDuktape_CreateInstanceMethod(ctx, "chdir", ILibDuktape_Process_chdir, 1);
ILibDuktape_CreateInstanceMethod(ctx, "setenv", ILibDuktape_Process_setenv, 2);
ILibDuktape_CreateEventWithSetterEx(ctx, "_SemaphoreTracking", ILibDuktape_Process_SemaphoreTracking);
ILibDuktape_CreateEventWithGetterAndSetterEx(ctx, "coreDumpLocation", ILibDuktape_ScriptContainer_Process_coreDumpLocation_getter, ILibDuktape_ScriptContainer_Process_coreDumpLocation_setter);
#ifndef WIN32
ILibDuktape_CreateEventWithGetter(ctx, "rlimit", ILibDuktape_ScriptContainer_Process_rlimit_getter);
Duktape_CreateEnumEx(ctx, (char*[]) { "AS", "CORE", "CPU", "DATA", "FSIZE", "LOCKS", "MEMLOCK", "MGSQUEUE", "NICE", "NOFILE", "NPROC", "RSS", "RTPRIO", "SIGPENDING", "STACK" },
(int[]) {9, 4, 0, 2, 1, 10, 8, 12, 13, 7, 6, 5, 14, 11, 3}, 15);
duk_put_prop_string(ctx, -2, "RLIMITS");
#endif
duk_push_object(ctx);
duk_push_int(ctx, 0); duk_put_prop_string(ctx, -2, "UNKNOWN" );
duk_push_int(ctx, 1); duk_put_prop_string(ctx, -2, "SIGHUP" );
duk_push_int(ctx, 2); duk_put_prop_string(ctx, -2, "SIGINT" );
duk_push_int(ctx, 3); duk_put_prop_string(ctx, -2, "SIGQUIT" );
duk_push_int(ctx, 4); duk_put_prop_string(ctx, -2, "SIGILL" );
duk_push_int(ctx, 5); duk_put_prop_string(ctx, -2, "SIGTRAP" );
duk_push_int(ctx, 6); duk_put_prop_string(ctx, -2, "SIGABRT" );
duk_push_int(ctx, 7); duk_put_prop_string(ctx, -2, "SIGBUS" );
duk_push_int(ctx, 8); duk_put_prop_string(ctx, -2, "SIGFPE" );
duk_push_int(ctx, 9); duk_put_prop_string(ctx, -2, "SIGKILL" );
duk_push_int(ctx, 10); duk_put_prop_string(ctx, -2, "SIGUSR1" );
duk_push_int(ctx, 11); duk_put_prop_string(ctx, -2, "SIGEGV" );
duk_push_int(ctx, 12); duk_put_prop_string(ctx, -2, "SIGUSR2" );
duk_push_int(ctx, 13); duk_put_prop_string(ctx, -2, "SIGPIPE" );
duk_push_int(ctx, 14); duk_put_prop_string(ctx, -2, "SIGALRM" );
duk_push_int(ctx, 15); duk_put_prop_string(ctx, -2, "SIGTERM" );
duk_push_int(ctx, 16); duk_put_prop_string(ctx, -2, "SIGSTKFLT");
duk_push_int(ctx, 17); duk_put_prop_string(ctx, -2, "SIGCHLD" );
duk_push_int(ctx, 18); duk_put_prop_string(ctx, -2, "SIGCONT" );
duk_push_int(ctx, 19); duk_put_prop_string(ctx, -2, "SIGSTOP" );
duk_push_int(ctx, 20); duk_put_prop_string(ctx, -2, "SIGTSTP" );
duk_push_int(ctx, 21); duk_put_prop_string(ctx, -2, "SIGTTIN" );
duk_push_int(ctx, 22); duk_put_prop_string(ctx, -2, "SIGTTOU" );
duk_push_int(ctx, 23); duk_put_prop_string(ctx, -2, "SIGURG" );
duk_push_int(ctx, 24); duk_put_prop_string(ctx, -2, "SIGXCPU" );
duk_push_int(ctx, 25); duk_put_prop_string(ctx, -2, "SIGXFSZ" );
duk_push_int(ctx, 26); duk_put_prop_string(ctx, -2, "SIGVTALRM");
duk_push_int(ctx, 27); duk_put_prop_string(ctx, -2, "SIGPROF" );
duk_push_int(ctx, 28); duk_put_prop_string(ctx, -2, "SIGWINCH" );
duk_push_int(ctx, 29); duk_put_prop_string(ctx, -2, "SIGIO" );
duk_push_int(ctx, 29); duk_put_prop_string(ctx, -2, "SIGPOLL" );
duk_push_int(ctx, 30); duk_put_prop_string(ctx, -2, "SIGPWR" );
duk_push_int(ctx, 31); duk_put_prop_string(ctx, -2, "SIGSYS" );
duk_put_prop_string(ctx, -2, "SIGTABLE");
duk_push_object(ctx);
#ifndef MICROSTACK_NOTLS
if (sslvS != ((char*)NULL + 1))
{
char *tmp = strstr(sslvS, " ");
if (tmp != NULL)
{
duk_push_lstring(ctx, sslvS, (duk_size_t)(tmp - sslvS));
duk_put_prop_string(ctx, -2, "openssl");
}
}
#endif
duk_push_string(ctx, DUK_GIT_DESCRIBE); duk_put_prop_string(ctx, -2, "duktape");
if (SOURCE_COMMIT_DATE != NULL)
{
duk_eval_string(ctx,
"(function translateDate(COMMIT_DATE)\
{\
var MONTH_TRANSLATE =\
{\
'Jan' : '01',\
'Feb' : '02',\
'Mar' : '03',\
'Apr' : '04',\
'May' : '05',\
'Jun' : '06',\
'Jul' : '07',\
'Aug' : '08',\
'Sep' : '09',\
'Oct' : '10',\
'Nov' : '11',\
'Dec' : '12'\
};\
var tz = COMMIT_DATE.substring(COMMIT_DATE.length-2);\
COMMIT_DATE = COMMIT_DATE.substring(0, COMMIT_DATE.length-2) + ':' + tz;\
var tmp = COMMIT_DATE.split('-');\
tmp[1] = MONTH_TRANSLATE[tmp[1]];\
var day = tmp[2];\
var day2 = day.split(' ');\
day2[0] = day2[0].padStart(2, '0');\
tmp[2] = day2.join(' ');\
return (new Date(tmp.join('-')));\
})"); // [func]
duk_push_string(ctx, SOURCE_COMMIT_DATE); // [func][date]
if (duk_pcall(ctx, 1) == 0)
{
duk_put_prop_string(ctx, -2, "commitDate");
}
else
{
duk_pop(ctx);
}
if (SOURCE_COMMIT_HASH != NULL)
{
duk_push_string(ctx, SOURCE_COMMIT_HASH); duk_put_prop_string(ctx, -2, "commitHash");
}
duk_push_sprintf(ctx, "%s, %s", __TIME__, __DATE__); duk_put_prop_string(ctx, -2, "compileTime");
}
ILibDuktape_CreateReadonlyProperty(ctx, "versions");
#if defined(WIN32) // [g][process][platform]
duk_push_string(ctx, "win32");
#elif defined(__APPLE__)
duk_push_string(ctx, "darwin");
#elif defined(_FREEBSD)
duk_push_string(ctx, "freebsd");
#else
duk_push_string(ctx, "linux");
#endif
duk_put_prop_string(ctx, -2, "platform"); // [g][process]
duk_push_heap_stash(ctx); // [g][process][stash]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_ExePath))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_ExePath); // [g][process][stash][path]
duk_swap_top(ctx, -2); // [g][process][path][stash]
duk_pop(ctx); // [g][process][path]
ILibDuktape_CreateReadonlyProperty(ctx, "execPath"); // [g][process]
}
else
{
duk_pop(ctx); // [g][process]
}
if (argList != NULL)
{
duk_push_array(ctx); // [g][process][array]
while (argList[i] != NULL)
{
duk_push_string(ctx, argList[i]); // [g][process][array][val]
duk_put_prop_index(ctx, -2, i); // [g][process][array]
++i;
}
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Process_ArgArray); // [g][process]
}
#ifdef _POSIX
duk_push_int(ctx, (duk_int_t)getpid());
#else
duk_push_int(ctx, (duk_int_t)GetCurrentProcessId());
#endif
ILibDuktape_CreateReadonlyProperty(ctx, "pid");
emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "exit");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit", ILibDuktape_ScriptContainer_Process_Exit, DUK_VARARGS);
ILibDuktape_CreateProperty_InstanceMethod(ctx, "_exit", ILibDuktape_ScriptContainer_Process_ExitEx, DUK_VARARGS);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "uncaughtException");
for (i = 1; i < 31; ++i)
{
ILibDuktape_EventEmitter_CreateEventEx(emitter, SIGTABLE[i]);
}
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "newListener", ILibDuktape_Process_SignalHooks);
ILibDuktape_EventEmitter_AddOnEx(ctx, -1, "removeListener", ILibDuktape_ScriptContainer_removeListenerSink);
ILibDuktape_CreateEventWithGetter(ctx, "exitting", ILibDuktape_Process_Exitting);
ILibDuktape_CreateEventWithGetter(ctx, "argv0", ILibDuktape_ScriptContainer_Process_Argv0);
duk_push_int(ctx, 1);
ILibDuktape_CreateEventWithGetterAndCustomProperty(ctx, "readOnly", "argv", ILibDuktape_ScriptContainer_Process_Argv);
duk_push_int(ctx, 0);
ILibDuktape_CreateEventWithGetterAndCustomProperty(ctx, "readOnly", "_argv", ILibDuktape_ScriptContainer_Process_Argv);
duk_push_heap_stash(ctx); // [g][process][stash]
if (!duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_SlavePtr))
{
duk_pop(ctx); // [g][process]
ILibDuktape_CreateEventWithGetter(ctx, "stdin", ILibDuktape_Process_stdin_get);
ILibDuktape_CreateEventWithGetter(ctx, "stdout", ILibDuktape_Process_stdout_get);
ILibDuktape_CreateEventWithGetter(ctx, "stderr", ILibDuktape_Process_stderr_get);
}
else
{
duk_pop(ctx); // [g][process]
}
ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ScriptContainer_Process_Kill, DUK_VARARGS);
duk_put_prop_string(ctx, -2, "process"); // [g]
duk_pop(ctx); // ...
ILibDuktape_EventEmitter_AddOnceEx(emitter, "~", ILibDuktape_ScriptContainer_Process_Finalizer, 1);
#ifdef _POSIX
if (SignalDescriptors[0] == 0 && SignalDescriptors[1] == 0)
{
if (pipe(SignalDescriptors) == 0)
{
fcntl(SignalDescriptors[0], F_SETFL, O_NONBLOCK);
fcntl(SignalDescriptors[1], F_SETFL, O_NONBLOCK);
void *chain = Duktape_GetChain(ctx);
ILibChain_Link *k = ILibChain_Link_Allocate(sizeof(ILibChain_Link), 2 * sizeof(void*));
((void**)k->ExtraMemoryPtr)[0] = ctx;
((void**)k->ExtraMemoryPtr)[1] = emitter->object;
k->MetaData = "Signal_Listener";
k->PreSelectHandler = ILibDuktape_ScriptContainer_Process_SignalListener_PreSelect;
k->PostSelectHandler = ILibDuktape_ScriptContainer_Process_SignalListener_PostSelect;
ILibAddToChain(chain, k);
duk_push_heapptr(ctx, emitter->object); // [process]
duk_push_pointer(ctx, k); // [process][ptr]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Signal_ListenerPtr); // [process]
duk_pop(ctx); // ...
}
}
#endif
}
void* ILibDuktape_Process_GetSignalListener(duk_context *ctx)
{
void *ret = NULL;
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "process"); // [g][p]
ret = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Signal_ListenerPtr);
duk_pop_2(ctx); // ...
return(ret);
}
void ILibDuktape_ScriptContainer_ExecTimeout_Finalizer(duk_context *ctx, void *timeoutKey)
{
if (ILibIsChainBeingDestroyed((Duktape_GetChain(ctx))) == 0)
{
ILibLifeTime_Remove(ILibGetBaseTimer(Duktape_GetChain(ctx)), timeoutKey);
}
free(timeoutKey);
}
// Called when the executation timeout occurs
void ILibDuktape_ScriptContainer_ExecTimeout(void *obj)
{
duk_context *ctx = (duk_context*)((void**)obj)[0];
ILibRemoteLogging_printf(ILibChainGetLogger(Duktape_GetChain(ctx)), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "Script Container Execution Timeout Elapsed");
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "process"); // [g][process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Exitting)) { duk_pop_2(ctx); return; }
duk_push_int(ctx, 5);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ExitCode); // [g][process]
duk_pop_2(ctx); // ...
Duktape_SafeDestroyHeap(ctx);
}
SCRIPT_ENGINE_SETTINGS* ILibDuktape_ScriptContainer_GetSettings(duk_context *ctx)
{
SCRIPT_ENGINE_SETTINGS *settings = (SCRIPT_ENGINE_SETTINGS*)ILibMemory_SmartAllocate(sizeof(SCRIPT_ENGINE_SETTINGS));
memset(settings, 0, sizeof(SCRIPT_ENGINE_SETTINGS));
settings->chain = Duktape_GetChain(ctx);
duk_push_heap_stash(ctx); // [s]
settings->securityFlags = (SCRIPT_ENGINE_SECURITY_FLAGS)Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_Settings_SecurityFlags, 0); // [s]
settings->executionTimeout = (unsigned int)Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExecutionTimeout, 0); // [s]
settings->exitHandler = (ILibDuktape_HelperEvent)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExitHandler); // [s]
settings->exitUserObject = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExitUser); // [s]
settings->db = (ILibSimpleDataStore)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_DB); // [s]
settings->exePath = Duktape_Duplicate_GetStringPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_ExePath, NULL); // [s]
settings->pipeManager = (ILibProcessPipe_Manager)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_PipeManager); // [s]
duk_pop(ctx); // ...
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "process"); // [g][process]
settings->coreDumpLocation = (char*)Duktape_Duplicate_GetBufferProperty(ctx, -1, ILibDuktape_ScriptContainer_Process_CoreDumpPath);
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray); // [g][process][array]
int i, count = (int)duk_get_length(ctx, -1);
if (count > 0)
{
settings->argList = (char**)ILibMemory_SmartAllocate((1 + count) * sizeof(char*));
for (i = 0; i < count; ++i)
{
duk_get_prop_index(ctx, -1, i); // [g][process][array][index]
settings->argList[i] = Duktape_Duplicate_GetString(ctx, -1);
duk_pop(ctx); // [g][process][array]
}
settings->argList[i] = NULL;
}
duk_pop(ctx); // [g][process]
if (duk_has_prop_string(ctx, -1, ILibDuktape_NativeUncaughtExceptionPtr))
{
duk_get_prop_string(ctx, -1, ILibDuktape_NativeUncaughtExceptionPtr); // [g][process][handler]
duk_get_prop_string(ctx, -2, ILibDuktape_NativeUncaughtExceptionUserPtr); // [g][process][handler][user]
settings->nExeptionHandler = (ILibDuktape_NativeUncaughtExceptionHandler)duk_get_pointer(ctx, -2);
settings->nExceptionUserObject = duk_get_pointer(ctx, -1);
duk_pop_2(ctx); // [g][process]
}
duk_pop_2(ctx); // ...
return(settings);
}
void ILibDuktape_ScriptContainer_FreeSettings(SCRIPT_ENGINE_SETTINGS *settings)
{
if (!ILibMemory_CanaryOK(settings)) { return; }
ILibMemory_Free(settings->exePath);
ILibMemory_Free(settings->coreDumpLocation);
if (settings->argList != NULL)
{
int i;
for (i = 0; settings->argList[i] != NULL; ++i)
{
ILibMemory_Free(settings->argList[i]);
}
ILibMemory_Free(settings->argList);
}
ILibMemory_Free(settings);
}
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx2(SCRIPT_ENGINE_SETTINGS *settings)
{
duk_context *ctx = ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(settings->securityFlags, settings->executionTimeout, settings->chain, settings->argList, settings->db, settings->exePath, settings->pipeManager, settings->exitHandler, settings->exitUserObject);
if (settings->coreDumpLocation != NULL)
{
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "process"); // [g][process]
#ifdef WIN32
ILibDuktape_String_PushWideString(ctx, settings->coreDumpLocation, 0);
#else
duk_push_string(ctx, settings->coreDumpLocation); // [g][process][location]
#endif
duk_put_prop_string(ctx, -2, "coreDumpLocation"); // [g][process]
duk_pop_2(ctx); // ...
}
return(ctx);
}
size_t ILibDuktape_ScriptContainer_TotalAllocations = 0;
void *ILibDuktape_ScriptContainer_Engine_malloc(void *udata, duk_size_t size)
{
ILibDuktape_ScriptContainer_TotalAllocations += size;
void *ptr = ILibMemory_SmartAllocateEx(size, sizeof(void*));
((void**)ILibMemory_Extra(ptr))[0] = udata;
return(ptr);
}
void *ILibDuktape_ScriptContainer_Engine_realloc(void *udata, void *ptr, duk_size_t size)
{
size_t difference = 0;
if (ptr != NULL)
{
if (ILibMemory_Size(ptr) > size)
{
// Memory Shrink
difference = ILibMemory_Size(ptr) - size;
ILibDuktape_ScriptContainer_TotalAllocations -= difference;
}
else
{
difference = size - ILibMemory_Size(ptr);
ILibDuktape_ScriptContainer_TotalAllocations += difference;
}
//if (size == 0)
//{
// ILibMemory_Free(ptr);
// ptr = NULL;
//}
//else
{
ptr = ILibMemory_SmartReAllocate(ptr, size);
}
}
else
{
//if (size > 0)
{
ptr = ILibMemory_SmartAllocateEx(size, sizeof(void*));
((void**)ILibMemory_Extra(ptr))[0] = udata;
ILibDuktape_ScriptContainer_TotalAllocations += size;
}
}
return(ptr);
}
void ILibDuktape_ScriptContainer_Engine_free(void *udata, void *ptr)
{
size_t sz = ptr == NULL ? 0 : ILibMemory_Size(ptr);
if (ptr != NULL && ILibMemory_CanaryOK(ptr))
{
ILibDuktape_ScriptContainer_TotalAllocations -= ILibMemory_Size(ptr);
ILibMemory_SecureZero(ptr, sz);
ILibMemory_Free(ptr);
}
}
void ILibDuktape_ScriptContainer_Engine_fatal(void *udata, const char *msg)
{
ILIBCRITICALEXITMSG(254, msg);
}
duk_ret_t ILibDuktape_ScriptContainer_OS_arch(duk_context *ctx)
{
#ifdef WIN32
if (sizeof(void*) == 8)
{
// We are 64 bit App, so we must be on 64 bit Windows
duk_push_string(ctx, "x64");
}
else
{
void *func = (void*)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
BOOL isWow = FALSE;
if (func != NULL)
{
isWow = FALSE;
BOOL result = ((BOOL(__stdcall *)(HANDLE, BOOL*))func)(GetCurrentProcess(), &isWow);
if (result)
{
// We are 32 bit App running on 64 bit Windows
if (isWow)
{
duk_push_string(ctx, "x64");
}
else
{
duk_push_string(ctx, "ia32");
}
}
else
{
// We are 32 bit App running on 32 bit Windows
duk_push_string(ctx, "ia32");
}
}
else
{
// We are 32 bit App running on 32 bit Windows
duk_push_string(ctx, "ia32");
}
}
return(1);
#else
struct utsname u;
if (uname(&u) != 0) { return(ILibDuktape_Error(ctx, "Could not determine architecture")); }
if (strcmp(u.machine, "amd64") == 0)
{
duk_push_string(ctx, "x64");
}
else if (u.machine[0] == 'i')
{
duk_push_string(ctx, "ia32");
}
else
{
if (strcmp(u.machine, "x86_64") == 0)
{
#if !defined(__APPLE__) && !defined(_FREEBSD)
duk_eval_string(ctx, "require('os')._longbit");
if (duk_get_int(ctx, -1) == 32)
{
duk_push_string(ctx, "ia32");
}
else
{
duk_push_string(ctx, "x64");
}
#else
duk_push_string(ctx, "x64");
#endif
}
else if (strcmp(u.machine, "arm64") == 0 || strcmp(u.machine, "aarch64") == 0)
{
duk_push_string(ctx, "arm64");
}
else
{
int mlen = strlen(u.machine); // size is not specified, but is gauranteed to be NULL terminated
if (mlen > 4 && strncmp(u.machine, "armv", 4) == 0)
{
if (ILib_atoi2_int32(u.machine + 4, mlen) > 7)
{
duk_push_string(ctx, "arm64");
}
else
{
duk_push_string(ctx, "arm");
}
}
else
{
if (strcmp(u.machine, "mips") == 0)
{
duk_push_string(ctx, "mips");
}
else if (strcmp(u.machine, "mipsel") == 0)
{
duk_push_string(ctx, "mipsel");
}
else
{
return(ILibDuktape_Error(ctx, "Could not determine architecture"));
}
}
}
}
return(1);
#endif
}
duk_ret_t ILibDuktape_ScriptContainer_OS_platform(duk_context *ctx)
{
duk_eval_string(ctx, "process.platform");
return 1;
}
#ifndef WIN32
int ILibDuktape_ScriptContainer_os_isWirelessInterface(char *interfaceName)
{
int s, retVal = 0;
char data[4096];
memset(&data, 0, sizeof(data));
strncpy(data, interfaceName, IFNAMSIZ);
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0 && (s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP)) < 0)
{
return(0);
}
if (ioctl(s, 0x8B01, &data) != -1)
{
retVal = 1;
}
close(s);
return(retVal);
}
#endif
#if !defined(__APPLE__) && !defined(_FREEBSD)
duk_ret_t ILibDuktape_ScriptContainer_OS_networkInterfaces(duk_context *ctx)
{
#if !defined(WIN32)
duk_eval_string(ctx, "require('os').getDefaultGateways();");
#ifndef NO_IFADDR
void *gwTable = duk_get_heapptr(ctx, -1);
#endif
#endif
duk_push_object(ctx); // [retVal]
#ifdef WIN32
duk_push_object(ctx); // [retVal][indexTable]
void *indexTable = duk_get_heapptr(ctx, -1);
ILibDuktape_CreateReadonlyProperty(ctx, "interfaceIndexes");
char fqdn[4096];
int i = 0;
char tmpBuffer[32768];
DWORD tmpBufferSize = sizeof(tmpBuffer);
IP_ADAPTER_ADDRESSES *padapters = (IP_ADAPTER_ADDRESSES*)tmpBuffer;
unsigned long mask;
if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_GATEWAYS | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST, NULL, (PIP_ADAPTER_ADDRESSES)tmpBuffer, &tmpBufferSize) != NO_ERROR) { return(ILibDuktape_Error(ctx, "os.networkInterfaces(): Internal Error")); }
while (padapters != NULL)
{
IP_ADAPTER_UNICAST_ADDRESS *addr = padapters->FirstUnicastAddress;
i = 0;
duk_push_array(ctx);
while (addr != NULL)
{
duk_push_object(ctx);
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)addr->Address.lpSockaddr));
duk_put_prop_string(ctx, -2, "address");
if (padapters->FirstGatewayAddress != NULL && ((struct sockaddr*)padapters->FirstGatewayAddress->Address.lpSockaddr)->sa_family == ((struct sockaddr*)addr->Address.lpSockaddr)->sa_family)
{
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)padapters->FirstGatewayAddress->Address.lpSockaddr));
duk_put_prop_string(ctx, -2, "gateway");
}
ILibWideToUTF8Ex((wchar_t*)padapters->DnsSuffix, -1, fqdn, (int)sizeof(fqdn));
duk_push_string(ctx, fqdn);
duk_put_prop_string(ctx, -2, "fqdn");
duk_push_string(ctx, ((struct sockaddr_in*)addr->Address.lpSockaddr)->sin_family == AF_INET6 ? "IPv6" : "IPv4");
duk_put_prop_string(ctx, -2, "family");
if (((struct sockaddr_in*)addr->Address.lpSockaddr)->sin_family == AF_INET)
{
if (ConvertLengthToIpv4Mask(addr->OnLinkPrefixLength, &mask) == NO_ERROR)
{
struct sockaddr_in tmpAddr;
memset(&tmpAddr, 0, sizeof(struct sockaddr_in));
tmpAddr.sin_family = AF_INET;
tmpAddr.sin_addr.s_addr = mask;
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)&tmpAddr));
duk_put_prop_string(ctx, -2, "netmask");
}
}
duk_push_string(ctx, padapters->PhysicalAddressLength>0 ? util_tohex2(padapters->PhysicalAddress, padapters->PhysicalAddressLength, ILibScratchPad) : "00:00:00:00:00:00");
duk_put_prop_string(ctx, -2, "mac");
duk_push_int(ctx, padapters->IfIndex); duk_put_prop_string(ctx, -2, "index");
duk_push_string(ctx, padapters->OperStatus == IfOperStatusUp ? "up" : "down");
duk_put_prop_string(ctx, -2, "status");
switch (padapters->IfType)
{
case IF_TYPE_ETHERNET_CSMACD:
duk_push_string(ctx, "ethernet");
break;
case IF_TYPE_IEEE80211:
duk_push_string(ctx, "wireless");
break;
case IF_TYPE_TUNNEL:
duk_push_string(ctx, "tunnel");
break;
case IF_TYPE_SOFTWARE_LOOPBACK:
duk_push_string(ctx, "loopback");
break;
default:
duk_push_string(ctx, "other");
break;
}
duk_put_prop_string(ctx, -2, "type");
duk_put_prop_index(ctx, -2, i++);
addr = addr->Next;
}
ILibWideToUTF8Ex(padapters->FriendlyName, -1, ILibScratchPad, (int)sizeof(ILibScratchPad));
duk_put_prop_string(ctx, -2, ILibScratchPad);
duk_push_heapptr(ctx, indexTable); // [table]
duk_push_int(ctx, (int)padapters->IfIndex); // [table][index]
duk_push_string(ctx, ILibScratchPad); // [table][index][name]
duk_put_prop(ctx, -3); // [table]
duk_pop(ctx); // ...
padapters = padapters->Next;
}
#else
#ifndef NO_IFADDR
struct ifaddrs *addrlist;
struct ifaddrs *current;
if (getifaddrs(&addrlist) == 0)
{
current = addrlist;
while (current != NULL)
{
if (current->ifa_addr != NULL)
{
if (((struct sockaddr_in*)current->ifa_addr)->sin_family == AF_PACKET)
{
struct sockaddr_ll *pk = (struct sockaddr_ll*)current->ifa_addr;
char *mac = "00:00:00:00:00:00";
int isWireless = ILibDuktape_ScriptContainer_os_isWirelessInterface(current->ifa_name);
if (pk->sll_halen > 0)
{
util_tohex2((char*)pk->sll_addr, pk->sll_halen, ILibScratchPad);
mac = ILibScratchPad;
}
if (!duk_has_prop_string(ctx, -1, current->ifa_name))
{
duk_push_array(ctx); // [array]
duk_push_string(ctx, mac);
duk_put_prop_string(ctx, -2, "\xFF_mac");
if (isWireless != 0) duk_push_string(ctx, "wireless"); else duk_push_string(ctx, "ethernet");
duk_put_prop_string(ctx, -2, "\xFF_type");
duk_put_prop_string(ctx, -2, current->ifa_name); // ...
}
else
{
int i, alen;
duk_get_prop_string(ctx, -1, current->ifa_name); // [array]
duk_push_string(ctx, mac);
duk_put_prop_string(ctx, -2, "\xFF_mac");
if (isWireless != 0) duk_push_string(ctx, "wireless"); else duk_push_string(ctx, "ethernet");
duk_put_prop_string(ctx, -2, "\xFF_type");
alen = duk_get_length(ctx, -1);
for (i = 0; i < alen; ++i)
{
duk_get_prop_index(ctx, -1, i);
duk_push_string(ctx, mac);
duk_put_prop_string(ctx, -2, "mac");
if (isWireless != 0) duk_push_string(ctx, "wireless"); else duk_push_string(ctx, "ethernet");
duk_put_prop_string(ctx, -2, "type");
duk_pop(ctx);
}
duk_pop(ctx); // ...
}
}
if (((struct sockaddr_in*)current->ifa_addr)->sin_family == AF_INET || ((struct sockaddr_in*)current->ifa_addr)->sin_family == AF_INET6)
{
if (duk_has_prop_string(ctx, -1, current->ifa_name))
{
duk_get_prop_string(ctx, -1, current->ifa_name);
}
else
{
duk_push_array(ctx);
}
duk_push_object(ctx);
if (duk_has_prop_string(ctx, -2, "\xFF_mac"))
{
duk_get_prop_string(ctx, -2, "\xFF_mac");
duk_put_prop_string(ctx, -2, "mac");
}
if (duk_has_prop_string(ctx, -2, "\xFF_type"))
{
duk_get_prop_string(ctx, -2, "\xFF_type");
duk_put_prop_string(ctx, -2, "type");
}
duk_push_string(ctx, "up");
duk_put_prop_string(ctx, -2, "status");
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress(current->ifa_addr));
duk_put_prop_string(ctx, -2, "address");
duk_push_string(ctx, ((struct sockaddr_in*)current->ifa_addr)->sin_family == AF_INET ? "IPv4" : "IPv6");
duk_put_prop_string(ctx, -2, "family");
if (((struct sockaddr_in*)current->ifa_addr)->sin_family == AF_INET)
{
duk_push_heapptr(ctx, gwTable); // [table]
if (duk_has_prop_string(ctx, -1, current->ifa_name))
{
duk_get_prop_string(ctx, -1, current->ifa_name); // [table][gwAddress]
duk_remove(ctx, -2); // [gwAddress]
duk_put_prop_string(ctx, -2, "gateway"); // ...
}
else
{
duk_pop(ctx);
}
}
duk_push_string(ctx, ILibRemoteLogging_ConvertAddress(current->ifa_netmask));
duk_put_prop_string(ctx, -2, "netmask");
duk_put_prop_index(ctx, -2, duk_get_length(ctx, -2));
duk_put_prop_string(ctx, -2, current->ifa_name);
}
}
current = current->ifa_next;
}
freeifaddrs(addrlist);
}
duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);
while (duk_next(ctx, -1, 1))
{
if (duk_get_length(ctx, -1) == 0)
{
duk_push_object(ctx);
duk_get_prop_string(ctx, -2, "\xFF_mac");
duk_put_prop_string(ctx, -2, "mac");
duk_get_prop_string(ctx, -2, "\xFF_type");
duk_put_prop_string(ctx, -2, "type");
duk_push_string(ctx, "up");
duk_put_prop_string(ctx, -2, "status");
duk_put_prop_index(ctx, -2, duk_get_length(ctx, -2));
}
duk_pop_2(ctx);
}
duk_pop(ctx);
#endif
#endif
return(1);
}
#endif
duk_ret_t ILibDuktape_ScriptContainer_OS_hostname(duk_context *ctx)
{
char name[1024];
if (gethostname(name, (int)sizeof(name)) == 0)
{
duk_push_string(ctx, name);
}
else
{
duk_push_string(ctx, "");
}
return(1);
}
duk_ret_t ILibDuktape_ScriptContainer_OS_endianness(duk_context *ctx)
{
int16_t test = 0x0001;
duk_push_string(ctx, ((char*)&test)[0] ? "LE" : "BE");
return(1);
}
duk_ret_t ILibDuktape_tmpdir(duk_context *ctx)
{
#ifdef WIN32
WCHAR tmp[1024];
if (GetTempPathW(sizeof(tmp) / 2, (LPWSTR)tmp) == 0) { return(ILibDuktape_Error(ctx, "Error getting temp folder")); }
ILibDuktape_String_PushWideString(ctx, (char*)tmp, 0);
#elif defined (_POSIX)
#if defined(__APPLE__)
duk_eval_string(ctx, "process.env['TMPDIR']");
if (duk_is_undefined(ctx, -1)) { duk_push_string(ctx, "/private/tmp/"); }
#else
duk_push_string(ctx, "/var/tmp/");
#endif
#endif
return(1);
}
void ILibDuktape_ScriptContainer_OS_Push(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [os]
ILibDuktape_WriteID(ctx, "os");
#ifdef WIN32
duk_push_string(ctx, "\r\n");
#else
duk_push_string(ctx, "\n");
#endif
ILibDuktape_CreateReadonlyProperty(ctx, "EOL");
#ifndef __APPLE__
ILibDuktape_CreateInstanceMethod(ctx, "arch", ILibDuktape_ScriptContainer_OS_arch, 0);
#endif
ILibDuktape_CreateInstanceMethod(ctx, "platform", ILibDuktape_ScriptContainer_OS_platform, 0);
ILibDuktape_CreateInstanceMethod(ctx, "endianness", ILibDuktape_ScriptContainer_OS_endianness, 0);
#if !defined(__APPLE__) && !defined(_FREEBSD)
ILibDuktape_CreateInstanceMethod(ctx, "networkInterfaces", ILibDuktape_ScriptContainer_OS_networkInterfaces, 0);
#endif
ILibDuktape_CreateInstanceMethod(ctx, "hostname", ILibDuktape_ScriptContainer_OS_hostname, 0);
ILibDuktape_CreateInstanceMethod(ctx, "tmpdir", ILibDuktape_tmpdir, 0);
char jsExtras[] = "exports.getPrimaryDnsSuffix = function getPrimaryDnsSuffix()\
{\
if (process.platform == 'win32')\
{\
var DsRolePrimaryDomainInfoBasic = 1;\
var marshal = require('_GenericMarshal');\
var netapi32 = marshal.CreateNativeProxy('netapi32.dll');\
netapi32.CreateMethod('DsRoleGetPrimaryDomainInformation');\
netapi32.CreateMethod('DsRoleFreeMemory');\
var kernel32 = marshal.CreateNativeProxy('kernel32.dll');\
kernel32.CreateMethod('GetLastError');\
var info = marshal.CreatePointer();\
if (netapi32.DsRoleGetPrimaryDomainInformation(0, DsRolePrimaryDomainInfoBasic, info).Val != 0) \
{\
throw ('Error[' = kernel32.GetLastError().Val + '] when trying to call DsRoleGetPrimaryDomainInformation');\
}\
var suffix = info.Deref().Deref(marshal.PointerSize == 4 ? 12 : 16, marshal.PointerSize).Deref().AnsiString;\
var flat = info.Deref().Deref(8, marshal.PointerSize).Deref().AnsiString;\
netapi32.DsRoleFreeMemory(info.Deref());\
return (suffix.length > 0 ? suffix : flat);\
}\
else\
{\
var resolv = require('fs').readFileSync('/etc/resolv.conf');\
var lines = resolv.toString().split('\\n');\
for (var i in lines)\
{\
var tokens = lines[i].split(' ');\
if (tokens[0] == 'domain')\
{\
return (tokens[1]);\
}\
}\
return ('');\
}\
};\
if(process.platform == 'darwin')\
{\
exports.arch = function arch()\
{\
var child = require('child_process').execFile('/bin/sh', ['sh']);\
child.stdout.str = ''; child.stdout.on('data', function(c) { this.str += c.toString(); });\
child.stderr.str = ''; child.stderr.on('data', function(c) { this.str += c.toString(); });\
child.stdin.write(\"sysctl -a | grep brand_string | awk -F: '{ split($2,tok,\\\" \\\"); if(tok[1]==\\\"Apple\\\" || tok[1]==\\\"VirtualApple\\\") { print \\\"arm64\\\"; } else { print \\\"x64\\\"; } }'\\nexit\\n\");\
child.waitExit();\
return(child.stdout.str.trim());\
};\
}\
if(process.platform == 'linux')\
{\
Object.defineProperty(exports, '_longbit', {value: (function ()\
{\
var child = require('child_process').execFile('/bin/sh', ['sh']);\
child.stdout.str = ''; child.stdout.on('data', function(c) { this.str += c.toString(); });\
child.stderr.str = ''; child.stderr.on('data', function(c) { this.str += c.toString(); });\
child.stdin.write('getconf LONG_BIT\\nexit\\n');\
child.waitExit();\
try\
{\
return(parseInt(child.stdout.str.trim()));\
}\
catch(ee)\
{return(0);}\
})() });\
}\
exports.getArpCache = function getArpCache()\
{\
if(process.platform == 'darwin')\
{\
var promise = require('promise');\
var ret = new promise(function (res, rej) { this._res = res; this._rej = rej; });\
var child_process = require('child_process');\
ret._child = child_process.execFile('/bin/sh', ['sh']);\
ret._child.promise = ret;\
ret._child.stdout._lines = '';\
ret._child.stdout.on('data', function (chunk) { this._lines += chunk.toString(); });\
ret._child.stdin.write('arp -a\\nexit\\n');\
ret._child.on('exit', function (code)\
{\
var lines = this.stdout._lines.split('\\n');\
var tokens, hw;\
var cache = {};\
for (var i in lines)\
{\
if (lines[i].length > 0)\
{\
tokens = lines[i].split(' ');\
if (tokens[3] != '(incomplete)')\
{\
if (!cache[tokens[5]]) { cache[tokens[5]] = {}; }\
var hwtokens = tokens[3].split(':');\
for (var hwi in hwtokens)\
{\
if (hwtokens[hwi].length == 1) { hwtokens[hwi] = '0' + hwtokens[hwi]; }\
hwtokens[hwi] = hwtokens[hwi].toUpperCase();\
}\
cache[tokens[5]][tokens[1].slice(1, tokens[1].length - 1)] = hwtokens.join(':');\
}\
}\
}\
Object.defineProperty(cache, 'flat',\
{\
value: function flat() {\
var r = {};\
for (var adapter in this) {\
for (var addr in this[adapter]) {\
r[addr] = this[adapter][addr];\
}\
}\
return (r);\
}\
});\
this.promise._res(cache);\
});\
return (ret);\
}\
var retVal = {};\
Object.defineProperty(retVal, 'flat',\
{\
value: function flat() {\
var r = {};\
for (var adapter in this) {\
for (var addr in this[adapter]) {\
r[addr] = this[adapter][addr];\
}\
}\
return (r);\
}\
});\
if (process.platform == 'win32')\
{\
var marshal = require('_GenericMarshal');\
var IpHlpApi = marshal.CreateNativeProxy('Iphlpapi.dll');\
var RESULTS = { ERROR_INSUFFICIENT_BUFFER: 122, ERROR_NO_DATA : 232, NO_ERROR : 0 };\
IpHlpApi.CreateMethod('GetIpNetTable');\
var sz = marshal.CreateVariable(4);\
sz.toBuffer().writeUInt32LE(0);\
switch (IpHlpApi.GetIpNetTable(0, sz, 0).Val) {\
case RESULTS.ERROR_NO_DATA:\
/*No OP, will return empty set*/ \
break;\
case RESULTS.ERROR_INSUFFICIENT_BUFFER:\
var arpTable = marshal.CreateVariable(sz.toBuffer().readUInt32LE());\
if (IpHlpApi.GetIpNetTable(arpTable, sz, 0).Val == RESULTS.NO_ERROR) {\
var adapters = require('os').networkInterfaces();\
var numEntries = arpTable.toBuffer().readUInt32LE(0);\
var buffer = arpTable.toBuffer().slice(4);\
for (var i = 0; i < numEntries; ++i) {\
var row = buffer.slice(i * 24, (i * 24) + 24);\
var addr = row.readUInt32BE(16);\
var address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255);\
var index = row.readUInt32LE(0);\
var mac = row.slice(8, 14).toString('hex:');\
if (!retVal[adapters.interfaceIndexes[index]]) { retVal[adapters.interfaceIndexes[index]] = {}; }\
retVal[adapters.interfaceIndexes[index]][address] = mac;\
}\
}\
break;\
default:\
throw ('Error accessing ARP/CACHE');\
break;\
}\
}\
else\
{\
var arpCache = require('fs').readFileSync('/proc/net/arp');\
var dataLines = arpCache.toString().split('\\x0A');\
var headers = {};\
var tokens = dataLines[0].split(' ');\
var key = 0;\
for (var i in tokens)\
{\
if (tokens[i].length > 0) { headers[key++] = tokens[i].trim(); }\
}\
for (var i = 1; i < dataLines.length; ++i)\
{\
var val = {};\
var k = 0;\
tokens = dataLines[i].split(' ');\
for (var x in tokens)\
{\
if (tokens[x].length > 0)\
{\
val[headers[k++]] = tokens[x].trim();\
}\
}\
if (tokens.length > 1)\
{\
if (!retVal[val['Device']]) { retVal[val['Device']] = {}; }\
retVal[val['Device']][val['IP address']] = val['HW address'].toUpperCase();\
}\
}\
}\
return (retVal);\
};\
if(process.platform == 'linux')\
{\
exports.getDefaultGateways = function getDefaultGateways()\
{\
var defaultGateways = {};\
var routingtable = require('fs').readFileSync('/proc/net/route');\
var lines = routingtable.toString().split('\\n');\
var headers = {};\
var tokens = lines[0].split('\\t');\
for (var i in tokens)\
{\
if (tokens[i].length > 0) { headers[tokens[i].trim()] = i; }\
}\
for (var i = 1; i < lines.length; ++i)\
{\
tokens = lines[i].split('\\t');\
if (tokens[headers['Mask']] == '00000000')\
{\
var gw;\
if(require('os').endianness()=='LE')\
{\
gw = Buffer.from(tokens[headers['Gateway']], 'hex').readUInt32LE();\
}\
else\
{\
gw = Buffer.from(tokens[headers['Gateway']], 'hex').readUInt32BE();\
}\
var gwAddr = ((gw >> 24) & 255) + '.' + ((gw >> 16) & 255) + '.' + ((gw >> 8) & 255) + '.' + (gw & 255);\
defaultGateways[tokens[headers['Iface']]] = gwAddr;\
}\
}\
return(defaultGateways);\
}\
}\
if(process.platform == 'darwin' || process.platform == 'freebsd')\
{\
exports.networkInterfaces = function()\
{\
var child_process = require('child_process');\
var child = child_process.execFile('/bin/sh', ['sh']);\
child.stdout._lines = '';\
child.stdout.on('data', function (chunk) { this._lines += chunk.toString(); });\
child.stdin.write(\"route get default | grep : | tr '\\\\n' '`' | awk -F'`' '{\" + ' printf \"{\"; for(i=1;i<NF;++i) { split($i, B, \":\"); gsub(/[ ]/, \"\", B[1]); gsub(/[ ]/, \"\", B[2]); printf \"%s\\\\\"%s\\\\\": \\\\\"%s\\\\\"\", (i>1?\", \":\"\"),B[1], B[2]; } printf \"}\"; ' + \"}'\\nexit\\n\");\
child.waitExit();\
var gwinfo=JSON.parse(child.stdout._lines.trim());\
child = child_process.execFile('/bin/sh', ['sh']);\
child.stdout._lines = '';\
child.stdout.on('data', function (chunk) { this._lines += chunk.toString(); });\
child.stdin.write('ifconfig\\nexit\\n');\
child.waitExit();\
var adapters = [];\
var adapter;\
var lines = child.stdout._lines.split('\\n');\
var tokens;\
for (var i in lines)\
{\
if (lines[i].length > 0 && lines[i][0] != '\\t')\
{\
if (adapters.length > 0 && adapters[adapters.length - 1].inet === undefined && adapters[adapters.length - 1].inet6 === undefined) { adapters.pop(); }\
adapters.push({ device: lines[i].split(':')[0] });\
}\
if (lines[i][0] == '\\t')\
{\
adapter = adapters[adapters.length - 1];\
tokens = lines[i].split(' ');\
tokens[0] = tokens[0].trim();\
switch (tokens[0])\
{\
case 'inet':\
adapter.inet = tokens[1];\
var tst = Buffer.from(tokens[3].substring(2), 'hex');\
adapter.netmask = tst[0].toString() + '.' + tst[1].toString() + '.' + tst[2].toString() + '.' + tst[3].toString();\
break;\
case 'inet6':\
if (adapter.inet6 === undefined) { adapter.inet6 = []; }\
var i6 = {};\
i6.address = tokens[1].toUpperCase().split('%')[0];\
if (tokens[tokens.length - 3] == 'scopeid')\
{\
i6.scope = tokens[tokens.length - 2].substring(2);\
if (i6.scope.length == 1) { i6.scope = '0' + i6.scope; }\
i6.scope = Buffer.from(i6.scope, 'hex')[0].toString();\
}\
adapter.inet6.push(i6);\
break;\
case 'ether':\
var ether = tokens[1].split(':');\
for (var x in ether)\
{\
if (ether[x].length == 1) { ether[x] = '0' + ether[x]; }\
ether[x] = ether[x].toUpperCase();\
}\
adapter.mac = ether.join(':');\
break;\
}\
}\
}\
if (adapters.length > 0 && adapters[adapters.length - 1].inet === undefined && adapters[adapters.length - 1].inet6 === undefined) { adapters.pop(); }\
var retval = {};\
while (adapters.length > 0)\
{\
adapter = adapters.pop();\
retval[adapter.device] = [];\
if (adapter.inet)\
{\
if(adapter.device == gwinfo.interface && gwinfo.gateway != null)\
{\
adapter.gateway = gwinfo.gateway;\
}\
retval[adapter.device].push({ address: adapter.inet, netmask : adapter.netmask, mac : adapter.mac, gateway: adapter.gateway, family : 'IPv4' });\
}\
if (adapter.inet6)\
{\
while (adapter.inet6.length > 0)\
{\
var i6 = adapter.inet6.pop();\
retval[adapter.device].push({ address: i6.address, mac : adapter.mac, family : 'IPv6', scope : i6.scope });\
}\
}\
}\
child = child_process.execFile('/bin/sh', ['sh']);\
child.stdout._lines = '';\
child.stdout.on('data', function(chunk) { this._lines += chunk.toString(); });\
child.stdin.write('networksetup -listallhardwareports\\nexit\\n');\
child.waitExit();\
lines = child.stdout._lines.split('\\n');\
for (var i = 0; i<lines.length; ++i)\
{\
if (lines[i].split('Hardware Port:').length > 1)\
{\
if (lines[i].split(':')[1].split('802.11').length > 1)\
{\
var dv = lines[i + 1].split(':')[1].trim();\
if (retval[dv])\
{\
for (var x in retval[dv])\
{\
retval[dv][x].type = 'wireless';\
}\
}\
else\
{\
retval[dv] = [{type: 'wireless', mac: lines[i + 2].split('Ethernet Address:')[1].trim().toUpperCase()}];\
}\
}\
else if (lines[i].split(':')[1].trim() == 'Ethernet')\
{\
var dv = lines[i + 1].split(':')[1].trim();\
if (retval[dv])\
{\
for (var x in retval[dv])\
{\
retval[dv][x].type = 'ethernet';\
}\
}\
else\
{\
retval[dv] = [{type: 'ethernet', mac: lines[i + 2].split('Ethernet Address:')[1].trim().toUpperCase()}];\
}\
}\
}\
}\
child = null;\
return(retval);\
};\
}\
exports.Name = (function Name()\
{\
var child;\
if(process.platform!='win32')\
{\
switch (process.platform)\
{\
case 'freebsd':\
case 'linux':\
case 'darwin':\
child = require('child_process').execFile('/bin/sh', ['sh']);\
break;\
}\
child.stdout.str=''; child.stdout.on('data', function(chunk) { this.str += chunk.toString(); });\
switch (process.platform)\
{\
case 'linux':\
child.stdin.write('cat /etc/*release\\nexit\\n');\
break;\
case 'darwin':\
child.stdin.write('sw_vers\\nexit\\n');\
break;\
case 'freebsd':\
child.stdin.write('uname -mrs\\nexit\\n');\
break;\
}\
child.waitExit();\
}\
var ret=null;\
var lines;\
var tokens;\
var i, j;\
switch (process.platform)\
{\
case 'win32':\
var friendly='';\
try\
{\
friendly = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SOFTWARE\\\\MICROSOFT\\\\WINDOWS NT\\\\CurrentVersion', 'DisplayVersion');\
friendly += '/';\
}\
catch(zz)\
{}\
try\
{\
ret = require('win-wmi').query('ROOT\\\\CIMV2', \"SELECT * FROM Win32_OperatingSystem\", ['Caption','BuildNumber']);\
ret = ret[0].Caption + ' - ' + friendly + ret[0].BuildNumber;\
}\
catch(zz)\
{\
try\
{\
ret = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SOFTWARE\\\\MICROSOFT\\\\WINDOWS NT\\\\CurrentVersion', 'ProductName');\
ret = ret + ' - ' + friendly + require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SOFTWARE\\\\MICROSOFT\\\\WINDOWS NT\\\\CurrentVersion', 'CurrentBuild');\
}\
catch(zzz)\
{\
ret = 'Windows (UNKNOWN) - ' + friendly;\
}\
ret += (' [WMI ERROR] ');\
}\
break;\
case 'linux':\
lines = child.stdout.str.split('\\n');\
for (i in lines)\
{\
tokens = lines[i].split('=');\
if (tokens[0] == 'PRETTY_NAME')\
{\
if(ret==null) { ret = (tokens[1].substring(1, tokens[1].length - 1)); }\
break;\
}\
}\
for (i in lines)\
{\
tokens = lines[i].split('=');\
if (tokens[0] == 'DISTRIB_DESCRIPTION')\
{\
if(ret==null) { ret = (tokens[1].substring(1, tokens[1].length - 1)); }\
break;\
}\
}\
if(ret==null) { ret = (lines[0]);}\
break;\
case 'darwin':\
var OSNAME = '';\
var OSVERSION = '';\
lines = child.stdout.str.split('\\n');\
for (i in lines)\
{\
tokens = lines[i].split(':');\
if (tokens[0] == 'ProductName') { OSNAME = tokens[1].trim(); }\
if (tokens[0] == 'ProductVersion') { OSVERSION = tokens[1].trim(); }\
}\
ret = (OSNAME + ' ' + OSVERSION);\
break;\
case 'freebsd':\
ret = (child.stdout.str.trim());\
break;\
}\
return(ret);\
})();\
exports.name = function name()\
{\
var promise = require('promise');\
var p = new promise(function(acc, rej) { this._acc = acc; this._rej = rej; });\
p._acc(this.Name);\
return (p);\
};\
if(process.platform=='freebsd')\
{\
exports.nics = function nics()\
{\
var child = require('child_process').execFile('/bin/sh', ['sh']);\
child.stdout.str = '';\
child.stdout.on('data', function(c) { this.str += c.toString(); });\
child.stdin.write('ifconfig | awk -F: \\'{ split($2, tok, \"=\"); if(tok[1]==\" flags\") { print $1 } }\\'\\nexit\\n');\
child.waitExit();\
return(child.stdout.str.trim());\
};\
}\
exports.uptime = function uptime()\
{\
switch(process.platform)\
{\
case 'win32':\
var GM = require('_GenericMarshal');\
var kernel32 = GM.CreateNativeProxy('kernel32.dll');\
kernel32.CreateMethod('GetTickCount64');\
var v = kernel32.GetTickCount64().bignum.div(require('bignum')('1000')).toString();\
return (parseInt(v));\
break;\
case 'linux':\
return (parseInt(require('fs').readFileSync('/proc/uptime').toString().split('.')[0]));\
break;\
case 'freebsd':\
case 'darwin':\
var child = require('child_process').execFile('/bin/sh', ['sh']);\
child.stdout.str = ''; child.stdout.on('data', function(c) { this.str += c.toString(); });\
child.stdin.write(\"sysctl kern.boottime | awk '\");\
child.stdin.write('{');\
child.stdin.write(' split($0,A,\"{\");');\
child.stdin.write(' split(A[2],B,\"}\");');\
child.stdin.write(' split(B[1],C,\",\");');\
child.stdin.write(' split(C[1],D,\"=\");');\
child.stdin.write(' gsub(/^[ ]+/,\"\",D[2]);');\
child.stdin.write(' SEC=D[2]+0;');\
child.stdin.write(' split(C[2],G,\"=\");');\
child.stdin.write(' gsub(/^[ ]+/,\"\",G[2]);');\
child.stdin.write(' USEC=G[2]+0;');\
child.stdin.write(' if(USEC>1000000) { SEC+=1; }');\
child.stdin.write(' print SEC;');\
child.stdin.write(\"}'\");\
child.stdin.write('\\nexit\\n');\
child.waitExit();\
var tmp = Math.round((new Date()).getTime()/1000) - parseInt(child.stdout.str);\
return(tmp);\
break;\
}\
};\
exports.dns = require('util-dns');";
ILibDuktape_ModSearch_AddHandler_AlsoIncludeJS(ctx, jsExtras, sizeof(jsExtras) - 1);
}
void ILibDuktape_ScriptContainer_OS_Init(duk_context *ctx)
{
ILibDuktape_ModSearch_AddHandler(ctx, "os", ILibDuktape_ScriptContainer_OS_Push);
}
extern void ILibDuktape_HttpStream_Init(duk_context *ctx);
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal()
{
ILibDuktape_ContextData *ctxd = (ILibDuktape_ContextData*)ILibMemory_SmartAllocate(sizeof(ILibDuktape_ContextData));
#ifndef MICROSTACK_NOTLS
util_openssl_init();
#endif
do { util_random(sizeof(ctxd->nonce), (char*)&(ctxd->nonce)); } while (ctxd->nonce == 0);
#ifndef MICROSTACK_NOTLS
util_openssl_uninit();
#endif
ctxd->threads = ILibLinkedList_Create();
#ifdef DUKTAPE_EXECUTION_MAXTIMEOUT
ctxd->maxExecutionTime = DUKTAPE_EXECUTION_MAXTIMEOUT;
#else
ctxd->maxExecutionTime = DUKTAPE_DEFAULT_MAX_EXECUTION_TIMEOUT;
#endif
duk_context *ctx = duk_create_heap(ILibDuktape_ScriptContainer_Engine_malloc, ILibDuktape_ScriptContainer_Engine_realloc, ILibDuktape_ScriptContainer_Engine_free, ctxd, ILibDuktape_ScriptContainer_Engine_fatal);
if (ctx == NULL) { ILIBCRITICALEXIT(254); }
return(ctx);
}
int ILibDuktape_ScriptContainer_DebuggingOK(duk_context *ctx)
{
int retVal = 0;
duk_push_heap_stash(ctx);
retVal = (Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_Settings_SecurityFlags, 0) & SCRIPT_ENGINE_NO_DEBUGGER) == SCRIPT_ENGINE_NO_DEBUGGER ? 0 : 1;
duk_pop(ctx);
return(retVal);
}
duk_ret_t ILibDuktape_Polyfills_promise_wait_impl_res(duk_context *ctx)
{
duk_push_current_function(ctx); // [func]
duk_get_prop_string(ctx, -1, "obj"); // [func][obj]
duk_push_true(ctx); duk_put_prop_string(ctx, -2, "settled");
duk_dup(ctx, 0); // [func][obj][resolvedValue]
duk_put_prop_string(ctx, -2, "return"); // [func][obj]
ILibChain_EndContinue(duk_ctx_chain(ctx));
return(0);
}
duk_ret_t ILibDuktape_Polyfills_promise_wait_impl_rej(duk_context *ctx)
{
duk_push_current_function(ctx); // [func]
duk_get_prop_string(ctx, -1, "obj"); // [func][obj]
duk_push_true(ctx); duk_put_prop_string(ctx, -2, "settled");
duk_dup(ctx, 0); // [func][obj][rejectedValue]
duk_put_prop_string(ctx, -2, "error"); // [func][obj]
ILibChain_EndContinue(duk_ctx_chain(ctx));
return(0);
}
duk_ret_t ILibDuktape_Polyfills_promise_wait_impl(duk_context *ctx)
{
ILibChain_Continue_Result continueResult;
int timeout = duk_is_number(ctx, 1) ? duk_require_int(ctx, 1) : -1;
int timerInfo = ILibChain_GetMinimumTimer(duk_ctx_chain(ctx));
int ret = 1;
if (timeout < 0 && timerInfo > 0) { timeout = 60000; }
duk_push_object(ctx); // [obj]
duk_prepare_method_call(ctx, 0, "then"); // [obj][then][this]
duk_push_c_function(ctx, ILibDuktape_Polyfills_promise_wait_impl_res, DUK_VARARGS); // [obj][then][this][res]
duk_dup(ctx, -4); duk_put_prop_string(ctx, -2, "obj");
duk_push_c_function(ctx, ILibDuktape_Polyfills_promise_wait_impl_rej, DUK_VARARGS); // [obj][then][this][res][rej]
duk_dup(ctx, -5); duk_put_prop_string(ctx, -2, "obj");
duk_call_method(ctx, 2); // [obj][retpromise]
if (!duk_has_prop_string(ctx, -2, "settled"))
{
#ifdef WIN32
continueResult = ILibChain_Continue(duk_ctx_chain(ctx), NULL, 0, timeout, NULL);
#else
continueResult = ILibChain_Continue(duk_ctx_chain(ctx), NULL, 0, timeout);
#endif
switch (continueResult)
{
case ILibChain_Continue_Result_ERROR_INVALID_STATE:
ret = ILibDuktape_Error(ctx, "wait() already in progress");
break;
case ILibChain_Continue_Result_ERROR_CHAIN_EXITING:
ret = ILibDuktape_Error(ctx, "wait() aborted because thread is exiting");
break;
case ILibChain_Continue_Result_ERROR_EMPTY_SET:
ret = ILibDuktape_Error(ctx, "wait() cannot wait on empty set");
break;
case ILibChain_Continue_Result_TIMEOUT:
ret = ILibDuktape_Error(ctx, "wait() timeout");
break;
default:
ret = 1;
break;
}
}
if (duk_has_prop_string(ctx, -2, "return"))
{
duk_get_prop_string(ctx, -2, "return");
}
else
{
duk_get_prop_string(ctx, -2, "error");
duk_throw(ctx);
}
return(ret);
}
void ILibDuktape_Polyfills_promise_wait(duk_context *ctx)
{
duk_eval_string(ctx, "require('promise');"); // [promise]
ILibDuktape_CreateInstanceMethod(ctx, "wait", ILibDuktape_Polyfills_promise_wait_impl, DUK_VARARGS);
duk_pop(ctx); // ...
}
duk_ret_t ILibDuktape_PAC_Impl(duk_context *ctx)
{
duk_push_current_function(ctx);
duk_context *ex = (duk_context*)Duktape_GetPointerProperty(ctx, -1, "embedded");
char *fqdn = Duktape_GetStringPropertyValue(ctx, -1, "fqdn", "127.0.0.2");
char *url = (char*)duk_require_string(ctx, 0);
char *addr;
unsigned short port;
char *path;
duk_push_sprintf(ex, "function myIpAddress() { return('%s'); }", fqdn);
duk_eval_noresult(ex);
ILibParseUri(url, &addr, &port, &path, NULL);
duk_push_sprintf(ex, "FindProxyForURL('%s', '%s');", url, addr);
if (duk_peval(ex) != 0)
{
sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), (char*)duk_safe_to_string(ex, -1));
duk_pop(ex);
return(ILibDuktape_Error(ctx, "Error: %s", ILibScratchPad));
}
duk_push_sprintf(ctx, "%s", duk_get_string(ex, -1));
duk_pop(ex);
duk_string_split(ctx, -1, " "); // [str][array]
duk_array_shift(ctx, -1); // [str][array][type]
if (strcasecmp("DIRECT", (char*)duk_get_string(ctx, -1)) == 0)
{
duk_push_null(ctx);
}
else
{
duk_array_pop(ctx, -2);
}
return(1);
}
duk_ret_t ILibDuktape_PAC_MyIPAddress(duk_context *ctx)
{
duk_push_string(ctx, "172.16.2.5");
return(1);
}
extern duk_ret_t ILibDuktape_Polyfills_resolve(duk_context *ctx);
extern void ILibDuktape_Polyfills_String(duk_context *ctx);
extern duk_ret_t ILibDuktape_Polyfills_ipv4From(duk_context *ctx);
duk_ret_t ILibDuktape_PAC_Create(duk_context *ctx)
{
duk_size_t wpadLen;
char *wpad = (char*)duk_get_lstring(ctx, 0, &wpadLen);
duk_context *ex = ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal();
if (ILibDuktape_ScriptContainer_CompileJavaScriptEx(ex, wpad, (int)wpadLen, "wpad.js", 7) != 0 ||
ILibDuktape_ScriptContainer_ExecuteByteCode(ex) != 0)
{
char *err = (char*)duk_safe_to_string(ex, -1);
sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "%s", err);
duk_destroy_heap(ex);
return(ILibDuktape_Error(ctx, "Error in WPAD: %s", ILibScratchPad));
}
duk_pop(ex);
duk_push_global_object(ex);
ILibDuktape_Polyfills_String(ex);
ILibDuktape_CreateInstanceMethod(ex, "resolve", ILibDuktape_Polyfills_resolve, 1);
ILibDuktape_CreateInstanceMethod(ex, "_ipv4From", ILibDuktape_Polyfills_ipv4From, 1);
duk_pop(ex);
char *pac = NULL;
int pacLen = ILibBase64Decode((unsigned char*)"LyoNCkNvcHlyaWdodCAyMDIxIEludGVsIENvcnBvcmF0aW9uDQpAYXV0aG9yIEJyeWFuIFJvZQ0KDQpMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgIkxpY2Vuc2UiKTsNCnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4NCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdA0KDQogICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wDQoNClVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmUNCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsDQpXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4NClNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQNCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLg0KKi8NCg0KDQoNCi8vIEV2YWx1YXRlcyBob3N0bmFtZXMgYW5kIHJldHVybnMgdHJ1ZSBpZiBob3N0bmFtZXMgbWF0Y2gNCmZ1bmN0aW9uIGRuc0RvbWFpbklzKHRhcmdldCwgaG9zdCkNCnsNCiAgICBpZighaG9zdC5zdGFydHNXaXRoKCcuJykpDQogICAgew0KICAgICAgICBob3N0ID0gJy4nICsgaG9zdDsNCiAgICB9DQogICAgcmV0dXJuICh0YXJnZXQudG9Mb3dlckNhc2UoKS5lbmRzV2l0aChob3N0LnRvTG93ZXJDYXNlKCkpKTsNCn0NCg0KLy8gbWF0Y2ggaG9zdG5hbWUgb3IgVVJMIHRvIGEgc3BlY2lmaWVkIHNoZWxsIGV4cHJlc3Npb24sICByZXR1cm5zIHRydWUgaWYgbWF0Y2hlZA0KZnVuY3Rpb24gc2hFeHBNYXRjaChob3N0LCBleHApDQp7DQogICAgZXhwID0gZXhwLnNwbGl0KCcuJykuam9pbignXFwuJyk7DQogICAgZXhwID0gZXhwLnNwbGl0KCc/Jykuam9pbignLicpOw0KICAgIGV4cCA9IGV4cC5zcGxpdCgnKicpLmpvaW4oJy4qJyk7DQogICAgZXhwID0gJ14nICsgZXhwICsgJyQnOw0KICAgIHJldHVybiAoaG9zdC5zZWFyY2goZXhwKSA+PSAwKTsNCn0NCg0KLy8gZXZhbHVhdGVzIHRoZSBJUCBhZGRyZXNzIG9mIGEgaG9zdG5hbWUsIGFuZCBpZiB3aXRoaW4gYSBzcGVjaWZpZWQgc3VibmV0IHJldHVybnMgdHJ1ZQ0KZnVuY3Rpb24gaXNJbk5ldCh0YXJnZXQsIGFkZHJlc3MsIG1hc2spDQp7DQogICAgdHJ5DQogICAgew0KICAgICAgICB2YXIgZGVzdEFkZHIgPSByZXNvbHZlKHRhcmdldCkuX2ludGVnZXJzWzBdOw0KICAgICAgICB2YXIgbWFza0FkZHIgPSByZXNvbHZlKG1hc2spLl9pbnRlZ2Vyc1swXTsNCiAgICAgICAgcmV0dXJuIChfaXB2NEZyb20oZGVzdEFkZHIgJiBtYXNrQWRkcikgPT0gYWRkcmVzcyk7DQogICAgfQ0KICAgIGNhdGNoKGUpDQogICAgew0KICAgICAgICByZXR1cm4gKGZhbHNlKTsNCiAgICB9DQp9DQoNCi8vIHJlc29sdmUgaG9zdCBuYW1lIHRvIGFkZHJlc3MNCmZ1bmN0aW9uIGRuc1Jlc29sdmUoaG9zdCkNCnsNCiAgICB2YXIgcmVzdWx0ID0gcmVzb2x2ZShob3N0KTsNCiAgICBpZihyZXN1bHQubGVuZ3RoID09IDApDQogICAgew0KICAgICAgICByZXR1cm4gKCcnKTsNCiAgICB9DQogICAgZWxzZQ0KICAgIHsNCiAgICAgICAgcmV0dXJuIChyZXN1bHRbMF0pOw0KICAgIH0NCn0NCg0KLy8gcmV0dXJuIHRydWUgaWYgdGhlIGhvc3RuYW1lIGNvbnRhaW5zIG5vIGRvdHMNCmZ1bmN0aW9uIGlzUGxhaW5Ib3N0TmFtZShob3N0KQ0Kew0KICAgIHJldHVybiAoaG9zdC5pbmRleE9mKCcuJykgPCAwKTsNCn0NCg0KLy8gZXZhbHVhdGUgaG9zdG5hbWUgYW5kIHJldHVybiB0cnVlIElGRiBleGFjdCBtYXRjaA0KZnVuY3Rpb24gbG9jYWxIb3N0T3JEb21haW5Jcyh0YXJnZXQsIGhvc3QpDQp7DQogICAgcmV0dXJuIChkbnNSZXNvbHZlKHRhcmdldCkgPT0gaG9zdCk7DQp9DQoNCi8vIHJldHVybiB0cnVlIGlmIHJlc29sdmUgaXMgc3VjY2Vzc2Z1bA0KZnVuY3Rpb24gaXNSZXNvbHZhYmxlKGhvc3QpDQp7DQogICAgcmV0dXJuIChyZXNvbHZlKGhvc3QpLmxlbmd0aCA+IDApOw0KfQ0KDQovLyByZXR1cm5zIHRoZSBudW1iZXIgb2YgRE5TIGRvbWFpbiBsZXZlbHMgKG51bWJlciBvZiBkb3RzKSBpbiB0aGUgaG9zdG5hbWUNCmZ1bmN0aW9uIGRuc0RvbWFpbkxldmVscyhob3N0KQ0Kew0KICAgIHJldHVybiAoaG9zdC5zcGxpdCgnLicpLmxlbmd0aCAtIDEpOw0KfQ0KDQoNCmZ1bmN0aW9uIHdlZWtkYXlSYW5nZShzdGFydCwgZW5kKQ0Kew0KDQp9DQpmdW5jdGlvbiBkYXRlUmFuZ2Uoc3RhcnQsIGVuZCkNCnsNCg0KfQ0KZnVuY3Rpb24gdGltZVJhbmdlKHN0YXJ0LCBlbmQpDQp7DQoNCn0NCg0KZnVuY3Rpb24gYWxlcnQobXNnKQ0Kew0KDQp9DQo=", 3276, (unsigned char **)&pac);
pac[pacLen] = 0;
duk_peval_string_noresult(ex, pac);
free(pac);
duk_push_c_function(ctx, ILibDuktape_PAC_Impl, 1);
duk_push_pointer(ctx, ex);
duk_put_prop_string(ctx, -2, "embedded");
char fqdn[] = "(function getFqdnInterface()\
{\
var interfaces = require('os').networkInterfaces();\
for (var i in interfaces)\
{\
for (var j in interfaces[i])\
{\
if (interfaces[i][j].fqdn != '' && interfaces[i][j].family == 'IPv4' && interfaces[i][j].status != 'down')\
{\
return (interfaces[i][j].address);\
}\
}\
}\
return ('127.0.0.1');\
})();";
duk_eval_string(ctx, fqdn); // [func][fqdn]
duk_put_prop_string(ctx, -2, "fqdn");
return(1);
}
duk_ret_t ILibDuktape_PAC_Find(duk_context *ctx)
{
duk_eval_string(ctx, "resolve('wpad');");
return(1);
}
void ILibDuktape_PAC_PUSH(duk_context *ctx, void *chain)
{
duk_push_object(ctx);
ILibDuktape_WriteID(ctx, "PAC");
ILibDuktape_CreateInstanceMethod(ctx, "Create", ILibDuktape_PAC_Create, 1);
ILibDuktape_CreateInstanceMethod(ctx, "Find", ILibDuktape_PAC_Find, 0);
}
void ILibDuktape_PAC_Init(duk_context *ctx)
{
ILibDuktape_ModSearch_AddHandler(ctx, "PAC", ILibDuktape_PAC_PUSH);
}
duk_ret_t ILibDuktape_ScriptContainer_SIGTERM_HANDLER(duk_context *ctx)
{
void *chain = duk_ctx_chain(ctx);
ILibStopChain(chain);
return(0);
}
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(duk_context *ctx, SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser)
{
void **timeoutKey = executionTimeout > 0 ? (void**)ILibMemory_Allocate(sizeof(void*), 0, NULL, NULL) : NULL;
if (chain == NULL)
{
duk_ctx_context_data(ctx)->fakechain = 1;
chain = ILibCreateChain();
}
duk_ctx_context_data(ctx)->chain = chain;
duk_push_heap_stash(ctx); // [s]
duk_push_int(ctx, (int)securityFlags); // [s][flags]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Settings_SecurityFlags); // [s]
duk_push_int(ctx, (int)executionTimeout); // [s][timeout]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Settings_ExecutionTimeout);// [s]
duk_push_pointer(ctx, db); // [s][db]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Settings_DB); // [s]
duk_push_pointer(ctx, exitHandler); // [s][exitHandler]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Settings_ExitHandler); // [s]
duk_push_pointer(ctx, exitUser); // [s][exitUser]
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_Settings_ExitUser); // [s]
if (exePath != NULL)
{
duk_push_string(ctx, exePath);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ExePath);
}
if (pipeManager != NULL)
{
duk_push_pointer(ctx, pipeManager);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_PipeManager);
}
duk_pop(ctx); // ...
// Setup Module Search and Database
ILibDuktape_ModSearch_Init(ctx, chain, db);
ILibDuktape_SimpleDataStore_init(ctx, db);
// Setup the permissions on this engine. JavaScript will only be allowed to access the libraries it has access to.
if ((securityFlags & SCRIPT_ENGINE_NO_NETWORK_ACCESS) == 0)
{
#ifndef NO_WEBRTC
ILibDuktape_WebRTC_Init(ctx); // WebRTC library (browser api)
#endif
ILibDuktape_net_init(ctx, chain); // Network library (node api)
ILibDuktape_DGram_Init(ctx); // Datagram Sockets
ILibDuktape_HttpStream_Init(ctx); // HTTP Library (node api)
}
if ((securityFlags & SCRIPT_ENGINE_NO_GENERIC_MARSHAL_ACCESS) == 0) { ILibDuktape_GenericMarshal_init(ctx); }
if ((securityFlags & SCRIPT_ENGINE_NO_PROCESS_SPAWNING) == 0)
{
ILibDuktape_ChildProcess_Init(ctx);
}
if ((securityFlags & SCRIPT_ENGINE_NO_FILE_SYSTEM_ACCESS) == 0) { ILibDuktape_fs_init(ctx); }
ILibDuktape_SHA256_Init(ctx); // SHA256 as node writable stream
ILibDuktape_EncryptionStream_init(ctx);
ILibDuktape_Polyfills_Init(ctx); // Various Polyfills
ILibDuktape_EventEmitter_Init(ctx); // event emitter
ILibDuktape_MemoryStream_Init(ctx); // Add MemoryStream support
ILibDuktape_NetworkMonitor_Init(ctx);
ILibDuktape_CompressedStream_init(ctx);
ILibDuktape_PAC_Init(ctx);
if (exitHandler != NULL) { ILibDuktape_Helper_AddHeapFinalizer(ctx, exitHandler, exitUser); }
Duktape_CreateEnum(ctx, "ContainerPermissions", (char*[]) { "DEFAULT", "NO_AGENT", "NO_MARSHAL", "NO_PROCESS_SPAWNING", "NO_FILE_SYSTEM_ACCESS", "NO_NETWORK_ACCESS" }, (int[]) { 0x00, 0x10000000, 0x08000000, 0x04000000, 0x00000001, 0x00000002 }, 6);
#ifdef WIN32
Duktape_CreateEnum(ctx, "ContainerUserTypes", (char*[]) { "DEFAULT", "USER", "TERMINAL", "WINLOGON" }, (int[]) { ILibProcessPipe_SpawnTypes_DEFAULT, ILibProcessPipe_SpawnTypes_USER, ILibProcessPipe_SpawnTypes_TERM, ILibProcessPipe_SpawnTypes_WINLOGON }, 4);
#else
Duktape_CreateEnum(ctx, "ContainerUserTypes", (char*[]) { "DEFAULT", "USER", "TERMINAL" }, (int[]) { ILibProcessPipe_SpawnTypes_DEFAULT, ILibProcessPipe_SpawnTypes_USER, ILibProcessPipe_SpawnTypes_TERM }, 3);
#endif
if (exePath != NULL && pipeManager != NULL)
{
ILibDuktape_ModSearch_AddHandler(ctx, "ScriptContainer", ILibDuktape_ScriptContainer_PUSH_MASTER);
}
else
{
ILibDuktape_ModSearch_AddHandler(ctx, "ScriptContainer", ILibDuktape_ScriptContainer_PUSH_SLAVE);
}
// Polyfill os functions
ILibDuktape_ScriptContainer_OS_Init(ctx);
// Polyfill process functions
ILibDuktape_ScriptContainer_Process_Init(ctx, argList);
// Setup execution timeout
if (timeoutKey != NULL)
{
timeoutKey[0] = ctx;
ILibDuktape_Helper_AddHeapFinalizer(ctx, ILibDuktape_ScriptContainer_ExecTimeout_Finalizer, timeoutKey);
ILibLifeTime_Add(ILibGetBaseTimer(Duktape_GetChain(ctx)), timeoutKey, executionTimeout, ILibDuktape_ScriptContainer_ExecTimeout, NULL);
}
ILibDuktape_Polyfills_JS_Init(ctx);
ILibDuktape_Polyfills_promise_wait(ctx);
#ifdef _POSIX
int tp = duk_get_top(ctx);
duk_eval_string(ctx, "process"); // [process]
duk_prepare_method_call(ctx, -1, "on"); // [process][on][this]
duk_push_string(ctx, "SIGTERM"); // [process][on][this][SIGTERM]
duk_push_c_function(ctx, ILibDuktape_ScriptContainer_SIGTERM_HANDLER, DUK_VARARGS); // [process][on][this][SIGTERM][func]
duk_pcall_method(ctx, 2);
duk_set_top(ctx, tp);
#endif
return ctx;
}
void ILibDuktape_ScriptContainer_Slave_HeapDestroyed(duk_context *ctx, void *user)
{
ILibDuktape_ScriptContainer_Slave *slave = (ILibDuktape_ScriptContainer_Slave*)user;
void *p = ILibDuktape_GetProcessObject(ctx);
if (p != NULL)
{
duk_push_heapptr(ctx, p); // [process]
if (!duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_Restart))
{
slave->exitCode = Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_ExitCode, 0);
ILibStopChain(slave->chain);
}
duk_pop(ctx); // ...
}
}
// Compiles the JavaScript to bytecode
int ILibDuktape_ScriptContainer_CompileJavaScript_FromFile(duk_context *ctx, char *path, int pathLen)
{
if (ctx == NULL)
{
return 1; // Error, but we can't put an error object on top of stack, because we don't have a valid heap ptr (ctx)
}
if (path == NULL || pathLen == 0)
{
duk_push_error_object(ctx, DUK_ERR_ERROR, "Invalid Path specified");
return(1);
}
else
{
return(duk_pcompile_lstring_filename(ctx, 0, path, pathLen));
}
}
// Compiles the JavaScript to bytecode
int ILibDuktape_ScriptContainer_CompileJavaScriptEx(duk_context *ctx, char *payload, int payloadLen, char *filename, int filenameLen)
{
if (ctx == NULL)
{
return 1; // Error, but we can't put an error object on top of stack, because we don't have a valid heap ptr (ctx)
}
ILibDuktape_Debugger_SetScript(payload, payloadLen, filename, filenameLen);
if (filename == NULL)
{
if ((payloadLen > 0 ? duk_pcompile_lstring(ctx, 0, payload, payloadLen) : duk_pcompile_string(ctx, 0, payload)) != 0)
{
return 1; // Error.... Error Object is on top of stack
}
else
{
return 0; // SUCCESS
}
}
else
{
if (filenameLen > 0)
{
duk_push_lstring(ctx, filename, filenameLen);
}
else
{
duk_push_string(ctx, filename);
}
if ((payloadLen > 0 ? duk_pcompile_lstring_filename(ctx, 0, payload, payloadLen) : duk_pcompile_string_filename(ctx, 0, payload)) != 0)
{
return 1; // Error.... Error Object is on top of stack
}
else
{
return 0; // SUCCESS
}
}
}
// Executes the bytecode. If JavaScript is written correctly, this should not block.
int ILibDuktape_ScriptContainer_ExecuteByteCode(duk_context *ctx)
{
if (duk_pcall(ctx, 0) == 0)
{
// SUCCESS
return(0);
}
else
{
// FAILURE
return(1);
}
}
// Slave process, process commmands from the master using stdin.
void ILibDuktape_ScriptContainer_Slave_ProcessCommands(ILibDuktape_ScriptContainer_Slave *slave, char *buffer, ILibProcessPipe_Pipe sender)
{
SCRIPT_ENGINE_COMMAND cmd = SCRIPT_ENGINE_COMMAND_UNKNOWN;
duk_context *codec = NULL;
if (slave->ctx == NULL)
{
if ((codec = duk_create_heap_default()) == NULL) { ILIBCRITICALEXIT(254); }
}
else
{
codec = slave->ctx;
}
duk_push_lstring(codec, buffer + 4, ((int*)buffer)[0] - 4);
duk_json_decode(codec, -1);
cmd = (SCRIPT_ENGINE_COMMAND)Duktape_GetIntPropertyValue(codec, -1, "command", SCRIPT_ENGINE_COMMAND_UNKNOWN);
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "MeshAgent_Slave: Command: %u", (unsigned int)cmd);
switch (cmd)
{
case SCRIPT_ENGINE_COMMAND_ADD_MODULE:
{
duk_size_t moduleLen;
char *moduleName = Duktape_GetStringPropertyValue(slave->ctx, -1, "name", NULL);
char *module = Duktape_GetStringPropertyValueEx(slave->ctx, -1, "module", NULL, &moduleLen);
ILibDuktape_ModSearch_AddModule(slave->ctx, moduleName, module, (int)moduleLen);
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "MeshAgent_Slave: Added module %s", moduleName);
break;
}
case SCRIPT_ENGINE_COMMAND_INIT:
{
SCRIPT_ENGINE_SECURITY_FLAGS securityFlags = (SCRIPT_ENGINE_SECURITY_FLAGS)Duktape_GetIntPropertyValue(codec, -1, "securityFlags", 0);
unsigned int executionTimeout = (unsigned int)Duktape_GetIntPropertyValue(codec, -1, "executionTimeout", 0);
void **argList = NULL;
if (duk_has_prop_string(codec, -1, "argv"))
{
duk_get_prop_string(codec, -1, "argv"); // [json][argv]
int i, argLen = (int)duk_get_length(codec, -1);
if (argLen > 0)
{
if ((argLen + 1) * sizeof(void*) > sizeof(ILibScratchPad))
{
duk_push_object(codec);
duk_push_int(codec, (int)SCRIPT_ENGINE_COMMAND_INIT);
duk_put_prop_string(codec, -2, "command");
duk_push_string(codec, "argv list was invalid");
duk_put_prop_string(codec, -2, "error");
ILibDuktape_ScriptContainer_Slave_SendJSON(codec);
duk_pop(codec); // [json]
break;
}
else
{
argList = (void**)ILibScratchPad;
for (i = 0; i < argLen; ++i)
{
duk_get_prop_index(codec, -1, i); // [json][argv][val]
argList[i] = (char*)duk_get_string(codec, -1);
duk_pop(codec); // [json][argv]
}
argList[i] = NULL;
duk_pop(codec); // [json]
}
}
}
if (slave->ctx != NULL) { Duktape_SafeDestroyHeap(slave->ctx); slave->ctx = codec = NULL; }
slave->ctx = ILibDuktape_ScriptContainer_InitializeJavaScriptEngine(securityFlags, executionTimeout, slave->chain, (char**)argList, NULL, ILibDuktape_ScriptContainer_Slave_HeapDestroyed, slave);
duk_push_heap_stash(slave->ctx); // [s]
duk_push_pointer(slave->ctx, slave); // [s][slave]
duk_put_prop_string(slave->ctx, -2, ILibDuktape_ScriptContainer_SlavePtr); // [s]
duk_pop(slave->ctx); // ...
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "MeshAgent_Slave: Created Java Script Engine: %p", (void*)slave->ctx);
duk_push_object(slave->ctx);
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_INIT);
duk_put_prop_string(slave->ctx, -2, "command");
ILibDuktape_ScriptContainer_Slave_SendJSON(slave->ctx);
}
break;
case SCRIPT_ENGINE_COMMAND_EXEC:
{
int seq = Duktape_GetIntPropertyValue(slave->ctx, -1, "sequence", -1); // [json]
char *execData;
duk_size_t execDataLen;
if (slave->ctx == NULL)
{
// Cannot call execute without first calling INIT
duk_push_object(codec); // [json][retJSON]
duk_push_int(codec, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][retJSON][command
duk_put_prop_string(codec, -2, "command"); // [json][retJSON]
if (seq >= 0)
{
duk_push_int(codec, seq); // [json][retJSON][sequence]
duk_put_prop_string(codec, -2, "sequence"); // [json][retJSON]
}
duk_push_string(codec, "Cannot call execute without first calling INIT"); // [json][retJSON][errMsg]
duk_put_prop_string(codec, -2, "error"); // [json][retJSON]
ILibDuktape_ScriptContainer_Slave_SendJSON(codec); // [json]
}
else
{
if (duk_has_prop_string(slave->ctx, -1, "string"))
{
// Execute String
execData = (char*)Duktape_GetStringPropertyValueEx(slave->ctx, -1, "string", NULL, &execDataLen);
if (ILibDuktape_ScriptContainer_CompileJavaScript(slave->ctx, execData, (int)execDataLen) == 0 && ILibDuktape_ScriptContainer_ExecuteByteCode(slave->ctx) == 0)
{
// Success
duk_push_object(slave->ctx); // [json][retJSON]
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][retJSON][command
duk_put_prop_string(slave->ctx, -2, "command"); // [json][retJSON]
if (seq >= 0)
{
duk_push_int(slave->ctx, seq); // [json][retJSON][sequence]
duk_put_prop_string(slave->ctx, -2, "sequence"); // [json][retJSON]
}
if (!duk_is_undefined(slave->ctx, -2))
{
if (duk_peval_string(slave->ctx, "JSON.stringify") == 0) // [json][retJSON][stringify]
{
duk_dup(slave->ctx, -3); // [json][retJSON][stringify][retVal]
if (duk_pcall(slave->ctx, 1) == 0) // [json][retJSON][retValJSON]
{
duk_put_prop_string(slave->ctx, -2, "result"); // [json][retJSON]
}
else
{
duk_pop(slave->ctx); // [json][retJSON]
}
}
else
{
duk_pop(slave->ctx); // [json][retJSON]
}
}
}
else
{
// Failure // [json][error]
char *errMsg = (char*)duk_safe_to_string(slave->ctx, -1);
duk_push_string(slave->ctx, errMsg); // [json][error][errMsg]
duk_swap_top(slave->ctx, -2); // [json][errMsg][error]
duk_pop(slave->ctx); // [json][errMsg]
duk_push_object(slave->ctx); // [json][errMsg][retJSON]
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][errMsg][retJSON][command
duk_put_prop_string(slave->ctx, -2, "command"); // [json][errMsg][retJSON]
if (seq >= 0)
{
duk_push_int(slave->ctx, seq); // [json][errMsg][retJSON][sequence]
duk_put_prop_string(slave->ctx, -2, "sequence"); // [json][errMsg][retJSON]
}
duk_swap_top(slave->ctx, -2); // [json][retJSON][errMsg]
duk_put_prop_string(slave->ctx, -2, "error"); // [json][retJSON]
}
ILibDuktape_ScriptContainer_Slave_SendJSON(slave->ctx); // [json]
}
else if (duk_has_prop_string(slave->ctx, -1, "path"))
{
// Execute Path
execData = (char*)Duktape_GetStringPropertyValueEx(slave->ctx, -1, "path", NULL, &execDataLen);
if (ILibDuktape_ScriptContainer_CompileJavaScript_FromFile(slave->ctx, execData, (int)execDataLen) == 0 && ILibDuktape_ScriptContainer_ExecuteByteCode(slave->ctx))
{
// SUCCESS
duk_push_object(slave->ctx); // [json][retJSON]
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][retJSON][command
duk_put_prop_string(slave->ctx, -2, "command"); // [json][retJSON]
if (seq >= 0)
{
duk_push_int(slave->ctx, seq); // [json][retJSON][sequence]
duk_put_prop_string(slave->ctx, -2, "sequence"); // [json][retJSON]
}
if (!duk_is_undefined(slave->ctx, -2))
{
duk_dup(slave->ctx, -2); // [json][retJSON][retVal]
duk_json_encode(slave->ctx, -1); // [json][retJSON][retValJSON]
duk_put_prop_string(slave->ctx, -2, "result"); // [json][retJSON]
}
}
else
{
// ERROR
char *errMsg = (char*)duk_safe_to_string(slave->ctx, -1);
duk_push_string(slave->ctx, errMsg); // [json][error][errMsg]
duk_swap_top(slave->ctx, -2); // [json][errMsg][error]
duk_pop(slave->ctx); // [json][errMsg]
duk_push_object(slave->ctx); // [json][errMsg][retJSON]
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][errMsg][retJSON][command
duk_put_prop_string(slave->ctx, -2, "command"); // [json][errMsg][retJSON]
if (seq >= 0)
{
duk_push_int(slave->ctx, seq); // [json][errMsg][retJSON][sequence]
duk_put_prop_string(slave->ctx, -2, "sequence"); // [json][errMsg][retJSON]
}
duk_swap_top(slave->ctx, -2); // [json][retJSON][errMsg]
duk_put_prop_string(slave->ctx, -2, "error"); // [json][retJSON]
}
ILibDuktape_ScriptContainer_Slave_SendJSON(slave->ctx); // [json]
}
else
{
// Error
duk_push_object(slave->ctx); // [json][retJSON]
duk_push_int(slave->ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [json][retJSON][command
duk_put_prop_string(slave->ctx, -2, "command"); // [json][retJSON]
if (seq >= 0)
{
duk_push_int(slave->ctx, seq); // [json][retJSON][sequence]
duk_put_prop_string(slave->ctx, -2, "sequence"); // [json][retJSON]
}
duk_push_string(slave->ctx, "Malformed Command"); // [json][retJSON][errmsg]
duk_put_prop_string(slave->ctx, -2, "error"); // [json][retJSON]
ILibDuktape_ScriptContainer_Slave_SendJSON(slave->ctx); // [json]
}
}
break;
}
break;
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
{
if (ILibDuktape_EventEmitter_HasListeners(slave->emitter, "data")!=0)
{
char *json = Duktape_GetStringPropertyValue(slave->ctx, -1, "json", NULL);
if (json != NULL)
{
ILibDuktape_EventEmitter_SetupEmit(slave->ctx, slave->emitter->object, "data"); // [emit][this][data]
duk_push_string(slave->ctx, json); // [emit][this][data][json]
duk_json_decode(slave->ctx, -1); // [emit][this][data][object]
if (duk_pcall_method(slave->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer.OnData(): "); }
duk_pop(slave->ctx); // ...
}
}
break;
}
case SCRIPT_ENGINE_COMMAND_EXIT:
if (slave->ctx != NULL) { Duktape_SafeDestroyHeap(slave->ctx); }
break;
default:
break;
}
if (codec != NULL && slave->ctx == NULL)
{
Duktape_SafeDestroyHeap(codec);
}
}
#ifdef WIN32
void ILibDuktape_ScriptContainer_Slave_OnReadStdInEx(void *chain, void *data)
{
if (!ILibMemory_CanaryOK(data)) { return; }
ILibDuktape_ScriptContainer_Slave *slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_Extra(data))[0];
char *buffer = (char*)((void**)ILibMemory_Extra(data))[1];
ILibDuktape_ScriptContainer_Slave_ProcessCommands(slave, buffer, (ILibProcessPipe_Pipe)data);
ILibProcessPipe_Pipe_Resume((ILibProcessPipe_Pipe)data);
}
#endif
void ILibDuktape_ScriptContainer_Slave_OnReadStdIn(ILibProcessPipe_Pipe sender, char *buffer, size_t bufferLen, size_t* bytesConsumed)
{
if (!ILibMemory_CanaryOK(sender)) { return; }
ILibDuktape_ScriptContainer_Slave *slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_Extra(sender))[0];
if (bufferLen < 4 || bufferLen < (size_t)((int*)buffer)[0]) { return; }
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "Slave read: %d bytes", bufferLen);
#ifdef WIN32
// Windows dispatches on a non-microstack thread, so we need to context switch to microstack/duktape thread
((void**)ILibMemory_Extra(sender))[1] = buffer;
ILibProcessPipe_Pipe_Pause(sender);
ILibChain_RunOnMicrostackThread(slave->chain, ILibDuktape_ScriptContainer_Slave_OnReadStdInEx, sender);
#else
ILibDuktape_ScriptContainer_Slave_ProcessCommands(slave, buffer, sender);
#endif
*bytesConsumed = ((int*)buffer)[0];
}
int ILibDuktape_ScriptContainer_StartSlave(void *chain, ILibProcessPipe_Manager manager)
{
// We are just a slave container
ILibProcessPipe_Pipe mStdIn = NULL;
ILibDuktape_ScriptContainer_Slave slaveObject;
#ifdef _REMOTELOGGING
ILibRemoteLogging logger = ILibRemoteLogging_Create(NULL);
ILibRemoteLogging_SetRawForward(logger, 0, ILibDuktape_ScriptContainer_Slave_LogForwarder);
ILibChainSetLogger(chain, logger);
#endif
#if defined(_POSIX) && !defined(__APPLE__)
ILibCriticalLogFilename = "/var/tmp/agentSlave";
#endif
#ifndef MICROSTACK_NOTLS
util_openssl_init();
#endif
memset(&slaveObject, 0, sizeof(ILibDuktape_ScriptContainer_Slave));
slaveObject.chain = chain;
ILibRemoteLogging_printf(logger, ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_1, "Starting Slave Process");
// We must attach StdIn to fetch parameters
#ifdef WIN32
mStdIn = ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(manager, GetStdHandle(STD_INPUT_HANDLE), ILibProcessPipe_Pipe_ReaderHandleType_NotOverLapped, 2 * sizeof(void*));
#else
mStdIn = ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(manager, STDIN_FILENO, sizeof(void*));
#endif
((void**)ILibMemory_Extra(mStdIn))[0] = &slaveObject;
ILibProcessPipe_Pipe_SetBrokenPipeHandler(mStdIn, ILibDuktape_ScriptContainer_Slave_OnBrokenPipe);
ILibProcessPipe_Pipe_AddPipeReadHandler(mStdIn, SCRIPT_ENGINE_PIPE_BUFFER_SIZE, ILibDuktape_ScriptContainer_Slave_OnReadStdIn);
ILibStartChain(chain);
#ifndef MICROSTACK_NOTLS
util_openssl_uninit();
#endif
return(slaveObject.exitCode);
}
int ILibDuktape_ScriptContainer_DecodeJSON(duk_context *ctx, char *json, int jsonLen)
{
int retVal = 0;
duk_push_global_object(ctx); // [g]
duk_get_prop_string(ctx, -1, "JSON"); // [g][JSON]
duk_get_prop_string(ctx, -1, "parse"); // [g][JSON][func]
duk_swap_top(ctx, -3); // [func][JSON][g]
duk_pop_2(ctx); // [func]
duk_push_lstring(ctx, json, jsonLen); // [func][str]
if (duk_pcall(ctx, 1) != 0) { retVal = 1; duk_pop(ctx); }
return(retVal);
}
int ILibDuktape_ScriptContainer_AddVoidPtr(duk_context *ctx, void *heapptr, void *ptr)
{
int i;
duk_push_heapptr(ctx, heapptr); // [master]
if (!duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_PtrTable))
{
duk_push_object(ctx); // [master][obj]
duk_dup(ctx, -1); // [master][obj][obj]
duk_put_prop_string(ctx, -3, ILibDuktape_ScriptContainer_PtrTable); // [master][obj]
}
i = 1 + Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_PtrTable_Idx, 0);
duk_push_int(ctx, i);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_PtrTable_Idx); // [master][obj]
duk_push_pointer(ctx, ptr);
duk_put_prop_index(ctx, -2, i);
duk_pop_2(ctx); // ...
return(i);
}
void* ILibDuktape_ScriptContainer_RemoveVoidPtr(duk_context *ctx, void *heapptr, int idx)
{
int i;
void *retVal = NULL;
duk_push_heapptr(ctx, heapptr); // [master]
if (duk_has_prop_string(ctx, -1, ILibDuktape_ScriptContainer_PtrTable))
{
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_PtrTable); // [master][obj]
i = Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_PtrTable_Idx, 0);
if (duk_has_prop_index(ctx, -1, i))
{
duk_get_prop_index(ctx, -1, i); // [master][obj][ptr]
retVal = duk_get_pointer(ctx, -1);
duk_pop(ctx); // [master][obj]
duk_del_prop_index(ctx, -1, i);
}
duk_pop(ctx); // [master]
}
duk_pop(ctx); // ...
return(retVal);
}
duk_ret_t ILibDuktape_ScriptContainer_Exit(duk_context *ctx)
{
ILibDuktape_ScriptContainer_Master *master;
duk_push_this(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr);
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
if (master->PeerChain != NULL)
{
char json[] = "{\"command\": \"128\"}";
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.slave = ((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
Duktape_RunOnEventLoopEx(master->PeerChain, duk_ctx_nonce(master->PeerCTX), master->PeerCTX, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd, 1);
return(0);
}
if (ILibIsChainBeingDestroyed(Duktape_GetChain(ctx)) == 0)
{
char *buffer;
char header[4];
duk_size_t bufferLen;
duk_push_object(ctx); // [obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_EXIT); // [obj][command]
duk_put_prop_string(ctx, -2, "command"); // [obj]
duk_json_encode(ctx, -1);
buffer = (char*)duk_get_lstring(ctx, -1, &bufferLen);
((int*)header)[0] = (int)bufferLen + 4;
ILibProcessPipe_Process_WriteStdIn(master->child, header, 4, ILibTransport_MemoryOwnership_USER);
ILibProcessPipe_Process_WriteStdIn(master->child, buffer, (int)bufferLen, ILibTransport_MemoryOwnership_USER);
//if (master->child != NULL) { ILibProcessPipe_Process_SoftKill(master->child); }
}
return 0;
}
duk_ret_t ILibDuktape_ScriptContainer_Exit2(duk_context *ctx)
{
ILibDuktape_ScriptContainer_Exit(ctx);
duk_push_this(ctx);
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBufferProperty(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr);
if (ILibIsChainBeingDestroyed(duk_ctx_chain(ctx)) == 0 && master->child != NULL)
{
ILibProcessPipe_Process p = (ILibProcessPipe_Process)master->child;
master->child = NULL;
ILibProcessPipe_Process_SoftKill(p);
}
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_ExecuteScript(duk_context *ctx)
{
return 0;
}
duk_ret_t ILibDuktape_ScriptContainer_ExecuteString(duk_context *ctx)
{
ILibDuktape_ScriptContainer_Master *master;
void *ptr = duk_get_top(ctx) > 1 ? duk_require_heapptr(ctx, 1) : NULL;
int seq = -1;
duk_size_t bufferLen;
char *buffer;
char header[4];
duk_require_string(ctx, 0);
duk_push_this(ctx); // [container]
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr); // [container][buffer]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL); // [container][buffer]
if (master->PeerChain != NULL)
{
char json[] = "{\"command\": \"2\", \"base64\": \"\"}";
char *payload;
duk_size_t payloadLen;
payload = (char*)duk_get_lstring(ctx, 0, &payloadLen);
size_t encodedPayloadLen = ILibBase64EncodeLength(payloadLen);
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate((int)(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + encodedPayloadLen + sizeof(json)), 0, NULL, NULL);
cmd->container.slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
int i = sprintf_s(cmd->json, sizeof(json) + encodedPayloadLen, json);
char *output = cmd->json + i -2;
i += ILibBase64Encode((unsigned char*)payload, (int)payloadLen, (unsigned char**)&output);
sprintf_s(cmd->json + i - 2, 3, "\"}");
Duktape_RunOnEventLoopEx(master->PeerChain, duk_ctx_nonce(master->PeerCTX), master->PeerCTX, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd, 1);
return(0);
}
if (ptr != NULL) { seq = ILibDuktape_ScriptContainer_AddVoidPtr(ctx, duk_get_heapptr(ctx, -2), ptr); }
duk_push_object(ctx); // [container][buffer][obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_EXEC); // [container][buffer][obj][command]
duk_put_prop_string(ctx, -2, "command"); // [container][buffer][obj]
duk_dup(ctx, 0); // [container][buffer][obj][string]
duk_put_prop_string(ctx, -2, "string"); // [container][buffer][obj]
if (ptr != NULL)
{
duk_push_int(ctx, seq); // [container][buffer][obj][seq]
duk_put_prop_string(ctx, -2, "sequence"); // [container][buffer][obj]
}
duk_json_encode(ctx, -1);
buffer = (char*)duk_get_lstring(ctx, -1, &bufferLen);
((int*)header)[0] = (int)bufferLen + 4;
ILibProcessPipe_Process_WriteStdIn(master->child, header, 4, ILibTransport_MemoryOwnership_USER);
ILibProcessPipe_Process_WriteStdIn(master->child, buffer, (int)bufferLen, ILibTransport_MemoryOwnership_USER);
return(0);
}
void ILibDuktape_ScriptContainer_ExitSink(ILibProcessPipe_Process sender, int exitCode, void* user)
{
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)user;
if (ILibMemory_CanaryOK(master))
{
duk_context *ctx = master->ctx;
ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "exit"); // [emit][this][exit]
duk_push_int(master->ctx, exitCode); // [emit][this][exit][code]
if (duk_pcall_method(master->ctx, 2) != 0)
{
ILibDuktape_Process_UncaughtException(master->ctx);
}
duk_pop(ctx);
if (ILibMemory_CanaryOK(master)) { master->child = NULL; }
}
}
void ILibDuktape_ScriptContainer_StdOutSink_Chain(void *chain, void *user)
{
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)((void**)user)[0];
if (ILibMemory_CanaryOK(master))
{
char *buffer = ILibMemory_Extra(user);
duk_push_global_object(master->ctx); // [g]
duk_get_prop_string(master->ctx, -1, "console"); // [g][console]
duk_get_prop_string(master->ctx, -1, "log"); // [g][console][log]
duk_swap_top(master->ctx, -2); // [g][log][this]
duk_push_string(master->ctx, "Child/StdOut"); // [g][log][this][s1]
duk_push_lstring(master->ctx, buffer, ILibMemory_ExtraSize(user)); // [g][log][this][s1][str]
duk_pcall_method(master->ctx, 2); duk_pop(master->ctx); // [g]
duk_pop(master->ctx); // ...
}
ILibMemory_Free(user);
}
void ILibDuktape_ScriptContainer_StdOutSink(ILibProcessPipe_Process sender, char *buffer, size_t bufferLen, size_t* bytesConsumed, void* user)
{
buffer[bufferLen] = 0;
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)user;
if (ILibMemory_CanaryOK(master))
{
void *tmp = ILibMemory_SmartAllocateEx(sizeof(void*), bufferLen + 1);
((void**)tmp)[0] = master;
memcpy_s(ILibMemory_Extra(tmp), ILibMemory_ExtraSize(tmp), buffer, bufferLen);
Duktape_RunOnEventLoop(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_StdOutSink_Chain, NULL, tmp);
}
*bytesConsumed = bufferLen;
}
void ILibDuktape_ScriptContainer_SendOkSink(ILibProcessPipe_Process sender, void* user)
{
}
void ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread(void *chain, void *user)
{
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)((void**)user)[0];
char *buffer = (char*)((void**)user)[1];
int bufferLen = ((int*)buffer)[0];
void *ptr;
int i;
duk_context *ctx = master->ctx;
if (ILibDuktape_ScriptContainer_DecodeJSON(master->ctx, buffer+4, bufferLen-4) == 0)
{
switch ((SCRIPT_ENGINE_COMMAND)Duktape_GetIntPropertyValue(master->ctx, -1, "command", (int)SCRIPT_ENGINE_COMMAND_UNKNOWN))
{
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
{
if(ILibDuktape_EventEmitter_HasListeners(master->emitter, "data")!=0)
{
char *json = Duktape_GetStringPropertyValue(master->ctx, -1, "json", NULL);
if (json != NULL)
{
ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "data"); // [emit][this][data]
duk_push_string(master->ctx, json); // [emit][this][data][str]
duk_json_decode(master->ctx, -1); // [emit][this][data][json]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer.OnData(): "); }
duk_pop(ctx);
}
}
break;
}
case SCRIPT_ENGINE_COMMAND_LOG:
{
ILibRemoteLogging_printf(ILibChainGetLogger(Duktape_GetChain(master->ctx)), (ILibRemoteLogging_Modules)Duktape_GetIntPropertyValue(master->ctx, -1, "module", (int)ILibRemoteLogging_Modules_ConsolePrint), (ILibRemoteLogging_Flags)Duktape_GetIntPropertyValue(master->ctx, -1, "flags", (int)ILibRemoteLogging_Flags_NONE), "%s", Duktape_GetStringPropertyValue(master->ctx, -1, "message", ""));
break;
}
case SCRIPT_ENGINE_COMMAND_EXEC:
{
if (duk_has_prop_string(master->ctx, -1, "error"))
{
// ERROR
if ((i = Duktape_GetIntPropertyValue(master->ctx, -1, "sequence", -1)) < 0)
{
// No callback was specified
ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "error"); // [emit][this][error]
duk_get_prop_string(master->ctx, -4, "error"); // [emit][this][error][errorObj]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnError_Dispatch(): "); }
duk_pop(ctx); // ...
}
else
{
if ((ptr = ILibDuktape_ScriptContainer_RemoveVoidPtr(master->ctx, master->emitter->object, i)) != NULL)
{
// Callback was provided
duk_push_heapptr(master->ctx, ptr); // [func]
duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
duk_push_false(master->ctx); // [func][this][false]
duk_get_prop_string(master->ctx, -4, "error"); // [func][this][false][error]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnError_Dispatch(): "); }
duk_pop(ctx); // ...
}
}
}
else
{
// SUCCESS
if ((i = Duktape_GetIntPropertyValue(master->ctx, -1, "sequence", -1)) >= 0 && (ptr = ILibDuktape_ScriptContainer_RemoveVoidPtr(master->ctx, master->emitter->object, i)) != NULL)
{
duk_push_heapptr(master->ctx, ptr); // [func]
duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
duk_push_true(master->ctx); // [func][this][true]
if (duk_has_prop_string(master->ctx, -4, "result"))
{
duk_get_prop_string(master->ctx, -4, "result");
duk_json_decode(master->ctx, -1); // [func][this][true][result]
}
else
{
duk_push_undefined(master->ctx); // [func][this][true][undefined]
}
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnExec_Dispatch(): "); }
duk_pop(ctx); // ...
}
}
break;
}
default:
break;
}
duk_pop(ctx); // ...
}
#ifdef WIN32
if (ILibMemory_CanaryOK(master))
{
if (master->child != NULL) { ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdErr(master->child)); }
}
#endif
}
void ILibDuktape_ScriptContainer_StdErrSink(ILibProcessPipe_Process sender, char *buffer, size_t bufferLen, size_t* bytesConsumed, void* user)
{
ILibDuktape_ScriptContainer_Master* master = (ILibDuktape_ScriptContainer_Master*)user;
if (bufferLen < 4 || bufferLen < (size_t)((int*)buffer)[0]) { return; }
*bytesConsumed = ((int*)buffer)[0];
#ifdef WIN32
if (ILibMemory_CanaryOK(sender))
{
void **ptr = (void**)ILibMemory_Extra(ILibProcessPipe_Process_GetStdErr(sender));
ptr[0] = master;
ptr[1] = buffer;
ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdErr(sender));
Duktape_RunOnEventLoop(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread, NULL, ptr);
}
#else
void *ptr[2] = { master, buffer };
ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread(master->chain, ptr);
#endif
}
duk_ret_t ILibDuktape_ScriptContainer_Finalizer(duk_context *ctx)
{
duk_get_prop_string(ctx, 0, ILibDuktape_ScriptContainer_MasterPtr);
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
if (master->child != NULL)
{
#ifdef WIN32
ILibProcessPipe_Process_RemoveHandlers(master->child);
#endif
ILibProcessPipe_Process_SoftKill(master->child);
}
else if (master->PeerChain != NULL)
{
char json[] = "{\"command\": \"128\", \"noResponse\": \"1\"}";
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.slave = ((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
Duktape_RunOnEventLoopEx(master->PeerChain, duk_ctx_nonce(master->PeerCTX), master->PeerCTX, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd, 1);
#ifdef WIN32
WaitForSingleObject(master->PeerThread, INFINITE);
#endif
}
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_SendToSlave(duk_context *ctx)
{
ILibDuktape_ScriptContainer_Master *master;
int len;
duk_push_this(ctx); // [container]
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr); // [container][master]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
duk_push_object(ctx); // [container][master][obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_SEND_JSON); // [container][master][obj][command]
duk_put_prop_string(ctx, -2, "command"); // [container][master][obj]
duk_dup(ctx, 0); // [container][master][obj][value]
duk_json_encode(ctx, -1); // [container][master][obj][json]
duk_put_prop_string(ctx, -2, "json"); // [container][master][obj]
duk_json_encode(ctx, -1); // [container][master][json]
if (master->child != NULL)
{
duk_size_t jsonlen;
char *json = (char*)duk_get_lstring(ctx, -1, &jsonlen);
char *payload = duk_push_fixed_buffer(ctx, jsonlen + 5);
len = sprintf_s(payload + 4, jsonlen + 1, "%s", json);
((int*)payload)[0] = len + 4;
ILibProcessPipe_Process_WriteStdIn(master->child, payload, len + 4, ILibTransport_MemoryOwnership_USER);
}
else if(master->PeerChain != NULL)
{
duk_size_t payloadLen;
char *payload = (char*)duk_get_lstring(ctx, -1, &payloadLen);
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = ILibMemory_Allocate(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + (int)payloadLen + 1, 0, NULL, NULL);
cmd->container.slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
memcpy_s(cmd->json, payloadLen + 1, payload, payloadLen + 1);
Duktape_RunOnEventLoopEx(master->PeerChain, duk_ctx_nonce(master->PeerCTX), master->PeerCTX, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, cmd, 1);
}
return(0);
}
duk_ret_t ILibDuktape_ScriptContainer_Master_AddModule(duk_context *ctx)
{
ILibDuktape_ScriptContainer_Master *master;
int len;
duk_push_this(ctx); // [container]
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_MasterPtr); // [container][master]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
duk_push_object(ctx);
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_ADD_MODULE);
duk_put_prop_string(ctx, -2, "command");
duk_dup(ctx, 0);
duk_put_prop_string(ctx, -2, "name");
duk_dup(ctx, 1);
duk_put_prop_string(ctx, -2, "module");
duk_json_encode(ctx, -1);
len = sprintf_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, "%s", duk_get_string(ctx, -1));
((int*)ILibScratchPad2)[0] = len + 4;
ILibProcessPipe_Process_WriteStdIn(master->child, ILibScratchPad2, len+4, ILibTransport_MemoryOwnership_USER);
return(0);
}
void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster(void *chain, void *user)
{
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)user;
ILibDuktape_ScriptContainer_Master *master = cmd->container.master;
ILibDuktape_ScriptContainer_Slave *slave = master->PeerChain == NULL ? NULL : (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(master->PeerChain, ILibMemory_CHAIN_CONTAINERSIZE))[1];
if (master->ctx == NULL) { return; }
int id;
duk_push_string(master->ctx, cmd->json); // [string]
duk_json_decode(master->ctx, -1); // [json]
free(cmd);
switch ((id = Duktape_GetIntPropertyValue(master->ctx, -1, "command", -1)))
{
case 0: // Ready
{
// Call INIT first
char json[] = "{\"command\": \"1\"}";
ILibDuktape_ScriptContainer_NonIsolated_Command* initCmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
initCmd->container.slave = slave;
memcpy_s(initCmd->json, sizeof(json), json, sizeof(json));
Duktape_RunOnEventLoopEx(master->PeerChain, duk_ctx_nonce(master->PeerCTX), master->PeerCTX, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave, initCmd, 1);
break;
}
case 1:
{
// Emit Ready Event
duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
duk_swap_top(master->ctx, -2); // [json][emit][this]
duk_push_string(master->ctx, "ready"); // [json][emit][this][ready]
if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Dispatching 'ready' event to Master Script Container"); }
duk_pop(master->ctx); // [json]
break;
}
case SCRIPT_ENGINE_COMMAND_ERROR:
duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
duk_swap_top(master->ctx, -2); // [json][emit][this]
duk_push_string(master->ctx, "error"); // [json][emit][this][error]
duk_get_prop_string(master->ctx, -4, "message"); // [json][emit][this][error][msg]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Emitting ScriptContainer Error Message: "); }
duk_pop(master->ctx); // [json]
break;
case SCRIPT_ENGINE_COMMAND_EXIT:
duk_push_heapptr(master->ctx, master->emitter->object); // [json][container]
duk_get_prop_string(master->ctx, -1, "emit"); // [json][container][emit]
duk_swap_top(master->ctx, -2); // [json][emit][this]
duk_push_string(master->ctx, "exit"); // [json][emit][this][exit]
duk_get_prop_string(master->ctx, -4, "exitCode"); // [json][emit][this][exit][msg]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Emitting ScriptContainer Exit: "); }
duk_pop(master->ctx); // [json]
master->PeerChain = NULL;
master->PeerCTX = NULL;
break;
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
ILibDuktape_EventEmitter_SetupEmit(master->ctx, master->emitter->object, "data"); // [json][emit][this][data]
duk_get_prop_string(master->ctx, -4, "json"); // [json][emit][this][data][str]
duk_json_decode(master->ctx, -1); // [json][emit][this][data][value]
if (duk_pcall_method(master->ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Error Emitting ScriptContainer Data: "); }
duk_pop(master->ctx); // [json]
break;
default:
ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "Unknown Command [%d] Received from Slave Container ", id);
break;
}
duk_pop(master->ctx); // ...
}
void ILibDuktape_ScriptContainer_NonIsolatedWorker_ExceptionSink(duk_context *ctx, char *msg, void *user)
{
duk_push_object(ctx); // [obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_ERROR);
duk_put_prop_string(ctx, -2, "command");
duk_push_string(ctx, msg);
duk_put_prop_string(ctx, -2, "message");
duk_json_encode(ctx, -1); // [json]
duk_size_t payloadLen;
char *payload = (char*)duk_get_lstring(ctx, -1, &payloadLen);
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate((int)(sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command) + payloadLen + 1), 0, NULL, NULL);
cmd->container.master = ((void**)ILibMemory_GetExtraMemory(Duktape_GetChain(ctx), ILibMemory_CHAIN_CONTAINERSIZE))[0];
memcpy_s(cmd->json, payloadLen + 1, payload, payloadLen + 1);
duk_pop(ctx); // ...
Duktape_RunOnEventLoopEx(cmd->container.master->chain, duk_ctx_nonce(cmd->container.master->ctx), cmd->container.master->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd, 1);
}
void ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsSlave(void *chain, void *user)
{
ILibDuktape_ScriptContainer_NonIsolated_Command *cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)user;
ILibDuktape_ScriptContainer_Slave *slave = cmd->container.slave;
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[0];
int id;
duk_push_string(slave->ctx, cmd->json); // [string]
duk_json_decode(slave->ctx, -1); // [json]
free(cmd);
switch ((id = Duktape_GetIntPropertyValue(slave->ctx, -1, "command", -1)))
{
case SCRIPT_ENGINE_COMMAND_INIT:
ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx3(slave->ctx, (SCRIPT_ENGINE_SECURITY_FLAGS)master->ChildSecurityFlags, 0, slave->chain, NULL, NULL, NULL, NULL, ILibDuktape_ScriptContainer_Slave_HeapDestroyed, slave);
ILibDuktape_SetNativeUncaughtExceptionHandler(slave->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ExceptionSink, master);
char json[] = "{\"command\": \"1\"}";
cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.master = master;
memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
Duktape_RunOnEventLoopEx(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd, 1);
break;
case SCRIPT_ENGINE_COMMAND_EXEC:
{
char *payload;
duk_size_t payloadLen;
payload = (char*)Duktape_GetStringPropertyValueEx(slave->ctx, -1, "base64", NULL, &payloadLen);
payloadLen = ILibBase64Decode((unsigned char*)payload, (int)payloadLen, (unsigned char**)&payload);
if (ILibDuktape_ScriptContainer_CompileJavaScript(slave->ctx, payload, (int)payloadLen) == 0 && ILibDuktape_ScriptContainer_ExecuteByteCode(slave->ctx) == 0)
{
// SUCCESS
duk_pop(slave->ctx);
}
else
{
// ERROR
ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer Error: ");
duk_pop(slave->ctx);
}
}
break;
case SCRIPT_ENGINE_COMMAND_SEND_JSON:
{
if (slave->emitter != NULL)
{
duk_get_prop_string(slave->ctx, -1, "json"); // [cmd][string]
duk_json_decode(slave->ctx, -1); // [cmd][obj]
duk_push_heapptr(slave->ctx, slave->emitter->object); // [cmd][obj][container]
duk_get_prop_string(slave->ctx, -1, "emit"); // [cmd][obj][container][emit]
duk_swap_top(slave->ctx, -2); // [cmd][obj][emit][this]
duk_push_string(slave->ctx, "data"); // [cmd][obj][emit][this][data]
duk_dup(slave->ctx, -4); // [cmd][obj][emit][this][data][obj]
if (duk_pcall_method(slave->ctx, 2) != 0) { ILibDuktape_Process_UncaughtException(slave->ctx); }
duk_pop_2(slave->ctx); // [cmd]
}
}
break;
case SCRIPT_ENGINE_COMMAND_EXIT:
slave->noRespond = Duktape_GetIntPropertyValue(slave->ctx, -1, "noResponse", 0);
duk_pop(slave->ctx);
Duktape_SafeDestroyHeap(slave->ctx);
return;
}
duk_pop(slave->ctx); // ...
}
void ILibDuktape_ScriptContainer_NonIsolatedWorker(void *arg)
{
ILibDuktape_ScriptContainer_Master *master = (ILibDuktape_ScriptContainer_Master*)arg;
ILibDuktape_ScriptContainer_Slave *slave = ILibMemory_AllocateA(sizeof(ILibDuktape_ScriptContainer_Slave));
char json[] = "{\"command\": \"0\"}";
slave->chain = ILibCreateChainEx(2 * sizeof(void*));
((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[0] = master;
((void**)ILibMemory_GetExtraMemory(slave->chain, ILibMemory_CHAIN_CONTAINERSIZE))[1] = slave;
master->PeerChain = slave->chain;
slave->ctx = ILibDuktape_ScriptContainer_InitializeJavaScriptEngine_minimal();
master->PeerCTX = slave->ctx;
duk_push_heap_stash(slave->ctx);
duk_push_pointer(slave->ctx, slave);
duk_put_prop_string(slave->ctx, -2, ILibDuktape_ScriptContainer_SlavePtr);
duk_push_pointer(slave->ctx, master);
duk_put_prop_string(slave->ctx, -2, ILibDuktape_ScriptContainer_MasterPtr);
duk_pop(slave->ctx);
ILibDuktape_ScriptContainer_NonIsolated_Command* cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(sizeof(json) + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.master = master;
memcpy_s(cmd->json, sizeof(json), json, sizeof(json));
Duktape_RunOnEventLoopEx(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd, 1);
ILibChain_DisableWatchDog(slave->chain);
ILibStartChain(slave->chain);
if (slave->noRespond == 0)
{
cmd = (ILibDuktape_ScriptContainer_NonIsolated_Command*)ILibMemory_Allocate(64 + sizeof(ILibDuktape_ScriptContainer_NonIsolated_Command), 0, NULL, NULL);
cmd->container.master = master;
sprintf_s(cmd->json, 64, "{\"command\": \"128\", \"exitCode\": \"%d\"}", slave->exitCode);
Duktape_RunOnEventLoopEx(master->chain, duk_ctx_nonce(master->ctx), master->ctx, ILibDuktape_ScriptContainer_NonIsolatedWorker_ProcessAsMaster, cmd, 1);
}
}
duk_ret_t ILibDuktape_ScriptContainer_Create(duk_context *ctx)
{
char *exePath;
ILibProcessPipe_Manager manager;
ILibDuktape_ScriptContainer_Master *master;
char *param[] = { (char*)"--slave", NULL };
duk_size_t bufferLen;
char *buffer;
char header[4];
ILibProcessPipe_SpawnTypes spawnType = (duk_get_top(ctx) > 2 && duk_is_number(ctx, 2)) ? (ILibProcessPipe_SpawnTypes)duk_require_int(ctx, 2) : ILibProcessPipe_SpawnTypes_DEFAULT;
int processIsolation = 1;
int sessionIdSpecified = 0;
void *sessionId = NULL;
if (duk_get_top(ctx) > 0 && duk_is_object(ctx, 0))
{
processIsolation = Duktape_GetIntPropertyValue(ctx, 0, "processIsolation", 1);
if (duk_has_prop_string(ctx, 0, "sessionId"))
{
sessionIdSpecified = 1;
sessionId = (void*)(ILibPtrCAST)(uint64_t)Duktape_GetIntPropertyValue(ctx, 0, "sessionId", 0);
}
}
duk_push_heap_stash(ctx);
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_ExePath);
duk_get_prop_string(ctx, -2, ILibDuktape_ScriptContainer_PipeManager);
exePath = (char*)duk_get_string(ctx, -2);
manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1);
duk_push_object(ctx); // [container]
ILibDuktape_WriteID(ctx, "ScriptContainer.master");
master = (ILibDuktape_ScriptContainer_Master*)Duktape_PushBuffer(ctx, sizeof(ILibDuktape_ScriptContainer_Master));
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_MasterPtr); // [container]
master->ctx = ctx;
master->emitter = ILibDuktape_EventEmitter_Create(ctx);
master->chain = Duktape_GetChain(ctx);
ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "exit");
ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "error");
ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "data");
ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "ready");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit", ILibDuktape_ScriptContainer_Exit, DUK_VARARGS);
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit2", ILibDuktape_ScriptContainer_Exit2, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(master->ctx, "ExecuteScript", ILibDuktape_ScriptContainer_ExecuteScript, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(master->ctx, "ExecuteString", ILibDuktape_ScriptContainer_ExecuteString, DUK_VARARGS);
ILibDuktape_CreateInstanceMethod(master->ctx, "send", ILibDuktape_ScriptContainer_SendToSlave, 1);
ILibDuktape_CreateInstanceMethod(master->ctx, "addModule", ILibDuktape_ScriptContainer_Master_AddModule, 2);
ILibDuktape_CreateFinalizer(master->ctx, ILibDuktape_ScriptContainer_Finalizer);
if (processIsolation)
{
// We're going to spawn a child process to run this ScriptContainer
unsigned int executionTimeout = duk_is_object(ctx, 0)?Duktape_GetIntPropertyValue(ctx, 0, "executionTimeout", 0): (unsigned int)duk_require_int(ctx, 0);
master->ChildSecurityFlags = (duk_is_object(ctx, 0) ? Duktape_GetIntPropertyValue(ctx, 0, "childSecurityFlags", 0): (unsigned int)duk_require_int(ctx, 1)) | SCRIPT_ENGINE_NO_MESH_AGENT_ACCESS;
if (duk_is_object(ctx, 0) && duk_has_prop_string(ctx, 0, "env"))
{
char tmp[32768];
size_t v = 0;
#ifdef WIN32
char *key, *value;
duk_size_t keyLen, valueLen;
#else
char **envvars = (char**)tmp;
#endif
duk_get_prop_string(ctx, 0, "env"); // [env]
duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);// [env][enum]
while (duk_next(ctx, -1, 1)) // [env][enum][key][val]
{
#ifdef WIN32
key = (char*)duk_to_lstring(ctx, -2, &keyLen);
value = (char*)duk_to_lstring(ctx, -1, &valueLen);
if (keyLen + valueLen + 3 + v > sizeof(tmp)) { return(ILibDuktape_Error(ctx, "Environment Variables too Large")); }
v += sprintf_s(tmp + v, sizeof(tmp) - v, "%s=%s", key, value);
(tmp + v)[0] = 0; ++v;
#else
v += (2 * sizeof(char*));
if (v < sizeof(tmp))
{
envvars[0] = (char*)duk_to_string(ctx, -2);
envvars[1] = (char*)duk_to_string(ctx, -1);
envvars = (char**)((char*)envvars + 2 * sizeof(char*));
}
#endif
duk_pop_2(ctx); // [env][enum]
}
duk_pop_2(ctx); // ...
#ifdef WIN32
(tmp + v)[0] = 0; ++v;
#else
v += sizeof(char*);
if (v < sizeof(tmp))
{
envvars[0] = NULL;
}
else
{
return(ILibDuktape_Error(ctx, "Environment Variables are too large"));
}
#endif
master->child = ILibProcessPipe_Manager_SpawnProcessEx4(manager, exePath, (char * const*)param, sessionIdSpecified!=0?ILibProcessPipe_SpawnTypes_SPECIFIED_USER:spawnType, sessionId, (void*)tmp, 2 * sizeof(void*));
}
else
{
master->child = ILibProcessPipe_Manager_SpawnProcessEx3(manager, exePath, (char * const*)param, sessionIdSpecified!=0?ILibProcessPipe_SpawnTypes_SPECIFIED_USER:spawnType, sessionId, 2 * sizeof(void*));
}
if (master->child == NULL) { return(ILibDuktape_Error(ctx, "ScriptContainer.Create(): Error spawning child process, using [%s]", exePath)); }
duk_push_true(ctx);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ProcessIsolated);
duk_push_object(ctx); // [container][obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_INIT);
duk_put_prop_string(ctx, -2, "command");
duk_push_int(ctx, (int)executionTimeout);
duk_put_prop_string(ctx, -2, "executionTimeout");
duk_push_int(ctx, (int)master->ChildSecurityFlags);
duk_put_prop_string(ctx, -2, "securityFlags");
duk_json_encode(ctx, -1);
buffer = (char*)Duktape_GetBuffer(ctx, -1, &bufferLen);
duk_swap_top(ctx, -2); // [json][container]
((int*)header)[0] = (int)bufferLen + 4;
ILibProcessPipe_Process_AddHandlers(master->child, SCRIPT_ENGINE_PIPE_BUFFER_SIZE, ILibDuktape_ScriptContainer_ExitSink, ILibDuktape_ScriptContainer_StdOutSink, ILibDuktape_ScriptContainer_StdErrSink, ILibDuktape_ScriptContainer_SendOkSink, master);
ILibProcessPipe_Process_WriteStdIn(master->child, header, sizeof(header), ILibTransport_MemoryOwnership_USER);
ILibProcessPipe_Process_WriteStdIn(master->child, buffer, (int)bufferLen, ILibTransport_MemoryOwnership_USER);
}
else
{
// We're going to spawn a thread to host this Script Container
duk_push_false(ctx);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_ProcessIsolated);
ILibDuktape_EventEmitter_CreateEventEx(master->emitter, "ready");
master->PeerThread = ILibSpawnNormalThread(ILibDuktape_ScriptContainer_NonIsolatedWorker, master);
master->ChildSecurityFlags = Duktape_GetIntPropertyValue(ctx, 0, "permissions", 0);
duk_push_fixed_buffer(ctx, sizeof(void*)); // [container][buffer]
((void**)Duktape_GetBuffer(ctx, -1, NULL))[0] = master->PeerThread;
duk_dup(ctx, -1); // [container][buffer][buffer]
duk_put_prop_string(ctx, -3, "\xFF_PointerBuffer"); // [container][buffer]
duk_push_buffer_object(ctx, -1, 0, sizeof(void*), DUK_BUFOBJ_NODEJS_BUFFER);// [container][buffer][NodeBuffer]
duk_remove(ctx, -2); // [container][NodeBuffer]
ILibDuktape_CreateReadonlyProperty(ctx, "_PeerThread"); // [container]
#ifdef WIN32
duk_push_int(ctx, (int)GetThreadId(master->PeerThread));
ILibDuktape_CreateReadonlyProperty(ctx, "_PeerThreadID"); // [container]
#endif
}
return 1;
}
void ILibDuktape_ScriptContainer_PUSH_MASTER(duk_context *ctx, void *chain)
{
duk_push_object(ctx);
ILibDuktape_CreateInstanceMethod(ctx, "Create", ILibDuktape_ScriptContainer_Create, DUK_VARARGS);
}
duk_ret_t ILibDuktape_ScriptContainer_Slave_SendToMaster(duk_context *ctx)
{
duk_push_object(ctx); // [obj]
duk_push_int(ctx, (int)SCRIPT_ENGINE_COMMAND_SEND_JSON); // [obj][cmd]
duk_put_prop_string(ctx, -2, "command"); // [obj]
duk_dup(ctx, 0); // [obj][value]
duk_json_encode(ctx, -1); // [obj][json]
duk_put_prop_string(ctx, -2, "json"); // [obj]
ILibDuktape_ScriptContainer_Slave_SendJSON(ctx);
return(0);
}
void ILibDuktape_ScriptContainer_PUSH_SLAVE(duk_context *ctx, void *chain)
{
ILibDuktape_ScriptContainer_Slave *slave;
duk_push_heap_stash(ctx); // [s]
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_SlavePtr); // [s][ptr]
slave = (ILibDuktape_ScriptContainer_Slave*)duk_get_pointer(ctx, -1);
duk_pop(ctx); // ...
duk_push_object(ctx);
ILibDuktape_WriteID(ctx, "ScriptContainer.slave");
slave->emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(slave->emitter, "data");
ILibDuktape_CreateInstanceMethod(ctx, "send", ILibDuktape_ScriptContainer_Slave_SendToMaster, 1);
ILibDuktape_CreateInstanceMethod(ctx, "Create", ILibDuktape_ScriptContainer_Create, DUK_VARARGS);
}
#ifdef __DOXY__
/*!
\brief The os module provides a number of operating system-related utility methods. <b>Note:</b> To use, must <b>require('os')</b>
*/
class os
{
public:
/*!
\brief Constant defining the operating system specific end-of-line marker (<b>'\\r'</b> or <b>'\\r\\n'</b>)
*/
String EOL;
/*!
\brief returns a String identifying the operating system platform (<b>'darwin'</b>, <b>'win32'</b>, or <b>'linux'</b>)
\return \<String\>
*/
String platform();
/*!
\brief Returns a String identifying the operating system CPU architecture (ie: <b>'x86'</b>, <b>'x64'</b>, etc) <b>Note:</b> Same as process.arch
\return \<String\>
*/
String arch();
/*!
\brief Returns an object containing the current network interfaces
*
Each key on the returned object identifies a network interfaces. The associated value is an array of objects that each describe an assigned network address.\n
\par The properties available on the network address object include:\n
<b>address</b> \<String\> The assigned IPv4 or IPv6 address\n
<b>netmask</b> \<String\> The IPv4 of IPv6 network mask\n
<b>family</b> \<String\> Either <b>'IPv4'</b> or <b>'IPv6'</b>\n
<b>mac</b> \<String\> The MAC address of the network interface\n
<b>status</b> \<String\> Either <b>'up'</b> or <b>'down'</b>\n
<b>type</b> \<String\> One of <b>'ethernet'</b>, <b>'wireless'</b>, <b>'tunnel'</b>, <b>'loopback'</b>, or <b>'other'</b>\n
\return <Object>
*/
Object networkInterfaces();
};
/*!
\implements EventEmitter
\brief The process object is a global that provides information about, and control over, the current process
*/
class process
{
public:
/*!
\brief Property String identifying the operating system platform on which the JavaScript engine is running. (<b>'darwin'</b>, <b>'linux'</b>, or <b>'win32'</b>)
*/
String platform;
/*!
\brief Event is emitted when the process is about to exit, either as a result of a call to exit(), or the event loop no longer having any work to perform.
\param code <integer> Intended exit code
*/
void exit;
/*!
\brief Terminate the process with the specified exit status
\param code <integer> Optional. Exit Status to use. <b>Default:</b> 0
*/
void exit([code]);
/*!
\brief Event is emitted when an uncaught JavaScript exception bubbles all the way back to the event loop
\param err <Error>
*/
void uncaughtException;
/*!
\brief Property stores a read-only copy of the original value of argv[0]
*/
String argv0;
/*!
\brief An array containing the command line arguments
*/
Array<String> argv;
/*!
\brief Property returns a String identifying the processor architecture. (ie: <b>'x86'</b>, <b>'x64'</b>, etc)
*/
String arch;
ILibDuktape_CreateEventWithGetter(ctx, "argv0", ILibDuktape_ScriptContainer_Process_Argv0);
ILibDuktape_CreateEventWithGetter(ctx, "argv", ILibDuktape_ScriptContainer_Process_Argv);
};
#endif