diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index 9a3b015..5584901 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -95,6 +95,8 @@ char exeMeshPolicyGuid[] = { 0xB9, 0x96, 0x01, 0x58, 0x80, 0x54, 0x4A, 0x19, 0xB #define DEFAULT_IDLE_TIMEOUT 120 #define MESH_USER_CHANGED_CB "\xFF_MeshAgent_UserChangedCallback" #define REMOTE_DESKTOP_UID "\xFF_RemoteDesktopUID" +#define MESHAGENT_DATAPING_ARRAY "\xFF_MeshAgent_DataPingArray" +#define MESHAGENT_DATAPAING_PROMISE_TIMEOUT "\xFF_MeshAgent_DataPing_Timeout" #define KVM_IPC_SOCKET "\xFF_KVM_IPC_SOCKET" int ILibDuktape_HECI_Debug = 0; @@ -361,6 +363,7 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject wcdo, MeshAgentHostCont char ContainerContextGUID[sizeof(JS_ENGINE_CONTEXT) + 1]; void MeshServer_ConnectEx(MeshAgentHostContainer *agent); int agent_VerifyMeshCertificates(MeshAgentHostContainer *agent); +void MeshServer_SendJSON(MeshAgentHostContainer* agent, ILibWebClient_StateObject WebStateObject, char *JSON, int JSONLength); #if defined(_LINKVM) && defined(_POSIX) && !defined(__APPLE__) extern void ILibProcessPipe_FreePipe(ILibProcessPipe_Pipe pipeObject); @@ -1670,6 +1673,13 @@ duk_ret_t ILibDuktape_MeshAgent_getIdleTimeout(duk_context *ctx) duk_push_int(ctx, agent->controlChannel_idleTimeout_seconds); return(1); } +duk_ret_t ILibDuktape_MeshAgent_getIdleTimeout_isDataMode(duk_context *ctx) +{ + duk_push_this(ctx); // [MeshAgent] + MeshAgentHostContainer *agent = (MeshAgentHostContainer*)Duktape_GetPointerProperty(ctx, -1, MESH_AGENT_PTR); + duk_push_boolean(ctx, agent->controlChannel_idleTimeout_dataMode); + return(1); +} duk_ret_t ILibDuktape_MeshAgent_getStartupOptions(duk_context *ctx) { @@ -1712,6 +1722,60 @@ duk_ret_t ILibDuktape_KVM_Refresh(duk_context *ctx) return(0); } #endif +duk_ret_t ILibDuktape_MeshAgent_log(duk_context *ctx) +{ + char *msg = (char*)duk_require_string(ctx, 0); + ILIBLOGMESSAGEX("meshcore: %s", msg); + return(0); +} +duk_ret_t ILibDuktape_MeshAgent_controlChannelDebug(duk_context *ctx) +{ + duk_push_this(ctx); + MeshAgentHostContainer *agent = (MeshAgentHostContainer*)Duktape_GetPointerProperty(ctx, -1, MESH_AGENT_PTR); + duk_push_boolean(ctx, agent->controlChannelDebug != 0); + return(1); +} +duk_ret_t ILibDuktape_MeshAgent_DataPing_Timeout(duk_context *ctx) +{ + duk_prepare_method_call(ctx, 0, "_rej"); // [_rej][this] + duk_call_method(ctx, 0); + return(0); +} +duk_ret_t ILibDuktape_MeshAgent_DataPing(duk_context *ctx) +{ + int nargs = duk_get_top(ctx); + int timeout = 0; + if (nargs > 0) { timeout = duk_require_int(ctx, 0); } + + duk_push_this(ctx); // [agent] + duk_get_prop_string(ctx, -1, MESHAGENT_DATAPING_ARRAY); // [agent][pingarray] + + MeshAgentHostContainer *agent = (MeshAgentHostContainer*)Duktape_GetPointerProperty(ctx, -2, MESH_AGENT_PTR); + duk_eval_string(ctx, "(function foo(){var p=require('promise');return(new p(function(res, rej) { this._res = res; this._rej = rej; }));})()"); + duk_dup(ctx, -1); // [agent][pingarray][promise][promise] + duk_array_push(ctx, -3); // [agent][pingarray][promise] + + if (timeout > 0) + { + duk_push_global_object(ctx); // [agent][pingarray][promise][g] + duk_prepare_method_call(ctx, -1, "setTimeout"); // [agent][pingarray][promise][g][setTimeout][this] + duk_push_c_function(ctx, ILibDuktape_MeshAgent_DataPing_Timeout, DUK_VARARGS);//omise][g][setTimeout][this][func] + duk_push_int(ctx, timeout); // [agent][pingarray][promise][g][setTimeout][this][func][timeout] + duk_dup(ctx, -6); // [agent][pingarray][promise][g][setTimeout][this][func][timeout][promise] + if (duk_pcall_method(ctx, 3) == 0) // [agent][pingarray][promise][g][timeout] + { + duk_put_prop_string(ctx, -3, MESHAGENT_DATAPAING_PROMISE_TIMEOUT); + } + else + { + duk_pop(ctx); // [agent][pingarray][promise][g] + } + duk_pop(ctx); // [agent][pingarray][promise] + } + + MeshServer_SendJSON(agent, agent->controlChannel, "{\"action\":\"ping\"}", 17); + return(1); +} void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) { MeshAgentHostContainer *agent; @@ -1763,7 +1827,7 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) duk_put_prop_string(ctx, -2, ILibDuktape_MeshAgent_Cert_NonLeaf); ILibDuktape_CreateInstanceMethod(ctx, "GenerateAgentCertificate", ILibDuktape_MeshAgent_GenerateCertsForDiagnosticAgent, 1); #endif - + duk_push_array(ctx); duk_put_prop_string(ctx, -2, MESHAGENT_DATAPING_ARRAY); ILibDuktape_EventEmitter_CreateEventEx(emitter, "Ready"); ILibDuktape_EventEmitter_CreateEventEx(emitter, "Connected"); ILibDuktape_EventEmitter_CreateEventEx(emitter, "Command"); @@ -1789,6 +1853,9 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) ILibDuktape_CreateInstanceMethod(ctx, "getStartupOptions", ILibDuktape_MeshAgent_getStartupOptions, 0); ILibDuktape_CreateEventWithGetter(ctx, "coreHash", ILibDuktape_MeshAgent_coreHash); ILibDuktape_CreateEventWithGetter(ctx, "updatesEnabled", ILibDuktape_MeshAgent_updatesEnabled); + ILibDuktape_CreateInstanceMethod(ctx, "log", ILibDuktape_MeshAgent_log, 1); + ILibDuktape_CreateEventWithGetter(ctx, "controlChannelDebug", ILibDuktape_MeshAgent_controlChannelDebug); + ILibDuktape_CreateInstanceMethod(ctx, "DataPing", ILibDuktape_MeshAgent_DataPing, DUK_VARARGS); #ifdef _LINKVM ILibDuktape_CreateReadonlyProperty_int(ctx, "hasKVM", 1); ILibDuktape_EventEmitter_CreateEventEx(emitter, "kvmConnected"); @@ -1813,6 +1880,8 @@ void ILibDuktape_MeshAgent_PUSH(duk_context *ctx, void *chain) ILibDuktape_CreateEventWithGetter(ctx, "NetInfo", ILibDuktape_MeshAgent_NetInfo); ILibDuktape_CreateEventWithGetter(ctx, "idleTimeout", ILibDuktape_MeshAgent_getIdleTimeout); + ILibDuktape_CreateEventWithGetter(ctx, "idleTimeoutDataMode", ILibDuktape_MeshAgent_getIdleTimeout_isDataMode); + ILibDuktape_EventEmitter_CreateEventEx(emitter, "idleTimeoutModeChanged"); ILibDuktape_CreateInstanceMethod(ctx, "ExecPowerState", ILibDuktape_MeshAgent_ExecPowerState, DUK_VARARGS); ILibDuktape_CreateInstanceMethod(ctx, "eval", ILibDuktape_MeshAgent_eval, 1); ILibDuktape_CreateInstanceMethod(ctx, "forceExit", ILibDuktape_MeshAgent_forceExit, DUK_VARARGS); @@ -2819,6 +2888,43 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge duk_pop(agent->meshCoreCtx); // [emit][this][Command] duk_push_lstring(agent->meshCoreCtx, cmd, cmdLen); // [emit][this][Command][str] } + else + { + // JSON command... Let's check if it's a PING + if (duk_has_prop_string(agent->meshCoreCtx, -1, "action")) + { + char *action = (char*)Duktape_GetStringPropertyValue(agent->meshCoreCtx, -1, "action", ""); + if (strcmp(action, "ping") == 0) + { + if (agent->controlChannel_idleTimeout_dataMode == 0) + { + ILibDuktape_MeshAgent_PUSH(agent->meshCoreCtx, agent->chain); // [agent] + ILibDuktape_EventEmitter_SetupEmitEx(agent->meshCoreCtx, -1, "idleTimeoutModeChanged"); // [agent][emit][this][idleTimeoutModeChanged] + duk_pcall_method(agent->meshCoreCtx, 1); duk_pop_2(agent->meshCoreCtx); // ... + } + agent->controlChannel_idleTimeout_dataMode = 1; + } + else if (strcmp(action, "pong") == 0) + { + ILibDuktape_MeshAgent_PUSH(agent->meshCoreCtx, agent->chain); // [agent] + duk_get_prop_string(agent->meshCoreCtx, -1, MESHAGENT_DATAPING_ARRAY); // [agent][pingarray] + if (duk_get_length(agent->meshCoreCtx, -1) > 0) + { + duk_array_shift(agent->meshCoreCtx, -1); // [agent][pingarray][promise] + if (duk_has_prop_string(agent->meshCoreCtx, -1, MESHAGENT_DATAPAING_PROMISE_TIMEOUT)) + { + duk_push_global_object(agent->meshCoreCtx); // [agent][pingarray][promise][g] + duk_prepare_method_call(agent->meshCoreCtx, -1, "clearTimeout"); // [agent][pingarray][promise][g][clearTimeout][this] + duk_get_prop_string(agent->meshCoreCtx, -4, MESHAGENT_DATAPAING_PROMISE_TIMEOUT); // [agent][pingarray][promise][g][clearTimeout][this][timeout] + duk_pcall_method(agent->meshCoreCtx, 1); duk_pop_2(agent->meshCoreCtx); // [agent][pingarray][promise] + } + duk_prepare_method_call(agent->meshCoreCtx, -1, "_res"); // [agent][pingarray][promise][_res][this] + duk_pcall_method(agent->meshCoreCtx, 0); duk_pop_2(agent->meshCoreCtx); // [agent][pingarray] + } + duk_pop_2(agent->meshCoreCtx); // ... + } + } + } popCount = 1; } else @@ -3354,6 +3460,26 @@ void MeshServer_OnResponse(ILibWebClient_StateObject WebStateObject, int Interru duk_push_int(agent->meshCoreCtx, 0); // [emit][this][Connected][0] (0 means disconnected) if (duk_pcall_method(agent->meshCoreCtx, 2) != 0) { ILibDuktape_Process_UncaughtException(agent->meshCoreCtx); } duk_pop(agent->meshCoreCtx); + + duk_eval_string(agent->meshCoreCtx, "require('https').globalAgent.sockets;"); // [table] + duk_eval_string(agent->meshCoreCtx, "require('http').globalAgent.getName(require('http').parseUri(require('MeshAgent').ServerUrl));"); // [table][key] + if (duk_has_prop_string(agent->meshCoreCtx, -2, duk_get_string(agent->meshCoreCtx, -1)) != 0) + { + duk_get_prop(agent->meshCoreCtx, -2); // [table][array] + while (duk_get_length(agent->meshCoreCtx, -1) > 0) + { + duk_array_pop(agent->meshCoreCtx, -1); // [table][array][socket] + duk_prepare_method_call(agent->meshCoreCtx, -1, "end"); // [table][array][socket][end][this] + duk_pcall_method(agent->meshCoreCtx, 0); // [table][array][socket][undef] + duk_pop_2(agent->meshCoreCtx); // [table][array] + } + duk_pop(agent->meshCoreCtx); // [table] + } + else + { + duk_pop(agent->meshCoreCtx); // [table] + } + duk_pop(agent->meshCoreCtx); // ... } } agent->serverAuthState = 0; diff --git a/meshcore/agentcore.h b/meshcore/agentcore.h index f4bd5df..0e841e5 100644 --- a/meshcore/agentcore.h +++ b/meshcore/agentcore.h @@ -225,6 +225,7 @@ typedef struct MeshAgentHostContainer int serverAuthState; int controlChannel_idleTimeout_seconds; + int controlChannel_idleTimeout_dataMode; char g_selfid[UTIL_SHA384_HASHSIZE]; void* microLMS; void* multicastDiscovery; diff --git a/microscript/ILibDuktape_HttpStream.c b/microscript/ILibDuktape_HttpStream.c index abcb2e4..5d2e61e 100644 --- a/microscript/ILibDuktape_HttpStream.c +++ b/microscript/ILibDuktape_HttpStream.c @@ -1053,6 +1053,22 @@ duk_ret_t ILibDuktape_HttpStream_http_OnConnect(duk_context *ctx) else { duk_get_prop_string(ctx, -1, ILibDuktape_Socket2Agent); // [socket][agent] + duk_get_prop_string(ctx, -1, "http"); // [socket][agent][http] + duk_get_prop_string(ctx, -1, "globalAgent"); // [socket][agent][http][globalAgent] + if (duk_get_heapptr(ctx, -1) != duk_get_heapptr(ctx, -3)) + { + // This agent is not a global agent, so lets stick the socket in the sockets list + char *key = (char*)Duktape_GetStringPropertyValue(ctx, -4, ILibDuktape_Socket2AgentKey, NULL); + duk_get_prop_string(ctx, -1, "sockets"); // [socket][agent][http][globalAgent][table] + if (!duk_has_prop_string(ctx, -1, key)) { duk_push_array(ctx); duk_put_prop_string(ctx, -2, key); } + duk_get_prop_string(ctx, -1, key); // [socket][agent][http][globalAgent][table][array] + duk_dup(ctx, -6); // [socket][agent][http][globalAgent][table][array][socket] + duk_array_push(ctx, -2); // [socket][agent][http][globalAgent][table][array] + duk_pop_2(ctx); // [socket][agent][http][globalAgent] + } + duk_pop_2(ctx); // [socket][agent] + + duk_get_prop_string(ctx, -1, "keepSocketAlive"); // [socket][agent][keepSocketAlive] duk_swap_top(ctx, -2); // [socket][keepSocketAlive][this] duk_dup(ctx, -3); // [socket][keepSocketAlive][this][socket] @@ -1327,15 +1343,30 @@ duk_ret_t ILibDuktape_HttpStream_http_request(duk_context *ctx) { if (duk_get_boolean(ctx, -1) == 0) { - duk_pop(ctx); // [clientRequest] - duk_eval_string(ctx, "require('http').Agent();"); // [clientRequest][tempAgent] + duk_pop(ctx); // [clientRequest] + if (isTLS == 0) + { + duk_eval_string(ctx, "require('http').Agent();"); // [clientRequest][tempAgent] + } + else + { + duk_eval_string(ctx, "require('https').Agent();"); // [clientRequest][tempAgent] + } agent = duk_get_heapptr(ctx, -1); duk_put_prop_string(ctx, -2, ILibDuktape_CR2Agent); // [clientRequest] } else { duk_pop(ctx); // [clientRequest] - duk_push_this(ctx); // [clientRequest][http] + + if (isTLS == 0) + { + duk_eval_string(ctx, "require('http')"); // [clientRequest][http] + } + else + { + duk_eval_string(ctx, "require('https')"); // [clientRequest][http] + } duk_get_prop_string(ctx, -1, "globalAgent"); // [clientRequest][http][agent] agent = duk_get_heapptr(ctx, -1); duk_remove(ctx, -2); // [clientRequest][agent] @@ -3453,6 +3484,7 @@ void ILibDuktape_RemoveObjFromTable(duk_context *ctx, duk_idx_t tableIdx, char * duk_ret_t ILibDuktape_HttpStream_Agent_socketEndSink(duk_context *ctx) { duk_push_this(ctx); // [socket] + //printf("socket has closed: %p\n", duk_get_heapptr(ctx, -1)); duk_get_prop_string(ctx, -1, ILibDuktape_Socket2Agent); // [socket][agent] duk_get_prop_string(ctx, -2, ILibDuktape_Socket2AgentKey); // [socket][agent][key] @@ -3469,6 +3501,14 @@ duk_ret_t ILibDuktape_HttpStream_Agent_socketEndSink(duk_context *ctx) ILibDuktape_RemoveObjFromTable(ctx, -1, key, duk_get_heapptr(ctx, 0)); duk_pop(ctx); // [socket][agent] + duk_eval_string(ctx, "require('http').globalAgent.sockets;"); // [socket][agent][table] + ILibDuktape_RemoveObjFromTable(ctx, -1, key, duk_get_heapptr(ctx, 0)); + duk_pop(ctx); // [socket][agent] + + duk_eval_string(ctx, "require('https').globalAgent.sockets;"); // [socket][agent][table] + ILibDuktape_RemoveObjFromTable(ctx, -1, key, duk_get_heapptr(ctx, 0)); + duk_pop(ctx); // [socket][agent] + // Now that we cleared this socket out of all the tables, we need to check to see if we need to create a new connection duk_get_prop_string(ctx, -1, "requests"); // [socket][agent][requestTable] if (duk_has_prop_string(ctx, -1, key)) @@ -3639,6 +3679,7 @@ duk_ret_t ILibDuktape_HttpStream_Agent_reuseSocket(duk_context *ctx) } duk_ret_t ILibDuktape_HttpStream_Agent_createConnection_eventSink(duk_context *ctx) { + // Error Sink duk_push_this(ctx); // [socket] char *key = Duktape_GetStringPropertyValue(ctx, -1, ILibDuktape_Socket2AgentKey, ""); duk_get_prop_string(ctx, -1, ILibDuktape_Socket2Agent); // [socket][agent] @@ -3708,6 +3749,8 @@ duk_ret_t ILibDuktape_HttpStream_Agent_new(duk_context *ctx) int maxFreeSockets = Duktape_GetIntPropertyValue(ctx, -1, "maxFreeSockets", 32); duk_push_object(ctx); // [Agent] + duk_push_this(ctx); // [Agent][http] + ILibDuktape_CreateReadonlyProperty(ctx, "http"); ILibDuktape_WriteID(ctx, "http.Agent"); duk_push_boolean(ctx, (duk_bool_t)keepAlive); // [Agent][keepAlive] duk_put_prop_string(ctx, -2, "keepAlive"); // [Agent]