1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2025-12-06 00:13:33 +00:00
Files
MeshAgent/microscript/ILibDuktape_ScriptContainer.c
2017-10-12 14:28:03 -07:00

1611 lines
62 KiB
C

/*
Copyright 2006 - 2017 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>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netpacket/packet.h>
#endif
#include "duktape.h"
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#endif
#include "ILibDuktape_ScriptContainer.h"
#include "ILibDuktapeModSearch.h"
#include "ILibDuktape_EventEmitter.h"
#include "ILibDuktape_Helpers.h"
#include "../microstack/ILibParsers.h"
#include "../microstack/ILibProcessPipe.h"
#include "../microstack/ILibRemoteLogging.h"
#include "../microstack/ILibCrypto.h"
#include "ILibDuktape_net.h"
#include "ILibDuktape_http.h"
#include "ILibDuktape_WebRTC.h"
#include "ILibDuktape_Dgram.h"
#include "ILibDuktape_GenericMarshal.h"
#include "ILibDuktape_ProcessPipe.h"
#include "ILibDuktape_fs.h"
#include "ILibDuktape_Polyfills.h"
#include "ILibDuktape_SimpleDataStore.h"
#include "ILibDuktape_NetworkMonitor.h"
#include "ILibDuktape_SHA256.h"
#include "ILibDuktape_EncryptionStream.h"
#define SCRIPT_ENGINE_PIPE_BUFFER_SIZE 65535
#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_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_ArgArray "\xFF_argArray"
#define ILibDuktape_ScriptContainer_Process_Restart "\xFF_ScriptContainer_Process_Restart"
#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
extern void ILibDuktape_MemoryStream_Init(duk_context *ctx);
extern void ILibDuktape_NetworkMonitor_Init(duk_context *ctx);
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_LOG = 0xFF
}SCRIPT_ENGINE_COMMAND;
typedef struct ILibDuktape_ScriptContainer_Master
{
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
ILibProcessPipe_Process child;
void *chain;
void *OnExit, *OnError, *OnJSON;
}ILibDuktape_ScriptContainer_Master;
typedef struct ILibDuktape_ScriptContainer_Slave
{
duk_context *ctx;
ILibDuktape_EventEmitter *emitter;
void *OnData;
void *chain;
int exitCode;
}ILibDuktape_ScriptContainer_Slave;
#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)
{
char *json = (char*)duk_json_encode(ctx, -1);
int len = 4 + sprintf_s(ILibScratchPad2 + 4, sizeof(ILibScratchPad2) - 4, "%s", json);
((int*)ILibScratchPad2)[0] = len;
#ifdef WIN32
DWORD tmpLen;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), ILibScratchPad2, len, &tmpLen, NULL);
#else
ignore_result(write(STDERR_FILENO, ILibScratchPad2, len));
#endif
duk_pop(ctx);
}
void ILibDuktape_ScriptContainer_Slave_OnBrokenPipe(ILibProcessPipe_Pipe sender)
{
ILibStopChain(((ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(sender, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[0])->chain);
}
// Polyfill process object:
void ILibDuktape_ScriptContainer_Process_ExitCallback(void *obj)
{
duk_context *ctx = ((void**)obj)[0];
free(obj);
duk_destroy_heap(ctx);
}
duk_ret_t ILibDuktape_ScriptContainer_Process_Exit(duk_context *ctx)
{
void **tmp;
int nargs = duk_get_top(ctx);
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(): Cannot call exit again, already Exiting...")); }
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**)ILibMemory_Allocate(sizeof(void*), 0, NULL, NULL);
tmp[0] = ctx;
ILibLifeTime_Add(ILibGetBaseTimer(Duktape_GetChain(ctx)), tmp, 0, ILibDuktape_ScriptContainer_Process_ExitCallback, NULL);
return 0;
}
// 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_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_dup(ctx, -1); // [process][array][array]
}
else
{
duk_push_array(ctx); // [process][array]
}
return 1;
}
void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList)
{
int i = 0;
ILibDuktape_EventEmitter *emitter;
duk_push_global_object(ctx); // [g]
duk_push_object(ctx); // [g][process]
#if defined(WIN32) // [g][process][platform]
duk_push_string(ctx, "win32");
#elif defined(__APPLE__)
duk_push_string(ctx, "darwin");
#else
duk_push_string(ctx, "linux");
#endif
duk_put_prop_string(ctx, -2, "platform"); // [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]
}
if (duk_peval_string(ctx, "require('os').arch();") == 0) // [g][process][arch]
{
ILibDuktape_CreateReadonlyProperty(ctx, "arch"); // [g][process]
}
else
{ // [g][process]
duk_pop(ctx);
}
emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "exit");
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit", ILibDuktape_ScriptContainer_Process_Exit, DUK_VARARGS);
ILibDuktape_EventEmitter_CreateEventEx(emitter, "uncaughtException");
ILibDuktape_CreateEventWithGetter(ctx, "argv0", ILibDuktape_ScriptContainer_Process_Argv0);
ILibDuktape_CreateEventWithGetter(ctx, "argv", ILibDuktape_ScriptContainer_Process_Argv);
duk_put_prop_string(ctx, -2, "process"); // [g]
duk_pop(ctx); // ...
}
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_Modules_ConsolePrint, 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); // ...
duk_destroy_heap(ctx);
}
SCRIPT_ENGINE_SETTINGS *ILibDuktape_ScriptContainer_GetSettings(duk_context *ctx)
{
SCRIPT_ENGINE_SETTINGS *retVal = (SCRIPT_ENGINE_SETTINGS*)ILibScratchPad;
memset(retVal, 0, sizeof(SCRIPT_ENGINE_SETTINGS));
retVal->chain = Duktape_GetChain(ctx);
duk_push_heap_stash(ctx); // [s]
retVal->securityFlags = (SCRIPT_ENGINE_SECURITY_FLAGS)Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_Settings_SecurityFlags, 0); // [s]
retVal->executionTimeout = (unsigned int)Duktape_GetIntPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExecutionTimeout, 0); // [s]
retVal->exitHandler = (ILibDuktape_HelperEvent)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExitHandler); // [s]
retVal->exitUserObject = Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_ExitUser); // [s]
retVal->db = (ILibSimpleDataStore)Duktape_GetPointerProperty(ctx, -1, ILibDuktape_ScriptContainer_Settings_DB); // [s]
retVal->exePath = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_ScriptContainer_ExePath, NULL); // [s]
retVal->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]
duk_get_prop_string(ctx, -1, ILibDuktape_ScriptContainer_Process_ArgArray); // [g][process][array]
int i, count = duk_get_length(ctx, -1);
for (i = 0; i < count; ++i)
{
duk_get_prop_index(ctx, -1, i); // [g][process][array][index]
retVal->argList[i] = (char*)duk_get_string(ctx, -1);
duk_pop(ctx); // [g][process][array]
}
retVal->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]
retVal->nExeptionHandler = (ILibDuktape_NativeUncaughtExceptionHandler)duk_get_pointer(ctx, -2);
retVal->nExceptionUserObject = duk_get_pointer(ctx, -1);
duk_pop_2(ctx); // [g][process]
}
duk_pop_2(ctx); // ...
return(retVal);
}
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx2(SCRIPT_ENGINE_SETTINGS *settings)
{
return(ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(settings->securityFlags, settings->executionTimeout, settings->chain, settings->argList, settings->db, settings->exePath, settings->pipeManager, settings->exitHandler, settings->exitUserObject));
}
void *ILibDuktape_ScriptContainer_Engine_malloc(void *udata, duk_size_t size)
{
return(ILibMemory_Allocate(size, 0, NULL, NULL));
}
void *ILibDuktape_ScriptContainer_Engine_realloc(void *udata, void *ptr, duk_size_t size)
{
if (size == 0)
{
return(ptr);
}
if ((ptr = realloc(ptr, size)) == NULL)
{
ILIBCRITICALEXITMSG(255, "REALLOC FAILURE");
}
return(ptr);
}
void ILibDuktape_ScriptContainer_Engine_free(void *udata, void *ptr)
{
free(ptr);
}
void ILibDuktape_ScriptContainer_Engine_fatal(duk_context *ctx, duk_errcode_t code, const char *msg)
{
ILIBCRITICALEXITMSG(code, msg);
}
duk_ret_t ILibDuktape_ScriptContainer_OS_arch(duk_context *ctx)
{
#ifdef MESH_AGENTID
duk_push_string(ctx, ARCHNAME[MESH_AGENTID]);
#else
return(ILibDuktape_Error(ctx, "Result for arch() cannot be determined"));
#endif
return 1;
}
duk_ret_t ILibDuktape_ScriptContainer_OS_platform(duk_context *ctx)
{
#ifdef WIN32
duk_push_string(ctx, "win32");
#else
#ifdef __APPLE__
duk_push_string(ctx, "darwin");
#else
duk_push_string(ctx, "linux");
#endif
#endif
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
duk_ret_t ILibDuktape_ScriptContainer_OS_networkInterfaces(duk_context *ctx)
{
duk_push_object(ctx);
#ifdef WIN32
int i = 0;
size_t converted;
char tmpBuffer[32768];
DWORD tmpBufferSize = sizeof(tmpBuffer);
IP_ADAPTER_ADDRESSES *padapters = (IP_ADAPTER_ADDRESSES*)tmpBuffer;
unsigned long mask;
if (GetAdaptersAddresses(AF_UNSPEC, 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");
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_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;
}
wcstombs_s(&converted, ILibScratchPad, sizeof(ILibScratchPad), padapters->FriendlyName, sizeof(ILibScratchPad));
duk_put_prop_string(ctx, -2, ILibScratchPad);
padapters = padapters->Next;
}
#else
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");
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
return(1);
}
void ILibDuktape_ScriptContainer_OS_Push(duk_context *ctx, void *chain)
{
duk_push_object(ctx); // [os]
#ifdef WIN32
duk_push_string(ctx, "\r\n");
#else
duk_push_string(ctx, "\n");
#endif
ILibDuktape_CreateReadonlyProperty(ctx, "EOL");
ILibDuktape_CreateInstanceMethod(ctx, "arch", ILibDuktape_ScriptContainer_OS_arch, 0);
ILibDuktape_CreateInstanceMethod(ctx, "platform", ILibDuktape_ScriptContainer_OS_platform, 0);
ILibDuktape_CreateInstanceMethod(ctx, "networkInterfaces", ILibDuktape_ScriptContainer_OS_networkInterfaces, 0);
}
void ILibDuktape_ScriptContainer_OS_Init(duk_context *ctx)
{
ILibDuktape_ModSearch_AddHandler(ctx, "os", ILibDuktape_ScriptContainer_OS_Push);
}
duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(SCRIPT_ENGINE_SECURITY_FLAGS securityFlags, unsigned int executionTimeout, void *chain, char **argList, ILibSimpleDataStore *db, char *exePath, ILibProcessPipe_Manager pipeManager, ILibDuktape_HelperEvent exitHandler, void *exitUser)
{
duk_context *ctx = duk_create_heap(ILibDuktape_ScriptContainer_Engine_malloc, ILibDuktape_ScriptContainer_Engine_realloc, ILibDuktape_ScriptContainer_Engine_free, NULL, ILibDuktape_ScriptContainer_Engine_fatal);
//duk_context *ctx = duk_create_heap_default();
void **timeoutKey = executionTimeout > 0 ? (void**)ILibMemory_Allocate(sizeof(void*), 0, NULL, NULL) : NULL;
duk_push_heap_stash(ctx); // [s]
duk_push_pointer(ctx, chain); // [s][chain]
duk_put_prop_string(ctx, -2, ILibDuktape_Context_Chain); // [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); // ...
if (exitHandler != NULL) { ILibDuktape_Helper_AddHeapFinalizer(ctx, exitHandler, exitUser); }
// 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)
{
ILibDuktape_WebRTC_Init(ctx); // WebRTC library (browser api)
ILibDuktape_http_init(ctx, chain); // HTTP library (node api)
ILibDuktape_net_init(ctx, chain); // Network library (node api)
ILibDuktape_DGram_Init(ctx); // Datagram Sockets
}
if ((securityFlags & SCRIPT_ENGINE_NO_GENERIC_MARSHAL_ACCESS) == 0) { ILibDuktape_GenericMarshal_init(ctx); }
if ((securityFlags & SCRIPT_ENGINE_NO_PROCESS_SPAWNING) == 0) { ILibDuktape_ProcessPipe_Init(ctx, chain); }
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_EventEmitter_Init(ctx); // event emitter
ILibDuktape_Polyfills_Init(ctx); // Various Polyfills
ILibDuktape_MemoryStream_Init(ctx); // Add MemoryStream support
ILibDuktape_NetworkMonitor_Init(ctx);
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);
}
// Setup Module Search and Database
ILibDuktape_ModSearch_Init(ctx, chain, db);
ILibDuktape_SimpleDataStore_init(ctx, db);
// 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);
}
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_API_ERROR, "Invalid Path specified");
return(1);
}
else
{
return(duk_pcompile_lstring_filename(ctx, 0, path, pathLen));
}
}
// Compiles the JavaScript to bytecode
int ILibDuktape_ScriptContainer_CompileJavaScript(duk_context *ctx, char *payload, int payloadLen)
{
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((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
}
}
// 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)
{
codec = duk_create_heap_default();
}
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_Modules_ConsolePrint, 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, moduleLen);
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint, 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 = 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) { duk_destroy_heap(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_Modules_ConsolePrint, 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, 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))
{
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
{
// 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, 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 (slave->OnData != NULL)
{
char *json = Duktape_GetStringPropertyValue(slave->ctx, -1, "json", NULL);
if (json != NULL)
{
duk_push_heapptr(slave->ctx, slave->OnData); // [func]
duk_push_heapptr(slave->ctx, slave->emitter->object); // [func][this]
duk_push_string(slave->ctx, json); // [func][this][json]
duk_json_decode(slave->ctx, -1); // [func][this][object]
if (duk_pcall_method(slave->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(slave->ctx, "ScriptContainer.OnData(): "); }
duk_pop(slave->ctx); // ...
}
}
break;
}
default:
break;
}
if (codec != NULL && slave->ctx == NULL)
{
duk_destroy_heap(codec);
}
}
#ifdef WIN32
void ILibDuktape_ScriptContainer_Slave_OnReadStdInEx(void *chain, void *data)
{
ILibDuktape_ScriptContainer_Slave *slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(data, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[0];
char *buffer = (char*)((void**)ILibMemory_GetExtraMemory(data, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[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, int bufferLen, int* bytesConsumed)
{
ILibDuktape_ScriptContainer_Slave *slave = (ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(sender, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[0];
if (bufferLen < 4 || bufferLen < ((int*)buffer)[0]) { return; }
ILibRemoteLogging_printf(ILibChainGetLogger(slave->chain), ILibRemoteLogging_Modules_Microstack_Generic | ILibRemoteLogging_Modules_ConsolePrint, 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_GetExtraMemory(sender, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[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
#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_Modules_ConsolePrint, 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_GetExtraMemory(mStdIn, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[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 (ILibIsChainBeingDestroyed(Duktape_GetChain(ctx)) == 0)
{
if (master->child != NULL) { ILibProcessPipe_Process_SoftKill(master->child); }
}
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 (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] = bufferLen + 4;
ILibProcessPipe_Process_WriteStdIn(master->child, header, 4, ILibTransport_MemoryOwnership_USER);
ILibProcessPipe_Process_WriteStdIn(master->child, buffer, 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 (master->OnExit != NULL)
{
duk_push_heapptr(master->ctx, master->OnExit); // [func]
duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
duk_push_int(master->ctx, exitCode); // [func][this][code]
if (duk_pcall_method(master->ctx, 1) != 0) // [retVal]
{
ILibDuktape_Process_UncaughtException(master->ctx);
}
duk_pop(master->ctx); // ...
}
master->child = NULL;
}
void ILibDuktape_ScriptContainer_StdOutSink(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
buffer[bufferLen] = 0;
printf("StdOut: %s", buffer);
*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;
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 (master->OnJSON != NULL)
{
char *json = Duktape_GetStringPropertyValue(master->ctx, -1, "json", NULL);
if (json != NULL)
{
duk_push_heapptr(master->ctx, master->OnJSON);
duk_push_heapptr(master->ctx, master->emitter->object);
duk_push_string(master->ctx, json);
duk_json_decode(master->ctx, -1);
if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer.OnData(): "); }
duk_pop(master->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
if (master->OnError != NULL)
{
duk_push_heapptr(master->ctx, master->OnError); // [func]
duk_push_heapptr(master->ctx, master->emitter->object); // [func][this]
duk_get_prop_string(master->ctx, -3, "error"); // [func][this][error]
if (duk_pcall_method(master->ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(master->ctx, "ScriptContainer_OnError_Dispatch(): "); }
duk_pop(master->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(master->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(master->ctx); // ...
}
}
break;
}
default:
break;
}
duk_pop(master->ctx); // ...
}
#ifdef WIN32
ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdErr(master->child));
#endif
}
void ILibDuktape_ScriptContainer_StdErrSink(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
{
ILibDuktape_ScriptContainer_Master* master = (ILibDuktape_ScriptContainer_Master*)user;
if (bufferLen < 4 || bufferLen < ((int*)buffer)[0]) { return; }
*bytesConsumed = ((int*)buffer)[0];
#ifdef WIN32
void **ptr = (void**)ILibMemory_GetExtraMemory(ILibProcessPipe_Process_GetStdErr(sender), ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE);
ptr[0] = master;
ptr[1] = buffer;
ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdErr(sender));
ILibChain_RunOnMicrostackThread(master->chain, ILibDuktape_ScriptContainer_StdErrSink_MicrostackThread, 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)
{
ILibProcessPipe_Process_KillEx(master->child);
}
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]
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);
}
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);
}
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;
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]
duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_ScriptContainer_Master)); // [container][buffer]
master = (ILibDuktape_ScriptContainer_Master*)Duktape_GetBuffer(ctx, -1, NULL);
duk_put_prop_string(ctx, -2, ILibDuktape_ScriptContainer_MasterPtr); // [container]
memset(master, 0, sizeof(ILibDuktape_ScriptContainer_Master));
master->ctx = ctx;
master->emitter = ILibDuktape_EventEmitter_Create(ctx);
master->chain = Duktape_GetChain(ctx);
ILibDuktape_EventEmitter_CreateEvent(master->emitter, "exit", &(master->OnExit));
ILibDuktape_EventEmitter_CreateEvent(master->emitter, "error", &(master->OnError));
ILibDuktape_EventEmitter_CreateEvent(master->emitter, "data", &(master->OnJSON));
ILibDuktape_CreateProperty_InstanceMethod(ctx, "exit", ILibDuktape_ScriptContainer_Exit, 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);
unsigned int executionTimeout = (unsigned int)duk_require_int(ctx, 0);
unsigned int securityFlags = (unsigned int)duk_require_int(ctx, 1) | SCRIPT_ENGINE_NO_MESH_AGENT_ACCESS;
master->child = ILibProcessPipe_Manager_SpawnProcessEx2(manager, exePath, (char * const*)param, spawnType, 2 * sizeof(void*));
if (master->child == NULL) { return(ILibDuktape_Error(ctx, "ScriptContainer.Create(): Error spawning child process, using [%s]", exePath)); }
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)securityFlags);
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] = 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);
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);
slave->emitter = ILibDuktape_EventEmitter_Create(ctx);
ILibDuktape_EventEmitter_CreateEvent(slave->emitter, "data", &(slave->OnData));
ILibDuktape_CreateInstanceMethod(ctx, "send", ILibDuktape_ScriptContainer_Slave_SendToMaster, 1);
}
#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