diff --git a/Debug/AMT.js b/Debug/AMT.js new file mode 100644 index 0000000..e1b3027 --- /dev/null +++ b/Debug/AMT.js @@ -0,0 +1,205 @@ +var http = require('http'); +var digest = require('http-digest').create("admin", "P@ssw0rd"); +console.log("Starting AMT Test"); + + +digest.http = require('http'); + + + +//console.log("First Test: HTTP/GET on '/'"); +//var req = digest.request({ protocol: "http:", method: "GET", host: "172.16.2.249", path: "/", port: 16992 }, OnGet1); +//req.end(); + +//console.log('First Test: POST /wsman'); +//WSManTest(); + +console.log('First Test: POST /wsman, [immediate]'); +WSManTest_Immediate(); + +function OnGet1(imsg) +{ + if(imsg.statusCode == 303) + { + console.log("...SUCCESS!"); + console.log("Next Test: Redirect to '" + imsg.header['Location'] + "'"); + req = digest.request({ protocol: "http:", method: "GET", host: "172.16.2.249", path: imsg.header['Location'], port: 16992 }, OnGet2); + req.end(); + } + else + { + console.log("...FAILED!"); + } +} + +function OnGet2(imsg) +{ + if (imsg.statusCode == 200) + { + console.log("...SUCCESS!"); + console.log("...Reading body of message"); + imsg.on('end', function () + { + console.log("...Finished"); + console.log("Next Test: '/index.htm'"); + req = digest.request({ protocol: "http:", method: "GET", host: "172.16.2.249", path: "/index.htm", port: 16992 }, OnGet3); + req.end(); + }); + } + else + { + console.log("...FAILED, status code was: " + imsg.statusCode); + } +} +function OnGet3(imsg) +{ + if (imsg.statusCode == 200) + { + console.log("...SUCCESS!"); + console.log("Next Test: 'POST /wsman'"); + WSManTest(); + } +} + +function WSManTest() +{ + req = digest.request({ protocol: "http:", method: "POST", host: "172.16.2.249", path: "/wsman", port: 16992, headers: { Expect: '100-Continue' }, timeout: 2000 }); + req.on('continue', WSManTest_Continue); + req.on('timeout', WSManTest_Timeout); + req.on('response', WSManTest_Response); +} + +function WSManTest_Immediate() +{ + req = digest.request({ protocol: "http:", method: "POST", host: "172.16.2.249", path: "/wsman", port: 16992 }); + req.on('response', WSManTest_Response); + + var xml = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48RW52ZWxvcGUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM6eHNkPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6YT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNC8wOC9hZGRyZXNzaW5nIiB4bWxuczp3PSJodHRwOi8vc2NoZW1hcy5kbXRmLm9yZy93YmVtL3dzbWFuLzEvd3NtYW4ueHNkIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMy8wNS9zb2FwLWVudmVsb3BlIiA+PEhlYWRlcj48YTpBY3Rpb24+aHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNC8wOS90cmFuc2Zlci9HZXQ8L2E6QWN0aW9uPjxhOlRvPi93c21hbjwvYTpUbz48dzpSZXNvdXJjZVVSST5odHRwOi8vc2NoZW1hcy5kbXRmLm9yZy93YmVtL3dzY2ltLzEvY2ltLXNjaGVtYS8yL0NJTV9Db21wdXRlclN5c3RlbVBhY2thZ2U8L3c6UmVzb3VyY2VVUkk+PGE6TWVzc2FnZUlEPjQ8L2E6TWVzc2FnZUlEPjxhOlJlcGx5VG8+PGE6QWRkcmVzcz5odHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA0LzA4L2FkZHJlc3Npbmcvcm9sZS9hbm9ueW1vdXM8L2E6QWRkcmVzcz48L2E6UmVwbHlUbz48dzpPcGVyYXRpb25UaW1lb3V0PlBUNjBTPC93Ok9wZXJhdGlvblRpbWVvdXQ+PC9IZWFkZXI+PEJvZHkgLz48L0VudmVsb3BlPg=='; + var b = Buffer.from(xml, 'base64'); + req.write(b); + req.end(); +} + +function WSManTest_Continue() +{ + console.log("Got Continue!"); +} +function WSManTest_Timeout() +{ + console.log("Timeout waiting for 100 Continue... Sending body anyways..."); + var xml = 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48RW52ZWxvcGUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeG1sbnM6eHNkPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6YT0iaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNC8wOC9hZGRyZXNzaW5nIiB4bWxuczp3PSJodHRwOi8vc2NoZW1hcy5kbXRmLm9yZy93YmVtL3dzbWFuLzEvd3NtYW4ueHNkIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMy8wNS9zb2FwLWVudmVsb3BlIiA+PEhlYWRlcj48YTpBY3Rpb24+aHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNC8wOS90cmFuc2Zlci9HZXQ8L2E6QWN0aW9uPjxhOlRvPi93c21hbjwvYTpUbz48dzpSZXNvdXJjZVVSST5odHRwOi8vc2NoZW1hcy5kbXRmLm9yZy93YmVtL3dzY2ltLzEvY2ltLXNjaGVtYS8yL0NJTV9Db21wdXRlclN5c3RlbVBhY2thZ2U8L3c6UmVzb3VyY2VVUkk+PGE6TWVzc2FnZUlEPjQ8L2E6TWVzc2FnZUlEPjxhOlJlcGx5VG8+PGE6QWRkcmVzcz5odHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA0LzA4L2FkZHJlc3Npbmcvcm9sZS9hbm9ueW1vdXM8L2E6QWRkcmVzcz48L2E6UmVwbHlUbz48dzpPcGVyYXRpb25UaW1lb3V0PlBUNjBTPC93Ok9wZXJhdGlvblRpbWVvdXQ+PC9IZWFkZXI+PEJvZHkgLz48L0VudmVsb3BlPg=='; + var b = Buffer.from(xml, 'base64'); + this.write(b); + this.end(); +} +function WSManTest_Response(imsg) +{ + imsg.on('data', function (chunk) { console.log(chunk); }); +} + + +//var req = digest.request({ protocol: "ws:", method: "GET", host: "127.0.0.1", path: "/", port: 9093 }, function (imsg) { console.log(imsg.statusCode == 200 ? "SUCCESS!" : "FAIL!"); }); +//var req = http.request({ protocol: "http:", method: "POST", host: "127.0.0.1", path: "/", port: 9093, headers: { Expect: '100-Continue' } }, function (imsg) { console.log(imsg.statusCode == 200 ? "SUCCESS!" : "FAIL!"); }); +//var req = digest.request({ protocol: "http:", method: "POST", host: "127.0.0.1", path: "/", port: 9093, headers: { Expect: '100-Continue' } }, function (imsg) { console.log(imsg.statusCode == 200 ? "SUCCESS!" : "FAIL!"); }); + +//req.on('upgrade', function (res, sk, h) { console.log("Upgraded to WebSocket!"); }); +//req.on('error', function () { console.log("Error occured"); }); +//req.on('continue', function () { console.log("Received Continue"); this.write("test"); this.end(); }); + +//function OnCheckContinue(imsg, resp) +//{ +// console.log("Recevied: Expect-100 Continue"); +// if (imsg.Digest_IsAuthenticated('www.meshcentral.com') == 1) +// { +// var uname = imsg.Digest_GetUsername(); +// console.log("Digest Username was: " + uname); +// if (uname == 'bryan' && imsg.Digest_ValidatePassword('roe') == 1) +// { +// console.log("Validated"); +// imsg.on('data', function (chunk) { console.log('Received: ' + chunk.toString()); }); +// imsg.on('end', function () { console.log('Received Complete'); }); +// resp.writeContinue(); +// } +// else +// { +// console.log("Bad Username/Password"); +// resp.statusCode = "500"; +// resp.statusMessage = "Error"; +// resp.end(); +// } +// } +// else +// { +// console.log("Sending Unauthorized"); +// imsg.Digest_SendUnauthorized('www.meshcentral.com', 'oops'); +// } +//} +//function OnCheckContinue_NoDigest(imsg, resp) +//{ +// console.log("Recevied: Expect-100 Continue"); + +// imsg.on('data', function (chunk) { console.log('Received: ' + chunk.toString()); }); +// imsg.on('end', function () { console.log('Received Complete'); }); +// resp.writeContinue(); +//} +//function OnServerUpgrade(imsg, sck, head) +//{ +// if(imsg.Digest_IsAuthenticated('www.meshcentral.com')==1) +// { +// var uname = imsg.Digest_GetUsername(); +// console.log("Digest Username was: " + uname); +// if(uname == 'bryan' && imsg.Digest_ValidatePassword('roe')==1) +// { +// console.log("Upgrading to WebSocket"); +// sck.upgradeWebSocket(); +// } +// else +// { +// console.log("Bad Username/Password"); +// sck.end(); +// } +// } +// else +// { +// console.log("Sending Unauthorized"); +// imsg.Digest_SendUnauthorized('www.meshcentral.com', 'oops'); +// } +//} + + +//function onVerifyServer(clientName, certs) { +// console.log("Server Name = " + clientName + "\n"); + +// for (var i = 0; i < certs.length; ++i) { +// console.log(" Fingerprint = " + certs[i].fingerprint + "\n"); +// } +// //throw ("Not Valid"); +//} +//function onVerifyClient(clientName, certs) +//{ +// console.log("Client Name = " + clientName + "\n"); + +// for (var i = 0; i < certs.length; ++i) { +// console.log(" Fingerprint = " + certs[i].fingerprint + "\n"); +// } +// //throw ("Not Valid"); +//} +//function onVerify(serverName, certs) +//{ +// console.log("ServerName = " + serverName + "\n"); + +// for (var i = 0; i < certs.length;++i) +// { +// console.log(" Fingerprint = " + certs[i].fingerprint + "\n"); +// } +// //throw ("Not Valid"); +//} + +//function OnRequest(req, res) +//{ +// console.log("Received Request for: " + req.url); + +//} + + + diff --git a/Debug/ChildProcessTest.js b/Debug/ChildProcessTest.js new file mode 100644 index 0000000..81cf49e --- /dev/null +++ b/Debug/ChildProcessTest.js @@ -0,0 +1,27 @@ +var child = require('child_process'); +var childProcess = null; + +if (process.platform == 'win32') +{ + childProcess = child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'dir'], OnChild); +} +else if (process.platform == 'linux') +{ + childProcess = child.execFile('/bin/sh', ['sh', '-c', 'ls'], OnChild); +} + +if (childProcess != null) +{ + console.log('PID = ' + childProcess.pid); + childProcess.stdout.on('data', function (chunk) { console.log(chunk.toString()); }); + childProcess.on('exit', function (code, sig) { console.log("Process Exited with code: " + code.toString()); }); +} +//for (var envkey in process.env) +//{ +// console.log("Environment Variable: [" + envkey + "] = " + process.env[envkey]); +//} + +function OnChild(err, stdErr, stdOut) +{ + +} \ No newline at end of file diff --git a/Debug/PostDigest.js b/Debug/PostDigest.js index bd50123..b577167 100644 --- a/Debug/PostDigest.js +++ b/Debug/PostDigest.js @@ -4,11 +4,15 @@ var req = ""; var gtunnel = ""; var digest = require('http-digest').create("bryan", "roe"); +console.log("Process.execPath = " + process.execPath); console.log("Starting POST Digest Test"); server = http.createServer(OnRequest); server.listen(9093); + +console.log("Server Address", server._address()); + server.on('upgrade', OnServerUpgrade); server.on('checkContinue', OnCheckContinue); //server.on('checkContinue', OnCheckContinue_NoDigest); diff --git a/makefile b/makefile index c260e8f..f772324 100644 --- a/makefile +++ b/makefile @@ -39,6 +39,7 @@ SOURCES += microscript/ILibWebServer_Duktape.c microscript/ILibDuktape_SimpleDat SOURCES += microscript/ILibDuktape_ProcessPipe.c microscript/ILibDuktape_fs.c microscript/ILibDuktape_SHA256.c microscript/ILibduktape_EventEmitter.c SOURCES += microscript/ILibDuktape_EncryptionStream.c microscript/ILibDuktape_Polyfills.c microscript/ILibDuktape_Dgram.c SOURCES += microscript/ILibDuktape_ScriptContainer.c microscript/ILibDuktape_MemoryStream.c microscript/ILibDuktape_NetworkMonitor.c +SOURCES += microscript/ILibDuktape_ChildProcess.c # Mesh Agent core SOURCES += meshcore/agentcore.c meshconsole/main.c meshcore/meshinfo.c diff --git a/meshconsole/MeshConsole.vcxproj b/meshconsole/MeshConsole.vcxproj index bf81d22..11da617 100644 --- a/meshconsole/MeshConsole.vcxproj +++ b/meshconsole/MeshConsole.vcxproj @@ -31,6 +31,7 @@ + @@ -91,6 +92,7 @@ + diff --git a/meshconsole/MeshConsole.vcxproj.filters b/meshconsole/MeshConsole.vcxproj.filters index cfd2e02..3bafde8 100644 --- a/meshconsole/MeshConsole.vcxproj.filters +++ b/meshconsole/MeshConsole.vcxproj.filters @@ -187,6 +187,9 @@ Microscript + + Microscript + @@ -337,6 +340,9 @@ Microscript + + Microscript + diff --git a/meshconsole/main.c b/meshconsole/main.c index c074852..abd90c7 100644 --- a/meshconsole/main.c +++ b/meshconsole/main.c @@ -29,6 +29,8 @@ limitations under the License. #include #endif +#include "microscript/ILibDuktape_ScriptContainer.h" + MeshAgentHostContainer *agentHost = NULL; #ifdef WIN32 @@ -64,45 +66,12 @@ void BreakSink(int s) int main(int argc, char **argv) { // Check if .JS file is integrated with executable - FILE *tmpFile; char *integratedJavaScript = NULL; int integratedJavaScriptLen = 0; -#ifdef WIN32 - if (ILibString_EndsWith(argv[0], -1, ".exe", 4) == 0) - { - sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "%s.exe", argv[0]); - tmpFile = fopen(ILibScratchPad, "rb"); - } - else - { - tmpFile = fopen(argv[0], "rb"); - } -#else - tmpFile = fopen(argv[0], "rb"); -#endif - - if (tmpFile != NULL) - { - fseek(tmpFile, 0, SEEK_END); - fseek(tmpFile, ftell(tmpFile) - 4, SEEK_SET); - ignore_result(fread(ILibScratchPad, 1, 4, tmpFile)); - fseek(tmpFile, 0, SEEK_END); - if (ftell(tmpFile) == ntohl(((int*)ILibScratchPad)[0])) - { - fseek(tmpFile, ftell(tmpFile) - 8, SEEK_SET); - ignore_result(fread(ILibScratchPad, 1, 4, tmpFile)); - integratedJavaScriptLen = ntohl(((int*)ILibScratchPad)[0]); - integratedJavaScript = ILibMemory_Allocate(1+integratedJavaScriptLen, 0, NULL, NULL); - fseek(tmpFile, 0, SEEK_END); - fseek(tmpFile, ftell(tmpFile) - 8 - integratedJavaScriptLen, SEEK_SET); - ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile)); - integratedJavaScript[integratedJavaScriptLen] = 0; - } - fclose(tmpFile); - } - int retCode = 0; + ILibDuktape_ScriptContainer_CheckEmbedded(argv, &integratedJavaScript, &integratedJavaScriptLen); + if (argc > 2 && memcmp(argv[1], "-faddr", 6) == 0) { uint64_t addrOffset; diff --git a/meshcore/agentcore.c b/meshcore/agentcore.c index da62b8b..a2540c3 100644 --- a/meshcore/agentcore.c +++ b/meshcore/agentcore.c @@ -111,6 +111,11 @@ typedef struct ScriptContainerSettings }ScriptContainerSettings; #pragma pack(push, 1) +typedef struct MeshCommand_BinaryPacket_ServerId +{ + unsigned short command; + char serverId[UTIL_HASHSIZE]; +}MeshCommand_BinaryPacket_ServerId; typedef struct MeshCommand_BinaryPacket_AuthRequest { unsigned short command; @@ -1087,12 +1092,10 @@ int agent_GenerateCertificates(MeshAgentHostContainer *agent, char* certfile) { // Generate a new random node certificate ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Agent_GuardPost, ILibRemoteLogging_Flags_VerbosityLevel_1, "...Generating new Node Certificate"); - do { if (util_mkCert(NULL, &(agent->selfcert), 3072, 10000, "MeshNodeCertificate", CERTIFICATE_ROOT, NULL) == 0) return -1; util_keyhash(agent->selfcert, agent->g_selfid); - } while (((int*)agent->g_selfid)[0] == 0); // This removes any chance that the self_id starts with 32 bits of zeros. ILibRemoteLogging_printf(ILibChainGetLogger(agent->chain), ILibRemoteLogging_Modules_Agent_GuardPost, ILibRemoteLogging_Flags_VerbosityLevel_1, "...g_selfid = %s", ILibRemoteLogging_ConvertToHex(agent->g_selfid, (int)sizeof(agent->g_selfid))); } @@ -1361,7 +1364,6 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge // Hash the server's web certificate and check if it matches the one in the auth request util_keyhash2(peer, ILibScratchPad2); // Hash the server certificate public key and place it - if (memcmp(ILibScratchPad2, AuthRequest->serverHash, sizeof(AuthRequest->serverHash)) != 0) { printf("Bad server certificate hash\r\n"); break; } // TODO: Disconnect memcpy_s(agent->serverNonce, sizeof(agent->serverNonce), AuthRequest->serverNonce, sizeof(AuthRequest->serverNonce)); @@ -1418,8 +1420,13 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge if (!d2i_X509(&serverCert, (const unsigned char**)&AuthVerify->cert, AuthVerify->certLen)) { printf("Invalid server certificate\r\n"); break; } // TODO: Disconnect // Check if this certificate public key hash matches what we want - X509_pubkey_digest(serverCert, EVP_sha384(), (unsigned char*)ILibScratchPad, (unsigned int*)&hashlen); // OpenSSL 1.1 - if (memcmp(ILibScratchPad, agent->serverHash, UTIL_HASHSIZE) != 0) { printf("Server certificate mismatch\r\n"); break; } // TODO: Disconnect + X509_pubkey_digest(serverCert, EVP_sha384(), (unsigned char*)ILibScratchPad, (unsigned int*)&hashlen); // OpenSSL 1.1, SHA384 + if (memcmp(ILibScratchPad, agent->serverHash, UTIL_HASHSIZE) != 0) { + X509_pubkey_digest(serverCert, EVP_sha256(), (unsigned char*)ILibScratchPad, (unsigned int*)&hashlen); // OpenSSL 1.1, SHA256 (For older .mshx policy file) + if (memcmp(ILibScratchPad, agent->serverHash, 32) != 0) { + printf("Server certificate mismatch\r\n"); break; // TODO: Disconnect + } + } // Compute the authentication hash SHA384_Init(&c); @@ -1440,6 +1447,7 @@ void MeshServer_ProcessCommand(ILibWebClient_StateObject WebStateObject, MeshAge // Send to the server information about this agent (TODO: Replace this with a struct) MeshCommand_BinaryPacket_AuthInfo *info = (MeshCommand_BinaryPacket_AuthInfo*)ILibScratchPad2; + memset(info, 0, sizeof(MeshCommand_BinaryPacket_AuthInfo)); // Required because if hash are SHA256, they will not fully fill the struct. info->command = htons(MeshCommand_AuthInfo); info->infoVersion = htonl(1); info->agentId = htonl(MESH_AGENTID); @@ -1777,6 +1785,12 @@ void MeshServer_OnResponse(ILibWebClient_StateObject WebStateObject, int Interru agent->serverAuthState = 0; // We are not authenticated. Bitmask: 1 = Server Auth, 2 = Agent Auth. agent->serverConnectionState = 2; + // Send the ServerID to the server, this is useful for the server to use the correct certificate to authenticate. + MeshCommand_BinaryPacket_ServerId *serveridcmd = (MeshCommand_BinaryPacket_ServerId*)ILibScratchPad2; + serveridcmd->command = htons(MeshCommand_ServerId); + memcpy_s(serveridcmd->serverId, sizeof(serveridcmd->serverId), agent->serverHash, sizeof(agent->serverHash)); // Place our mesh agent nonce + ILibWebClient_WebSocket_Send(WebStateObject, ILibWebClient_WebSocket_DataType_BINARY, (char*)serveridcmd, sizeof(MeshCommand_BinaryPacket_ServerId), ILibAsyncSocket_MemoryOwnership_USER, ILibWebClient_WebSocket_FragmentFlag_Complete); + // Start authentication by sending a auth nonce & server TLS cert hash. // Send 384 bits SHA384 hash of TLS cert public key + 384 bits nonce util_random(sizeof(agent->agentNonce), agent->agentNonce); // Generate a new mesh agent connection nonce @@ -1977,11 +1991,14 @@ void MeshServer_ConnectEx(MeshAgentHostContainer *agent) return; } + memset(agent->serverHash, 0, sizeof(agent->serverHash)); util_hexToBuf(f->data, f->datalength, agent->serverHash); ILibDestructParserResults(rs); - - if (ILibSimpleDataStore_Get(agent->masterDb, "MeshID", ILibScratchPad, sizeof(ILibScratchPad)) == 0) { printf("MeshID entry not found in Db!\n"); return; } - memcpy_s(agent->meshId, sizeof(agent->meshId), ILibScratchPad, UTIL_HASHSIZE); + + len = ILibSimpleDataStore_Get(agent->masterDb, "MeshID", ILibScratchPad, sizeof(ILibScratchPad)); + if ((len != 32) && (len != 48)) { printf("MeshID entry not found in db or bad size.\n"); return; } // Make sure MeshID is both present and SHA256 or SHA384. + memset(agent->meshId, 0, sizeof(agent->meshId)); // Clear the meshid first in case we copy SHA256 + memcpy_s(agent->meshId, sizeof(agent->meshId), ILibScratchPad, len); // Copy the correct length #ifndef MICROSTACK_NOTLS util_keyhash(agent->selfcert, agent->g_selfid); // Compute our own identifier using our certificate @@ -2393,6 +2410,7 @@ int MeshAgent_AgentMode(MeshAgentHostContainer *agentHost, int paramLen, char ** #endif // Check to see if we need to import a settings file + importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".mshx")); importSettings(agentHost, MeshAgent_MakeAbsolutePath(agentHost->exePath, ".msh")); #ifdef WIN32 diff --git a/meshcore/agentcore.h b/meshcore/agentcore.h index 2b1d401..2fd9cd0 100644 --- a/meshcore/agentcore.h +++ b/meshcore/agentcore.h @@ -92,6 +92,7 @@ typedef enum MeshCommands_Binary MeshCommand_AuthVerify = 2, // Agent or server signature MeshCommand_AuthInfo = 3, // Agent information MeshCommand_AuthConfirm = 4, // Server confirm to the agent that is it authenticated + MeshCommand_ServerId = 5, // Optional, agent sends the expected serverid to the server. Useful if the server has many server certificates. MeshCommand_CoreModule = 10, // New core modules to be used instead of the old one, if empty, remove the core module MeshCommand_CoreModuleHash = 11, // Request/return the SHA384 hash of the core module MeshCommand_AgentHash = 12, // Request/return the SHA384 hash of the agent executable diff --git a/meshservice/MeshService.vcxproj b/meshservice/MeshService.vcxproj index 5e8143e..cca3471 100644 --- a/meshservice/MeshService.vcxproj +++ b/meshservice/MeshService.vcxproj @@ -259,6 +259,7 @@ + @@ -321,6 +322,7 @@ + diff --git a/meshservice/MeshService.vcxproj.filters b/meshservice/MeshService.vcxproj.filters index 3105250..3f7f925 100644 --- a/meshservice/MeshService.vcxproj.filters +++ b/meshservice/MeshService.vcxproj.filters @@ -184,6 +184,9 @@ Microstack + + Microscript + @@ -358,5 +361,8 @@ Microstack + + Microscript + \ No newline at end of file diff --git a/meshservice/ServiceMain.c b/meshservice/ServiceMain.c index 2995c94..8422c35 100644 --- a/meshservice/ServiceMain.c +++ b/meshservice/ServiceMain.c @@ -35,6 +35,8 @@ limitations under the License. #include "microstack/ILibCrypto.h" #include "meshcore/agentcore.h" +#include "microscript/ILibDuktape_ScriptContainer.h" + #ifndef _MINCORE // #include "../kvm/kvm.h" int SetupWindowsFirewall(wchar_t* processname); @@ -702,6 +704,10 @@ int main(int argc, char* argv[]) return(0); } + char *integratedJavaScript; + int integragedJavaScriptLen; + ILibDuktape_ScriptContainer_CheckEmbedded(argv, &integratedJavaScript, &integragedJavaScriptLen); + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // Process extra switches @@ -759,7 +765,7 @@ int main(int argc, char* argv[]) return 0; } #else - else if (argc > 1 && ((strcasecmp(argv[1], "run") == 0) || (strcasecmp(argv[1], "--slave") == 0))) + else if (integratedJavaScript != NULL || (argc > 1 && ((strcasecmp(argv[1], "run") == 0) || (strcasecmp(argv[1], "--slave") == 0)))) { // Run the mesh agent in console mode, since the agent is compiled for windows service, the KVM will not work right. This is only good for testing. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); // Set SIGNAL on windows to listen for Ctrl-C @@ -767,6 +773,8 @@ int main(int argc, char* argv[]) __try { agent = MeshAgent_Create(); + agent->meshCoreCtx_embeddedScript = integratedJavaScript; + agent->meshCoreCtx_embeddedScriptLen = integragedJavaScriptLen; MeshAgent_Start(agent, argc, argv); retCode = agent->exitCode; MeshAgent_Destroy(agent); diff --git a/microlms/service/ServiceMain.c b/microlms/service/ServiceMain.c index 62ad927..2f69390 100644 --- a/microlms/service/ServiceMain.c +++ b/microlms/service/ServiceMain.c @@ -136,7 +136,7 @@ void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) // Run the MicroLMS Service CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); Chain = ILibCreateChain(); - MicroLMS = ILibLMS_Create(Chain, selfexe); + MicroLMS = ILibLMS_Create(Chain, selfexe, NULL); if (MicroLMS != NULL) { printf("Starting MicroLMS.\r\n"); @@ -580,7 +580,7 @@ int main(int argc, char* argv[]) { // Run as an command line application Chain = ILibCreateChain(); - MicroLMS = ILibLMS_Create(Chain, selfexe); + MicroLMS = ILibLMS_Create(Chain, selfexe, NULL); if (MicroLMS != NULL) { #ifdef NOCOMMANDER diff --git a/microscript/ILibDuktape_ChildProcess.c b/microscript/ILibDuktape_ChildProcess.c new file mode 100644 index 0000000..f1955b9 --- /dev/null +++ b/microscript/ILibDuktape_ChildProcess.c @@ -0,0 +1,285 @@ +#include "ILibDuktape_ChildProcess.h" + +#include "ILibDuktapeModSearch.h" +#include "../microstack/ILibParsers.h" +#include "../microstack/ILibProcessPipe.h" + +#include "ILibDuktape_Helpers.h" +#include "ILibDuktape_ReadableStream.h" +#include "ILibDuktape_WritableStream.h" +#include "ILibDuktape_EventEmitter.h" + +#define ILibDuktape_ChildProcess_Manager "\xFF_ChildProcess_Manager" +#define ILibDuktape_ChildProcess_Process "\xFF_ChildProcess_Process" +#define ILibDuktape_ChildProcess_MemBuf "\xFF_ChildProcess_MemBuf" + +typedef struct ILibDuktape_ChildProcess_SubProcess +{ + duk_context *ctx; + void *subProcess; + void *chain; + ILibProcessPipe_Process childProcess; + + ILibDuktape_readableStream *stdOut; + ILibDuktape_readableStream *stdErr; + ILibDuktape_WritableStream *stdIn; + + int exitCode; +}ILibDuktape_ChildProcess_SubProcess; + +void ILibDuktape_ChildProcess_SubProcess_StdOut_OnPause(ILibDuktape_readableStream *sender, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdOut(p->childProcess)); +} +void ILibDuktape_ChildProcess_SubProcess_StdOut_OnResume(ILibDuktape_readableStream *sender, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdOut(p->childProcess)); +} +void ILibDuktape_ChildProcess_SubProcess_StdErr_OnPause(ILibDuktape_readableStream *sender, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdErr(p->childProcess)); +} +void ILibDuktape_ChildProcess_SubProcess_StdErr_OnResume(ILibDuktape_readableStream *sender, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdErr(p->childProcess)); +} +ILibTransport_DoneState ILibDuktape_ChildProcess_SubProcess_StdIn_WriteHandler(ILibDuktape_WritableStream *stream, char *buffer, int bufferLen, void *user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + return(ILibProcessPipe_Process_WriteStdIn(p->childProcess, buffer, bufferLen, ILibTransport_MemoryOwnership_USER)); +} +void ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler(ILibDuktape_WritableStream *sender, void *user) +{ +} + +void ILibDuktape_ChildProcess_SubProcess_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + p->exitCode = exitCode; + + duk_push_heapptr(p->ctx, p->subProcess); // [childProcess] + duk_get_prop_string(p->ctx, -1, "emit"); // [childProcess][emit] + duk_swap_top(p->ctx, -2); // [emit][this] + duk_push_string(p->ctx, "exit"); // [emit][this][exit] + duk_push_int(p->ctx, p->exitCode); // [emit][this][exit][exitCode] + duk_push_null(p->ctx); // [emit][this][exit][exitCode][sig] + if (duk_pcall_method(p->ctx, 3) != 0) { ILibDuktape_Process_UncaughtExceptionEx(p->ctx, "child_process.subProcess.exit(): "); } + duk_pop(p->ctx); + +} +void ILibDuktape_ChildProcess_SubProcess_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibDuktape_readableStream_WriteData(p->stdOut, buffer, bufferLen); + *bytesConsumed = bufferLen; +} +void ILibDuktape_ChildProcess_SubProcess_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibDuktape_readableStream_WriteData(p->stdErr, buffer, bufferLen); + *bytesConsumed = bufferLen; +} +void ILibDuktape_ChildProcess_SubProcess_SendOK(ILibProcessPipe_Process sender, void* user) +{ + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)user; + ILibDuktape_WritableStream_Ready(p->stdIn); +} +duk_ret_t ILibDuktape_ChildProcess_Kill(duk_context *ctx) +{ + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, ILibDuktape_ChildProcess_MemBuf); + ILibDuktape_ChildProcess_SubProcess *p = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBuffer(ctx, -1, NULL); + + ILibProcessPipe_Process_SoftKill(p->childProcess); + + return(0); +} +ILibDuktape_ChildProcess_SubProcess* ILibDuktape_ChildProcess_SpawnedProcess_PUSH(duk_context *ctx, ILibProcessPipe_Process mProcess, void *callback) +{ + duk_push_object(ctx); // [ChildProcess] + duk_push_pointer(ctx, mProcess); // [ChildProcess][ptr] + duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Process); // [ChildProcess] + duk_push_fixed_buffer(ctx, sizeof(ILibDuktape_ChildProcess_SubProcess)); // [ChildProcess][buffer] + ILibDuktape_ChildProcess_SubProcess *retVal = (ILibDuktape_ChildProcess_SubProcess*)Duktape_GetBuffer(ctx, -1, NULL); + duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_MemBuf); // [ChildProcess] + + memset(retVal, 0, sizeof(ILibDuktape_ChildProcess_SubProcess)); + retVal->ctx = ctx; + retVal->subProcess = duk_get_heapptr(ctx, -1); + retVal->childProcess = mProcess; + retVal->chain = Duktape_GetChain(ctx); + + ILibDuktape_CreateReadonlyProperty_int(ctx, "pid", ILibProcessPipe_Process_GetPID(mProcess)); + ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_Create(ctx); + + ILibDuktape_EventEmitter_CreateEventEx(emitter, "exit"); + ILibDuktape_EventEmitter_CreateEventEx(emitter, "error"); + + ILibDuktape_CreateInstanceMethod(ctx, "kill", ILibDuktape_ChildProcess_Kill, 0); + + duk_push_object(ctx); + retVal->stdOut = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdOut_OnPause, ILibDuktape_ChildProcess_SubProcess_StdOut_OnResume, retVal); + ILibDuktape_CreateReadonlyProperty(ctx, "stdout"); + + duk_push_object(ctx); + retVal->stdErr = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdErr_OnPause, ILibDuktape_ChildProcess_SubProcess_StdErr_OnResume, retVal); + ILibDuktape_CreateReadonlyProperty(ctx, "stderr"); + + duk_push_object(ctx); + retVal->stdIn = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_ChildProcess_SubProcess_StdIn_WriteHandler, ILibDuktape_ChildProcess_SubProcess_StdIn_EndHandler, retVal); + ILibDuktape_CreateReadonlyProperty(ctx, "stdin"); + + if (callback != NULL) { ILibDuktape_EventEmitter_AddOnce(emitter, "exit", callback); } + + ILibProcessPipe_Process_AddHandlers(mProcess, 4096, ILibDuktape_ChildProcess_SubProcess_ExitHandler, + ILibDuktape_ChildProcess_SubProcess_StdOutHandler, + ILibDuktape_ChildProcess_SubProcess_StdErrHandler, + ILibDuktape_ChildProcess_SubProcess_SendOK, retVal); + + return(retVal); +} + +duk_ret_t ILibDuktape_ChildProcess_Manager_Finalizer(duk_context *ctx) +{ + duk_get_prop_string(ctx, 0, ILibDuktape_ChildProcess_Manager); + ILibProcessPipe_Manager manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1); + + ILibChain_SafeRemove(((ILibChain_Link*)manager)->ParentChain, manager); + return(0); +} +duk_ret_t ILibDuktape_ChildProcess_execFile(duk_context *ctx) +{ + int nargs = duk_get_top(ctx); + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, ILibDuktape_ChildProcess_Manager); + ILibProcessPipe_Manager manager = (ILibProcessPipe_Manager)duk_get_pointer(ctx, -1); + duk_size_t targetLen; + char *target = (char*)duk_get_lstring(ctx, 0, &targetLen); + char **args = NULL; + int i, x; + void *callback = NULL; + ILibProcessPipe_Process p = NULL; + + for (i = 0; i < nargs; ++i) + { + if (duk_is_array(ctx, i) != 0) + { + int arrLen = duk_get_length(ctx, i); +#ifdef WIN32 + args = (char**)_alloca((arrLen + 1) * sizeof(char*)); +#else + args = (char**)alloca((arrLen + 1) * sizeof(char*)); +#endif + for (x = 0; x < arrLen; ++x) + { + duk_get_prop_index(ctx, i, x); + args[x] = (char*)duk_get_string(ctx, -1); + } + args[x] = NULL; + } + else if (duk_is_function(ctx, i)) + { + callback = duk_get_heapptr(ctx, i); + } + } + +#ifdef WIN32 + if (target[0] == '%') + { + size_t evsize; + int pctx = ILibString_IndexOf(target + 1, (int)targetLen - 1, "%", 1); + if (pctx > 0) + { + memcpy_s(ILibScratchPad, sizeof(ILibScratchPad), target + 1, pctx); + ILibScratchPad[pctx] = 0; + getenv_s(&evsize, ILibScratchPad2, sizeof(ILibScratchPad2), ILibScratchPad); + if (evsize > 0) + { + strncpy_s(ILibScratchPad2 + evsize - 1, sizeof(ILibScratchPad2) - evsize, target + pctx + 2, targetLen - pctx - 2); + target = ILibScratchPad2; + } + } + } +#endif + + p = ILibProcessPipe_Manager_SpawnProcess(manager, target, args); + if (p == NULL) + { + return(ILibDuktape_Error(ctx, "child_process.execFile(): Could not exec [%s]", target)); + } + ILibDuktape_ChildProcess_SpawnedProcess_PUSH(ctx, p, callback); + return(1); +} +void ILibDuktape_ChildProcess_PUSH(duk_context *ctx, void *chain) +{ + duk_push_object(ctx); + duk_push_pointer(ctx, (void*)ILibProcessPipe_Manager_Create(chain)); + duk_put_prop_string(ctx, -2, ILibDuktape_ChildProcess_Manager); + ILibDuktape_CreateFinalizer(ctx, ILibDuktape_ChildProcess_Manager_Finalizer); + + ILibDuktape_CreateInstanceMethod(ctx, "execFile", ILibDuktape_ChildProcess_execFile, DUK_VARARGS); +} +void ILibDuktape_ChildProcess_Init(duk_context *ctx) +{ + ILibDuktape_ModSearch_AddHandler(ctx, "child_process", ILibDuktape_ChildProcess_PUSH); +} + +#ifdef __DOXY__ +/*! +\implements EventEmitter +\brief The child_process module provides the ability to spawn child processes. Note: To use, must require('child_process') +*/ +class ChildProcess +{ +public: + /*! + \brief The specified file is spawned as a child process + \param file \ Required. The name or path of the executable file to run + \param args \ Optional. List of string arguments + \param options Optional. \n + cwd \ Current working directory\n + env Environment key-value pairs\n + timeout Default: 0\n + \returns \ + */ + static ChildProcess execFile(file[, args][, options][, callback]); + + /*! + \brief Event emitted whenever process cannot be killed or spawned + \param err The Error + */ + void error; + /*! + \brief Event emitted after the child process ends + \param code Exit code + \param signal \ Not used. + */ + void exit; + /*! + \brief Process ID of the child process + */ + Integer pid; + /*! + \brief Sends SIGTERM to child process + */ + void kill(); + + /*! + \brief StdOut ReadableStream + */ + ReadableStream stdout; + /*! + \brief StdErr ReadableStream + */ + ReadableStream stderr; + /*! + \brief StdIn WritableStream + */ + WritableStream stdin; + +}; +#endif \ No newline at end of file diff --git a/microscript/ILibDuktape_ChildProcess.h b/microscript/ILibDuktape_ChildProcess.h new file mode 100644 index 0000000..45a9546 --- /dev/null +++ b/microscript/ILibDuktape_ChildProcess.h @@ -0,0 +1,9 @@ +#ifndef __ILIBDUKTAPE_CHILDPROCESS__ +#define __ILIBDUKTAPE_CHILDPROCESS__ + +#include "duktape.h" + +void ILibDuktape_ChildProcess_Init(duk_context *ctx); + + +#endif diff --git a/microscript/ILibDuktape_EventEmitter.h b/microscript/ILibDuktape_EventEmitter.h index c915337..67b388e 100644 --- a/microscript/ILibDuktape_EventEmitter.h +++ b/microscript/ILibDuktape_EventEmitter.h @@ -30,8 +30,11 @@ void ILibDuktape_EventEmitter_RemoveEventHeapptr(ILibDuktape_EventEmitter *emitt int ILibDuktape_EventEmitter_AddEventHeapptr(ILibDuktape_EventEmitter *emitter, char *eventName, void **heapptr); // Add Callback after the fact int ILibDuktape_EventEmitter_AddSink(ILibDuktape_EventEmitter *emitter, char *eventName, ILibDuktape_EventEmitter_Handler handler); // Add Native Event Handler int ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler 'once' +int ILibDuktape_EventEmitter_AddOnceEx(ILibDuktape_EventEmitter *emitter, char *eventName, duk_c_function func, duk_idx_t funcArgs); +int ILibDuktape_EventEmitter_AddOnceEx2(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func, duk_idx_t funcArgs); int ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr); // Add native event handler + void ILibDuktape_EventEmitter_AddHook(ILibDuktape_EventEmitter *emitter, char *eventName, ILibDuktape_EventEmitter_HookHandler handler); diff --git a/microscript/ILibDuktape_Helpers.c b/microscript/ILibDuktape_Helpers.c index 091048c..be69b3d 100644 --- a/microscript/ILibDuktape_Helpers.c +++ b/microscript/ILibDuktape_Helpers.c @@ -37,7 +37,21 @@ struct sockaddr_in6 duktape_internalAddress; #define ILibDuktape_EventEmitter_Table "\xFF_EventEmitterTable" #define ILibDuktape_Process_ExitCode "\xFF_ExitCode" #define ILibDuktape_Memory_AllocTable "\xFF_MemoryAllocTable" +#define ILibDuktape_ObjectStashKey "\xFF_ObjectStashKey" +void ILibDuktape_Push_ObjectStash(duk_context *ctx) +{ + if (duk_has_prop_string(ctx, -1, ILibDuktape_ObjectStashKey)) + { + duk_get_prop_string(ctx, -1, ILibDuktape_ObjectStashKey); // [obj][stash] + } + else + { + duk_push_object(ctx); // [obj][stash] + duk_dup(ctx, -1); // [obj][stash][stash] + duk_put_prop_string(ctx, -3, ILibDuktape_ObjectStashKey); // [obj][stash] + } +} duk_ret_t ILibDuktape_Error(duk_context *ctx, char *format, ...) { char dest[4096]; @@ -444,27 +458,15 @@ void ILibDuktape_Process_UncaughtException(duk_context *ctx) char* Duktape_GetContextGuidHex(duk_context *ctx) { char *retVal = NULL; - char *guid; - duk_size_t guidLength; - int i; - duk_push_heap_stash(ctx); // [stash] - if (duk_has_prop_string(ctx, -1, CONTEXT_GUID_BUFFER)) + duk_push_heap_stash(ctx); // [stash] + if (duk_has_prop_string(ctx, -1, "\xFF_ScriptContainerSettings_DB")) { - duk_get_prop_string(ctx, -1, CONTEXT_GUID_BUFFER); // [stash][str] - guid = (char*)Duktape_GetBuffer(ctx, -1, &guidLength); - for (i = (int)guidLength-1; i > 1 && guid[i] == 0; --i) - { - } - util_tohex(guid, (int)guidLength, ILibScratchPad); - duk_pop(ctx); // [stash] - for (i = ((int)guidLength * 2) - 1; i > 1 && ILibScratchPad[i] == 48; --i) - { - } - retVal = ILibScratchPad; - retVal[i] = 0; + duk_get_prop_string(ctx, -1, "\xFF_ScriptContainerSettings_DB"); // [stash][db] + if (duk_get_pointer(ctx, -1) != NULL) { retVal = "0"; } + duk_pop(ctx); // [stash] } - duk_pop(ctx); // ... + duk_pop(ctx); // ... return retVal; } void *Duktape_GetChain(duk_context *ctx) diff --git a/microscript/ILibDuktape_Helpers.h b/microscript/ILibDuktape_Helpers.h index 72d83dc..070c941 100644 --- a/microscript/ILibDuktape_Helpers.h +++ b/microscript/ILibDuktape_Helpers.h @@ -83,4 +83,6 @@ void ILibDuktape_CreateReadonlyProperty(duk_context *ctx, char *propName); void *ILibDuktape_Memory_Alloc(duk_context *ctx, duk_size_t size); void ILibDuktape_Helper_AddHeapFinalizer(duk_context *ctx, ILibDuktape_HelperEvent handler, void *user); +void ILibDuktape_Push_ObjectStash(duk_context *ctx); + #endif \ No newline at end of file diff --git a/microscript/ILibDuktape_Polyfills.c b/microscript/ILibDuktape_Polyfills.c index d034cca..12d36d7 100644 --- a/microscript/ILibDuktape_Polyfills.c +++ b/microscript/ILibDuktape_Polyfills.c @@ -81,7 +81,17 @@ duk_ret_t ILibDuktape_Polyfills_Buffer_from(duk_context *ctx) char *buffer; int bufferLen; - if (!(nargs == 2 && duk_is_string(ctx, 0) && duk_is_string(ctx, 1))) + if (nargs == 1) + { + str = (char*)duk_get_lstring(ctx, 0, &strlength); + duk_push_fixed_buffer(ctx, strlength + 1); + buffer = Duktape_GetBuffer(ctx, -1, NULL); + memcpy_s(buffer, strlength + 1, str, strlength); + buffer[strlength] = 0; + duk_push_buffer_object(ctx, -1, 0, strlength+1, DUK_BUFOBJ_ARRAYBUFFER); + return(1); + } + else if(!(nargs == 2 && duk_is_string(ctx, 0) && duk_is_string(ctx, 1))) { duk_push_string(ctx, "Buffer.from(): Usage not supported yet."); duk_throw(ctx); @@ -97,14 +107,14 @@ duk_ret_t ILibDuktape_Polyfills_Buffer_from(duk_context *ctx) duk_push_fixed_buffer(ctx, ILibBase64DecodeLength((int)strlength)); buffer = Duktape_GetBuffer(ctx, -1, NULL); bufferLen = ILibBase64Decode((unsigned char*)str, (int)strlength, (unsigned char**)&buffer); - duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_DUKTAPE_BUFFER); + duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_ARRAYBUFFER); } else if (strcmp(encoding, "hex") == 0) { duk_push_fixed_buffer(ctx, strlength / 2); buffer = Duktape_GetBuffer(ctx, -1, NULL); bufferLen = util_hexToBuf(str, (int)strlength, buffer); - duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_DUKTAPE_BUFFER); + duk_push_buffer_object(ctx, -1, 0, bufferLen, DUK_BUFOBJ_ARRAYBUFFER); } else { @@ -219,7 +229,25 @@ duk_ret_t ILibDuktape_Polyfills_Console_log(duk_context *ctx) else { duk_dup(ctx, i); - printf("%s%s", (i == 0 ? "" : ", "), duk_to_string(ctx, -1)); + if (strcmp("[object Object]", duk_to_string(ctx, -1)) == 0) + { + duk_pop(ctx); + duk_dup(ctx, i); + printf("%s", (i == 0 ? "{" : ", {")); + duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY); + int propNum = 0; + while (duk_next(ctx, -1, 1)) + { + printf("%s%s: %s", ((propNum++ == 0) ? " " : ", "), (char*)duk_to_string(ctx, -2), (char*)duk_to_string(ctx, -1)); + duk_pop_2(ctx); + } + duk_pop(ctx); + printf(" }"); + } + else + { + printf("%s%s", (i == 0 ? "" : ", "), duk_to_string(ctx, -1)); + } } } printf("\n"); diff --git a/microscript/ILibDuktape_ReadableStream.c b/microscript/ILibDuktape_ReadableStream.c index 3260f08..329ded8 100644 --- a/microscript/ILibDuktape_ReadableStream.c +++ b/microscript/ILibDuktape_ReadableStream.c @@ -386,10 +386,13 @@ int ILibDuktape_readableStream_WriteDataEx(ILibDuktape_readableStream *stream, i else { // Need to PAUSE, and context switch to Chain Thread, so we can dispatch into JavaScript - if (stream->paused == 0 && stream->PauseHandler != NULL) { stream->paused = 1; stream->PauseHandler(stream, stream->user); } + sem_wait(&(stream->pipeLock)); stream->extBuffer_Reserved = streamReserved; stream->extBuffer_buffer = buffer; stream->extBuffer_bufferLen = bufferLen; + sem_post(&(stream->pipeLock)); + + if (stream->paused == 0 && stream->PauseHandler != NULL) { stream->paused = 1; stream->PauseHandler(stream, stream->user); } ILibChain_RunOnMicrostackThread(stream->chain, ILibDuktape_readableStream_WriteData_OnData_ChainThread, stream); } } diff --git a/microscript/ILibDuktape_ScriptContainer.c b/microscript/ILibDuktape_ScriptContainer.c index 020f6fc..4befe29 100644 --- a/microscript/ILibDuktape_ScriptContainer.c +++ b/microscript/ILibDuktape_ScriptContainer.c @@ -57,7 +57,11 @@ limitations under the License. #include "ILibDuktape_SHA256.h" #include "ILibDuktape_EncryptionStream.h" +#include "ILibDuktape_ChildProcess.h" +#ifdef _POSIX +extern char **environ; +#endif #define SCRIPT_ENGINE_PIPE_BUFFER_SIZE 65535 #define ILibDuktape_ScriptContainer_MasterPtr "\xFF_ScriptContainer_MasterPtr" #define ILibDuktape_ScriptContainer_SlavePtr "\xFF_ScriptContainer_SlavePtr" @@ -183,6 +187,58 @@ void ILibDuktape_ScriptContainer_Slave_OnBrokenPipe(ILibProcessPipe_Pipe sender) ILibStopChain(((ILibDuktape_ScriptContainer_Slave*)((void**)ILibMemory_GetExtraMemory(sender, ILibMemory_ILibProcessPipe_Pipe_CONTAINERSIZE))[0])->chain); } + +void ILibDuktape_ScriptContainer_CheckEmbedded(char **argv, char **script, int *scriptLen) +{ + // Check if .JS file is integrated with executable + FILE *tmpFile; + char *integratedJavaScript = NULL; + int integratedJavaScriptLen = 0; +#ifdef WIN32 + if (ILibString_EndsWith(argv[0], -1, ".exe", 4) == 0) + { + sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "%s.exe", argv[0]); + tmpFile = fopen(ILibScratchPad, "rb"); + } + else + { + tmpFile = fopen(argv[0], "rb"); + } +#else + tmpFile = fopen(argv[0], "rb"); +#endif + + if (tmpFile != NULL) + { + fseek(tmpFile, 0, SEEK_END); + fseek(tmpFile, ftell(tmpFile) - 4, SEEK_SET); + ignore_result(fread(ILibScratchPad, 1, 4, tmpFile)); + fseek(tmpFile, 0, SEEK_END); + if (ftell(tmpFile) == ntohl(((int*)ILibScratchPad)[0])) + { + fseek(tmpFile, ftell(tmpFile) - 8, SEEK_SET); + ignore_result(fread(ILibScratchPad, 1, 4, tmpFile)); + integratedJavaScriptLen = ntohl(((int*)ILibScratchPad)[0]); + integratedJavaScript = ILibMemory_Allocate(1 + integratedJavaScriptLen, 0, NULL, NULL); + fseek(tmpFile, 0, SEEK_END); + fseek(tmpFile, ftell(tmpFile) - 8 - integratedJavaScriptLen, SEEK_SET); + ignore_result(fread(integratedJavaScript, 1, integratedJavaScriptLen, tmpFile)); + integratedJavaScript[integratedJavaScriptLen] = 0; + } + fclose(tmpFile); + } + *script = integratedJavaScript; + *scriptLen = integratedJavaScriptLen; +} + + + + + + + + + // Polyfill process object: void ILibDuktape_ScriptContainer_Process_ExitCallback(void *obj) { @@ -247,6 +303,49 @@ duk_ret_t ILibDuktape_ScriptContainer_Process_Argv(duk_context *ctx) 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); +} + void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) { int i = 0; @@ -254,6 +353,8 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) duk_push_global_object(ctx); // [g] duk_push_object(ctx); // [g][process] + ILibDuktape_CreateEventWithGetter(ctx, "env", ILibDuktape_ScriptContainer_Process_env); + #if defined(WIN32) // [g][process][platform] duk_push_string(ctx, "win32"); #elif defined(__APPLE__) @@ -263,6 +364,19 @@ void ILibDuktape_ScriptContainer_Process_Init(duk_context *ctx, char **argList) #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] @@ -691,7 +805,7 @@ duk_context *ILibDuktape_ScriptContainer_InitializeJavaScriptEngineEx(SCRIPT_ENG 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_PROCESS_SPAWNING) == 0) { ILibDuktape_ProcessPipe_Init(ctx, chain); ILibDuktape_ChildProcess_Init(ctx); } if ((securityFlags & SCRIPT_ENGINE_NO_FILE_SYSTEM_ACCESS) == 0) { ILibDuktape_fs_init(ctx); } diff --git a/microscript/ILibDuktape_ScriptContainer.h b/microscript/ILibDuktape_ScriptContainer.h index 18fb4c6..534cd90 100644 --- a/microscript/ILibDuktape_ScriptContainer.h +++ b/microscript/ILibDuktape_ScriptContainer.h @@ -140,6 +140,7 @@ typedef struct SCRIPT_ENGINE_SETTINGS }SCRIPT_ENGINE_SETTINGS; +void ILibDuktape_ScriptContainer_CheckEmbedded(char **argv, char **script, int *scriptLen); void ILibDuktape_ScriptContainer_InitMaster(void *chain, char *exePath, ILibProcessPipe_Manager manager); int ILibDuktape_ScriptContainer_StartSlave(void *chain, ILibProcessPipe_Manager manager); diff --git a/microscript/ILibDuktape_http.c b/microscript/ILibDuktape_http.c index b228720..29ea72d 100644 --- a/microscript/ILibDuktape_http.c +++ b/microscript/ILibDuktape_http.c @@ -35,6 +35,7 @@ limitations under the License. #include "ILibDuktape_DuplexStream.h" #include "ILibDuktape_EventEmitter.h" #include "microstack/ILibCrypto.h" +#include "microstack/ILibRemoteLogging.h" #define HTTP_SERVER_PTR "\xFF_ServerPtr" #define HTTP_WEBCLIENT_MGR "_RequestManagerPtr" @@ -52,13 +53,20 @@ limitations under the License. #define HTTP_STREAM_WRAPPER_BUFSIZE 4096 #define HTTP_CLIENTREQUEST_PARAMETER "\xFF_http_clientRequest_parameter" #define CLIENTREQUEST_HTTP "\xFF_clientRequest_HTTP" +#define CLIENTREQUEST_SOCKET_WCDO "\xFF_clientRequest_SOCKET_WCDO" #define HTTP_INCOMINGMSG_WebStateObject "\xFF_incomingMessage_WebStateObject" #define DIGEST_USERNAME "\xFF_DigestUsername" #define DIGEST_PASSWORD "\xFF_DigestPassword" +#define DIGEST_WCDO "\xFF_DIGEST_WCDO" #define HTTP_DIGEST "\xFF_HTTP_DIGEST" #define DIGEST_CLIENT_REQUEST "\xFF_DIGEST_CLIENT_REQUEST" #define HTTP_CLIENTREQUEST_DATAPTR "\xFF_CLIENTREQUEST_DATAPTR" #define CLIENTREQUEST_EVENT_NAME "\xFF_CLIENTREQUEST_EVENT_NAME" +#define CLIENTREQUEST_IMSG_RSPTR "\xFF_CLIENTREQUEST_IMSG_RSPTR" +#define DIGESTCLIENTREQUEST_END_CALLED "\xFF_DIGESTCLIENTREQUEST_END_CALLED" +#define DIGESTCLIENTREQUEST_CONTINUE "\xFF_DIGESTCLIENTREQUEST_CONTINUE" +#define DIGESTCLIENTREQUEST_TmpBuffer "\xFF_DIGESTCLIENTREQUEST_TmpBuffer" +#define DIGESTCLIENTREQUEST_DIGEST "\xFF_DIGESTCLIENTREQUEST_DIGEST" extern duk_idx_t ILibWebServer_DukTape_Push_ILibWebServerSession(duk_context *ctx, ILibWebServer_Session *session); void* ILibDuktape_http_request_PUSH_clientRequest(duk_context *ctx, ILibWebClient_RequestToken token, int isWebSocket); @@ -84,6 +92,7 @@ typedef struct ILibDuktape_http_requestClient_callbacks void *requestStream; void *OnReceive; void *OnContinue; + void *OnSocket; #ifndef MICROSTACK_NOTLS int rejectUnauthorized; void *checkServerIdentity; @@ -954,6 +963,33 @@ duk_ret_t ILibDuktape_http_server_tlsSettings_Finalizer(duk_context *ctx) { return 0; } +duk_ret_t ILibDuktape_http_server_address(duk_context *ctx) +{ + duk_push_this(ctx); + if (!duk_has_prop_string(ctx, -1, HTTP_SERVER_PTR)) + { + return(ILibDuktape_Error(ctx, "http.server.address(): Not listening")); + } + duk_get_prop_string(ctx, -1, HTTP_SERVER_PTR); + ILibAsyncServerSocket_ServerModule s = ILibWebServer_GetServerSocketModule((ILibWebServer_ServerToken)duk_get_pointer(ctx, -1)); + struct sockaddr_in6 local; + memset(&local, 0, sizeof(struct sockaddr_in6)); + + ILibAsyncServerSocket_GetLocal(s, (struct sockaddr*)&local, sizeof(struct sockaddr_in6)); + if (local.sin6_family == AF_UNSPEC) { return(ILibDuktape_Error(ctx, "net.server.address(): call to getsockname() failed")); } + + duk_push_object(ctx); + duk_push_string(ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4"); + duk_put_prop_string(ctx, -2, "family"); + + duk_push_int(ctx, (int)ntohs(local.sin6_port)); + duk_put_prop_string(ctx, -2, "port"); + + duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)&local)); + duk_put_prop_string(ctx, -2, "address"); + + return(1); +} duk_ret_t ILibDuktape_http_createServer(duk_context *ctx) { int nargs = duk_get_top(ctx); @@ -1060,6 +1096,7 @@ duk_ret_t ILibDuktape_http_createServer(duk_context *ctx) duk_push_c_function(ctx, ILibDuktape_http_server_listen, DUK_VARARGS); // [http][server][func] duk_put_prop_string(ctx, -2, "listen"); // [http][server] + ILibDuktape_CreateInstanceMethod(ctx, "_address", ILibDuktape_http_server_address, 0); return 1; } @@ -1096,15 +1133,13 @@ void ILibDuktape_http_request_OnResponse(ILibWebClient_StateObject WebStateObjec { if (ctx != NULL) { - duk_push_heapptr(ctx, ptrs->OnReceive); // [func] - duk_push_heapptr(ctx, ptrs->clientRequest); // [func][this] - duk_del_prop_string(ctx, -1, HTTP_REQUEST_TOKEN_PTR); // (Prevents crash in Request Finalizer) - duk_push_null(ctx); // [func][this][null] - if (duk_pcall_method(ctx, 1) != 0) // [retVal] - { - ILibDuktape_Process_UncaughtException(ctx); - } - duk_pop(ctx); // ... + duk_push_heapptr(ctx, ptrs->clientRequest); // [clientRequest] + duk_get_prop_string(ctx, -1, "emit"); // [clientRequest][emit] + duk_swap_top(ctx, -2); // [emit][this] + duk_push_string(ctx, "error"); // [emit][this][error] + duk_push_error_object(ctx, DUK_ERR_ERROR, "Socket was unexpectedly closed"); // [emit][this][error][err] + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.request.OnError(): "); } + duk_pop(ctx); // ... } return; } @@ -1147,6 +1182,7 @@ void ILibDuktape_http_request_OnResponse(ILibWebClient_StateObject WebStateObjec { duk_push_heapptr(ctx, ptrs->clientRequest); // [clientRequest] duk_del_prop_string(ctx, -1, HTTP_REQUEST_TOKEN_PTR); + duk_del_prop_string(ctx, -1, HTTP_REQUEST_USER_PTR); ILibDuktape_EventEmitter_RemoveAll(ILibDuktape_EventEmitter_GetEmitter(ctx, -1)); duk_pop(ctx); // ... } @@ -1479,8 +1515,27 @@ void ILibDuktape_http_webSocket_onSendOk(ILibWebClient_StateObject sender, void ILibDuktape_DuplexStream_Ready(ptrs->stream); } } +void ILibDuktape_http_request_idleTimeout(ILibAsyncSocket_SocketModule sender, void *user) +{ + ILibWebClient_RequestToken token = ILibWebClient_GetRequestToken_FromStateObject(user); + void ** u = ILibWebClient_RequestToken_GetUserObjects(token); + + if (u[1] != NULL && ((ILibDuktape_http_request_dataType*)u[1])->STRUCT_TYPE == ILibDuktape_http_request_dataType_request && + ((ILibDuktape_http_requestClient_callbacks*)u[1])->clientRequest != NULL) + { + duk_context *ctx = (duk_context*)u[0]; + ILibDuktape_http_requestClient_callbacks *cb = (ILibDuktape_http_requestClient_callbacks*)u[1]; + duk_push_heapptr(ctx, cb->clientRequest); // [clientRequest] + duk_get_prop_string(ctx, -1, "emit"); // [clientRequest][emit] + duk_swap_top(ctx, -2); // [emit][this] + duk_push_string(ctx, "timeout"); // [emit][this][timeout] + if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.clientRequest.onTimeout(): "); } + duk_pop(ctx); + } +} duk_ret_t ILibDuktape_http_request(duk_context *ctx) { + union { int i; void*p; }u; ILibHTTPPacket *packet; char *host; duk_size_t hostLen; @@ -1509,6 +1564,10 @@ duk_ret_t ILibDuktape_http_request(duk_context *ctx) { duk_get_prop_string(ctx, -1, HTTP_WEBCLIENT_MGR); wcm = (ILibWebClient_RequestManager)duk_to_pointer(ctx, -1); + if (protocol == ILibWebClient_RequestToken_USE_HTTPS) + { + ILibWebClient_EnableHTTPS(wcm, NULL, NULL, ILibDuktape_http_request_tls_verify); + } } else { @@ -1589,7 +1648,6 @@ duk_ret_t ILibDuktape_http_request(duk_context *ctx) if (isWebSocket != 0) { - union { int i; void*p; }u; int len; char value[32]; char nonce[16]; @@ -1607,6 +1665,13 @@ duk_ret_t ILibDuktape_http_request(duk_context *ctx) ILibHTTPPacket_Stash_Put(packet, "_WebSocketOnSendOK", -1, ILibDuktape_http_webSocket_onSendOk); } + u.i = Duktape_GetIntPropertyValue(ctx, 0, "timeout", 0); + if (u.i > 0) + { + ILibHTTPPacket_Stash_Put(packet, "_idleTimeout", -1, u.p); + ILibHTTPPacket_Stash_Put(packet, "_idleTimeoutHandler", -1, ILibDuktape_http_request_idleTimeout); + } + if (duk_has_prop_string(ctx, 0, "headers")) { duk_get_prop_string(ctx, 0, "headers"); @@ -1750,10 +1815,66 @@ duk_ret_t ILibDuktape_http_request_no_op(duk_context *ctx) { return 0; } +void ILibDuktape_http_request_connect(ILibWebClient_RequestToken token) +{ + ILibWebClient_StateObject wcdo = ILibWebClient_GetStateObjectFromRequestToken(token); + void **user = ILibWebClient_RequestToken_GetUserObjects(token); + duk_context *ctx = (duk_context*)user[0]; + ILibDuktape_http_requestClient_callbacks *ptr = (ILibDuktape_http_requestClient_callbacks*)user[1]; + if (ctx != NULL && ptr != NULL && ptr->OnSocket != NULL) + { + duk_push_object(ctx); // [socket] + duk_push_pointer(ctx, wcdo); // [socket][wcdo] + duk_put_prop_string(ctx, -2, CLIENTREQUEST_SOCKET_WCDO); // [socket] + duk_push_heapptr(ctx, ptr->clientRequest); // [socket][clientRequest] + duk_dup(ctx, -2); // [socket][clientRequest][socket] + ILibDuktape_CreateReadonlyProperty(ctx, "socket"); // [socket][clientRequest] + duk_pop(ctx); // [socket] + + duk_push_heapptr(ctx, ptr->clientRequest); // [socket][clientRequest] + ILibDuktape_Push_ObjectStash(ctx); // [socket][clientRequest][stash] + duk_dup(ctx, -3); // [socket][clientRequest][stash][socket] + duk_put_prop_string(ctx, -2, Duktape_GetStashKey(wcdo)); // [socket][clientRequest][stash] + duk_pop_2(ctx); // [socket] + + ILibDuktape_EventEmitter *emitter = ILibDuktape_EventEmitter_Create(ctx); + ILibDuktape_EventEmitter_CreateEventEx(emitter, "end"); + duk_push_heapptr(ctx, ptr->OnSocket); // [socket][OnSocket] + duk_push_heapptr(ctx, ptr->clientRequest); // [socket][OnSocket][this] + duk_dup(ctx, -3); // [socket][OnSocket][this][socket] + if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.request_connect.onSocket(): "); } + duk_pop_2(ctx); // ... + } +} +void ILibDuktape_http_request_disconnect(ILibWebClient_RequestToken token) +{ + ILibWebClient_StateObject wcdo = ILibWebClient_GetStateObjectFromRequestToken(token); + char *key = Duktape_GetStashKey(wcdo); + void **user = ILibWebClient_RequestToken_GetUserObjects(token); + if (user == NULL) { return; } + duk_context *ctx = (duk_context*)user[0]; + ILibDuktape_http_requestClient_callbacks *ptr = (ILibDuktape_http_requestClient_callbacks*)user[1]; + if (ctx != NULL && ptr != NULL) + { + duk_push_heapptr(ctx, ptr->clientRequest); // [clientRequest] + ILibDuktape_Push_ObjectStash(ctx); // [clientRequest][stash] + if (duk_has_prop_string(ctx, -1, key)) + { + duk_get_prop_string(ctx, -1, key); // [clientRequest][stash][socket] + duk_get_prop_string(ctx, -1, "emit"); // [clientRequest][stash][socket][emit] + duk_swap_top(ctx, -2); // [clientRequest][stash][emit][this] + duk_push_string(ctx, "end"); // [clientRequest][stash][emit][this][end] + if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http.request_disconnect(): "); } + duk_pop(ctx); // [clientRequest][stash] + duk_del_prop_string(ctx, -2, key); + } + duk_pop_2(ctx); // ... + } +} void* ILibDuktape_http_request_PUSH_clientRequest(duk_context *ctx, ILibWebClient_RequestToken token, int isWebSocket) { ILibDuktape_EventEmitter *emitter = NULL; - void **user = ILibWebClient_RequestToken_GetUserObjects_Tail(token); + void **user = ILibWebClient_RequestToken_GetUserObjects(token); if (user[1] != NULL && ((ILibDuktape_http_request_dataType*)user[1])->STRUCT_TYPE == ILibDuktape_http_request_dataType_request && ((ILibDuktape_http_requestClient_callbacks*)user[1])->clientRequest != NULL) @@ -1762,6 +1883,11 @@ void* ILibDuktape_http_request_PUSH_clientRequest(duk_context *ctx, ILibWebClien return(user[1]); } + if (isWebSocket == 0) + { + ILibWebClient_RequestToken_ConnectionHandler_Set(token, ILibDuktape_http_request_connect, ILibDuktape_http_request_disconnect); + } + duk_push_object(ctx); // [obj] duk_push_pointer(ctx, user); duk_put_prop_string(ctx, -2, HTTP_REQUEST_USER_PTR); @@ -1783,6 +1909,9 @@ void* ILibDuktape_http_request_PUSH_clientRequest(duk_context *ctx, ILibWebClien { ILibDuktape_EventEmitter_CreateEvent(emitter, "response", &(((ILibDuktape_http_requestClient_callbacks*)user[1])->OnReceive)); ILibDuktape_EventEmitter_CreateEvent(emitter, "continue", &(((ILibDuktape_http_requestClient_callbacks*)user[1])->OnContinue)); + ILibDuktape_EventEmitter_CreateEvent(emitter, "socket", &(((ILibDuktape_http_requestClient_callbacks*)user[1])->OnSocket)); + + ILibDuktape_EventEmitter_CreateEventEx(emitter, "timeout"); ((ILibDuktape_http_requestClient_callbacks*)user[1])->requestStream = ILibDuktape_WritableStream_Init(ctx, ILibDuktape_http_request_write, ILibDuktape_http_request_end, token); ((ILibDuktape_http_requestClient_callbacks*)user[1])->clientRequest = duk_get_heapptr(ctx, -1); } @@ -2433,6 +2562,14 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response2(duk_context *ctx) duk_dup(ctx, 0); // [emit][this][response][imsg] if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error dispatching response event"); } } + else + { + duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit] + duk_swap_top(ctx, -2); // [emit][this] + duk_push_string(ctx, "error"); // [emit][this][response] + duk_dup(ctx, 0); // [emit][this][response][imsg] + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "http-digest: Error dispatching response event"); } + } return(0); } @@ -2469,15 +2606,81 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_propagateEvent(duk_context *ctx) } extern void* ILibWebClient_Digest_GenerateTable(ILibWebClient_StateObject state); +void ILibDuktape_httpDigest_clientRequest_IncomingMessage_PauseHandler(ILibDuktape_readableStream *sender, void *user) +{ + duk_push_heapptr(sender->ctx, user); // [imsg] + duk_get_prop_string(sender->ctx, -1, "pause"); // [imsg][pause] + duk_swap_top(sender->ctx, -2); // [pause][this] + if (duk_pcall_method(sender->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(sender->ctx, "ILibDuktape_httpDigest_clientRequest_IncomingMessage_PauseHandler: Error Invoking Pause on ClientRequest: "); } + duk_pop(sender->ctx); // ... +} +void ILibDuktape_httpDigest_clientRequest_IncomingMessage_ResumeHandler(ILibDuktape_readableStream *sender, void *user) +{ + duk_push_heapptr(sender->ctx, user); // [imsg] + duk_get_prop_string(sender->ctx, -1, "resume"); // [imsg][pause] + duk_swap_top(sender->ctx, -2); // [pause][this] + if (duk_pcall_method(sender->ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(sender->ctx, "ILibDuktape_httpDigest_clientRequest_IncomingMessage_ResumeHandler: Error Invoking Resume on ClientRequest: "); } + duk_pop(sender->ctx); // ... +} +duk_ret_t ILibDuktape_httpDigest_clientRequest_OnData(duk_context *ctx) +{ + duk_push_current_function(ctx); + duk_get_prop_string(ctx, -1, CLIENTREQUEST_IMSG_RSPTR); + ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)duk_get_pointer(ctx, -1); + duk_size_t bufferLen; + char *buffer; + + buffer = Duktape_GetBuffer(ctx, 0, &bufferLen); + ILibDuktape_readableStream_WriteData(rs, buffer, (int)bufferLen); + + return(0); +} +duk_ret_t ILibDuktape_httpDigest_clientRequest_OnEnd(duk_context *ctx) +{ + duk_push_current_function(ctx); + duk_get_prop_string(ctx, -1, CLIENTREQUEST_IMSG_RSPTR); + ILibDuktape_readableStream *rs = (ILibDuktape_readableStream*)duk_get_pointer(ctx, -1); + ILibDuktape_readableStream_WriteEnd(rs); + return(0); +} + +duk_ret_t ILibDuktape_httpDigest_http_request_socketEvent_end(duk_context *ctx) +{ + duk_push_this(ctx); // [socket] + duk_get_prop_string(ctx, -1, CLIENTREQUEST_SOCKET_WCDO);// [socket][wcdo] + duk_get_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [socket][wcdo][digest] + duk_get_prop_string(ctx, -1, DIGEST_WCDO); // [socket][wcdo][digest][wcdo] + if (duk_get_pointer(ctx, -1) == duk_get_pointer(ctx, -3)) + { + duk_del_prop_string(ctx, -2, DIGEST_WCDO); + } + return(0); +} +duk_ret_t ILibDuktape_httpDigest_http_request_socketEvent(duk_context *ctx) +{ + duk_push_this(ctx); // [clientRequest] + duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [clientRequest][digestClientRequest] + duk_get_prop_string(ctx, -1, DIGESTCLIENTREQUEST_DIGEST); // [clientRequest][digestClientRequest][digest] + duk_get_prop_string(ctx, 0, CLIENTREQUEST_SOCKET_WCDO); // [clientRequest][digestClientRequest][digest][wcdo] + duk_put_prop_string(ctx, -2, DIGEST_WCDO); // [clientRequest][digestClientRequest][digest] + + duk_dup(ctx, 0); // [clientRequest][digestClientRequest][digest][socket] + duk_swap_top(ctx, -2); // [clientRequest][digestClientRequest][socket][digest] + duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [clientRequest][digestClientRequest][socket] + + ILibDuktape_EventEmitter_AddOnceEx(ILibDuktape_EventEmitter_GetEmitter(ctx, 0), "end", ILibDuktape_httpDigest_http_request_socketEvent_end, 0); + return(0); +} + duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) { ILibHTTPPacket *packet; ILibWebClient_StateObject wcdo; char *username, *password; - int tmpLen = 0; char *uri = NULL; void *digestClientPtr; void *paramPtr = NULL; + void *cr_self; duk_push_current_function(ctx); duk_get_prop_string(ctx, -1, "digestClientRequest"); @@ -2494,7 +2697,8 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) if (packet->StatusCode == 401) { duk_push_heapptr(ctx, digestClientPtr); // [digestClientRequest] - if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST)) + int endCalledAlready = Duktape_GetBooleanProperty(ctx, -1, DIGESTCLIENTREQUEST_END_CALLED, 0); + if (endCalledAlready == 0 && duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST)) { duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest] duk_get_prop_string(ctx, -1, "end"); // [digestClientRequest][clientRequest][end] @@ -2508,16 +2712,14 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) duk_get_prop_string(ctx, 0, HTTP_INCOMINGMSG_WebStateObject); wcdo = (ILibWebClient_StateObject)duk_get_pointer(ctx, -1); - int freePath = 0; - char *method, *path; - char result1[33]; - char result2[33]; - char result3[33]; - void* table = ILibWebClient_Digest_GenerateTable(wcdo); - char* realm = (char*)ILibGetEntry(table, "realm", 5); - char* nonce = (char*)ILibGetEntry(table, "nonce", 5); - char* opaque = (char*)ILibGetEntry(table, "opaque", 6); - ILibDestroyHashTree(table); + duk_size_t methodLen, pathLen; + int authLen; + char *method, *path, *auth; + + void *ReservedMemory = ILibMemory_AllocateA(8000); + ILibHTTPPacket *pk = ILibCreateEmptyPacketEx(ReservedMemory); + pk->Version = "1.1"; + pk->VersionLength = 3; duk_push_this(ctx); // [clientRequest] duk_get_prop_string(ctx, -1, HTTP_CLIENTREQUEST_PARAMETER); // [clientRequest][param] @@ -2528,31 +2730,25 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) unsigned short tmpPort; uri = (char*)duk_get_string(ctx, -1); ILibParseUri(uri, &tmpHost, &tmpPort, &path, NULL); - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s", (method = "GET"), path); - util_md5hex(ILibScratchPad2, tmpLen, result2); + ILibSetDirective(pk, "GET", 3, path, -1); + free(tmpHost); - freePath = 1; + free(path); } else { - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s", (method = Duktape_GetStringPropertyValue(ctx, -1, "method", "GET")), (path = Duktape_GetStringPropertyValue(ctx, -1, "path", "/"))); - util_md5hex(ILibScratchPad2, tmpLen, result2); + method = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, "method", "GET", &methodLen); + path = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, "path", "/", &pathLen); + ILibSetDirective(pk, method, (int)methodLen, path, (int)pathLen); paramPtr = duk_get_heapptr(ctx, -1); } - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", username, realm, password); - util_md5hex(ILibScratchPad2, tmpLen, result1); + ILibWebClient_GenerateAuthenticationHeader(wcdo, pk, username, password); + auth = ILibGetHeaderLineEx(pk, "Authorization", 13, &authLen); - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", result1, nonce, result2); - util_md5hex(ILibScratchPad2, tmpLen, result3); - - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", opaque=\"%s\", response=\"%s\"", username, realm, nonce, path, opaque, result3); + duk_push_this(ctx); // [clientReqeust] + duk_get_prop_string(ctx, -1, CLIENTREQUEST_HTTP); // [clientReqeust][http] - duk_push_this(ctx); // [clientReqeust] - duk_get_prop_string(ctx, -1, CLIENTREQUEST_HTTP); // [clientReqeust][http] - if (freePath != 0) { free(path); } - - if (paramPtr == NULL) { duk_get_prop_string(ctx, -1, "get"); // [clientRequest][http][get] @@ -2566,6 +2762,7 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) duk_get_prop_string(ctx, -1, "request"); // [clientRequest][http][request] duk_swap_top(ctx, -2); // [clientRequest][request][this] duk_push_heapptr(ctx, paramPtr); // [clientRequest][request][this][options] + duk_del_prop_string(ctx, -1, "timeout"); } if(!duk_has_prop_string(ctx, -1, "headers")) @@ -2577,15 +2774,17 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) duk_get_prop_string(ctx, -1, "headers"); // [clientReqeust][get][this][options][headers] } - duk_push_lstring(ctx, ILibScratchPad2, tmpLen); // [clientReqeust][get][this][options][headers][Auth] + duk_push_lstring(ctx, auth, authLen); // [clientReqeust][get][this][options][headers][Auth] duk_put_prop_string(ctx, -2, "Authorization"); // [clientReqeust][get][this][options][headers] duk_put_prop_string(ctx, -2, "headers"); // [clientReqeust][get][this][options] duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response2, DUK_VARARGS); // [clientReqeust][get][this][options][callback] duk_push_heapptr(ctx, digestClientPtr); // [clientReqeust][get][this][options][callback][digestClientRequest] duk_put_prop_string(ctx, -2, "digestClientRequest"); // [clientReqeust][get][this][options][callback] if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digest_onResponse: Error Invoking http.get"); } - - + + duk_push_heapptr(ctx, digestClientPtr); // [clientRequest][digestClientRequest] + duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [clientRequest] + ILibDuktape_EventEmitter_AddOnceEx2(ctx, -1, "socket", ILibDuktape_httpDigest_http_request_socketEvent, 1); duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_propagateEvent, DUK_VARARGS); // [clientReqeust][EventDispatcher] duk_push_heapptr(ctx, digestClientPtr); // [clientReqeust][EventDispatcher][digestClientRequest] @@ -2612,17 +2811,87 @@ duk_ret_t ILibDuktape_httpDigest_clientRequest_response(duk_context *ctx) ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter_GetEmitter(ctx, -2), "continue", duk_get_heapptr(ctx, -1)); duk_pop(ctx); // [clientReqeust] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_propagateEvent, DUK_VARARGS); // [clientReqeust][EventDispatcher] + duk_push_heapptr(ctx, digestClientPtr); // [clientReqeust][EventDispatcher][digestClientRequest] + duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [clientReqeust][EventDispatcher] + duk_push_string(ctx, "timeout"); // [clientReqeust][EventDispatcher][eventName] + duk_put_prop_string(ctx, -2, CLIENTREQUEST_EVENT_NAME); // [clientReqeust][EventDispatcher] + ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter_GetEmitter(ctx, -2), "timeout", duk_get_heapptr(ctx, -1)); + duk_pop(ctx); // [clientReqeust] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_onDrain, DUK_VARARGS); // [clientReqeust][onDrain] duk_push_heapptr(ctx, digestClientPtr); // [clientReqeust][onDrain][digestClientRequest] duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [clientReqeust][onDrain] ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter_GetEmitter(ctx, -2), "drain", duk_get_heapptr(ctx, -1)); duk_pop(ctx); // [clientReqeust] + if (endCalledAlready != 0) + { + duk_push_heapptr(ctx, digestClientPtr); + if (duk_has_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer)) + { + duk_get_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer); // [clientReqeust][digestClientRequest][buffer] + duk_swap_top(ctx, -2); // [clientRequesat][buffer][digestClientRequest] + duk_pop(ctx); // [clientRequest][buffer] + duk_dup(ctx, -2); // [clientRequest][buffer][clientRequest] + duk_get_prop_string(ctx, -1, "write"); // [clientRequest][buffer][clientRequest][write] + duk_swap_top(ctx, -2); // [clientRequest][buffer][write][this] + duk_swap(ctx, -3, -2); // [clientRequest][write][buffer][this] + duk_swap_top(ctx, -2); // [clientReqeust][write][this][buffer] + if (duk_pcall_method(ctx, 1) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpDigest.clientRequest.onResponse(): Error calling clientRequest.write(): "); } + duk_pop(ctx); // [clientRequest] + } + else + { + duk_pop(ctx); // [clientRequest] + } + + duk_dup(ctx, -1); // [clientReqeust][clientReqeust] + duk_get_prop_string(ctx, -1, "end"); // [clientReqeust][clientReqeust][end] + duk_swap_top(ctx, -2); // [clientReqeust][end][this] + if (duk_pcall_method(ctx, 0) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "httpDigest.onResponse(): Error invoking ClientRequest.end(): "); } + duk_pop(ctx); // [clientRequest] + } + duk_push_heapptr(ctx, digestClientPtr); // [clientRequest][digestClientRequest] duk_swap_top(ctx, -2); // [digestClientRequest][clientRequest] duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [digestClientRequest] } + else + { + duk_dup(ctx, 0); + cr_self = duk_get_heapptr(ctx, -1); + duk_pop(ctx); + duk_push_heapptr(ctx, digestClientPtr); // [digestClientRequest] + duk_get_prop_string(ctx, -1, "emit"); // [digestClientRequest][emit] + duk_swap_top(ctx, -2); // [emit][this] + duk_push_string(ctx, "response"); // [emit][this][response] + ILibDuktape_http_server_PUSH_IncomingMessage(ctx, packet, NULL); // [emit][this][response][imsg] + ILibDuktape_readableStream *rs = ILibDuktape_ReadableStream_Init(ctx, ILibDuktape_httpDigest_clientRequest_IncomingMessage_PauseHandler, ILibDuktape_httpDigest_clientRequest_IncomingMessage_ResumeHandler, cr_self); + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digestClientRequest.onResponse(): "); } + duk_pop(ctx); // ... + + duk_dup(ctx, 0); // [imsg] + duk_get_prop_string(ctx, -1, "on"); // [imsg][on] + duk_swap_top(ctx, -2); // [on][this] + duk_push_string(ctx, "data"); // [on][this][data] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_OnData, DUK_VARARGS); // [on][this][data][func] + duk_push_pointer(ctx, rs); // [on][this][data][func][ptr] + duk_put_prop_string(ctx, -2, CLIENTREQUEST_IMSG_RSPTR); // [on][this][data][func] + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digestClientRequst.onResponse(): Error attaching event to clientRequest.on('data'): "); } + duk_pop(ctx); + + duk_dup(ctx, 0); // [imsg] + duk_get_prop_string(ctx, -1, "on"); // [imsg][on] + duk_swap_top(ctx, -2); // [on][this] + duk_push_string(ctx, "end"); // [on][this][end] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_OnEnd, DUK_VARARGS); // [on][this][end][func] + duk_push_pointer(ctx, rs); // [on][this][end][func][ptr] + duk_put_prop_string(ctx, -2, CLIENTREQUEST_IMSG_RSPTR); // [on][this][end][func] + if (duk_pcall_method(ctx, 2) != 0) { ILibDuktape_Process_UncaughtExceptionEx(ctx, "digestClientRequst.onResponse(): Error attaching event to clientRequest.on('end'): "); } + duk_pop(ctx); + } return(0); } duk_ret_t ILibDuktape_httpDigest_clientRequest_setter(duk_context *ctx) @@ -2673,7 +2942,31 @@ ILibTransport_DoneState ILibDuktape_httpDigest_http_request_WriteHandler(struct ILibTransport_DoneState retVal = ILibTransport_DoneState_ERROR; duk_context *ctx = stream->ctx; - duk_push_heapptr(ctx, stream->obj); // [digestClientRequest] + duk_push_heapptr(ctx, stream->obj); // [digestClientRequest] + + if (Duktape_GetBooleanProperty(ctx, -1, DIGESTCLIENTREQUEST_CONTINUE, 0) == 0) + { + duk_size_t bufLen; + char *tmpBuffer; + + if (duk_has_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer)) + { + duk_get_prop_string(ctx, -1, DIGESTCLIENTREQUEST_TmpBuffer); // [digestClientRequest][oldBuffer] + bufLen = duk_get_length(ctx, -1); + duk_resize_buffer(ctx, -1, bufLen + bufferLen); + tmpBuffer = (char*)Duktape_GetBuffer(ctx, -1, &bufLen); + memcpy_s(tmpBuffer + bufLen - (size_t)bufferLen, (size_t)bufferLen, buffer, (size_t)bufferLen); + duk_pop(ctx); // [digestClientRequest] + } + else + { + duk_push_dynamic_buffer(ctx, (duk_size_t)bufferLen); // [digestClientRequest][buffer] + tmpBuffer = (char*)Duktape_GetBuffer(ctx, -1, &bufLen); + duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_TmpBuffer); // [digestClientRequest] + memcpy_s(tmpBuffer, bufLen, buffer, (size_t)bufferLen); + } + } + if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST)) { duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest] @@ -2710,6 +3003,9 @@ void ILibDuktape_httpDigest_http_request_DoneHandler(struct ILibDuktape_Writable duk_context *ctx = stream->ctx; duk_push_heapptr(ctx, stream->obj); // [digestClientRequest] + duk_push_true(ctx); + duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_END_CALLED); + if (duk_has_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST)) { duk_get_prop_string(ctx, -1, DIGEST_CLIENT_REQUEST); // [digestClientRequest][clientRequest] @@ -2722,16 +3018,33 @@ void ILibDuktape_httpDigest_http_request_DoneHandler(struct ILibDuktape_Writable } duk_pop(ctx); // ... } +duk_ret_t ILibDuktape_httpDigest_http_request_continueOccured(duk_context *ctx) +{ + duk_push_this(ctx); // [digestClientRequest] + duk_push_true(ctx); + duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_CONTINUE); + return(0); +} + duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx) { int nargs = duk_get_top(ctx); void *clientRequest = NULL; ILibDuktape_EventEmitter *emitter; ILibDuktape_EventEmitter *crEmitter; + char *username = NULL; + char *password = NULL; duk_push_current_function(ctx); // [func] duk_get_prop_string(ctx, -1, "isGet"); // [func][isGet] duk_push_this(ctx); // [func][isGet][digest] + + duk_get_prop_string(ctx, -1, DIGEST_USERNAME); // [func][isGet][digest][username] + duk_get_prop_string(ctx, -2, DIGEST_PASSWORD); // [func][isGet][digest][username][password] + username = (char*)duk_get_string(ctx, -2); + password = (char*)duk_get_string(ctx, -1); + duk_pop_2(ctx); // [func][isGet][digest] + duk_get_prop_string(ctx, -1, HTTP_DIGEST); // [func][isGet][digest][http] if (duk_get_int(ctx, -3) != 0) { @@ -2744,6 +3057,46 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx) duk_swap_top(ctx, -2); // [func][isGet][digest][get/request][this] duk_dup(ctx, 0); // [func][isGet][digest][get/request][this][param1] + // + // Check to see if we can insert Auth Headers, in case we already authenticated + // + if (duk_has_prop_string(ctx, -4, DIGEST_WCDO)) + { + void *wcdo = NULL; + ILibHTTPPacket *pk = ILibCreateEmptyPacketEx(ILibMemory_AllocateA(4096)); + duk_size_t methodLen, pathLen; + char *method, *path; + pk->Version = "1.1"; + pk->VersionLength = 3; + method = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, "method", "GET", &methodLen); + path = (char*)Duktape_GetStringPropertyValueEx(ctx, -1, "path", "/", &pathLen); + ILibSetDirective(pk, method, (int)methodLen, path, (int)pathLen); + + duk_get_prop_string(ctx, -4, DIGEST_WCDO); + wcdo = duk_get_pointer(ctx, -1); + duk_pop(ctx); + + ILibWebClient_GenerateAuthenticationHeader(wcdo, pk, username, password); + char *auth = ILibGetHeaderLine(pk, "Authorization", 13); + if (auth != NULL) + { + if (duk_has_prop_string(ctx, -1, "headers")) // [func][isGet][digest][get/request][this][param1] + { + duk_get_prop_string(ctx, -1, "headers"); // [func][isGet][digest][get/request][this][param1][headers] + } + else + { + duk_push_object(ctx); // [func][isGet][digest][get/request][this][param1][headers] + duk_dup(ctx, -1); // [func][isGet][digest][get/request][this][param1][headers][headers] + duk_put_prop_string(ctx, -3, "headers"); // [func][isGet][digest][get/request][this][param1][headers] + } + duk_push_string(ctx, auth); // [func][isGet][digest][get/request][this][param1][headers][auth] + duk_put_prop_string(ctx, -2, "Authorization"); // [func][isGet][digest][get/request][this][param1][headers] + duk_pop(ctx); // [func][isGet][digest][get/request][this][param1] + } + } + + if (duk_pcall_method(ctx, 1) != 0) { duk_throw(ctx); return(DUK_RET_ERROR); } // [clientRequest] clientRequest = duk_get_heapptr(ctx, -1); @@ -2755,6 +3108,8 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx) duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_response, DUK_VARARGS); // [once][this][response][method] duk_push_object(ctx); // [once][this][response][method][digest-clientRequest] + duk_push_this(ctx); // [once][this][response][method][digest-clientRequest][digest] + duk_put_prop_string(ctx, -2, DIGESTCLIENTREQUEST_DIGEST); // [once][this][response][method][digest-clientRequest] duk_push_heapptr(ctx, clientRequest); // [once][this][response][method][digest-clientRequest][clientRequest] duk_dup(ctx, -2); // [once][this][response][method][digest-clientRequest][clientRequest][digest-clientRequest] duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [once][this][response][method][digest-clientRequest][clientRequest] @@ -2764,7 +3119,11 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx) ILibDuktape_EventEmitter_CreateEventEx(emitter, "error"); ILibDuktape_EventEmitter_CreateEventEx(emitter, "upgrade"); ILibDuktape_EventEmitter_CreateEventEx(emitter, "continue"); - + ILibDuktape_EventEmitter_CreateEventEx(emitter, "timeout"); + + ILibDuktape_EventEmitter_AddOnceEx(emitter, "continue", ILibDuktape_httpDigest_http_request_continueOccured, 0); + ILibDuktape_EventEmitter_AddOnceEx(crEmitter, "socket", ILibDuktape_httpDigest_http_request_socketEvent, 1); + ILibDuktape_WritableStream_Init(ctx, ILibDuktape_httpDigest_http_request_WriteHandler, ILibDuktape_httpDigest_http_request_DoneHandler, NULL); if (nargs > 1 && duk_is_function(ctx, 1)) @@ -2803,6 +3162,14 @@ duk_ret_t ILibDuktape_httpDigest_http_request(duk_context *ctx) ILibDuktape_EventEmitter_AddOnce(crEmitter, "continue", duk_get_heapptr(ctx, -1)); // [digestClientRequest][EventDispatcher] duk_pop(ctx); // [digestClientRequest] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_propagateEvent, DUK_VARARGS); // [digestClientRequest][EventDispatcher] + duk_dup(ctx, -2); // [digestClientRequest][EventDispatcher][digestClientRequest] + duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [digestClientRequest][EventDispatcher] + duk_push_string(ctx, "timeout"); // [digestClientRequest][EventDispatcher][eventName] + duk_put_prop_string(ctx, -2, CLIENTREQUEST_EVENT_NAME); // [digestClientRequest][EventDispatcher] + ILibDuktape_EventEmitter_AddOnce(crEmitter, "timeout", duk_get_heapptr(ctx, -1)); // [digestClientRequest][EventDispatcher] + duk_pop(ctx); // [digestClientRequest] + duk_push_c_function(ctx, ILibDuktape_httpDigest_clientRequest_onDrain, DUK_VARARGS); // [digestClientRequest][onDrain] duk_dup(ctx, -2); // [digestClientRequest][onDrain][digestClientRequest] duk_put_prop_string(ctx, -2, DIGEST_CLIENT_REQUEST); // [digestClientRequest][onDrain] diff --git a/microscript/ILibDuktape_net.c b/microscript/ILibDuktape_net.c index 4b45e62..e08f74c 100644 --- a/microscript/ILibDuktape_net.c +++ b/microscript/ILibDuktape_net.c @@ -24,6 +24,7 @@ limitations under the License. #include "microstack/ILibAsyncSocket.h" #include "microstack/ILibCrypto.h" #include "microstack/ILibAsyncServerSocket.h" +#include "microstack/ILibRemoteLogging.h" typedef struct ILibDuktape_net_socket { @@ -264,6 +265,7 @@ duk_ret_t ILibDuktape_net_socket_address(duk_context *ctx) duk_push_string(ctx, ILibInet_ntop2((struct sockaddr*)&local, ILibScratchPad, sizeof(ILibScratchPad))); duk_put_prop_string(ctx, -2, "address"); + return 1; } @@ -918,6 +920,29 @@ duk_ret_t ILibDuktape_net_server_Finalizer(duk_context *ctx) return 0; } +duk_ret_t ILibDuktape_net_server_address(duk_context *ctx) +{ + duk_push_this(ctx); // [server] + duk_get_prop_string(ctx, -1, ILibDuktape_net_Server_buffer); // [server][buffer] + ILibDuktape_net_server *server = (ILibDuktape_net_server*)Duktape_GetBuffer(ctx, -1, NULL); + struct sockaddr_in6 local; + memset(&local, 0, sizeof(struct sockaddr_in6)); + + ILibAsyncServerSocket_GetLocal(server->server, (struct sockaddr*)&local, sizeof(struct sockaddr_in6)); + if (local.sin6_family == AF_UNSPEC) { return(ILibDuktape_Error(ctx, "net.server.address(): call to getsockname() failed")); } + + duk_push_object(ctx); + duk_push_string(ctx, local.sin6_family == AF_INET6 ? "IPv6" : "IPv4"); + duk_put_prop_string(ctx, -2, "family"); + + duk_push_int(ctx, (int)ntohs(local.sin6_port)); + duk_put_prop_string(ctx, -2, "port"); + + duk_push_string(ctx, ILibRemoteLogging_ConvertAddress((struct sockaddr*)&local)); + duk_put_prop_string(ctx, -2, "address"); + + return(1); +} duk_ret_t ILibDuktape_net_createServer(duk_context *ctx) { int nargs = duk_get_top(ctx); @@ -939,6 +964,7 @@ duk_ret_t ILibDuktape_net_createServer(duk_context *ctx) ILibDuktape_EventEmitter_CreateEvent(server->emitter, "listening", &(server->OnListening)); ILibDuktape_CreateInstanceMethod(ctx, "listen", ILibDuktape_net_server_listen, DUK_VARARGS); + ILibDuktape_CreateInstanceMethod(ctx, "address", ILibDuktape_net_server_address, 0); ILibDuktape_CreateFinalizer(ctx, ILibDuktape_net_server_Finalizer); for (i = 0; i < 2 && i < nargs; ++i) diff --git a/microscript/ILibduktape_EventEmitter.c b/microscript/ILibduktape_EventEmitter.c index 8f0f2ed..b575f85 100644 --- a/microscript/ILibduktape_EventEmitter.c +++ b/microscript/ILibduktape_EventEmitter.c @@ -261,6 +261,39 @@ int ILibDuktape_EventEmitter_AddOnce(ILibDuktape_EventEmitter *emitter, char *ev return retVal; } +int ILibDuktape_EventEmitter_AddOnceEx2(duk_context *ctx, duk_idx_t idx, char *eventName, duk_c_function func, duk_idx_t funcArgs) +{ + int retVal = 1; + + duk_dup(ctx, idx); // [obj] + ILibDuktape_Push_ObjectStash(ctx); // [obj][stash] + duk_push_c_function(ctx, func, funcArgs); // [obj][stash][func] + duk_dup(ctx, -1); // [obj][stash][func][func] + duk_put_prop_string(ctx, -3, Duktape_GetStashKey(duk_get_heapptr(ctx, -1))); // [obj][stash][func] + duk_get_prop_string(ctx, -3, "once"); // [obj][stash][func][once] + duk_swap(ctx, -3, -1); // [obj][once][func][stash] + duk_swap(ctx, -4, -3); // [once][this][func][stash] + duk_pop(ctx); // [once][this][func] + duk_push_string(ctx, eventName); // [once][this][func][eventName] + duk_swap_top(ctx, -2); // [once][this][eventName][func] + retVal = duk_pcall_method(ctx, 2); // [retVal] + duk_pop(ctx); // ... + + return(retVal); +} +int ILibDuktape_EventEmitter_AddOnceEx(ILibDuktape_EventEmitter *emitter, char *eventName, duk_c_function func, duk_idx_t funcArgs) +{ + int retVal = 1; + + duk_push_heapptr(emitter->ctx, emitter->object); // [obj] + ILibDuktape_Push_ObjectStash(emitter->ctx); // [obj][stash] + + duk_push_c_function(emitter->ctx, func, funcArgs); // [obj][stash][func] + retVal = ILibDuktape_EventEmitter_AddOnce(emitter, eventName, duk_get_heapptr(emitter->ctx, -1)); + duk_put_prop_string(emitter->ctx, -2, Duktape_GetStashKey(duk_get_heapptr(emitter->ctx, -1))); // [obj][stash] + duk_pop_2(emitter->ctx); // ... + return(retVal); +} int ILibDuktape_EventEmitter_AddOn(ILibDuktape_EventEmitter *emitter, char *eventName, void *heapptr) { int retVal = 1; diff --git a/microstack/ILibAsyncServerSocket.c b/microstack/ILibAsyncServerSocket.c index 5ac8a0a..5579632 100644 --- a/microstack/ILibAsyncServerSocket.c +++ b/microstack/ILibAsyncServerSocket.c @@ -715,6 +715,14 @@ ILibAsyncServerSocket_ServerModule ILibCreateAsyncServerSocketModuleWithMemory(v return RetVal; } +void ILibAsyncServerSocket_GetLocal(ILibAsyncServerSocket_ServerModule ServerSocketModule, struct sockaddr* addr, size_t addrLen) +{ + socklen_t ssize = (socklen_t)addrLen; + if (getsockname(((struct ILibAsyncServerSocketModule*)ServerSocketModule)->ListenSocket, addr, &ssize) != 0) + { + ((struct sockaddr_in6*)addr)->sin6_family = AF_UNSPEC; + } +} /*! \fn ILibAsyncServerSocket_GetPortNumber(ILibAsyncServerSocket_ServerModule ServerSocketModule) \brief Returns the port number the server is bound to \param ServerSocketModule The ILibAsyncServer to query diff --git a/microstack/ILibAsyncServerSocket.h b/microstack/ILibAsyncServerSocket.h index 763deae..3981160 100644 --- a/microstack/ILibAsyncServerSocket.h +++ b/microstack/ILibAsyncServerSocket.h @@ -134,6 +134,7 @@ void ILibAsyncServerSocket_StopListening(ILibAsyncServerSocket_ServerModule modu void ILibAsyncServerSocket_ResumeListening(ILibAsyncServerSocket_ServerModule module); unsigned short ILibAsyncServerSocket_GetPortNumber(ILibAsyncServerSocket_ServerModule ServerSocketModule); +void ILibAsyncServerSocket_GetLocal(ILibAsyncServerSocket_ServerModule ServerSocketModule, struct sockaddr* addr, size_t addrLen); /*! \def ILibAsyncServerSocket_Send \brief Sends data onto the TCP stream diff --git a/microstack/ILibAsyncSocket.c b/microstack/ILibAsyncSocket.c index cdb87e6..2497db5 100644 --- a/microstack/ILibAsyncSocket.c +++ b/microstack/ILibAsyncSocket.c @@ -962,7 +962,7 @@ void ILibAsyncSocket_ConnectToProxy(void* socketModule, struct sockaddr *localIn ILibAsyncSocket_ConnectTo(socketModule, localInterface, remoteAddress, InterruptPtr, user); } #endif - +#ifndef MICROSTACK_NOTLS ILibAsyncSocket_SendStatus ILibAsyncSocket_ProcessEncryptedBuffer(ILibAsyncSocketModule *Reader) { int j; @@ -1019,7 +1019,7 @@ ILibAsyncSocket_SendStatus ILibAsyncSocket_ProcessEncryptedBuffer(ILibAsyncSocke sem_post(&(Reader->SendLock)); return retVal; } - +#endif // // Internal method called when data is ready to be processed on an ILibAsyncSocket // @@ -1342,10 +1342,10 @@ void ILibAsyncSocket_SetUser3(ILibAsyncSocket_SocketModule socketModule, int use ((struct ILibAsyncSocketModule*)socketModule)->user3 = user3; } -void ILibAsyncSocket_SetTimeout(ILibAsyncSocket_SocketModule socketModule, int timeoutSeconds, ILibAsyncSocket_TimeoutHandler timeoutHandler) +void ILibAsyncSocket_SetTimeoutEx(ILibAsyncSocket_SocketModule socketModule, int timeoutMilliseconds, ILibAsyncSocket_TimeoutHandler timeoutHandler) { struct ILibAsyncSocketModule *module = (struct ILibAsyncSocketModule*)socketModule; - module->timeout_milliSeconds = timeoutSeconds * 1000; + module->timeout_milliSeconds = timeoutMilliseconds; module->timeout_handler = timeoutHandler; } @@ -1848,7 +1848,11 @@ void ILibAsyncSocket_PostSelect(void* socketModule, int slct, fd_set *readset, f if (module->PendingSend_Head == NULL && bytesSent != -1) { TriggerSendOK = 1; } SEM_TRACK(AsyncSocket_TrackUnLock("ILibAsyncSocket_PostSelect", 2, module);) sem_post(&(module->SendLock)); +#ifndef MICROSTACK_NOTLS if (TriggerSendOK != 0 && (module->ssl == NULL || module->SSLConnect != 0)) +#else + if (TriggerSendOK != 0) +#endif { module->OnSendOK(module, module->user); if (module->Transport.SendOkPtr != NULL) { module->Transport.SendOkPtr(module); } diff --git a/microstack/ILibAsyncSocket.h b/microstack/ILibAsyncSocket.h index 3a99616..9afac60 100644 --- a/microstack/ILibAsyncSocket.h +++ b/microstack/ILibAsyncSocket.h @@ -234,7 +234,8 @@ int ILibAsyncSocket_IsIPv6LinkLocal(struct sockaddr *LocalAddress); int ILibAsyncSocket_IsModuleIPv6LinkLocal(ILibAsyncSocket_SocketModule module); typedef void(*ILibAsyncSocket_TimeoutHandler)(ILibAsyncSocket_SocketModule module, void *user); -void ILibAsyncSocket_SetTimeout(ILibAsyncSocket_SocketModule module, int timeoutSeconds, ILibAsyncSocket_TimeoutHandler timeoutHandler); +void ILibAsyncSocket_SetTimeoutEx(ILibAsyncSocket_SocketModule module, int timeoutMilliseconds, ILibAsyncSocket_TimeoutHandler timeoutHandler); +#define ILibAsyncSocket_SetTimeout(module, timeoutSeconds, timeoutHandler) ILibAsyncSocket_SetTimeoutEx(module, timeoutSeconds*1000, timeoutHandler) #ifndef MICROSTACK_NOTLS X509 *ILibAsyncSocket_SslGetCert(ILibAsyncSocket_SocketModule socketModule); diff --git a/microstack/ILibParsers.c b/microstack/ILibParsers.c index 56509b1..e5ba62d 100644 --- a/microstack/ILibParsers.c +++ b/microstack/ILibParsers.c @@ -210,6 +210,7 @@ struct HashNode_Root { struct HashNode *Root; int CaseInSensitive; + void *Reserved; sem_t LOCK; }; struct HashNode @@ -1063,7 +1064,30 @@ typedef struct ILibBaseChain }ILibBaseChain; const int ILibMemory_CHAIN_CONTAINERSIZE = sizeof(ILibBaseChain); +void* ILibMemory_AllocateA_InitMem(void *buffer, size_t bufferLen) +{ + char *retVal = ((char*)buffer + 8 + sizeof(void*)); + + ((int*)(retVal - 4))[0] = (int)(bufferLen - 8 - sizeof(void*)); // Size + ((void**)(retVal - 4 - sizeof(void*)))[0] = retVal; // Next + ((int*)buffer)[0] = (int)bufferLen; // RawSize + memset(retVal, 0, bufferLen - 8 - sizeof(void*)); + return((void*)retVal); +} +void* ILibMemory_AllocateA_Get(void *buffer, size_t sz) +{ + char *retVal = NULL; + + if (ILibMemory_AllocateA_Size(buffer) > (int)sz) + { + retVal = ILibMemory_AllocateA_Next(buffer); + ILibMemory_AllocateA_Size(buffer) -= (int)sz; + ILibMemory_AllocateA_Next(buffer) = (char*)ILibMemory_AllocateA_Next(buffer) + (int)sz; + } + + return(retVal); +} void* ILibMemory_Allocate(int containerSize, int extraMemorySize, void** allocatedContainer, void **extraMemory) { char* retVal = (char*)malloc(containerSize + extraMemorySize + (extraMemorySize > 0 ? 4 : 0)); @@ -3671,26 +3695,47 @@ void ILibHashTree_GetValueEx(void *tree_enumerator, char **key, int *keyLength, \brief Creates an empty ILibHashTree, whose keys are case sensitive. \return An empty ILibHashTree */ -void* ILibInitHashTree() +void* ILibInitHashTreeEx(void *ReservedMemory) { struct HashNode_Root *Root; struct HashNode *RetVal; - if ((Root = (struct HashNode_Root*)malloc(sizeof(struct HashNode_Root))) == NULL) ILIBCRITICALEXIT(254); - if ((RetVal = (struct HashNode*)malloc(sizeof(struct HashNode))) == NULL) ILIBCRITICALEXIT(254); - memset(RetVal, 0, sizeof(struct HashNode)); - memset(Root, 0, sizeof(struct HashNode_Root)); + + if (ReservedMemory != NULL) + { + if (ILibMemory_AllocateA_Size(ReservedMemory) > sizeof(struct HashNode_Root) + sizeof(struct HashNode)) + { + Root = (struct HashNode_Root*)ILibMemory_AllocateA_Get(ReservedMemory, sizeof(struct HashNode_Root)); + RetVal = (struct HashNode*)ILibMemory_AllocateA_Get(ReservedMemory, sizeof(struct HashNode)); + if (Root == NULL || RetVal == NULL) { ILIBCRITICALEXIT(254); } + memset(RetVal, 0, sizeof(struct HashNode)); + memset(Root, 0, sizeof(struct HashNode_Root)); + Root->Reserved = ReservedMemory; + } + else + { + return(NULL); + } + } + else + { + if ((Root = (struct HashNode_Root*)malloc(sizeof(struct HashNode_Root))) == NULL) ILIBCRITICALEXIT(254); + if ((RetVal = (struct HashNode*)malloc(sizeof(struct HashNode))) == NULL) ILIBCRITICALEXIT(254); + memset(RetVal, 0, sizeof(struct HashNode)); + memset(Root, 0, sizeof(struct HashNode_Root)); + } + Root->Root = RetVal; - sem_init(&(Root->LOCK), 0, 1); + if (ReservedMemory == NULL) { sem_init(&(Root->LOCK), 0, 1); } return(Root); } /*! \fn void* ILibInitHashTree_CaseInSensitive() \brief Creates an empty ILibHashTree, whose keys are case insensitive. \return An empty ILibHashTree */ -void* ILibInitHashTree_CaseInSensitive() +void* ILibInitHashTree_CaseInSensitiveEx(void *ReservedMemory) { - struct HashNode_Root *Root = (struct HashNode_Root*)ILibInitHashTree(); - Root->CaseInSensitive = 1; + struct HashNode_Root *Root = (struct HashNode_Root*)ILibInitHashTreeEx(ReservedMemory); + if (Root != NULL) { Root->CaseInSensitive = 1; } return(Root); } @@ -3865,11 +3910,11 @@ struct HashNode* ILibFindEntry(void *hashtree, void *key, int keylength, int cre // // If there is no match, and the create flag is set, we need to create an entry // - if ((current->Next = (struct HashNode*)malloc(sizeof(struct HashNode))) == NULL) ILIBCRITICALEXIT(254); + if ((current->Next = (struct HashNode*)(root->Reserved == NULL ? (malloc(sizeof(struct HashNode))) : ILibMemory_AllocateA_Get(root->Reserved, sizeof(struct HashNode)))) == NULL) ILIBCRITICALEXIT(254); memset(current->Next,0,sizeof(struct HashNode)); current->Next->Prev = current; current->Next->KeyHash = HashValue; - if ((current->Next->KeyValue = (void*)malloc(keylength + 1)) == NULL) ILIBCRITICALEXIT(254); + if ((current->Next->KeyValue = (root->Reserved == NULL ? (void*)malloc(keylength + 1) : ILibMemory_AllocateA_Get(root->Reserved, keylength + 1))) == NULL) ILIBCRITICALEXIT(254); memcpy_s(current->Next->KeyValue, keylength + 1, key ,keylength); current->Next->KeyValue[keylength] = 0; current->Next->KeyLength = keylength; @@ -5171,17 +5216,18 @@ ILibParseUriResult ILibParseUriEx (const char* URI, size_t URILen, char** Addr, \brief Creates an empty packetheader structure \return An empty packet */ -struct packetheader *ILibCreateEmptyPacket() +struct packetheader *ILibCreateEmptyPacketEx(void *ReservedMemory) { - struct packetheader *RetVal; - if ((RetVal = (struct packetheader*)malloc(sizeof(struct packetheader))) == NULL) ILIBCRITICALEXIT(254); + ILibHTTPPacket *RetVal = ReservedMemory == NULL ? (ILibHTTPPacket*)malloc(sizeof(ILibHTTPPacket)) : (ILibHTTPPacket*)ILibMemory_AllocateA_Get(ReservedMemory, sizeof(ILibHTTPPacket)); + if (RetVal == NULL) { ILIBCRITICALEXIT(254); } memset(RetVal,0,sizeof(struct packetheader)); + RetVal->ReservedMemory = ReservedMemory; RetVal->UserAllocStrings = -1; RetVal->StatusCode = -1; RetVal->Version = "1.0"; RetVal->VersionLength = 3; - RetVal->HeaderTable = ILibInitHashTree_CaseInSensitive(); + RetVal->HeaderTable = ILibInitHashTree_CaseInSensitiveEx(ReservedMemory); return RetVal; } @@ -5285,16 +5331,32 @@ void ILibSetDirective(struct packetheader *packet, char* Directive, int Directiv if (DirectiveLength < 0)DirectiveLength = (int)strnlen_s(Directive, 255); if (DirectiveObjLength < 0)DirectiveObjLength = (int)strnlen_s(DirectiveObj, 255); - if ((packet->Directive = (char*)malloc(DirectiveLength+1)) == NULL) ILIBCRITICALEXIT(254); + if (packet->ReservedMemory != NULL) + { + if (ILibMemory_AllocateA_Size(packet->ReservedMemory) > (DirectiveLength + DirectiveObjLength + 2)) + { + packet->Directive = (char*)ILibMemory_AllocateA_Get(packet->ReservedMemory, (size_t)DirectiveLength + 1); + packet->DirectiveObj = (char*)ILibMemory_AllocateA_Get(packet->ReservedMemory, (size_t)DirectiveObjLength + 1); + } + else + { + ILIBCRITICALEXIT(254); + } + } + else + { + if ((packet->Directive = (char*)malloc(DirectiveLength + 1)) == NULL) ILIBCRITICALEXIT(254); + if ((packet->DirectiveObj = (char*)malloc(DirectiveObjLength + 1)) == NULL) ILIBCRITICALEXIT(254); + packet->UserAllocStrings = -1; + } + memcpy_s(packet->Directive, DirectiveLength + 1, Directive,DirectiveLength); packet->Directive[DirectiveLength] = '\0'; packet->DirectiveLength = DirectiveLength; - - if ((packet->DirectiveObj = (char*)malloc(DirectiveObjLength+1)) == NULL) ILIBCRITICALEXIT(254); + memcpy_s(packet->DirectiveObj, DirectiveObjLength + 1, DirectiveObj, DirectiveObjLength); packet->DirectiveObj[DirectiveObjLength] = '\0'; packet->DirectiveObjLength = DirectiveObjLength; - packet->UserAllocStrings = -1; } void ILibHTTPPacket_Stash_Put(ILibHTTPPacket *packet, char* key, int keyLen, void *data) @@ -5335,26 +5397,41 @@ void ILibAddHeaderLine(struct packetheader *packet, const char* FieldName, int F struct packetheader_field_node *node; if (FieldNameLength < 0) { FieldNameLength = (int)strnlen_s(FieldName, 255); } if (FieldDataLength < 0) { FieldDataLength = (int)strnlen_s(FieldData, 255); } + if (packet->ReservedMemory != NULL) + { + if (ILibMemory_AllocateA_Size(packet->ReservedMemory) > (sizeof(struct packetheader_field_node) + FieldNameLength + FieldDataLength + 2)) + { + node = (packetheader_field_node*)ILibMemory_AllocateA_Get(packet->ReservedMemory, sizeof(packetheader_field_node)); + node->Field = (char*)ILibMemory_AllocateA_Get(packet->ReservedMemory, (size_t)FieldNameLength + 1); + node->FieldData = (char*)ILibMemory_AllocateA_Get(packet->ReservedMemory, (size_t)FieldDataLength + 1); + } + else + { + return; + } + } + else + { + // + // Create the Header Node + // + if ((node = (struct packetheader_field_node*)malloc(sizeof(struct packetheader_field_node))) == NULL) ILIBCRITICALEXIT(254); + node->UserAllocStrings = -1; + if ((node->Field = (char*)malloc(FieldNameLength + 1)) == NULL) ILIBCRITICALEXIT(254); + if ((node->FieldData = (char*)malloc(FieldDataLength + 1)) == NULL) ILIBCRITICALEXIT(254); + } - // - // Create the Header Node - // - if ((node = (struct packetheader_field_node*)malloc(sizeof(struct packetheader_field_node))) == NULL) ILIBCRITICALEXIT(254); - node->UserAllocStrings = -1; - if ((node->Field = (char*)malloc(FieldNameLength+1)) == NULL) ILIBCRITICALEXIT(254); memcpy_s(node->Field, FieldNameLength + 1, (char*)FieldName, FieldNameLength); node->Field[FieldNameLength] = '\0'; node->FieldLength = FieldNameLength; - if ((node->FieldData = (char*)malloc(FieldDataLength+1)) == NULL) ILIBCRITICALEXIT(254); memcpy_s(node->FieldData, FieldDataLength + 1, (char*)FieldData, FieldDataLength); node->FieldData[FieldDataLength] = '\0'; node->FieldDataLength = FieldDataLength; - node->NextField = NULL; - ILibAddEntryEx(packet->HeaderTable,node->Field,node->FieldLength,node->FieldData,node->FieldDataLength); - + if (packet->HeaderTable != NULL) { ILibAddEntryEx(packet->HeaderTable, node->Field, node->FieldLength, node->FieldData, node->FieldDataLength); } + // // And attach it to the linked list // diff --git a/microstack/ILibParsers.h b/microstack/ILibParsers.h index 001a093..d7e695f 100644 --- a/microstack/ILibParsers.h +++ b/microstack/ILibParsers.h @@ -224,7 +224,7 @@ long ILibGetTimeStamp(); #endif #ifndef strnlen_s -#define strnlen_s(source, maxCount) (strlen(source) < (maxCount) ? strlen(source) : (maxCount)) +#define strnlen_s(source, maxCount) (strlen(source) < (maxCount) ? strlen(source) : ((size_t)(maxCount))) #endif #ifndef sprintf_s @@ -233,10 +233,6 @@ long ILibGetTimeStamp(); int sprintf_s(void *dest, size_t destSize, char *format, ...); #endif -#ifndef strnlen_s -#define strnlen_s(source, maxLen) strnlen(source, maxLen) -#endif - #endif @@ -305,6 +301,18 @@ int ILibIsRunningOnChainThread(void* chain); ILibChain_Link* ILibChain_Link_Allocate(int structSize, int extraMemorySize); int ILibChain_Link_GetExtraMemorySize(ILibChain_Link* link); +#ifdef WIN32 + #define ILibMemory_AllocateA(bufferLen) ILibMemory_AllocateA_InitMem(_alloca(8+bufferLen+sizeof(void*)), (size_t)(8+bufferLen+sizeof(void*))) +#else + #define ILibMemory_AllocateA(bufferLen) ILibMemory_AllocateA_InitMem(alloca(8+bufferLen+sizeof(void*)), (size_t)(8+bufferLen+sizeof(void*))) +#endif + #define ILibMemory_AllocateA_Size(buffer) (((int*)((char*)(buffer)-4))[0]) + #define ILibMemory_AllocateA_Next(buffer) (((void**)((char*)(buffer)-4-sizeof(void*)))[0]) + #define ILibMemory_AllocateA_Raw(buffer) ((void*)((char*)(buffer)-4-sizeof(void*)-4)) + #define ILibMemory_AllocateA_RawSize(buffer) (((int*)((char*)(buffer)-4-sizeof(void*)-4))[0]) + + void* ILibMemory_AllocateA_Get(void *buffer, size_t sz); + void* ILibMemory_AllocateA_InitMem(void *buffer, size_t bufferLen); void* ILibMemory_Allocate(int containerSize, int extraMemorySize, void** allocatedContainer, void **extraMemory); int ILibMemory_GetExtraMemorySize(void* extraMemory); ILibExportMethod void* ILibMemory_GetExtraMemory(void *container, int containerSize); @@ -534,6 +542,7 @@ int ILibIsRunningOnChainThread(void* chain); */ void *Reserved; + char *ReservedMemory; int DirectiveObjLength; /*! \var StatusCode @@ -1049,9 +1058,10 @@ int ILibIsRunningOnChainThread(void* chain); \b Note: Duplicate key entries will be overwritten. *@{ */ - - void* ILibInitHashTree(); - void* ILibInitHashTree_CaseInSensitive(); + #define ILibInitHashTree() ILibInitHashTreeEx(NULL) + void* ILibInitHashTreeEx(void *ReservedMemory); + void* ILibInitHashTree_CaseInSensitiveEx(void *ReservedMemory); + #define ILibInitHashTree_CaseInSensitive() ILibInitHashTree_CaseInSensitiveEx(NULL) void ILibDestroyHashTree(void *tree); int ILibHasEntry(void *hashtree, char* key, int keylength); void ILibAddEntry(void* hashtree, char* key, int keylength, void *value); @@ -1187,7 +1197,8 @@ int ILibIsRunningOnChainThread(void* chain); /* Packet Methods */ - struct packetheader *ILibCreateEmptyPacket(); + struct packetheader *ILibCreateEmptyPacketEx(void *ReservedMemory); + #define ILibCreateEmptyPacket() ILibCreateEmptyPacketEx(NULL) void ILibAddHeaderLine(struct packetheader *packet, const char* FieldName, int FieldNameLength, const char* FieldData, int FieldDataLength); void ILibDeleteHeaderLine(struct packetheader *packet, char* FieldName, int FieldNameLength); void ILibHTTPPacket_Stash_Put(ILibHTTPPacket *packet, char* key, int keyLen, void *data); diff --git a/microstack/ILibProcessPipe.c b/microstack/ILibProcessPipe.c index 37b40c4..579140d 100644 --- a/microstack/ILibProcessPipe.c +++ b/microstack/ILibProcessPipe.c @@ -109,6 +109,7 @@ typedef struct ILibProcessPipe_Process_Object ILibProcessPipe_Process_ExitHandler exitHandler; #ifdef WIN32 HANDLE hProcess; + int hProcess_needAdd; #endif void *chain; }ILibProcessPipe_Process_Object; @@ -153,6 +154,7 @@ ILibProcessPipe_Pipe ILibProcessPipe_Process_GetStdOut(ILibProcessPipe_Process p } #ifdef WIN32 +BOOL ILibProcessPipe_Process_OnExit(HANDLE event, void* user); typedef struct ILibProcessPipe_WaitHandle { ILibProcessPipe_Manager_Object *parent; @@ -203,6 +205,7 @@ void ILibProcessPipe_WaitHandle_AddEx(ILibProcessPipe_Manager mgr, ILibProcessPi { // We're on the same thread, so we can just add it in ILibLinkedList_AddTail(manager->ActivePipes, waitHandle); + SetEvent(manager->updateEvent); } else @@ -222,7 +225,6 @@ void ILibProcessPipe_WaitHandle_Add(ILibProcessPipe_Manager mgr, HANDLE event, v waitHandle->user = user; waitHandle->callback = callback; - ILibProcessPipe_WaitHandle_AddEx(mgr, waitHandle); } @@ -740,9 +742,9 @@ void ILibProcessPipe_Pipe_SwapBuffers(ILibProcessPipe_Pipe obj, char* newBuffer, ILibProcessPipe_PipeObject *pipeObject = (ILibProcessPipe_PipeObject*)obj; *oldBuffer = pipeObject->buffer; - *oldBufferLen = pipeObject->bufferSize; - *oldBufferReadOffset = pipeObject->readOffset; - *oldBufferTotalBytesRead = pipeObject->totalRead; + if (oldBufferLen != NULL) { *oldBufferLen = pipeObject->bufferSize; } + if (oldBufferReadOffset != NULL) { *oldBufferReadOffset = pipeObject->readOffset; } + if (oldBufferTotalBytesRead != NULL) { *oldBufferTotalBytesRead = pipeObject->totalRead; } pipeObject->buffer = newBuffer; pipeObject->bufferSize = newBufferLen; @@ -1129,6 +1131,11 @@ void ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Pipe pipeObject) else { ILibProcessPipe_Pipe_ResumeEx(p); + if (p->mProcess != NULL && p->mProcess->hProcess_needAdd != 0) + { + p->mProcess->hProcess_needAdd = 0; + ILibProcessPipe_WaitHandle_Add(p->manager, p->mProcess->hProcess, p->mProcess, ILibProcessPipe_Process_OnExit); + } } #else ILibProcessPipe_Pipe_ResumeEx(p); @@ -1231,6 +1238,7 @@ void ILibProcessPipe_Process_PipeHandler_StdIn(void *user1, void *user2) if (sendOk != NULL) sendOk(j, j->userObject); } + #ifdef WIN32 void ILibProcessPipe_Process_OnExit_ChainSink(void *chain, void *user) { @@ -1241,9 +1249,9 @@ void ILibProcessPipe_Process_OnExit_ChainSink(void *chain, void *user) result = GetExitCodeProcess(j->hProcess, &exitCode); j->exiting = 1; j->exitHandler(j, exitCode, j->userObject); - j->exiting = 0; + j->exiting ^= 1; - ILibProcessPipe_Process_Destroy(j); + if (j->exiting == 0) { ILibProcessPipe_Process_Destroy(j); } } BOOL ILibProcessPipe_Process_OnExit(HANDLE event, void* user) { @@ -1251,15 +1259,21 @@ BOOL ILibProcessPipe_Process_OnExit(HANDLE event, void* user) UNREFERENCED_PARAMETER(event); ILibProcessPipe_WaitHandle_Remove(j->parent, j->hProcess); - - if (j->exitHandler != NULL) + if (j->stdOut->PAUSED != 0 || j->stdErr->PAUSED != 0) { - // Everyone's lifes is made easier, by context switching to chain thread before making this call - ILibChain_RunOnMicrostackThread(j->parent->ChainLink.ParentChain, ILibProcessPipe_Process_OnExit_ChainSink, user); + j->hProcess_needAdd = 1; } else { - ILibProcessPipe_Process_Destroy(j); + if (j->exitHandler != NULL) + { + // Everyone's lifes is made easier, by context switching to chain thread before making this call + ILibChain_RunOnMicrostackThread(j->parent->ChainLink.ParentChain, ILibProcessPipe_Process_OnExit_ChainSink, user); + } + else + { + ILibProcessPipe_Process_Destroy(j); + } } return(FALSE); } diff --git a/microstack/ILibWebClient.c b/microstack/ILibWebClient.c index ca62b2a..03b9ac3 100644 --- a/microstack/ILibWebClient.c +++ b/microstack/ILibWebClient.c @@ -149,6 +149,8 @@ struct ILibWebClient_StreamedRequestState int done; int canceled; int doNotSendRightAway; + int idleTimeout; + ILibAsyncSocket_TimeoutHandler idleTimeoutHandler; }; struct ILibWebClientManager @@ -204,9 +206,12 @@ typedef struct ILibWebClientDataObject int IsOrphan; int PipelineFlag; int ActivityCounter; + int NC; + char CNONCE[17]; struct sockaddr_in6 remote; struct sockaddr_in6 proxy; struct ILibWebClientManager *Parent; + char* DigestData; int PendingConnectionIndex; @@ -248,6 +253,7 @@ typedef struct ILibWebClientDataObject char CertificateHash[32]; // Used by the Mesh to store NodeID of this session }ILibWebClientDataObject; +struct ILibWebRequest; typedef struct ILibWebClient_PipelineRequestToken { struct ILibWebClientDataObject *wcdo; @@ -255,6 +261,7 @@ typedef struct ILibWebClient_PipelineRequestToken char* WebSocketKey; int WebSocketMaxBuffer; ILibWebClient_OnSendOK WebSocketSendOK; + struct ILibWebRequest *parent; char host[255]; char reserved[29]; }ILibWebClient_PipelineRequestToken; @@ -277,6 +284,8 @@ typedef struct ILibWebRequest ILibWebRequest_buffer *buffered; struct sockaddr_in6 remote; void *user1,*user2; + ILibWebClient_OnConnectHandler ConnectSink, DisconnectSink; + int connectionCloseWasSpecified; struct ILibWebClient_PipelineRequestToken *requestToken; struct ILibWebClient_StreamedRequestState *streamedState; @@ -332,6 +341,7 @@ void ILibWebClient_DestroyWebRequest(struct ILibWebRequest *wr) struct ILibWebClient_StreamedRequestBuffer *b; if (wr == NULL) return; + if (wr != NULL && wr->connectionCloseWasSpecified != 0 && wr->DisconnectSink != NULL) { wr->DisconnectSink(wr->requestToken); } if (wr->buffered != NULL) { free(wr->buffered); } if (wr->streamedState != NULL) { @@ -455,12 +465,13 @@ void ILibWebClient_DestroyWebClientDataObject(ILibWebClient_StateObject token) { free(((ILibWebClient_WebSocketState*)wr->Buffer[0])->WebSocketFragmentBuffer); } + wr->connectionCloseWasSpecified = 2; ILibWebClient_DestroyWebRequest(wr); ILibQueue_DeQueue(wcdo->RequestQueue); } ILibQueue_Destroy(wcdo->RequestQueue); - + if (wcdo->DigestData != NULL) { free(ILibMemory_AllocateA_Raw(wcdo->DigestData)); } free(wcdo); } @@ -674,7 +685,7 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s { int i; struct ILibWebRequest *wr; - + int closeSpecified = 0; UNREFERENCED_PARAMETER( socketModule ); if (wcdo == NULL) return; @@ -718,6 +729,7 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s } // Reset the flags + closeSpecified = wcdo->ConnectionCloseSpecified; ILibWebClient_ResetWCDO(wcdo); // If this socket isn't connected, it's because it was previously closed, @@ -726,7 +738,9 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s { SEM_TRACK(WebClient_TrackLock("ILibWebClient_FinishedResponse", 1, wcdo->Parent);) sem_wait(&(wcdo->Parent->QLock)); - ILibWebClient_DestroyWebRequest((struct ILibWebRequest*)ILibQueue_DeQueue(wcdo->RequestQueue)); + wr = (struct ILibWebRequest*)ILibQueue_DeQueue(wcdo->RequestQueue); + wr->connectionCloseWasSpecified = 2; + ILibWebClient_DestroyWebRequest(wr); SEM_TRACK(WebClient_TrackUnLock("ILibWebClient_FinishedResponse", 2, wcdo->Parent);) sem_post(&(wcdo->Parent->QLock)); return; @@ -741,6 +755,7 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s // Only execute this logic, if there was a pending request. If there wasn't one, that means // that this session was closed the last time the app as called with data, making this next step unnecessary. // + wr->connectionCloseWasSpecified = closeSpecified; ILibWebClient_DestroyWebRequest(wr); wr = (struct ILibWebRequest*)ILibQueue_PeekQueue(wcdo->RequestQueue); if (wr == NULL) @@ -764,7 +779,7 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s // // There are still pending requests in the queue, so try to send them // - if (wcdo->PipelineFlag != PIPELINE_NO) + if (wcdo->PipelineFlag != PIPELINE_NO && closeSpecified == 0) { ILibWebRequest_buffer *b; // @@ -789,7 +804,7 @@ void ILibWebClient_FinishedResponse(ILibAsyncSocket_SocketModule socketModule, s } } } - if (wcdo->PipelineFlag == PIPELINE_NO) + if (wcdo->PipelineFlag == PIPELINE_NO || closeSpecified != 0) { //{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}} /* Pipelining is not supported, so we should just close the socket, instead @@ -2012,6 +2027,7 @@ void ILibWebClient_OnConnect(ILibAsyncSocket_SocketModule socketModule, int Conn //printf("ILibWebClient_OnConnect(). Connected=%d, DisconnectSent=%d\r\n", Connected, wcdo->DisconnectSent); + if (wcdo->Closing != 0) return; // Already closing, exit now wcdo->SOCK = socketModule; @@ -2031,6 +2047,7 @@ void ILibWebClient_OnConnect(ILibAsyncSocket_SocketModule socketModule, int Conn sem_post(&(wcdo->Parent->QLock)); if (r != NULL) { + if (r->ConnectSink != NULL) { r->ConnectSink(r->requestToken); } ILibWebRequest_buffer *b; for(i = 0; i < r->NumberOfBuffers; ++i) { @@ -2044,7 +2061,11 @@ void ILibWebClient_OnConnect(ILibAsyncSocket_SocketModule socketModule, int Conn r->buffered = r->buffered->next; free(b); } - if (r->streamedState != NULL) ILibWebClient_OnSendOKSink(socketModule, wcdo); + if (r->streamedState != NULL) + { + if (r->streamedState->idleTimeout > 0 && r->streamedState->idleTimeoutHandler != NULL) { ILibAsyncSocket_SetTimeoutEx(socketModule, r->streamedState->idleTimeout, r->streamedState->idleTimeoutHandler); } + ILibWebClient_OnSendOKSink(socketModule, wcdo); + } } } else @@ -2162,7 +2183,8 @@ void ILibWebClient_OnDisconnectSink(ILibAsyncSocket_SocketModule socketModule, v } ILibWebClient_ResetWCDO(wcdo); if (wcdo->DisconnectSent == 1) wcdo->DisconnectSent = 0; - if (wr != NULL) ILibWebClient_DestroyWebRequest(wr); + if (wr != NULL && wr->DisconnectSink != NULL) { wr->DisconnectSink(wr->requestToken); } + if (wr != NULL) { wr->connectionCloseWasSpecified = 3; ILibWebClient_DestroyWebRequest(wr); } if (h != NULL) ILibDestructPacket(h); } @@ -2209,6 +2231,7 @@ void ILibWebClient_OnDisconnectSink(ILibAsyncSocket_SocketModule socketModule, v { free(((ILibWebClient_WebSocketState*)wr->Buffer[0])->WebSocketFragmentBuffer); } + wr->connectionCloseWasSpecified = 2; ILibWebClient_DestroyWebRequest(wr); } } @@ -2634,7 +2657,7 @@ ILibWebClient_RequestToken ILibWebClient_PipelineRequestEx2( request->UserFree[0] = headerBuffer_FREE; ILibMemory_Allocate(sizeof(ILibWebClient_PipelineRequestToken), 32, (void**)&(request->requestToken), NULL); - + request->requestToken->parent = request; request->requestToken->timer = wcm->timer; if (headerBufferLength > 5 && strncasecmp("HEAD ", headerBuffer, 5) == 0) @@ -2727,11 +2750,9 @@ ILibWebClient_RequestToken ILibWebClient_PipelineRequestEx2( RequestTokenLength = ILibCreateTokenStr(RemoteEndpoint, 0, RequestToken); } - if (ILibHasEntry(wcm->DataTable, RequestToken, RequestTokenLength)!=0) + if ((wcdo = (struct ILibWebClientDataObject*)ILibGetEntry(wcm->DataTable, RequestToken, RequestTokenLength)) != NULL) { - // Yes it does! - wcdo = (struct ILibWebClientDataObject*)ILibGetEntry(wcm->DataTable, RequestToken, RequestTokenLength); - if (wcdo == NULL) ILIBCRITICALEXIT(253); // TODO: Better handling.... + // Previous connection exists! request->requestToken->wcdo = wcdo; if (ILibQueue_IsEmpty(wcdo->RequestQueue) != 0) { @@ -2739,14 +2760,14 @@ ILibWebClient_RequestToken ILibWebClient_PipelineRequestEx2( ILibQueue_EnQueue(wcdo->RequestQueue, request); // Take out of Idle State - wcm->idleCount = wcm->idleCount == 0?0:wcm->idleCount-1; + wcm->idleCount = wcm->idleCount == 0 ? 0 : wcm->idleCount - 1; ILibDeleteEntry(wcm->idleTable, RequestToken, RequestTokenLength); ILibLifeTime_Remove(wcm->timer, wcdo); if (wcdo->DisconnectSent == 0 && (wcdo->SOCK == NULL || ILibAsyncSocket_IsFree(wcdo->SOCK))) { // If this was in our idleTable, then most likely the select doesn't know about // it, so we need to force it to unblock - ILibQueue_EnQueue(wcm->backlogQueue, wcdo); + ILibQueue_EnQueue(wcm->backlogQueue, wcdo); ForceUnBlock = 1; } else if (wcdo->SOCK != NULL) @@ -2754,13 +2775,14 @@ ILibWebClient_RequestToken ILibWebClient_PipelineRequestEx2( // Socket is still there if (wcdo->WaitForClose == 0) { - for(i = 0; i < request->NumberOfBuffers; ++i) + for (i = 0; i < request->NumberOfBuffers; ++i) { // TODO: Sandeep: This function call can be locking!! ILibAsyncSocket_Send(wcdo->SOCK, request->Buffer[i], request->BufferLength[i], ILibAsyncSocket_MemoryOwnership_STATIC); } if (request->streamedState != NULL) { + if (request->streamedState->idleTimeout > 0 && request->streamedState->idleTimeoutHandler != NULL) { ILibAsyncSocket_SetTimeoutEx(wcdo->SOCK, request->streamedState->idleTimeout, request->streamedState->idleTimeoutHandler); } ILibWebClient_OnSendOKSink(wcdo->SOCK, wcdo); } } @@ -3162,22 +3184,8 @@ ILibWebClient_RequestToken ILibWebClient_GetRequestToken_FromStateObject(ILibWeb void **ILibWebClient_RequestToken_GetUserObjects(ILibWebClient_RequestToken tok) { - struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)ILibWebClient_GetStateObjectFromRequestToken(tok); - struct ILibWebRequest *wr; - - if (wcdo == NULL) return(NULL); - wr = (struct ILibWebRequest*)ILibQueue_PeekQueue(wcdo->RequestQueue); - if (wr != NULL) { return(&(wr->user1)); } else { return(NULL); } -} -void **ILibWebClient_RequestToken_GetUserObjects_Tail(ILibWebClient_RequestToken tok) -{ - struct ILibWebClientDataObject *wcdo = (struct ILibWebClientDataObject*)ILibWebClient_GetStateObjectFromRequestToken(tok); - struct ILibWebRequest *wr; - - if (wcdo == NULL) return(NULL); - wr = (struct ILibWebRequest*)ILibQueue_PeekTail(wcdo->RequestQueue); - if (wr != NULL) { return(&(wr->user1)); } - else { return(NULL); } + ILibWebClient_PipelineRequestToken *prt = (ILibWebClient_PipelineRequestToken*)tok; + return(prt->parent != NULL ? &(prt->parent->user1) : NULL); } /*! \fn ILibWebClient_StateObject ILibWebClient_GetStateObjectFromRequestToken(ILibWebClient_RequestToken token) @@ -3210,6 +3218,13 @@ ILibWebClient_RequestToken ILibWebClient_PipelineStreamedRequest(ILibWebClient_R state->BufferQueue = ILibQueue_Create(); state->OnSendOK = OnSendOK; state->doNotSendRightAway = 1; + if (ILibHTTPPacket_Stash_HasKey(packet, "_idleTimeout", 12) != 0) + { + union { int i; void*p; }u; + u.p = ILibHTTPPacket_Stash_Get(packet, "_idleTimeout", 12); + state->idleTimeout = u.i; + state->idleTimeoutHandler = (ILibAsyncSocket_TimeoutHandler)ILibHTTPPacket_Stash_Get(packet, "_idleTimeoutHandler", 19); + } ILibAddHeaderLine(packet,"Transfer-Encoding",17,"chunked",7); @@ -3662,14 +3677,27 @@ int ILibWebClient_Digest_NeedAuthenticate(ILibWebClient_StateObject state) char* authenticate = ILibGetHeaderLine(wcdo->header, "WWW-Authenticate", 16); return(wcdo->header->StatusCode == 401 && authenticate != NULL); } -void* ILibWebClient_Digest_GenerateTable(ILibWebClient_StateObject state) +void* ILibWebClient_Digest_GenerateTableEx(ILibWebClient_StateObject state, void *ReservedMemory) { + ILibWebClientDataObject *wcdo = (ILibWebClientDataObject*)state; char* authenticate = ILibGetHeaderLineSP(((ILibWebClientDataObject*)state)->header, "WWW-Authenticate", 16); - void* table = ILibInitHashTree_CaseInSensitive(); + + if (wcdo->DigestData == NULL) { wcdo->DigestData = ILibMemory_AllocateA_InitMem(ILibMemory_Allocate(1024, 0, NULL, NULL), 1024); } + if (authenticate != NULL) + { + ILibMemory_AllocateA_InitMem(ILibMemory_AllocateA_Raw(wcdo->DigestData), ILibMemory_AllocateA_RawSize(wcdo->DigestData)); + strncpy_s(wcdo->DigestData, ILibMemory_AllocateA_Size(wcdo->DigestData), authenticate, strnlen_s(authenticate, sizeof(ILibScratchPad))); + } + else + { + authenticate = wcdo->DigestData; + } + + void* table = ILibInitHashTree_CaseInSensitiveEx(ReservedMemory); ILibWebServer_Digest_ParseAuthenticationHeader(table, authenticate, (int)strnlen_s(authenticate, sizeof(ILibScratchPad) - sizeof(void*))); return(table); } - +#define ILibWebClient_Digest_GenerateTable(state) ILibWebClient_Digest_GenerateTableEx(state, NULL) char* ILibWebClient_Digest_GetRealm(ILibWebClient_StateObject state) { void* table = ILibWebClient_Digest_GenerateTable(state); @@ -3681,15 +3709,18 @@ char* ILibWebClient_Digest_GetRealm(ILibWebClient_StateObject state) void ILibWebClient_GenerateAuthenticationHeader(ILibWebClient_StateObject state, ILibHTTPPacket *packet, char* username, char* password) { + ILibWebClientDataObject *wcdo = (ILibWebClientDataObject*)state; int tmpLen; char result1[33]; char result2[33]; char result3[33]; - void* table = ILibWebClient_Digest_GenerateTable(state); + + void *ReservedMemory = packet->ReservedMemory == NULL ? ILibMemory_AllocateA(8000) : packet->ReservedMemory; + void* table = ILibWebClient_Digest_GenerateTableEx(state, ReservedMemory); char* realm = (char*)ILibGetEntry(table, "realm", 5); char* nonce = (char*)ILibGetEntry(table, "nonce", 5); char* opaque = (char*)ILibGetEntry(table, "opaque", 6); - ILibDestroyHashTree(table); + char *qop = (char*)ILibGetEntry(table, "qop", 3); tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", username, realm, password); util_md5hex(ILibScratchPad2, tmpLen, result1); @@ -3699,10 +3730,30 @@ void ILibWebClient_GenerateAuthenticationHeader(ILibWebClient_StateObject state, tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s", packet->Directive, packet->DirectiveObj); util_md5hex(ILibScratchPad2, tmpLen, result2); - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", result1, nonce, result2); + if (qop == NULL) + { + tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%s", result1, nonce, result2); + } + else + { + if (wcdo->NC == 0) + { + util_randomtext(sizeof(wcdo->CNONCE)-1, wcdo->CNONCE); + wcdo->CNONCE[sizeof(wcdo->CNONCE) - 1] = 0; + } + wcdo->NC++; + tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "%s:%s:%08x:%s:%s:%s", result1, nonce, wcdo->NC, wcdo->CNONCE, qop, result2); + } util_md5hex(ILibScratchPad2, tmpLen, result3); - tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", opaque=\"%s\", response=\"%s\"", username, realm, nonce, packet->DirectiveObj, opaque, result3); + tmpLen = sprintf_s(ILibScratchPad2, sizeof(ILibScratchPad2), "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\"", username, realm, nonce, packet->DirectiveObj); + if (opaque != NULL) { tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", opaque=\"%s\"", opaque); } + if (qop != NULL) + { + tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", qop=\"%s\", nc=%08x, cnonce=\"%s\"", qop, wcdo->NC, wcdo->CNONCE); + } + + tmpLen += sprintf_s(ILibScratchPad2 + tmpLen, sizeof(ILibScratchPad2) - tmpLen, ", response=\"%s\"", result3); ILibAddHeaderLine(packet, "Authorization", 13, ILibScratchPad2, tmpLen); } void ILibWebClient_AddWebSocketRequestHeaders(ILibHTTPPacket *packet, int FragmentReassemblyMaxBufferSize, ILibWebClient_OnSendOK OnSendOK) @@ -3725,6 +3776,23 @@ void ILibWebClient_AddWebSocketRequestHeaders(ILibHTTPPacket *packet, int Fragme ILibHTTPPacket_Stash_Put(packet, "_WebSocketBufferSize", 20, u.p); ILibHTTPPacket_Stash_Put(packet, "_WebSocketOnSendOK", 18, OnSendOK); } +void ILibWebClient_RequestToken_ConnectionHandler_Set(ILibWebClient_RequestToken token, ILibWebClient_OnConnectHandler OnConnect, ILibWebClient_OnConnectHandler OnDisconnect) +{ + ILibWebClientDataObject *wcdo = ILibWebClient_GetStateObjectFromRequestToken(token); + struct ILibWebRequest *wr; + + if (wcdo != NULL) + { + sem_wait(&(wcdo->Parent->QLock)); + wr = (struct ILibWebRequest*)ILibQueue_PeekTail(wcdo->RequestQueue); + if (wr != NULL) + { + wr->ConnectSink = OnConnect; + wr->DisconnectSink = OnDisconnect; + } + sem_post(&(wcdo->Parent->QLock)); + } +} #ifdef MICROSTACK_PROXY struct sockaddr_in6* ILibWebClient_SetProxy(ILibWebClient_RequestToken token, char *proxyHost, unsigned short proxyPort, char *username, char *password) { diff --git a/microstack/ILibWebClient.h b/microstack/ILibWebClient.h index ac05220..7c202c9 100644 --- a/microstack/ILibWebClient.h +++ b/microstack/ILibWebClient.h @@ -133,6 +133,7 @@ typedef void(*ILibWebClient_OnResponse)(ILibWebClient_StateObject WebStateObject \param user2 User2 object that was associated with this connection */ typedef void(*ILibWebClient_OnSendOK)(ILibWebClient_StateObject sender, void *user1, void *user2); +typedef void(*ILibWebClient_OnConnectHandler)(ILibWebClient_RequestToken sender); /*! \typedef ILibWebClient_OnDisconnect \brief Handler for when the session has disconnected \param sender The \a ILibWebClient_StateObject that has been disconnected @@ -241,7 +242,8 @@ void ILibWebClient_ResetUserObjects(ILibWebClient_StateObject webstate, void *us ILibWebClient_RequestToken ILibWebClient_GetRequestToken_FromStateObject(ILibWebClient_StateObject WebStateObject); ILibWebClient_StateObject ILibWebClient_GetStateObjectFromRequestToken(ILibWebClient_RequestToken token); void **ILibWebClient_RequestToken_GetUserObjects(ILibWebClient_RequestToken tok); -void **ILibWebClient_RequestToken_GetUserObjects_Tail(ILibWebClient_RequestToken tok); + +void ILibWebClient_RequestToken_ConnectionHandler_Set(ILibWebClient_RequestToken tok, ILibWebClient_OnConnectHandler OnConnect, ILibWebClient_OnConnectHandler OnDisconnect); void ILibWebClient_Parse_ContentRange(char *contentRange, int *Start, int *End, int *TotalLength); enum ILibWebClient_Range_Result ILibWebClient_Parse_Range(char *Range, long *Start, long *Length, long TotalLength); diff --git a/microstack/ILibWebServer.c b/microstack/ILibWebServer.c index f50f61f..6449566 100644 --- a/microstack/ILibWebServer.c +++ b/microstack/ILibWebServer.c @@ -1910,7 +1910,10 @@ int ILibWebServer_GetLocalInterface(struct ILibWebServer_Session *session, struc return ILibAsyncSocket_GetLocalInterface(ILibWebServer_Session_GetSystemData(session)->ConnectionToken, localAddress); } - +ILibAsyncServerSocket_ServerModule ILibWebServer_GetServerSocketModule(ILibWebServer_ServerToken server) +{ + return(((ILibWebServer_StateModule*)server)->ServerSocket); +} /*! \fn ILibWebServer_RegisterVirtualDirectory(ILibWebServer_ServerToken WebServerToken, char *vd, int vdLength, ILibWebServer_VirtualDirectory OnVirtualDirectory, void *user) \brief Registers a Virtual Directory with the ILibWebServer diff --git a/microstack/ILibWebServer.h b/microstack/ILibWebServer.h index 4ac1771..732c1df 100644 --- a/microstack/ILibWebServer.h +++ b/microstack/ILibWebServer.h @@ -197,6 +197,7 @@ ILibWebServer_ServerToken ILibWebServer_CreateEx(void *Chain, int MaxConnections ILibExportMethod ILibWebServer_ServerToken ILibWebServer_CreateEx2(void *Chain, int MaxConnections, unsigned short PortNumber, int loopbackFlag, ILibWebServer_Session_OnSession OnSession, int ExtraMemorySize, void *User); #define ILibWebServer_Create(Chain, MaxConnections, PortNumber, OnSession, User) ILibWebServer_CreateEx(Chain, MaxConnections, PortNumber, INADDR_ANY, OnSession, User) #define ILibWebServer_Create2(Chain, MaxConnections, PortNumber, OnSession, ExtraMemorySize, User) ILibWebServer_CreateEx2(Chain, MaxConnections, PortNumber, INADDR_ANY, OnSession, ExtraMemorySize, User) +ILibAsyncServerSocket_ServerModule ILibWebServer_GetServerSocketModule(ILibWebServer_ServerToken server); void ILibWebServer_StopListener(ILibWebServer_ServerToken server); void ILibWebServer_RestartListener(ILibWebServer_ServerToken server);