space-data-module-sdk 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -20
- package/bin/space-data-module.js +263 -0
- package/docs/.nojekyll +1 -0
- package/docs/AGENTS.md +34 -0
- package/docs/architecture.svg +141 -0
- package/docs/browser-wasmedge-isomorphic.md +179 -0
- package/docs/flatsql-streaming-standard.md +341 -0
- package/docs/gpu-module-abi.md +193 -0
- package/docs/index.html +125 -0
- package/docs/isomorphic-pthreads.md +188 -0
- package/docs/isomorphic-sdn-runtime-plan.md +167 -0
- package/docs/language-runtime-matrix.md +82 -0
- package/docs/manifest-structure.svg +114 -0
- package/docs/module-bundle-runtime-plan.md +19 -0
- package/docs/module-lifecycle.svg +70 -0
- package/docs/module-publication-standard.md +540 -0
- package/docs/node-red-default-node-parity.md +88 -0
- package/docs/protocol-installation.md +196 -0
- package/docs/secrets-capability.md +152 -0
- package/docs/styles.css +288 -0
- package/docs/testing-harness.md +408 -0
- package/docs/tri-runtime-parity.md +132 -0
- package/docs/wallet-callback.html +2 -0
- package/package.json +26 -6
- package/schemas/HttpRequestAbi.fbs +41 -0
- package/schemas/HttpResponseAbi.fbs +36 -0
- package/schemas/PluginManifest.fbs +2 -1
- package/src/AGENTS.md +1 -1
- package/src/app/codec.js +548 -0
- package/src/app/index.js +6 -0
- package/src/browser.js +5 -0
- package/src/bundle/constants.js +1 -0
- package/src/bundle/index.js +15 -0
- package/src/bundle/sigdomain.js +179 -0
- package/src/bundle/signing.js +767 -0
- package/src/bundle/wasm.js +3 -2
- package/src/capabilities.js +3 -0
- package/src/compat/index.js +7 -0
- package/src/compat/sdnLegacy.js +449 -0
- package/src/compiler/compileModule.js +556 -55
- package/src/compiler/flatcSupport.js +41 -27
- package/src/compiler/index.d.ts +2 -0
- package/src/compiler/index.js +18 -0
- package/src/compiler/invokeGlue.js +1212 -183
- package/src/compiler/pthreadArtifactGuard.js +910 -0
- package/src/compiler/sdnShimGenerator.js +323 -0
- package/src/compiler/wasiThreadsToolchain.js +150 -0
- package/src/compliance/index.js +11 -1
- package/src/compliance/legacyWildcardPorts.js +228 -0
- package/src/compliance/pluginCompliance.js +1000 -96
- package/src/field-stream/index.d.ts +31 -0
- package/src/field-stream/index.js +119 -0
- package/src/flow/dependencyStreamBridge.js +234 -0
- package/src/flow/flatsqlLinkShim.js +304 -0
- package/src/flow/flowCodec.js +107 -0
- package/src/flow/flowCompiler.js +2900 -0
- package/src/flow/flowRuntimeHost.js +877 -0
- package/src/flow/index.d.ts +117 -0
- package/src/flow/index.js +31 -0
- package/src/flow/isomorphicFlowHost.js +384 -0
- package/src/flow/jsFlowRuntime.js +275 -0
- package/src/flow/normalize.js +294 -0
- package/src/flow/runtime-src/flow_runtime.cpp +1699 -0
- package/src/flow/vendor/sdn-flow/MethodRegistry.js +400 -0
- package/src/flow/vendor/sdn-flow/constants.js +39 -0
- package/src/flow/vendor/sdn-flow/index.js +29 -0
- package/src/flow/vendor/sdn-flow/normalize.js +506 -0
- package/src/flow/vendor/sdn-flow/wasmCompatibility.js +189 -0
- package/src/generated/http/cpp/HttpRequestAbi_generated.h +285 -0
- package/src/generated/http/cpp/HttpResponseAbi_generated.h +192 -0
- package/src/generated/http/sdn/http/http-header.js +53 -0
- package/src/generated/http/sdn/http/http-header.ts +67 -0
- package/src/generated/http/sdn/http/http-request.js +132 -0
- package/src/generated/http/sdn/http/http-request.ts +179 -0
- package/src/generated/http/sdn/http/http-response.js +144 -0
- package/src/generated/http/sdn/http/http-response.ts +168 -0
- package/src/generated/http/sdn/http.js +11 -0
- package/src/generated/http/sdn/http.ts +4 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts +12 -0
- package/src/generated/orbpro/flow/backpressure-policy.d.ts.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.js +17 -0
- package/src/generated/orbpro/flow/backpressure-policy.js.map +1 -0
- package/src/generated/orbpro/flow/backpressure-policy.ts +15 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts +142 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js +304 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.js.map +1 -0
- package/src/generated/orbpro/flow/flow-bundle-manifest.ts +399 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts +113 -0
- package/src/generated/orbpro/flow/flow-edge.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.js +221 -0
- package/src/generated/orbpro/flow/flow-edge.js.map +1 -0
- package/src/generated/orbpro/flow/flow-edge.ts +292 -0
- package/src/generated/orbpro/flow/flow-node.d.ts +80 -0
- package/src/generated/orbpro/flow/flow-node.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-node.js +158 -0
- package/src/generated/orbpro/flow/flow-node.js.map +1 -0
- package/src/generated/orbpro/flow/flow-node.ts +202 -0
- package/src/generated/orbpro/flow/flow-program.d.ts +164 -0
- package/src/generated/orbpro/flow/flow-program.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-program.js +350 -0
- package/src/generated/orbpro/flow/flow-program.js.map +1 -0
- package/src/generated/orbpro/flow/flow-program.ts +477 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts +108 -0
- package/src/generated/orbpro/flow/flow-trigger.d.ts.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.js +207 -0
- package/src/generated/orbpro/flow/flow-trigger.js.map +1 -0
- package/src/generated/orbpro/flow/flow-trigger.ts +276 -0
- package/src/generated/orbpro/flow/node-kind.d.ts +13 -0
- package/src/generated/orbpro/flow/node-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/node-kind.js +16 -0
- package/src/generated/orbpro/flow/node-kind.js.map +1 -0
- package/src/generated/orbpro/{invoke.ts → flow/node-kind.ts} +12 -2
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts +52 -0
- package/src/generated/orbpro/flow/plugin-version-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js +85 -0
- package/src/generated/orbpro/flow/plugin-version-binding.js.map +1 -0
- package/src/generated/orbpro/flow/plugin-version-binding.ts +121 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts +70 -0
- package/src/generated/orbpro/flow/schema-hash-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js +143 -0
- package/src/generated/orbpro/flow/schema-hash-binding.js.map +1 -0
- package/src/generated/orbpro/flow/schema-hash-binding.ts +189 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts +71 -0
- package/src/generated/orbpro/flow/trigger-binding.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.js +142 -0
- package/src/generated/orbpro/flow/trigger-binding.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-binding.ts +181 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts +14 -0
- package/src/generated/orbpro/flow/trigger-kind.d.ts.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.js +17 -0
- package/src/generated/orbpro/flow/trigger-kind.js.map +1 -0
- package/src/generated/orbpro/flow/trigger-kind.ts +17 -0
- package/src/generated/orbpro/flow.d.ts +21 -0
- package/src/generated/orbpro/flow.d.ts.map +1 -0
- package/src/generated/orbpro/flow.js +23 -0
- package/src/generated/orbpro/flow.js.map +1 -0
- package/src/generated/orbpro/flow.ts +24 -0
- package/src/generated/orbpro/manifest/capability-kind.d.ts +2 -1
- package/src/generated/orbpro/manifest/capability-kind.js +1 -0
- package/src/generated/orbpro/manifest/capability-kind.ts +1 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.d.ts +93 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.js +160 -0
- package/src/generated/orbpro/plugin/stream-invoke-request.ts +211 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.d.ts +99 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.js +175 -0
- package/src/generated/orbpro/plugin/stream-invoke-response.ts +226 -0
- package/src/generated/orbpro/plugin.js +8 -0
- package/src/generated/orbpro/stream.d.ts +12 -0
- package/src/generated/orbpro/stream.js +14 -0
- package/src/generated/orbpro/stream.ts +15 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts +52 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.js +106 -0
- package/src/generated/spacedatastandards/plg/EntryFunction.ts +162 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts +90 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.js +189 -0
- package/src/generated/spacedatastandards/plg/FlatBufferTypeRef.ts +270 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts +492 -0
- package/src/generated/spacedatastandards/plg/PLG.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLG.js +1139 -0
- package/src/generated/spacedatastandards/plg/PLG.ts +1600 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts +63 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.js +138 -0
- package/src/generated/spacedatastandards/plg/PLGAcceptedTypeSet.ts +189 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.js +104 -0
- package/src/generated/spacedatastandards/plg/PLGBuildArtifact.ts +151 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts +68 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.js +124 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdge.ts +184 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts +58 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.js +126 -0
- package/src/generated/spacedatastandards/plg/PLGFlowEdgeContract.ts +161 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.js +164 -0
- package/src/generated/spacedatastandards/plg/PLGFlowNode.ts +244 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts +55 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.js +105 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTrigger.ts +162 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.js +83 -0
- package/src/generated/spacedatastandards/plg/PLGFlowTriggerBinding.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts +36 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.js +90 -0
- package/src/generated/spacedatastandards/plg/PLGHostCapability.ts +127 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts +53 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.js +153 -0
- package/src/generated/spacedatastandards/plg/PLGMethodManifest.ts +210 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts +70 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.js +149 -0
- package/src/generated/spacedatastandards/plg/PLGPortManifest.ts +212 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts +73 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.js +199 -0
- package/src/generated/spacedatastandards/plg/PLGProtocolSpec.ts +292 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts +40 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.js +103 -0
- package/src/generated/spacedatastandards/plg/PLGTimerSpec.ts +148 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts +41 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginCapability.js +82 -0
- package/src/generated/spacedatastandards/plg/{plugin-capability.ts → PluginCapability.ts} +55 -18
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts +42 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.js +80 -0
- package/src/generated/spacedatastandards/plg/PluginDependency.ts +124 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts +85 -0
- package/src/generated/spacedatastandards/plg/TAB.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/TAB.js +173 -0
- package/src/generated/spacedatastandards/plg/TAB.ts +228 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferMutability.ts +23 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.js +20 -0
- package/src/generated/spacedatastandards/plg/bufferOwnership.ts +23 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts +20 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.js +22 -0
- package/src/generated/spacedatastandards/plg/drainBehavior.ts +25 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts +10 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.js +12 -0
- package/src/generated/spacedatastandards/plg/flowEdgeRoutePolicy.ts +13 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts +51 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.js +53 -0
- package/src/generated/spacedatastandards/plg/hostCapabilityKind.ts +55 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts +15 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.js +17 -0
- package/src/generated/spacedatastandards/plg/invokeSurfaceKind.ts +19 -0
- package/src/generated/spacedatastandards/plg/main.d.ts +29 -0
- package/src/generated/spacedatastandards/plg/main.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/main.js +30 -0
- package/src/generated/spacedatastandards/plg/main.ts +32 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts +17 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.js +19 -0
- package/src/generated/spacedatastandards/plg/payloadWireFormat.ts +21 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts +82 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.js +84 -0
- package/src/generated/spacedatastandards/plg/pluginCategory.ts +103 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/publicationState.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/publicationState.js +20 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts +18 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.d.ts.map +1 -0
- package/src/generated/spacedatastandards/plg/purchaseTier.js +20 -0
- package/src/host/AGENTS.md +2 -2
- package/src/host/abi.js +53 -66
- package/src/host/browserHost.js +355 -8
- package/src/host/cpp/keyslotClient.hpp +231 -0
- package/src/host/cpp/secretsClient.hpp +583 -0
- package/src/host/hostcallWire.js +183 -0
- package/src/host/index.js +2 -0
- package/src/host/isomorphicLoader.js +44 -7
- package/src/host/nodeHost.js +227 -8
- package/src/host/sabHostcallChannel.js +206 -0
- package/src/host/timerDriver.js +203 -0
- package/src/host/wasiShim.js +41 -1
- package/src/host/wasiThreadBrowserWorker.mjs +48 -0
- package/src/host/wasiThreadHost.js +393 -0
- package/src/host/wasiThreadWorker.mjs +32 -0
- package/src/host/wasiThreadWorkerRuntime.js +93 -0
- package/src/http/index.js +339 -0
- package/src/index.d.ts +716 -10
- package/src/index.js +4 -0
- package/src/invoke/codec.js +1202 -128
- package/src/invoke/index.js +5 -1
- package/src/licensing/index.d.ts +2 -0
- package/src/licensing/index.js +2 -0
- package/src/licensing/records.js +287 -8
- package/src/manifest/codec.js +62 -14
- package/src/manifest/index.js +2 -0
- package/src/manifest/legacyToPlg.js +164 -25
- package/src/manifest/normalize.js +1 -0
- package/src/manifest/plgCodec.js +1303 -62
- package/src/manifest/typeRefs.js +162 -24
- package/src/runtime/compiledRuntimeAbi.js +47 -0
- package/src/runtime/compiledRuntimeAbi.json +33 -0
- package/src/runtime/index.d.ts +32 -0
- package/src/runtime/index.js +1 -0
- package/src/runtime-host/index.js +3 -0
- package/src/runtime-host/methodRegistry.js +55 -0
- package/src/standards/index.js +200 -56
- package/src/standards/sharedCatalog.js +16 -0
- package/src/testing/browserModuleHarness.js +604 -31
- package/src/testing/docker/wasmedge-parity.Dockerfile +39 -0
- package/src/testing/index.d.ts +151 -0
- package/src/testing/index.js +21 -0
- package/src/testing/native/wasmedge_emscripten_pthread_runner.c +25 -1
- package/src/testing/parityBrowserRunner.js +138 -0
- package/src/testing/parityHarness.js +616 -0
- package/src/testing/parityLanes.js +537 -0
- package/src/testing/processInvoke.js +29 -21
- package/src/testing/streamInvokeCodec.js +10 -175
- package/src/testing/wasmedgePin.json +6 -0
- package/src/testing/workerModuleHarness.js +242 -0
- package/src/testing/workerModuleHarnessWorker.js +176 -0
- package/src/transport/index.js +3 -0
- package/src/transport/pki.js +299 -11
- package/src/transport/records.js +16 -7
- package/src/utils/ecdsaDer.js +106 -0
- package/src/utils/wasmCrypto.js +0 -43
- package/templates/gpu-module/README.md +48 -0
- package/templates/gpu-module/include/space_data_gpu_abi.h +122 -0
- package/templates/gpu-module/manifest.json +84 -0
- package/schemas/PluginInvokeRequest.fbs +0 -18
- package/schemas/PluginInvokeResponse.fbs +0 -30
- package/schemas/spacedatastandards/PLG.fbs +0 -191
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +0 -51
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +0 -131
- package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.ts +0 -173
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +0 -76
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +0 -184
- package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +0 -1
- package/src/generated/orbpro/invoke/plugin-invoke-response.ts +0 -243
- package/src/generated/orbpro/invoke.d.ts +0 -3
- package/src/generated/orbpro/invoke.js +0 -5
- package/src/generated/spacedatastandards/plg/entry-function.js +0 -86
- package/src/generated/spacedatastandards/plg/entry-function.ts +0 -119
- package/src/generated/spacedatastandards/plg/index.js +0 -16
- package/src/generated/spacedatastandards/plg/index.ts +0 -11
- package/src/generated/spacedatastandards/plg/plg.js +0 -657
- package/src/generated/spacedatastandards/plg/plg.ts +0 -924
- package/src/generated/spacedatastandards/plg/plugin-capability.js +0 -66
- package/src/generated/spacedatastandards/plg/plugin-category.js +0 -15
- package/src/generated/spacedatastandards/plg/plugin-category.ts +0 -53
- package/src/generated/spacedatastandards/plg/plugin-dependency.js +0 -63
- package/src/generated/spacedatastandards/plg/plugin-dependency.ts +0 -86
- package/src/generated/spacedatastandards/plg/publication-state.js +0 -9
- package/src/generated/spacedatastandards/plg/purchase-tier.js +0 -9
- /package/src/generated/spacedatastandards/plg/{publication-state.ts → publicationState.ts} +0 -0
- /package/src/generated/spacedatastandards/plg/{purchase-tier.ts → purchaseTier.ts} +0 -0
|
@@ -20,6 +20,47 @@ function uniqueOutputPorts(method) {
|
|
|
20
20
|
return Array.isArray(method?.outputPorts) ? method.outputPorts : [];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function acceptedTypesForPort(port) {
|
|
24
|
+
const acceptedTypes = [];
|
|
25
|
+
for (const typeSet of Array.isArray(port?.acceptedTypeSets)
|
|
26
|
+
? port.acceptedTypeSets
|
|
27
|
+
: []) {
|
|
28
|
+
for (const allowedType of Array.isArray(typeSet?.allowedTypes)
|
|
29
|
+
? typeSet.allowedTypes
|
|
30
|
+
: []) {
|
|
31
|
+
acceptedTypes.push(allowedType ?? {});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return acceptedTypes;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function wireFormatLiteral(value) {
|
|
38
|
+
return String(value ?? "").toLowerCase() === "aligned-binary" ? "1u" : "0u";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function schemaHashBytes(value) {
|
|
42
|
+
if (typeof value === "string") {
|
|
43
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
44
|
+
if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex)) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
const bytes = [];
|
|
48
|
+
for (let index = 0; index < hex.length; index += 2) {
|
|
49
|
+
bytes.push(Number.parseInt(hex.slice(index, index + 2), 16));
|
|
50
|
+
}
|
|
51
|
+
return bytes;
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(value) || value instanceof Uint8Array) {
|
|
54
|
+
return Array.from(value, (entry) => Number(entry));
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function unsignedLiteral(value) {
|
|
60
|
+
const numeric = Number(value ?? 0);
|
|
61
|
+
return `${Number.isFinite(numeric) ? Math.max(0, Math.trunc(numeric)) : 0}u`;
|
|
62
|
+
}
|
|
63
|
+
|
|
23
64
|
export function resolveInvokeSurfaces(manifest = {}) {
|
|
24
65
|
if (!Array.isArray(manifest.invokeSurfaces) || manifest.invokeSurfaces.length === 0) {
|
|
25
66
|
return [InvokeSurface.DIRECT, InvokeSurface.COMMAND];
|
|
@@ -62,18 +103,32 @@ typedef struct plugin_input_frame_t {
|
|
|
62
103
|
const char *file_identifier;
|
|
63
104
|
uint32_t wire_format;
|
|
64
105
|
const char *root_type_name;
|
|
106
|
+
/* Legacy TABF-only metadata. SDS PIV/TAB inputs set this to 0. */
|
|
65
107
|
uint16_t fixed_string_length;
|
|
108
|
+
/* SDS PIV/TAB inputs expose TYPE_REF.BYTE_LENGTH here (zero for canonical). */
|
|
66
109
|
uint32_t byte_length;
|
|
67
110
|
uint16_t required_alignment;
|
|
68
111
|
uint16_t alignment;
|
|
69
112
|
uint32_t size;
|
|
113
|
+
/* Legacy TABF-only metadata. SDS PIV/TAB inputs set this to 0. */
|
|
70
114
|
uint32_t generation;
|
|
115
|
+
/* SDS PIV/TAB maps TAB.FRAME_ID here. */
|
|
71
116
|
uint64_t trace_id;
|
|
117
|
+
/* Legacy TABF-only metadata. SDS PIV/TAB inputs set this to 0. */
|
|
72
118
|
uint32_t stream_id;
|
|
119
|
+
/* SDS PIV/TAB decodes this from TAB.FRAME_ID as frame_id >> 1. */
|
|
73
120
|
uint64_t sequence;
|
|
121
|
+
/* SDS PIV/TAB decodes this from TAB.FRAME_ID bit 0. */
|
|
74
122
|
int32_t end_of_stream;
|
|
75
123
|
const uint8_t *payload;
|
|
76
124
|
uint32_t payload_length;
|
|
125
|
+
/* Exact SDS type identity and TAB access metadata; appended for ABI-prefix stability. */
|
|
126
|
+
const char *schema_version;
|
|
127
|
+
const uint8_t *schema_hash;
|
|
128
|
+
uint32_t schema_hash_length;
|
|
129
|
+
uint32_t ownership;
|
|
130
|
+
uint32_t mutability;
|
|
131
|
+
uint64_t frame_id;
|
|
77
132
|
} plugin_input_frame_t;
|
|
78
133
|
|
|
79
134
|
uint32_t plugin_get_input_count(void);
|
|
@@ -111,6 +166,12 @@ int32_t plugin_push_output_ex(
|
|
|
111
166
|
const uint8_t *payload_ptr,
|
|
112
167
|
uint32_t payload_length
|
|
113
168
|
);
|
|
169
|
+
int32_t plugin_set_output_frame_id(uint32_t output_index, uint64_t frame_id);
|
|
170
|
+
int32_t plugin_set_output_stream_frame(
|
|
171
|
+
uint32_t output_index,
|
|
172
|
+
uint64_t sequence,
|
|
173
|
+
int32_t end_of_stream
|
|
174
|
+
);
|
|
114
175
|
|
|
115
176
|
void plugin_set_yielded(int32_t yielded);
|
|
116
177
|
void plugin_set_backlog_remaining(uint32_t backlog_remaining);
|
|
@@ -132,17 +193,53 @@ uint32_t plugin_invoke_stream(
|
|
|
132
193
|
`;
|
|
133
194
|
}
|
|
134
195
|
|
|
196
|
+
function renderAcceptedTypeArrays(method, ports, direction) {
|
|
197
|
+
return ports
|
|
198
|
+
.map((port, portIndex) => {
|
|
199
|
+
const acceptedTypes = acceptedTypesForPort(port);
|
|
200
|
+
if (acceptedTypes.length === 0) {
|
|
201
|
+
return "";
|
|
202
|
+
}
|
|
203
|
+
const arrayPrefix = `kMethod_${methodSymbol(method)}_${direction}_port_${portIndex}`;
|
|
204
|
+
const hashArrays = acceptedTypes
|
|
205
|
+
.map((type, typeIndex) => {
|
|
206
|
+
const bytes = schemaHashBytes(type.schemaHash);
|
|
207
|
+
if (bytes.length === 0) {
|
|
208
|
+
return "";
|
|
209
|
+
}
|
|
210
|
+
return `static const uint8_t ${arrayPrefix}_type_${typeIndex}_schema_hash[] = { ${bytes
|
|
211
|
+
.map((entry) => `0x${entry.toString(16).padStart(2, "0")}`)
|
|
212
|
+
.join(", ")} };\n`;
|
|
213
|
+
})
|
|
214
|
+
.join("");
|
|
215
|
+
return `${hashArrays}static const AcceptedTypeRef ${arrayPrefix}_accepted_types[] = {
|
|
216
|
+
${acceptedTypes
|
|
217
|
+
.map((type, typeIndex) => {
|
|
218
|
+
const hash = schemaHashBytes(type.schemaHash);
|
|
219
|
+
return ` { ${boolLiteral(type.acceptsAnyFlatbuffer === true)}, ${quoteCString(type.schemaName)}, ${quoteCString(type.fileIdentifier)}, ${wireFormatLiteral(type.wireFormat)}, ${boolLiteral(type.wireFormat !== undefined)}, ${quoteCString(type.rootTypeName)}, ${quoteCString(type.schemaVersion)}, ${hash.length > 0 ? `${arrayPrefix}_type_${typeIndex}_schema_hash` : "nullptr"}, ${hash.length}u, ${unsignedLiteral(type.fixedStringLength)}, ${unsignedLiteral(type.byteLength)}, ${unsignedLiteral(type.requiredAlignment)} },`;
|
|
220
|
+
})
|
|
221
|
+
.join("\n")}
|
|
222
|
+
};
|
|
223
|
+
`;
|
|
224
|
+
})
|
|
225
|
+
.join("");
|
|
226
|
+
}
|
|
227
|
+
|
|
135
228
|
function renderInputPortArrays(method) {
|
|
136
229
|
const inputPorts = uniqueInputPorts(method);
|
|
137
230
|
if (inputPorts.length === 0) {
|
|
138
231
|
return "";
|
|
139
232
|
}
|
|
140
|
-
return
|
|
233
|
+
return `${renderAcceptedTypeArrays(method, inputPorts, "input")}static const PortRequirement kMethod_${methodSymbol(method)}_input_ports[] = {
|
|
141
234
|
${inputPorts
|
|
142
|
-
.map(
|
|
143
|
-
(port)
|
|
144
|
-
|
|
145
|
-
|
|
235
|
+
.map((port, portIndex) => {
|
|
236
|
+
const acceptedTypes = acceptedTypesForPort(port);
|
|
237
|
+
return ` { ${quoteCString(port.portId)}, ${boolLiteral(port.required !== false)}, ${
|
|
238
|
+
acceptedTypes.length > 0
|
|
239
|
+
? `kMethod_${methodSymbol(method)}_input_port_${portIndex}_accepted_types`
|
|
240
|
+
: "nullptr"
|
|
241
|
+
}, ${acceptedTypes.length}u },`;
|
|
242
|
+
})
|
|
146
243
|
.join("\n")}
|
|
147
244
|
};
|
|
148
245
|
`;
|
|
@@ -153,8 +250,17 @@ function renderOutputPortArrays(method) {
|
|
|
153
250
|
if (outputPorts.length === 0) {
|
|
154
251
|
return "";
|
|
155
252
|
}
|
|
156
|
-
return
|
|
157
|
-
${outputPorts
|
|
253
|
+
return `${renderAcceptedTypeArrays(method, outputPorts, "output")}static const PortRequirement kMethod_${methodSymbol(method)}_output_ports[] = {
|
|
254
|
+
${outputPorts
|
|
255
|
+
.map((port, portIndex) => {
|
|
256
|
+
const acceptedTypes = acceptedTypesForPort(port);
|
|
257
|
+
return ` { ${quoteCString(port.portId)}, ${boolLiteral(port.required !== false)}, ${
|
|
258
|
+
acceptedTypes.length > 0
|
|
259
|
+
? `kMethod_${methodSymbol(method)}_output_port_${portIndex}_accepted_types`
|
|
260
|
+
: "nullptr"
|
|
261
|
+
}, ${acceptedTypes.length}u },`;
|
|
262
|
+
})
|
|
263
|
+
.join("\n")}
|
|
158
264
|
};
|
|
159
265
|
`;
|
|
160
266
|
}
|
|
@@ -203,7 +309,9 @@ export function generateInvokeSupportSource({ manifest = {}, includeCommandMain
|
|
|
203
309
|
#include <cstdio>
|
|
204
310
|
#include <cstdlib>
|
|
205
311
|
#include <cstring>
|
|
312
|
+
#include <limits>
|
|
206
313
|
#include <memory>
|
|
314
|
+
#include <stdlib.h>
|
|
207
315
|
#include <string>
|
|
208
316
|
#include <string_view>
|
|
209
317
|
#include <utility>
|
|
@@ -211,18 +319,54 @@ export function generateInvokeSupportSource({ manifest = {}, includeCommandMain
|
|
|
211
319
|
|
|
212
320
|
#include <flatbuffers/flatbuffers.h>
|
|
213
321
|
|
|
214
|
-
#include "
|
|
215
|
-
#include "PluginInvokeResponse_generated.h"
|
|
216
|
-
#include "TypedArenaBuffer_generated.h"
|
|
322
|
+
#include "sds/PIV/main_generated.h"
|
|
217
323
|
#include "space_data_module_invoke.h"
|
|
218
324
|
|
|
219
325
|
${renderMethodDeclarations(methods)}
|
|
220
326
|
|
|
221
327
|
namespace {
|
|
222
328
|
|
|
329
|
+
constexpr payloadWireFormat kPayloadWireFormatFlatbuffer =
|
|
330
|
+
static_cast<payloadWireFormat>(0);
|
|
331
|
+
constexpr payloadWireFormat kPayloadWireFormatAlignedBinary =
|
|
332
|
+
static_cast<payloadWireFormat>(1);
|
|
333
|
+
constexpr bufferMutability kBufferMutabilityImmutable =
|
|
334
|
+
static_cast<bufferMutability>(0);
|
|
335
|
+
constexpr bufferMutability kBufferMutabilitySingleWriterMutable =
|
|
336
|
+
static_cast<bufferMutability>(1);
|
|
337
|
+
constexpr bufferMutability kBufferMutabilityAppendOnly =
|
|
338
|
+
static_cast<bufferMutability>(2);
|
|
339
|
+
constexpr bufferOwnership kBufferOwnershipHostOwned =
|
|
340
|
+
static_cast<bufferOwnership>(0);
|
|
341
|
+
constexpr bufferOwnership kBufferOwnershipPluginOwned =
|
|
342
|
+
static_cast<bufferOwnership>(1);
|
|
343
|
+
constexpr bufferOwnership kBufferOwnershipTransferred =
|
|
344
|
+
static_cast<bufferOwnership>(2);
|
|
345
|
+
constexpr pivStatus kPivStatusOk = static_cast<pivStatus>(0);
|
|
346
|
+
constexpr pivStatus kPivStatusNotFound = static_cast<pivStatus>(1);
|
|
347
|
+
constexpr pivStatus kPivStatusYielded = static_cast<pivStatus>(2);
|
|
348
|
+
constexpr pivStatus kPivStatusFailed = static_cast<pivStatus>(3);
|
|
349
|
+
|
|
350
|
+
struct AcceptedTypeRef {
|
|
351
|
+
bool accepts_any_flatbuffer;
|
|
352
|
+
const char *schema_name;
|
|
353
|
+
const char *file_identifier;
|
|
354
|
+
uint32_t wire_format;
|
|
355
|
+
bool has_wire_format;
|
|
356
|
+
const char *root_type_name;
|
|
357
|
+
const char *schema_version;
|
|
358
|
+
const uint8_t *schema_hash;
|
|
359
|
+
uint32_t schema_hash_length;
|
|
360
|
+
uint16_t fixed_string_length;
|
|
361
|
+
uint32_t byte_length;
|
|
362
|
+
uint16_t required_alignment;
|
|
363
|
+
};
|
|
364
|
+
|
|
223
365
|
struct PortRequirement {
|
|
224
366
|
const char *port_id;
|
|
225
367
|
bool required;
|
|
368
|
+
const AcceptedTypeRef *accepted_types;
|
|
369
|
+
size_t accepted_type_count;
|
|
226
370
|
};
|
|
227
371
|
|
|
228
372
|
struct MethodDescriptor {
|
|
@@ -230,7 +374,7 @@ struct MethodDescriptor {
|
|
|
230
374
|
int (*handler)(void);
|
|
231
375
|
const PortRequirement *input_ports;
|
|
232
376
|
size_t input_port_count;
|
|
233
|
-
const
|
|
377
|
+
const PortRequirement *output_ports;
|
|
234
378
|
size_t output_port_count;
|
|
235
379
|
bool raw_shortcut_allowed;
|
|
236
380
|
const char *raw_input_port_id;
|
|
@@ -243,24 +387,45 @@ struct InputFrameOwned {
|
|
|
243
387
|
std::string schema_name{};
|
|
244
388
|
std::string file_identifier{};
|
|
245
389
|
std::string root_type_name{};
|
|
390
|
+
std::string schema_version{};
|
|
391
|
+
std::vector<uint8_t> schema_hash{};
|
|
392
|
+
uint32_t type_wire_format = 0;
|
|
393
|
+
// Owned storage is only used for the raw stdin shortcut path; the direct
|
|
394
|
+
// invoke path points views straight into the (8-aligned) request arena.
|
|
246
395
|
std::vector<uint8_t> payload{};
|
|
396
|
+
const uint8_t *external_payload = nullptr;
|
|
397
|
+
uint32_t external_payload_length = 0;
|
|
247
398
|
};
|
|
248
399
|
|
|
400
|
+
// Alignment guaranteed for every FlatBuffer base crossing the host<->module
|
|
401
|
+
// boundary: the host-allocated request region, the module-returned response
|
|
402
|
+
// pointer, and the payload arena inside each invoke envelope.
|
|
403
|
+
constexpr uint32_t kInvokeArenaAlignment = 8u;
|
|
404
|
+
// plugin_alloc hands out 16-aligned regions so frames declaring
|
|
405
|
+
// required_alignment up to 16 (e.g. SIMD/aligned-binary state vectors) hold
|
|
406
|
+
// as absolute addresses in linear memory.
|
|
407
|
+
constexpr uint32_t kInvokeAllocAlignment = 16u;
|
|
408
|
+
|
|
249
409
|
struct OutputFrameOwned {
|
|
250
410
|
std::string port_id{};
|
|
251
411
|
std::string schema_name{};
|
|
252
412
|
std::string file_identifier{};
|
|
253
413
|
std::string root_type_name{};
|
|
414
|
+
std::string schema_version{};
|
|
415
|
+
std::vector<uint8_t> schema_hash{};
|
|
254
416
|
uint32_t wire_format = 0;
|
|
255
417
|
uint16_t fixed_string_length = 0;
|
|
256
418
|
uint32_t byte_length = 0;
|
|
257
419
|
uint16_t required_alignment = 0;
|
|
258
420
|
uint16_t alignment = 8;
|
|
259
421
|
uint32_t generation = 0;
|
|
260
|
-
|
|
422
|
+
bool has_frame_id = false;
|
|
423
|
+
uint64_t frame_id = 0;
|
|
261
424
|
uint32_t stream_id = 0;
|
|
262
425
|
uint64_t sequence = 0;
|
|
263
426
|
bool end_of_stream = false;
|
|
427
|
+
const uint8_t *payload_ptr = nullptr;
|
|
428
|
+
uint32_t payload_length = 0;
|
|
264
429
|
std::vector<uint8_t> payload{};
|
|
265
430
|
};
|
|
266
431
|
|
|
@@ -268,19 +433,28 @@ struct InvokeContext {
|
|
|
268
433
|
const MethodDescriptor *method = nullptr;
|
|
269
434
|
std::vector<InputFrameOwned> inputs{};
|
|
270
435
|
std::vector<OutputFrameOwned> outputs{};
|
|
436
|
+
uint64_t trace_id = 0;
|
|
271
437
|
uint32_t backlog_remaining = 0;
|
|
272
438
|
bool yielded = false;
|
|
439
|
+
bool direct_external_arena_outputs = false;
|
|
273
440
|
int32_t status_code = 0;
|
|
274
441
|
std::string error_code{};
|
|
275
442
|
std::string error_message{};
|
|
276
443
|
};
|
|
277
444
|
|
|
445
|
+
struct AllocationRecord {
|
|
446
|
+
uint32_t ptr = 0;
|
|
447
|
+
uint32_t size = 0;
|
|
448
|
+
};
|
|
449
|
+
|
|
278
450
|
${renderMethodTables(methods)}
|
|
279
451
|
static const MethodDescriptor kMethodTable[] = {
|
|
280
452
|
${renderMethodDescriptors(methods)}
|
|
281
453
|
};
|
|
282
454
|
|
|
283
455
|
static InvokeContext g_invoke_context;
|
|
456
|
+
static std::vector<AllocationRecord> g_allocations{};
|
|
457
|
+
static bool g_direct_invoke_stream = false;
|
|
284
458
|
|
|
285
459
|
static uintptr_t PtrFromU32(uint32_t value) {
|
|
286
460
|
return static_cast<uintptr_t>(value);
|
|
@@ -298,6 +472,53 @@ static uint32_t *MutableU32Ptr(uint32_t value) {
|
|
|
298
472
|
return reinterpret_cast<uint32_t *>(PtrFromU32(value));
|
|
299
473
|
}
|
|
300
474
|
|
|
475
|
+
static bool U32RangeExceeds(uint32_t offset, uint32_t size, uint32_t arena_size) {
|
|
476
|
+
return offset > arena_size || size > arena_size - offset;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
static bool AllocationContains(uint32_t ptr, uint32_t length) {
|
|
480
|
+
if (length == 0u) {
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
if (ptr == 0u) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
for (const auto &allocation : g_allocations) {
|
|
487
|
+
if (ptr < allocation.ptr) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const uint32_t offset = ptr - allocation.ptr;
|
|
491
|
+
if (!U32RangeExceeds(offset, length, allocation.size)) {
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
static void TrackAllocation(uint32_t ptr, uint32_t size) {
|
|
499
|
+
if (ptr != 0u) {
|
|
500
|
+
g_allocations.push_back(AllocationRecord{ptr, size});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
static bool UntrackAllocation(uint32_t ptr) {
|
|
505
|
+
if (ptr == 0u) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
const auto before = g_allocations.size();
|
|
509
|
+
g_allocations.erase(
|
|
510
|
+
std::remove_if(
|
|
511
|
+
g_allocations.begin(),
|
|
512
|
+
g_allocations.end(),
|
|
513
|
+
[ptr](const AllocationRecord &allocation) {
|
|
514
|
+
return allocation.ptr == ptr;
|
|
515
|
+
}
|
|
516
|
+
),
|
|
517
|
+
g_allocations.end()
|
|
518
|
+
);
|
|
519
|
+
return g_allocations.size() != before;
|
|
520
|
+
}
|
|
521
|
+
|
|
301
522
|
static const MethodDescriptor *FindMethod(std::string_view method_id) {
|
|
302
523
|
for (const auto &method : kMethodTable) {
|
|
303
524
|
if (method_id == method.method_id) {
|
|
@@ -307,18 +528,258 @@ static const MethodDescriptor *FindMethod(std::string_view method_id) {
|
|
|
307
528
|
return nullptr;
|
|
308
529
|
}
|
|
309
530
|
|
|
310
|
-
static bool
|
|
311
|
-
|
|
531
|
+
static bool CStringExactlyMatches(const char *expected, const std::string &actual) {
|
|
532
|
+
return actual == (expected ? expected : "");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
static bool SchemaHashExactlyMatches(
|
|
536
|
+
const AcceptedTypeRef &accepted,
|
|
537
|
+
const std::vector<uint8_t> &actual
|
|
538
|
+
) {
|
|
539
|
+
if (accepted.schema_hash_length != actual.size()) {
|
|
312
540
|
return false;
|
|
313
541
|
}
|
|
314
|
-
|
|
315
|
-
|
|
542
|
+
if (accepted.schema_hash_length == 0u) {
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
if (!accepted.schema_hash) {
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
return std::equal(
|
|
549
|
+
accepted.schema_hash,
|
|
550
|
+
accepted.schema_hash + accepted.schema_hash_length,
|
|
551
|
+
actual.begin()
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
static bool IsPowerOfTwo(uint32_t value) {
|
|
556
|
+
return value > 0u && (value & (value - 1u)) == 0u;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
static const PortRequirement *FindInputPort(const MethodDescriptor *method, const std::string &port_id) {
|
|
560
|
+
if (!method) {
|
|
561
|
+
return nullptr;
|
|
562
|
+
}
|
|
563
|
+
for (size_t index = 0; index < method->input_port_count; index += 1) {
|
|
564
|
+
const auto &port = method->input_ports[index];
|
|
565
|
+
if (port.port_id && port_id == port.port_id) {
|
|
566
|
+
return &port;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return nullptr;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// A WILDCARD PORT IS BLIND TO FRAMING, NOT ONLY TO IDENTITY.
|
|
573
|
+
//
|
|
574
|
+
// acceptsAnyFlatbuffer declares application-blindness: the port cannot name
|
|
575
|
+
// one SDS identity because its payloads are defined by a host op, a foreign
|
|
576
|
+
// wire format, or an intra-flow control frame. Restricting it to the FLATBUFFER
|
|
577
|
+
// wire format made the SDK refuse frames its own convenience API produces:
|
|
578
|
+
// plugin_push_output_ex(..., PLUGIN_PAYLOAD_WIRE_FORMAT_ALIGNED_BINARY, ...)
|
|
579
|
+
// is the only way to emit variable-length raw bytes (JSON control frames,
|
|
580
|
+
// opaque byte routes), and every such frame was rejected as
|
|
581
|
+
// "does not match a declared type on port". The flow compiler already routes a
|
|
582
|
+
// wildcard edge as an OPAQUE byte route — that route IS aligned-binary bytes.
|
|
583
|
+
//
|
|
584
|
+
// An aligned-binary frame on a wildcard port still has to be self-consistent:
|
|
585
|
+
// alignment must be declared (>= 1). There is nothing else to check it against,
|
|
586
|
+
// because a wildcard declares no layout of its own.
|
|
587
|
+
static bool WildcardAcceptsWireFormat(uint32_t wire_format, uint16_t required_alignment) {
|
|
588
|
+
if (wire_format == static_cast<uint32_t>(kPayloadWireFormatFlatbuffer)) {
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
if (wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)) {
|
|
592
|
+
return required_alignment > 0u;
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
static bool InputTypeMatches(const AcceptedTypeRef &accepted, const InputFrameOwned &frame) {
|
|
598
|
+
if (accepted.accepts_any_flatbuffer) {
|
|
599
|
+
return WildcardAcceptsWireFormat(
|
|
600
|
+
frame.view.wire_format,
|
|
601
|
+
frame.view.required_alignment
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
if (accepted.has_wire_format && frame.view.wire_format != accepted.wire_format) {
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
if (!accepted.has_wire_format &&
|
|
608
|
+
frame.view.wire_format != static_cast<uint32_t>(kPayloadWireFormatFlatbuffer)) {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
if (frame.type_wire_format != frame.view.wire_format) {
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
if (
|
|
615
|
+
!CStringExactlyMatches(accepted.schema_name, frame.schema_name) ||
|
|
616
|
+
!CStringExactlyMatches(accepted.file_identifier, frame.file_identifier) ||
|
|
617
|
+
!CStringExactlyMatches(accepted.root_type_name, frame.root_type_name) ||
|
|
618
|
+
!CStringExactlyMatches(accepted.schema_version, frame.schema_version) ||
|
|
619
|
+
!SchemaHashExactlyMatches(accepted, frame.schema_hash)
|
|
620
|
+
) {
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
if (
|
|
624
|
+
frame.view.fixed_string_length != accepted.fixed_string_length ||
|
|
625
|
+
frame.view.required_alignment != accepted.required_alignment
|
|
626
|
+
) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
// A variable-length aligned stream (accepted.byte_length == 0) carries the
|
|
630
|
+
// frame's own size in byte_length, so an equality test would refuse every
|
|
631
|
+
// frame it accepts. The size contract is applied below, where the two shapes
|
|
632
|
+
// are distinguished.
|
|
633
|
+
if (accepted.byte_length != 0u && frame.view.byte_length != accepted.byte_length) {
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
if (frame.view.wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)) {
|
|
637
|
+
// byte_length == 0 declares a VARIABLE-LENGTH aligned stream (see the
|
|
638
|
+
// byteLength note in src/compliance/pluginCompliance.js): the frame must
|
|
639
|
+
// still be placed on the declared alignment, but there is no stride to
|
|
640
|
+
// check its size against. A declared stride is still enforced exactly.
|
|
641
|
+
if (
|
|
642
|
+
accepted.required_alignment == 0u ||
|
|
643
|
+
!IsPowerOfTwo(frame.view.alignment) ||
|
|
644
|
+
frame.view.alignment < accepted.required_alignment
|
|
645
|
+
) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
if (accepted.byte_length != 0u && frame.view.size != accepted.byte_length) {
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return true;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
static bool InputTypeAllowed(const PortRequirement &port, const InputFrameOwned &frame) {
|
|
656
|
+
if (port.accepted_type_count == 0u) {
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
for (size_t index = 0; index < port.accepted_type_count; index += 1) {
|
|
660
|
+
if (InputTypeMatches(port.accepted_types[index], frame)) {
|
|
316
661
|
return true;
|
|
317
662
|
}
|
|
318
663
|
}
|
|
319
664
|
return false;
|
|
320
665
|
}
|
|
321
666
|
|
|
667
|
+
static const AcceptedTypeRef *FindCanonicalInputType(const PortRequirement &port) {
|
|
668
|
+
for (size_t index = 0; index < port.accepted_type_count; index += 1) {
|
|
669
|
+
const auto &accepted = port.accepted_types[index];
|
|
670
|
+
if (
|
|
671
|
+
accepted.wire_format == static_cast<uint32_t>(kPayloadWireFormatFlatbuffer) &&
|
|
672
|
+
!accepted.accepts_any_flatbuffer
|
|
673
|
+
) {
|
|
674
|
+
return &accepted;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return nullptr;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
static const PortRequirement *FindOutputPort(
|
|
681
|
+
const MethodDescriptor *method,
|
|
682
|
+
const char *port_id
|
|
683
|
+
) {
|
|
684
|
+
if (!method || !port_id || !port_id[0]) {
|
|
685
|
+
return nullptr;
|
|
686
|
+
}
|
|
687
|
+
for (size_t index = 0; index < method->output_port_count; index += 1) {
|
|
688
|
+
const auto &port = method->output_ports[index];
|
|
689
|
+
if (port.port_id && std::strcmp(port.port_id, port_id) == 0) {
|
|
690
|
+
return &port;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return nullptr;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
static bool OptionalCStringMatches(const char *actual, const char *expected) {
|
|
697
|
+
return !actual || !actual[0] || std::strcmp(actual, expected ? expected : "") == 0;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
static bool OutputTypeMatches(
|
|
701
|
+
const AcceptedTypeRef &accepted,
|
|
702
|
+
const char *schema_name,
|
|
703
|
+
const char *file_identifier,
|
|
704
|
+
uint32_t wire_format,
|
|
705
|
+
const char *root_type_name,
|
|
706
|
+
uint16_t fixed_string_length,
|
|
707
|
+
uint32_t byte_length,
|
|
708
|
+
uint16_t required_alignment,
|
|
709
|
+
uint32_t payload_length
|
|
710
|
+
) {
|
|
711
|
+
if (accepted.accepts_any_flatbuffer) {
|
|
712
|
+
// Mirror of InputTypeMatches — see WildcardAcceptsWireFormat.
|
|
713
|
+
return WildcardAcceptsWireFormat(wire_format, required_alignment);
|
|
714
|
+
}
|
|
715
|
+
if (
|
|
716
|
+
!schema_name || !schema_name[0] ||
|
|
717
|
+
!file_identifier || !file_identifier[0] ||
|
|
718
|
+
std::strcmp(schema_name, accepted.schema_name ? accepted.schema_name : "") != 0 ||
|
|
719
|
+
std::strcmp(file_identifier, accepted.file_identifier ? accepted.file_identifier : "") != 0 ||
|
|
720
|
+
!OptionalCStringMatches(root_type_name, accepted.root_type_name)
|
|
721
|
+
) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
const uint32_t accepted_wire_format = accepted.has_wire_format
|
|
725
|
+
? accepted.wire_format
|
|
726
|
+
: static_cast<uint32_t>(kPayloadWireFormatFlatbuffer);
|
|
727
|
+
if (wire_format != accepted_wire_format) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
if (wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)) {
|
|
731
|
+
if (
|
|
732
|
+
fixed_string_length != accepted.fixed_string_length ||
|
|
733
|
+
required_alignment != accepted.required_alignment ||
|
|
734
|
+
accepted.required_alignment == 0u
|
|
735
|
+
) {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
// accepted.byte_length == 0: VARIABLE-LENGTH aligned stream — any payload
|
|
739
|
+
// size, placed on the declared alignment. Otherwise a fixed stride, which
|
|
740
|
+
// both the declared byte_length and the payload must match exactly.
|
|
741
|
+
if (accepted.byte_length == 0u) {
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
return byte_length == accepted.byte_length && payload_length == accepted.byte_length;
|
|
745
|
+
}
|
|
746
|
+
return fixed_string_length == 0u && byte_length == 0u && required_alignment == 0u;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
static const AcceptedTypeRef *ResolveOutputType(
|
|
750
|
+
const PortRequirement &port,
|
|
751
|
+
const char *schema_name,
|
|
752
|
+
const char *file_identifier,
|
|
753
|
+
uint32_t wire_format,
|
|
754
|
+
const char *root_type_name,
|
|
755
|
+
uint16_t fixed_string_length,
|
|
756
|
+
uint32_t byte_length,
|
|
757
|
+
uint16_t required_alignment,
|
|
758
|
+
uint32_t payload_length
|
|
759
|
+
) {
|
|
760
|
+
const AcceptedTypeRef *match = nullptr;
|
|
761
|
+
for (size_t index = 0; index < port.accepted_type_count; index += 1) {
|
|
762
|
+
const auto &accepted = port.accepted_types[index];
|
|
763
|
+
if (!OutputTypeMatches(
|
|
764
|
+
accepted,
|
|
765
|
+
schema_name,
|
|
766
|
+
file_identifier,
|
|
767
|
+
wire_format,
|
|
768
|
+
root_type_name,
|
|
769
|
+
fixed_string_length,
|
|
770
|
+
byte_length,
|
|
771
|
+
required_alignment,
|
|
772
|
+
payload_length)) {
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
if (match) {
|
|
776
|
+
return nullptr;
|
|
777
|
+
}
|
|
778
|
+
match = &accepted;
|
|
779
|
+
}
|
|
780
|
+
return match;
|
|
781
|
+
}
|
|
782
|
+
|
|
322
783
|
static void ResetInvokeContext(const MethodDescriptor *method) {
|
|
323
784
|
g_invoke_context = InvokeContext{};
|
|
324
785
|
g_invoke_context.method = method;
|
|
@@ -341,63 +802,188 @@ static uint32_t AlignOffset(uint32_t offset, uint32_t alignment) {
|
|
|
341
802
|
return remainder == 0u ? offset : offset + alignment - remainder;
|
|
342
803
|
}
|
|
343
804
|
|
|
344
|
-
static bool
|
|
805
|
+
static bool AlignOffsetChecked(size_t offset, uint32_t alignment, size_t *aligned_offset) {
|
|
806
|
+
if (!aligned_offset) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
if (alignment <= 1u) {
|
|
810
|
+
*aligned_offset = offset;
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
const size_t remainder = offset % static_cast<size_t>(alignment);
|
|
814
|
+
const size_t padding = remainder == 0u ? 0u : static_cast<size_t>(alignment) - remainder;
|
|
815
|
+
if (padding > std::numeric_limits<size_t>::max() - offset) {
|
|
816
|
+
return false;
|
|
817
|
+
}
|
|
818
|
+
*aligned_offset = offset + padding;
|
|
819
|
+
return true;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
static std::string FlatBufferStringValue(const ::flatbuffers::String *value) {
|
|
823
|
+
return value ? std::string(value->c_str(), value->size()) : std::string();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
static uint64_t DecodeSdsFrameSequence(uint64_t frame_id) {
|
|
827
|
+
return frame_id >> 1u;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
static bool DecodeSdsFrameEndOfStream(uint64_t frame_id) {
|
|
831
|
+
return (frame_id & 1u) != 0u;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
static uint64_t EncodeSdsFrameId(uint64_t sequence, bool end_of_stream) {
|
|
835
|
+
return (sequence << 1u) | (end_of_stream ? 1u : 0u);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
static bool FrameRangeExceedsArena(
|
|
839
|
+
size_t payload_offset,
|
|
840
|
+
size_t payload_size,
|
|
841
|
+
size_t arena_size
|
|
842
|
+
) {
|
|
843
|
+
return payload_offset > arena_size || payload_size > arena_size - payload_offset;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
static void PopulateInputView(InputFrameOwned *owned) {
|
|
847
|
+
if (!owned) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
owned->view.port_id = owned->port_id.empty() ? nullptr : owned->port_id.c_str();
|
|
851
|
+
owned->view.schema_name = owned->schema_name.empty() ? nullptr : owned->schema_name.c_str();
|
|
852
|
+
owned->view.file_identifier = owned->file_identifier.empty() ? nullptr : owned->file_identifier.c_str();
|
|
853
|
+
owned->view.root_type_name = owned->root_type_name.empty() ? nullptr : owned->root_type_name.c_str();
|
|
854
|
+
owned->view.schema_version = owned->schema_version.empty() ? nullptr : owned->schema_version.c_str();
|
|
855
|
+
owned->view.schema_hash = owned->schema_hash.empty() ? nullptr : owned->schema_hash.data();
|
|
856
|
+
owned->view.schema_hash_length = static_cast<uint32_t>(owned->schema_hash.size());
|
|
857
|
+
owned->view.frame_id = owned->view.trace_id;
|
|
858
|
+
if (owned->external_payload && owned->external_payload_length > 0u) {
|
|
859
|
+
owned->view.payload = owned->external_payload;
|
|
860
|
+
owned->view.payload_length = owned->external_payload_length;
|
|
861
|
+
} else {
|
|
862
|
+
owned->view.payload = owned->payload.empty() ? nullptr : owned->payload.data();
|
|
863
|
+
owned->view.payload_length = static_cast<uint32_t>(owned->payload.size());
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
static bool LoadInputsFromPivRequest(const PIVRequest &request) {
|
|
345
868
|
g_invoke_context.inputs.clear();
|
|
346
|
-
g_invoke_context.inputs.reserve(request.input_frames.size());
|
|
347
869
|
|
|
348
|
-
|
|
349
|
-
|
|
870
|
+
const auto *input_frames = request.INPUTS();
|
|
871
|
+
const auto *payload_arena = request.PAYLOAD_ARENA();
|
|
872
|
+
const size_t input_count = input_frames ? input_frames->size() : 0u;
|
|
873
|
+
const size_t arena_size = payload_arena ? payload_arena->size() : 0u;
|
|
874
|
+
g_invoke_context.inputs.reserve(input_count);
|
|
875
|
+
|
|
876
|
+
for (size_t index = 0; index < input_count; index += 1) {
|
|
877
|
+
const auto *frame = input_frames->Get(static_cast<::flatbuffers::uoffset_t>(index));
|
|
878
|
+
if (!frame) {
|
|
350
879
|
continue;
|
|
351
880
|
}
|
|
352
881
|
|
|
353
|
-
const auto
|
|
354
|
-
const auto
|
|
355
|
-
const
|
|
356
|
-
if (
|
|
882
|
+
const auto payload_offset = static_cast<size_t>(frame->OFFSET());
|
|
883
|
+
const auto payload_size = static_cast<size_t>(frame->SIZE());
|
|
884
|
+
const uint32_t frame_alignment = frame->ALIGNMENT() > 0u ? frame->ALIGNMENT() : 1u;
|
|
885
|
+
if (frame_alignment > std::numeric_limits<uint16_t>::max()) {
|
|
886
|
+
SetError("invalid-request-frame", "SDS PIV TAB alignment exceeds the module ABI limit.");
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
889
|
+
const uint8_t *payload_ptr = nullptr;
|
|
890
|
+
if (payload_size > 0u && arena_size == 0u) {
|
|
891
|
+
if (
|
|
892
|
+
payload_offset > std::numeric_limits<uint32_t>::max() ||
|
|
893
|
+
payload_size > std::numeric_limits<uint32_t>::max() ||
|
|
894
|
+
!AllocationContains(
|
|
895
|
+
static_cast<uint32_t>(payload_offset),
|
|
896
|
+
static_cast<uint32_t>(payload_size)
|
|
897
|
+
)
|
|
898
|
+
) {
|
|
899
|
+
SetError(
|
|
900
|
+
"invalid-request-pointer",
|
|
901
|
+
"SDS PIV external arena TAB payload range is not owned by the module SDK allocator."
|
|
902
|
+
);
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
payload_ptr = ConstPtr(static_cast<uint32_t>(payload_offset));
|
|
906
|
+
} else if (FrameRangeExceedsArena(payload_offset, payload_size, arena_size)) {
|
|
357
907
|
SetError("invalid-request-frame", "Input frame payload range exceeds request payload arena.");
|
|
358
908
|
return false;
|
|
909
|
+
} else if (payload_size > 0u && payload_arena) {
|
|
910
|
+
payload_ptr = payload_arena->data() + static_cast<std::ptrdiff_t>(payload_offset);
|
|
911
|
+
}
|
|
912
|
+
if (
|
|
913
|
+
payload_ptr &&
|
|
914
|
+
frame_alignment > 1u &&
|
|
915
|
+
(reinterpret_cast<uintptr_t>(payload_ptr) % frame_alignment) != 0u
|
|
916
|
+
) {
|
|
917
|
+
SetError("misaligned-input-frame", "SDS PIV TAB payload violates its declared alignment.");
|
|
918
|
+
return false;
|
|
359
919
|
}
|
|
360
920
|
|
|
361
921
|
g_invoke_context.inputs.emplace_back();
|
|
362
922
|
auto &owned = g_invoke_context.inputs.back();
|
|
363
923
|
owned = InputFrameOwned{};
|
|
364
|
-
owned.port_id = frame
|
|
365
|
-
if (frame
|
|
366
|
-
owned.schema_name =
|
|
367
|
-
owned.file_identifier =
|
|
368
|
-
owned.root_type_name =
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
owned.
|
|
388
|
-
owned.
|
|
389
|
-
|
|
390
|
-
owned.view.
|
|
391
|
-
owned.view.
|
|
392
|
-
owned.view.
|
|
393
|
-
owned.view.
|
|
394
|
-
|
|
395
|
-
owned.view.
|
|
924
|
+
owned.port_id = FlatBufferStringValue(frame->PORT_ID());
|
|
925
|
+
if (const auto *type_ref = frame->TYPE_REF()) {
|
|
926
|
+
owned.schema_name = FlatBufferStringValue(type_ref->SCHEMA_NAME());
|
|
927
|
+
owned.file_identifier = FlatBufferStringValue(type_ref->FILE_IDENTIFIER());
|
|
928
|
+
owned.root_type_name = FlatBufferStringValue(type_ref->ROOT_TYPE());
|
|
929
|
+
owned.schema_version = FlatBufferStringValue(type_ref->SCHEMA_VERSION());
|
|
930
|
+
if (const auto *schema_hash = type_ref->SCHEMA_HASH()) {
|
|
931
|
+
owned.schema_hash.assign(schema_hash->begin(), schema_hash->end());
|
|
932
|
+
}
|
|
933
|
+
owned.type_wire_format = static_cast<uint32_t>(type_ref->WIRE_FORMAT());
|
|
934
|
+
// A compiled edge descriptor describes the canonical/aligned pair. A
|
|
935
|
+
// host may therefore carry the aligned peer's fixed-layout scalars on a
|
|
936
|
+
// canonical PIV type reference. They are not part of the canonical
|
|
937
|
+
// representation and the public input ABI promises canonical zeroes.
|
|
938
|
+
// Preserve them only for aligned-binary frames, where exact layout and
|
|
939
|
+
// alignment validation below remains mandatory.
|
|
940
|
+
if (owned.type_wire_format ==
|
|
941
|
+
static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)) {
|
|
942
|
+
owned.view.fixed_string_length = type_ref->FIXED_STRING_LENGTH();
|
|
943
|
+
owned.view.byte_length = type_ref->BYTE_LENGTH();
|
|
944
|
+
owned.view.required_alignment = type_ref->REQUIRED_ALIGNMENT();
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
owned.external_payload = payload_ptr;
|
|
948
|
+
owned.external_payload_length = static_cast<uint32_t>(payload_size);
|
|
949
|
+
|
|
950
|
+
owned.view.wire_format = static_cast<uint32_t>(frame->WIRE_FORMAT());
|
|
951
|
+
owned.view.alignment = static_cast<uint16_t>(frame_alignment);
|
|
952
|
+
owned.view.size = frame->SIZE();
|
|
953
|
+
owned.view.generation = 0;
|
|
954
|
+
const auto frame_id = frame->FRAME_ID();
|
|
955
|
+
owned.view.trace_id = frame_id;
|
|
956
|
+
owned.view.stream_id = 0;
|
|
957
|
+
owned.view.sequence = DecodeSdsFrameSequence(frame_id);
|
|
958
|
+
owned.view.end_of_stream = DecodeSdsFrameEndOfStream(frame_id) ? 1 : 0;
|
|
959
|
+
owned.view.ownership = static_cast<uint32_t>(frame->OWNERSHIP());
|
|
960
|
+
owned.view.mutability = static_cast<uint32_t>(frame->MUTABILITY());
|
|
961
|
+
PopulateInputView(&owned);
|
|
396
962
|
}
|
|
397
963
|
|
|
398
964
|
return true;
|
|
399
965
|
}
|
|
400
966
|
|
|
967
|
+
static bool PivRequestUsesExternalPayloadArena(const PIVRequest &request) {
|
|
968
|
+
const auto *payload_arena = request.PAYLOAD_ARENA();
|
|
969
|
+
if (payload_arena && payload_arena->size() > 0u) {
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
const auto *input_frames = request.INPUTS();
|
|
973
|
+
if (!input_frames) {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
for (size_t index = 0; index < input_frames->size(); index += 1) {
|
|
977
|
+
const auto *frame = input_frames->Get(
|
|
978
|
+
static_cast<::flatbuffers::uoffset_t>(index)
|
|
979
|
+
);
|
|
980
|
+
if (frame && frame->SIZE() > 0u) {
|
|
981
|
+
return true;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
|
|
401
987
|
static bool ValidateRequiredInputs(const MethodDescriptor *method) {
|
|
402
988
|
if (!method) {
|
|
403
989
|
return false;
|
|
@@ -425,61 +1011,255 @@ static bool ValidateRequiredInputs(const MethodDescriptor *method) {
|
|
|
425
1011
|
return true;
|
|
426
1012
|
}
|
|
427
1013
|
|
|
428
|
-
static
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
1014
|
+
static bool InputBufferContractAllowed(const plugin_input_frame_t &frame) {
|
|
1015
|
+
const bool known_ownership =
|
|
1016
|
+
frame.ownership == static_cast<uint32_t>(kBufferOwnershipHostOwned) ||
|
|
1017
|
+
frame.ownership == static_cast<uint32_t>(kBufferOwnershipPluginOwned) ||
|
|
1018
|
+
frame.ownership == static_cast<uint32_t>(kBufferOwnershipTransferred);
|
|
1019
|
+
const bool immutable =
|
|
1020
|
+
frame.mutability == static_cast<uint32_t>(kBufferMutabilityImmutable);
|
|
1021
|
+
const bool mutable_or_append_only =
|
|
1022
|
+
frame.mutability == static_cast<uint32_t>(kBufferMutabilitySingleWriterMutable) ||
|
|
1023
|
+
frame.mutability == static_cast<uint32_t>(kBufferMutabilityAppendOnly);
|
|
1024
|
+
if (!known_ownership || (!immutable && !mutable_or_append_only)) {
|
|
1025
|
+
return false;
|
|
1026
|
+
}
|
|
1027
|
+
return immutable ||
|
|
1028
|
+
frame.ownership == static_cast<uint32_t>(kBufferOwnershipTransferred);
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
static bool ValidateInputFrames(const MethodDescriptor *method) {
|
|
1032
|
+
if (!method) {
|
|
1033
|
+
return false;
|
|
1034
|
+
}
|
|
1035
|
+
for (const auto &frame : g_invoke_context.inputs) {
|
|
1036
|
+
const auto *port = FindInputPort(method, frame.port_id);
|
|
1037
|
+
if (!port) {
|
|
1038
|
+
SetError(
|
|
1039
|
+
"unknown-input-port",
|
|
1040
|
+
std::string("Input frame uses undeclared port: ") + frame.port_id
|
|
1041
|
+
);
|
|
1042
|
+
return false;
|
|
1043
|
+
}
|
|
1044
|
+
if (!InputBufferContractAllowed(frame.view)) {
|
|
1045
|
+
SetError(
|
|
1046
|
+
"incompatible-input-buffer-contract",
|
|
1047
|
+
std::string("Input frame ownership/mutability is incompatible with port: ") +
|
|
1048
|
+
frame.port_id
|
|
1049
|
+
);
|
|
1050
|
+
return false;
|
|
1051
|
+
}
|
|
1052
|
+
if (!InputTypeAllowed(*port, frame)) {
|
|
1053
|
+
SetError(
|
|
1054
|
+
"unsupported-input-type",
|
|
1055
|
+
std::string("Input frame type is not accepted by port: ") + frame.port_id
|
|
1056
|
+
);
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
return ValidateRequiredInputs(method);
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
static pivStatus ResolvePivStatus(
|
|
1064
|
+
int32_t status_code,
|
|
1065
|
+
bool yielded,
|
|
1066
|
+
const std::string &error_code
|
|
1067
|
+
) {
|
|
1068
|
+
if (yielded) {
|
|
1069
|
+
return kPivStatusYielded;
|
|
1070
|
+
}
|
|
1071
|
+
if (status_code == 404) {
|
|
1072
|
+
return kPivStatusNotFound;
|
|
1073
|
+
}
|
|
1074
|
+
if (status_code != 0 || !error_code.empty()) {
|
|
1075
|
+
return kPivStatusFailed;
|
|
1076
|
+
}
|
|
1077
|
+
return kPivStatusOk;
|
|
1078
|
+
}
|
|
435
1079
|
|
|
436
|
-
|
|
437
|
-
|
|
1080
|
+
static std::vector<uint8_t> SerializePivResponse(
|
|
1081
|
+
int32_t status_code,
|
|
1082
|
+
bool yielded,
|
|
1083
|
+
uint32_t backlog_remaining,
|
|
1084
|
+
const std::vector<OutputFrameOwned> &outputs,
|
|
1085
|
+
const std::string &error_code,
|
|
1086
|
+
const std::string &error_message,
|
|
1087
|
+
uint64_t trace_id = 0,
|
|
1088
|
+
bool external_payload_descriptors = false
|
|
1089
|
+
) {
|
|
1090
|
+
struct PackedOutputFrame {
|
|
1091
|
+
const OutputFrameOwned *output = nullptr;
|
|
1092
|
+
uint32_t offset = 0;
|
|
1093
|
+
uint32_t size = 0;
|
|
1094
|
+
uint32_t alignment = 1;
|
|
1095
|
+
bufferOwnership ownership = kBufferOwnershipHostOwned;
|
|
1096
|
+
};
|
|
1097
|
+
|
|
1098
|
+
std::vector<uint8_t> payload_arena{};
|
|
1099
|
+
std::vector<PackedOutputFrame> packed_outputs{};
|
|
1100
|
+
size_t arena_offset = 0;
|
|
1101
|
+
for (const auto &output : outputs) {
|
|
438
1102
|
const uint32_t alignment = std::max<uint32_t>(
|
|
439
1103
|
1u,
|
|
440
1104
|
output.required_alignment > 0 ? output.required_alignment : output.alignment
|
|
441
1105
|
);
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
1106
|
+
if (external_payload_descriptors) {
|
|
1107
|
+
if (!output.payload_ptr && output.payload_length > 0u) {
|
|
1108
|
+
return SerializePivResponse(
|
|
1109
|
+
500,
|
|
1110
|
+
false,
|
|
1111
|
+
0,
|
|
1112
|
+
{},
|
|
1113
|
+
"invalid-output-payload",
|
|
1114
|
+
"Direct output descriptor payload pointer is null but payload length is non-zero.",
|
|
1115
|
+
trace_id,
|
|
1116
|
+
false
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
const uintptr_t payload_address = reinterpret_cast<uintptr_t>(output.payload_ptr);
|
|
1120
|
+
if (
|
|
1121
|
+
payload_address > std::numeric_limits<uint32_t>::max() ||
|
|
1122
|
+
output.payload_length >
|
|
1123
|
+
static_cast<uint32_t>(std::numeric_limits<uint32_t>::max() - payload_address)
|
|
1124
|
+
) {
|
|
1125
|
+
return SerializePivResponse(
|
|
1126
|
+
500,
|
|
1127
|
+
false,
|
|
1128
|
+
0,
|
|
1129
|
+
{},
|
|
1130
|
+
"output-pointer-overflow",
|
|
1131
|
+
"Direct output descriptor exceeds the 32-bit SDS TAB offset range.",
|
|
1132
|
+
trace_id,
|
|
1133
|
+
false
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
packed_outputs.push_back(PackedOutputFrame{
|
|
1137
|
+
&output,
|
|
1138
|
+
static_cast<uint32_t>(payload_address),
|
|
1139
|
+
output.payload_length,
|
|
1140
|
+
alignment,
|
|
1141
|
+
kBufferOwnershipPluginOwned,
|
|
1142
|
+
});
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
size_t aligned_offset = 0;
|
|
1147
|
+
if (
|
|
1148
|
+
!AlignOffsetChecked(arena_offset, alignment, &aligned_offset) ||
|
|
1149
|
+
aligned_offset > std::numeric_limits<uint32_t>::max() ||
|
|
1150
|
+
output.payload.size() >
|
|
1151
|
+
static_cast<size_t>(std::numeric_limits<uint32_t>::max()) - aligned_offset
|
|
1152
|
+
) {
|
|
1153
|
+
return SerializePivResponse(
|
|
1154
|
+
500,
|
|
1155
|
+
false,
|
|
1156
|
+
0,
|
|
1157
|
+
{},
|
|
1158
|
+
"output-arena-overflow",
|
|
1159
|
+
"Output payload arena exceeds the 32-bit SDS TAB offset range.",
|
|
1160
|
+
trace_id,
|
|
1161
|
+
false
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
payload_arena.resize(aligned_offset, 0);
|
|
1165
|
+
payload_arena.insert(
|
|
1166
|
+
payload_arena.end(),
|
|
446
1167
|
output.payload.begin(),
|
|
447
1168
|
output.payload.end()
|
|
448
1169
|
);
|
|
449
|
-
arena_offset = aligned_offset +
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
output.byte_length > 0 ? output.byte_length : static_cast<uint32_t>(output.payload.size());
|
|
460
|
-
type_ref->required_alignment = output.required_alignment;
|
|
461
|
-
|
|
462
|
-
auto frame = std::make_unique<orbpro::stream::TypedArenaBufferT>();
|
|
463
|
-
frame->type_ref = std::move(type_ref);
|
|
464
|
-
frame->port_id = output.port_id;
|
|
465
|
-
frame->alignment = static_cast<uint16_t>(alignment);
|
|
466
|
-
frame->offset = aligned_offset;
|
|
467
|
-
frame->size = static_cast<uint32_t>(output.payload.size());
|
|
468
|
-
frame->generation = output.generation;
|
|
469
|
-
frame->trace_id = output.trace_id;
|
|
470
|
-
frame->stream_id = output.stream_id;
|
|
471
|
-
frame->sequence = output.sequence;
|
|
472
|
-
frame->end_of_stream = output.end_of_stream;
|
|
473
|
-
response.output_frames.emplace_back(std::move(frame));
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
return response;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
static std::vector<uint8_t> SerializeResponse(const orbpro::invoke::PluginInvokeResponseT &response) {
|
|
1170
|
+
arena_offset = aligned_offset + output.payload.size();
|
|
1171
|
+
packed_outputs.push_back(PackedOutputFrame{
|
|
1172
|
+
&output,
|
|
1173
|
+
static_cast<uint32_t>(aligned_offset),
|
|
1174
|
+
static_cast<uint32_t>(output.payload.size()),
|
|
1175
|
+
alignment,
|
|
1176
|
+
kBufferOwnershipHostOwned,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
|
|
480
1180
|
::flatbuffers::FlatBufferBuilder builder(1024);
|
|
481
|
-
|
|
482
|
-
|
|
1181
|
+
std::vector<::flatbuffers::Offset<TAB>> output_frames{};
|
|
1182
|
+
output_frames.reserve(packed_outputs.size());
|
|
1183
|
+
for (const auto &packed : packed_outputs) {
|
|
1184
|
+
const auto *output = packed.output;
|
|
1185
|
+
const auto wire_format =
|
|
1186
|
+
output && output->wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)
|
|
1187
|
+
? kPayloadWireFormatAlignedBinary
|
|
1188
|
+
: kPayloadWireFormatFlatbuffer;
|
|
1189
|
+
const auto type_ref = CreateFlatBufferTypeRefDirect(
|
|
1190
|
+
builder,
|
|
1191
|
+
output && !output->schema_name.empty() ? output->schema_name.c_str() : nullptr,
|
|
1192
|
+
output && !output->file_identifier.empty() ? output->file_identifier.c_str() : nullptr,
|
|
1193
|
+
output && !output->schema_version.empty() ? output->schema_version.c_str() : nullptr,
|
|
1194
|
+
output && !output->root_type_name.empty() ? output->root_type_name.c_str() : nullptr,
|
|
1195
|
+
output && !output->schema_hash.empty() ? &output->schema_hash : nullptr,
|
|
1196
|
+
false,
|
|
1197
|
+
wire_format,
|
|
1198
|
+
output ? output->fixed_string_length : 0u,
|
|
1199
|
+
output ? output->byte_length : 0u,
|
|
1200
|
+
output ? output->required_alignment : 0u
|
|
1201
|
+
);
|
|
1202
|
+
output_frames.push_back(CreateTABDirect(
|
|
1203
|
+
builder,
|
|
1204
|
+
packed.offset,
|
|
1205
|
+
packed.size,
|
|
1206
|
+
packed.alignment,
|
|
1207
|
+
wire_format,
|
|
1208
|
+
type_ref,
|
|
1209
|
+
kBufferMutabilityImmutable,
|
|
1210
|
+
packed.ownership,
|
|
1211
|
+
output && output->has_frame_id ? output->frame_id : 0,
|
|
1212
|
+
output && !output->port_id.empty() ? output->port_id.c_str() : nullptr
|
|
1213
|
+
));
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
const auto output_vector = builder.CreateVector(output_frames);
|
|
1217
|
+
size_t arena_alignment = static_cast<size_t>(kInvokeArenaAlignment);
|
|
1218
|
+
for (const auto &packed : packed_outputs) {
|
|
1219
|
+
if (static_cast<size_t>(packed.alignment) > arena_alignment) {
|
|
1220
|
+
arena_alignment = static_cast<size_t>(packed.alignment);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
builder.ForceVectorAlignment(
|
|
1224
|
+
payload_arena.size(),
|
|
1225
|
+
sizeof(uint8_t),
|
|
1226
|
+
arena_alignment
|
|
1227
|
+
);
|
|
1228
|
+
const auto arena_vector = builder.CreateVector(payload_arena);
|
|
1229
|
+
const auto error_code_offset =
|
|
1230
|
+
error_code.empty() ? 0 : builder.CreateString(error_code);
|
|
1231
|
+
const auto error_message_offset =
|
|
1232
|
+
error_message.empty() ? 0 : builder.CreateString(error_message);
|
|
1233
|
+
const auto response = CreatePIVResponse(
|
|
1234
|
+
builder,
|
|
1235
|
+
status_code,
|
|
1236
|
+
ResolvePivStatus(status_code, yielded, error_code),
|
|
1237
|
+
yielded,
|
|
1238
|
+
backlog_remaining,
|
|
1239
|
+
output_vector,
|
|
1240
|
+
arena_vector,
|
|
1241
|
+
error_code_offset,
|
|
1242
|
+
error_message_offset,
|
|
1243
|
+
trace_id
|
|
1244
|
+
);
|
|
1245
|
+
const auto root = CreatePIV(builder, 0, response);
|
|
1246
|
+
FinishPIVBuffer(builder, root);
|
|
1247
|
+
if (!payload_arena.empty()) {
|
|
1248
|
+
const auto *serialized =
|
|
1249
|
+
GetPIV(builder.GetBufferPointer());
|
|
1250
|
+
const auto *response_table = serialized ? serialized->RESPONSE() : nullptr;
|
|
1251
|
+
const auto *serialized_arena = response_table ? response_table->PAYLOAD_ARENA() : nullptr;
|
|
1252
|
+
if (!serialized_arena) {
|
|
1253
|
+
std::abort();
|
|
1254
|
+
}
|
|
1255
|
+
const auto arena_offset = static_cast<size_t>(
|
|
1256
|
+
serialized_arena->data() - builder.GetBufferPointer()
|
|
1257
|
+
);
|
|
1258
|
+
if (arena_offset % arena_alignment != 0u) {
|
|
1259
|
+
std::abort();
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
483
1263
|
return std::vector<uint8_t>(
|
|
484
1264
|
builder.GetBufferPointer(),
|
|
485
1265
|
builder.GetBufferPointer() + builder.GetSize()
|
|
@@ -489,20 +1269,59 @@ static std::vector<uint8_t> SerializeResponse(const orbpro::invoke::PluginInvoke
|
|
|
489
1269
|
static std::vector<uint8_t> SerializeErrorResponse(
|
|
490
1270
|
int32_t status_code,
|
|
491
1271
|
const char *error_code,
|
|
492
|
-
const std::string &error_message
|
|
1272
|
+
const std::string &error_message,
|
|
1273
|
+
uint64_t trace_id = 0
|
|
493
1274
|
) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
1275
|
+
return SerializePivResponse(
|
|
1276
|
+
status_code,
|
|
1277
|
+
false,
|
|
1278
|
+
0,
|
|
1279
|
+
{},
|
|
1280
|
+
error_code ? error_code : "invoke-error",
|
|
1281
|
+
error_message,
|
|
1282
|
+
trace_id
|
|
1283
|
+
);
|
|
499
1284
|
}
|
|
500
1285
|
|
|
501
|
-
static std::vector<uint8_t>
|
|
502
|
-
|
|
1286
|
+
static std::vector<uint8_t> SerializeContextResponse() {
|
|
1287
|
+
return SerializePivResponse(
|
|
1288
|
+
g_invoke_context.status_code,
|
|
1289
|
+
g_invoke_context.yielded,
|
|
1290
|
+
g_invoke_context.backlog_remaining,
|
|
1291
|
+
g_invoke_context.outputs,
|
|
1292
|
+
g_invoke_context.error_code,
|
|
1293
|
+
g_invoke_context.error_message,
|
|
1294
|
+
g_invoke_context.trace_id,
|
|
1295
|
+
g_invoke_context.direct_external_arena_outputs
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
static std::vector<uint8_t> DispatchLoadedContext(
|
|
1300
|
+
const MethodDescriptor *method,
|
|
1301
|
+
bool inputs_loaded,
|
|
503
1302
|
bool *runtime_error
|
|
504
1303
|
) {
|
|
505
|
-
|
|
1304
|
+
if (!inputs_loaded || !ValidateInputFrames(method)) {
|
|
1305
|
+
if (runtime_error) {
|
|
1306
|
+
*runtime_error = true;
|
|
1307
|
+
}
|
|
1308
|
+
if (g_invoke_context.status_code == 0) {
|
|
1309
|
+
g_invoke_context.status_code = 400;
|
|
1310
|
+
}
|
|
1311
|
+
return SerializeContextResponse();
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
g_invoke_context.status_code = method->handler ? method->handler() : -1;
|
|
1315
|
+
return SerializeContextResponse();
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
static std::vector<uint8_t> DispatchPivRequestObject(
|
|
1319
|
+
const PIVRequest &request,
|
|
1320
|
+
bool *runtime_error
|
|
1321
|
+
) {
|
|
1322
|
+
const auto method_id = FlatBufferStringValue(request.METHOD_ID());
|
|
1323
|
+
const auto trace_id = request.TRACE_ID();
|
|
1324
|
+
const auto *method = FindMethod(method_id);
|
|
506
1325
|
if (!method) {
|
|
507
1326
|
if (runtime_error) {
|
|
508
1327
|
*runtime_error = true;
|
|
@@ -510,23 +1329,20 @@ static std::vector<uint8_t> DispatchRequestObject(
|
|
|
510
1329
|
return SerializeErrorResponse(
|
|
511
1330
|
404,
|
|
512
1331
|
"unknown-method",
|
|
513
|
-
std::string("Unknown method: ") +
|
|
1332
|
+
std::string("Unknown method: ") + method_id,
|
|
1333
|
+
trace_id
|
|
514
1334
|
);
|
|
515
1335
|
}
|
|
516
1336
|
|
|
517
1337
|
ResetInvokeContext(method);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
g_invoke_context.status_code = method->handler ? method->handler() : -1;
|
|
529
|
-
return SerializeResponse(BuildResponseObject());
|
|
1338
|
+
g_invoke_context.trace_id = trace_id;
|
|
1339
|
+
g_invoke_context.direct_external_arena_outputs =
|
|
1340
|
+
g_direct_invoke_stream && PivRequestUsesExternalPayloadArena(request);
|
|
1341
|
+
return DispatchLoadedContext(
|
|
1342
|
+
method,
|
|
1343
|
+
LoadInputsFromPivRequest(request),
|
|
1344
|
+
runtime_error
|
|
1345
|
+
);
|
|
530
1346
|
}
|
|
531
1347
|
|
|
532
1348
|
static std::vector<uint8_t> DispatchRequestBytes(
|
|
@@ -541,17 +1357,30 @@ static std::vector<uint8_t> DispatchRequestBytes(
|
|
|
541
1357
|
return SerializeErrorResponse(400, "invalid-request", "Invoke request bytes are empty.");
|
|
542
1358
|
}
|
|
543
1359
|
|
|
1360
|
+
if (request_len < 8u || !PIVBufferHasIdentifier(request_bytes)) {
|
|
1361
|
+
if (runtime_error) {
|
|
1362
|
+
*runtime_error = true;
|
|
1363
|
+
}
|
|
1364
|
+
return SerializeErrorResponse(400, "invalid-request", "Invoke request must be an SDS PIV envelope.");
|
|
1365
|
+
}
|
|
1366
|
+
|
|
544
1367
|
::flatbuffers::Verifier verifier(request_bytes, request_len);
|
|
545
|
-
if (!
|
|
1368
|
+
if (!VerifyPIVBuffer(verifier)) {
|
|
546
1369
|
if (runtime_error) {
|
|
547
1370
|
*runtime_error = true;
|
|
548
1371
|
}
|
|
549
|
-
return SerializeErrorResponse(400, "invalid-request", "
|
|
1372
|
+
return SerializeErrorResponse(400, "invalid-request", "SDS PIV invoke envelope verification failed.");
|
|
550
1373
|
}
|
|
551
1374
|
|
|
552
|
-
const auto *
|
|
553
|
-
auto
|
|
554
|
-
|
|
1375
|
+
const auto *envelope = GetPIV(request_bytes);
|
|
1376
|
+
const auto *request = envelope ? envelope->REQUEST() : nullptr;
|
|
1377
|
+
if (!request) {
|
|
1378
|
+
if (runtime_error) {
|
|
1379
|
+
*runtime_error = true;
|
|
1380
|
+
}
|
|
1381
|
+
return SerializeErrorResponse(400, "invalid-request", "SDS PIV invoke envelope does not contain a request.");
|
|
1382
|
+
}
|
|
1383
|
+
return DispatchPivRequestObject(*request, runtime_error);
|
|
555
1384
|
}
|
|
556
1385
|
|
|
557
1386
|
static bool ReadAllStdin(std::vector<uint8_t> *bytes_out) {
|
|
@@ -586,26 +1415,68 @@ static bool WriteAllStdout(const uint8_t *bytes, size_t length) {
|
|
|
586
1415
|
return std::fwrite(bytes, 1, length, stdout) == length && std::fflush(stdout) == 0;
|
|
587
1416
|
}
|
|
588
1417
|
|
|
589
|
-
static bool
|
|
1418
|
+
static bool LoadRawShortcutInput(
|
|
590
1419
|
const MethodDescriptor *method,
|
|
591
|
-
const std::vector<uint8_t> &stdin_bytes
|
|
592
|
-
orbpro::invoke::PluginInvokeRequestT *request
|
|
1420
|
+
const std::vector<uint8_t> &stdin_bytes
|
|
593
1421
|
) {
|
|
594
|
-
if (!method || !method->raw_shortcut_allowed
|
|
1422
|
+
if (!method || !method->raw_shortcut_allowed) {
|
|
595
1423
|
return false;
|
|
596
1424
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
1425
|
+
g_invoke_context.inputs.clear();
|
|
1426
|
+
g_invoke_context.inputs.emplace_back();
|
|
1427
|
+
auto &owned = g_invoke_context.inputs.back();
|
|
1428
|
+
owned = InputFrameOwned{};
|
|
1429
|
+
if (method->input_port_count != 1u) {
|
|
1430
|
+
return false;
|
|
1431
|
+
}
|
|
1432
|
+
const auto *accepted = FindCanonicalInputType(method->input_ports[0]);
|
|
1433
|
+
if (!accepted) {
|
|
1434
|
+
return false;
|
|
1435
|
+
}
|
|
1436
|
+
owned.port_id = method->raw_input_port_id ? method->raw_input_port_id : "";
|
|
1437
|
+
owned.schema_name = accepted->schema_name ? accepted->schema_name : "";
|
|
1438
|
+
owned.file_identifier = accepted->file_identifier ? accepted->file_identifier : "";
|
|
1439
|
+
owned.root_type_name = accepted->root_type_name ? accepted->root_type_name : "";
|
|
1440
|
+
owned.schema_version = accepted->schema_version ? accepted->schema_version : "";
|
|
1441
|
+
if (accepted->schema_hash && accepted->schema_hash_length > 0u) {
|
|
1442
|
+
owned.schema_hash.assign(
|
|
1443
|
+
accepted->schema_hash,
|
|
1444
|
+
accepted->schema_hash + accepted->schema_hash_length
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
owned.type_wire_format = accepted->wire_format;
|
|
1448
|
+
owned.payload = stdin_bytes;
|
|
1449
|
+
owned.view.wire_format = static_cast<uint32_t>(kPayloadWireFormatFlatbuffer);
|
|
1450
|
+
owned.view.fixed_string_length = accepted->fixed_string_length;
|
|
1451
|
+
owned.view.byte_length = accepted->byte_length;
|
|
1452
|
+
owned.view.required_alignment = accepted->required_alignment;
|
|
1453
|
+
owned.view.alignment = 1;
|
|
1454
|
+
owned.view.size = static_cast<uint32_t>(stdin_bytes.size());
|
|
1455
|
+
owned.view.generation = 0;
|
|
1456
|
+
owned.view.trace_id = 0;
|
|
1457
|
+
owned.view.stream_id = 0;
|
|
1458
|
+
owned.view.sequence = 0;
|
|
1459
|
+
owned.view.end_of_stream = 0;
|
|
1460
|
+
owned.view.ownership = static_cast<uint32_t>(kBufferOwnershipHostOwned);
|
|
1461
|
+
owned.view.mutability = static_cast<uint32_t>(kBufferMutabilityImmutable);
|
|
1462
|
+
PopulateInputView(&owned);
|
|
606
1463
|
return true;
|
|
607
1464
|
}
|
|
608
1465
|
|
|
1466
|
+
static std::vector<uint8_t> DispatchRawShortcut(
|
|
1467
|
+
const MethodDescriptor *method,
|
|
1468
|
+
const std::vector<uint8_t> &stdin_bytes,
|
|
1469
|
+
bool *runtime_error
|
|
1470
|
+
) {
|
|
1471
|
+
ResetInvokeContext(method);
|
|
1472
|
+
g_invoke_context.trace_id = 0;
|
|
1473
|
+
return DispatchLoadedContext(
|
|
1474
|
+
method,
|
|
1475
|
+
LoadRawShortcutInput(method, stdin_bytes),
|
|
1476
|
+
runtime_error
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
609
1480
|
} // namespace
|
|
610
1481
|
|
|
611
1482
|
extern "C" uint32_t plugin_get_input_count(void) {
|
|
@@ -655,7 +1526,7 @@ extern "C" int32_t plugin_push_output(
|
|
|
655
1526
|
port_id,
|
|
656
1527
|
schema_name,
|
|
657
1528
|
file_identifier,
|
|
658
|
-
static_cast<uint32_t>(
|
|
1529
|
+
static_cast<uint32_t>(kPayloadWireFormatFlatbuffer),
|
|
659
1530
|
nullptr,
|
|
660
1531
|
0,
|
|
661
1532
|
0,
|
|
@@ -680,29 +1551,116 @@ extern "C" int32_t plugin_push_output_typed(
|
|
|
680
1551
|
SetError("invalid-output-port", "Output frames must declare a non-empty port id.");
|
|
681
1552
|
return -1;
|
|
682
1553
|
}
|
|
683
|
-
|
|
1554
|
+
const PortRequirement *output_port = FindOutputPort(g_invoke_context.method, port_id);
|
|
1555
|
+
if (!output_port) {
|
|
684
1556
|
SetError(
|
|
685
1557
|
"unknown-output-port",
|
|
686
1558
|
std::string("Output port is not declared on the active method: ") + port_id
|
|
687
1559
|
);
|
|
688
1560
|
return -1;
|
|
689
1561
|
}
|
|
1562
|
+
if (!payload_ptr && payload_length > 0u) {
|
|
1563
|
+
SetError("invalid-output-payload", "Output payload pointer is null but payload length is non-zero.");
|
|
1564
|
+
return -1;
|
|
1565
|
+
}
|
|
1566
|
+
const AcceptedTypeRef *accepted_type = output_port->accepted_type_count > 0u
|
|
1567
|
+
? ResolveOutputType(
|
|
1568
|
+
*output_port,
|
|
1569
|
+
schema_name,
|
|
1570
|
+
file_identifier,
|
|
1571
|
+
wire_format,
|
|
1572
|
+
root_type_name,
|
|
1573
|
+
fixed_string_length,
|
|
1574
|
+
byte_length,
|
|
1575
|
+
required_alignment,
|
|
1576
|
+
payload_length)
|
|
1577
|
+
: nullptr;
|
|
1578
|
+
if (output_port->accepted_type_count > 0u && !accepted_type) {
|
|
1579
|
+
SetError(
|
|
1580
|
+
"unsupported-output-type",
|
|
1581
|
+
std::string("Output frame does not match a declared type on port: ") + port_id
|
|
1582
|
+
);
|
|
1583
|
+
return -1;
|
|
1584
|
+
}
|
|
690
1585
|
|
|
691
1586
|
OutputFrameOwned frame{};
|
|
692
1587
|
frame.port_id = ReadCString(port_id);
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
frame
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
1588
|
+
// A MATCHED WILDCARD IS NOT A TYPE DESCRIPTION.
|
|
1589
|
+
//
|
|
1590
|
+
// The manifest is authoritative over a frame's identity and layout only when
|
|
1591
|
+
// the matched entry actually DESCRIBES one. An acceptsAnyFlatbuffer entry
|
|
1592
|
+
// describes nothing: no schema name, no root type, no byteLength, no
|
|
1593
|
+
// alignment. Copying it over the caller's values stamped every wildcard frame
|
|
1594
|
+
// with byteLength 0 / requiredAlignment 0 and then, for an aligned-binary
|
|
1595
|
+
// payload, re-declared its wire format as flatbuffer — producing a TAB
|
|
1596
|
+
// descriptor the SDK's own decoder rejects ("aligned type requiredAlignment
|
|
1597
|
+
// must be a positive power of two"). A wildcard match overrides nothing; the
|
|
1598
|
+
// frame keeps what the guest declared.
|
|
1599
|
+
const AcceptedTypeRef *typed_match =
|
|
1600
|
+
(accepted_type && !accepted_type->accepts_any_flatbuffer) ? accepted_type : nullptr;
|
|
1601
|
+
frame.schema_name = typed_match
|
|
1602
|
+
? ReadCString(typed_match->schema_name)
|
|
1603
|
+
: ReadCString(schema_name);
|
|
1604
|
+
frame.file_identifier = typed_match
|
|
1605
|
+
? ReadCString(typed_match->file_identifier)
|
|
1606
|
+
: ReadCString(file_identifier);
|
|
1607
|
+
frame.root_type_name = typed_match
|
|
1608
|
+
? ReadCString(typed_match->root_type_name)
|
|
1609
|
+
: ReadCString(root_type_name);
|
|
1610
|
+
frame.schema_version = typed_match
|
|
1611
|
+
? ReadCString(typed_match->schema_version)
|
|
1612
|
+
: std::string{};
|
|
1613
|
+
if (typed_match && typed_match->schema_hash && typed_match->schema_hash_length > 0u) {
|
|
1614
|
+
frame.schema_hash.assign(
|
|
1615
|
+
typed_match->schema_hash,
|
|
1616
|
+
typed_match->schema_hash + typed_match->schema_hash_length
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
frame.wire_format = typed_match && typed_match->has_wire_format
|
|
1620
|
+
? typed_match->wire_format
|
|
1621
|
+
: wire_format;
|
|
1622
|
+
const bool aligned_binary =
|
|
1623
|
+
frame.wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary);
|
|
1624
|
+
frame.fixed_string_length = aligned_binary
|
|
1625
|
+
? (typed_match ? typed_match->fixed_string_length : fixed_string_length)
|
|
1626
|
+
: 0u;
|
|
1627
|
+
frame.byte_length = aligned_binary
|
|
1628
|
+
? (typed_match
|
|
1629
|
+
? typed_match->byte_length
|
|
1630
|
+
: (byte_length > 0u ? byte_length : payload_length))
|
|
1631
|
+
: 0u;
|
|
1632
|
+
frame.required_alignment = aligned_binary
|
|
1633
|
+
? (typed_match ? typed_match->required_alignment : required_alignment)
|
|
1634
|
+
: 0u;
|
|
1635
|
+
frame.alignment = aligned_binary && frame.required_alignment > 0
|
|
1636
|
+
? frame.required_alignment
|
|
1637
|
+
: 8;
|
|
1638
|
+
frame.payload_ptr = payload_ptr;
|
|
1639
|
+
frame.payload_length = payload_length;
|
|
1640
|
+
bool payload_is_sdk_owned = false;
|
|
701
1641
|
if (payload_ptr && payload_length > 0u) {
|
|
1642
|
+
const uintptr_t payload_address = reinterpret_cast<uintptr_t>(payload_ptr);
|
|
1643
|
+
payload_is_sdk_owned =
|
|
1644
|
+
payload_address <= std::numeric_limits<uint32_t>::max() &&
|
|
1645
|
+
AllocationContains(static_cast<uint32_t>(payload_address), payload_length);
|
|
1646
|
+
}
|
|
1647
|
+
if (
|
|
1648
|
+
payload_ptr &&
|
|
1649
|
+
payload_length > 0u &&
|
|
1650
|
+
(!g_invoke_context.direct_external_arena_outputs || !payload_is_sdk_owned)
|
|
1651
|
+
) {
|
|
702
1652
|
frame.payload.insert(frame.payload.end(), payload_ptr, payload_ptr + payload_length);
|
|
703
1653
|
}
|
|
704
1654
|
|
|
705
1655
|
g_invoke_context.outputs.emplace_back(std::move(frame));
|
|
1656
|
+
OutputFrameOwned &stored_frame = g_invoke_context.outputs.back();
|
|
1657
|
+
if (
|
|
1658
|
+
g_invoke_context.direct_external_arena_outputs &&
|
|
1659
|
+
!stored_frame.payload.empty()
|
|
1660
|
+
) {
|
|
1661
|
+
stored_frame.payload_ptr = stored_frame.payload.data();
|
|
1662
|
+
stored_frame.payload_length = static_cast<uint32_t>(stored_frame.payload.size());
|
|
1663
|
+
}
|
|
706
1664
|
return static_cast<int32_t>(g_invoke_context.outputs.size() - 1u);
|
|
707
1665
|
}
|
|
708
1666
|
|
|
@@ -724,13 +1682,39 @@ extern "C" int32_t plugin_push_output_ex(
|
|
|
724
1682
|
wire_format,
|
|
725
1683
|
root_type_name,
|
|
726
1684
|
fixed_string_length,
|
|
727
|
-
|
|
1685
|
+
wire_format == static_cast<uint32_t>(kPayloadWireFormatAlignedBinary)
|
|
1686
|
+
? payload_length
|
|
1687
|
+
: 0u,
|
|
728
1688
|
required_alignment,
|
|
729
1689
|
payload_ptr,
|
|
730
1690
|
payload_length
|
|
731
1691
|
);
|
|
732
1692
|
}
|
|
733
1693
|
|
|
1694
|
+
extern "C" int32_t plugin_set_output_frame_id(uint32_t output_index, uint64_t frame_id) {
|
|
1695
|
+
if (output_index >= g_invoke_context.outputs.size()) {
|
|
1696
|
+
SetError("invalid-output-frame", "Output frame index is out of range.");
|
|
1697
|
+
return -1;
|
|
1698
|
+
}
|
|
1699
|
+
auto &frame = g_invoke_context.outputs[output_index];
|
|
1700
|
+
frame.has_frame_id = true;
|
|
1701
|
+
frame.frame_id = frame_id;
|
|
1702
|
+
frame.sequence = DecodeSdsFrameSequence(frame_id);
|
|
1703
|
+
frame.end_of_stream = DecodeSdsFrameEndOfStream(frame_id);
|
|
1704
|
+
return 0;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
extern "C" int32_t plugin_set_output_stream_frame(
|
|
1708
|
+
uint32_t output_index,
|
|
1709
|
+
uint64_t sequence,
|
|
1710
|
+
int32_t end_of_stream
|
|
1711
|
+
) {
|
|
1712
|
+
return plugin_set_output_frame_id(
|
|
1713
|
+
output_index,
|
|
1714
|
+
EncodeSdsFrameId(sequence, end_of_stream != 0)
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
734
1718
|
extern "C" void plugin_set_yielded(int32_t yielded) {
|
|
735
1719
|
g_invoke_context.yielded = yielded != 0;
|
|
736
1720
|
}
|
|
@@ -745,14 +1729,30 @@ extern "C" void plugin_set_error(const char *error_code, const char *error_messa
|
|
|
745
1729
|
}
|
|
746
1730
|
|
|
747
1731
|
extern "C" uint32_t plugin_alloc(uint32_t size) {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
1732
|
+
// Every region handed across the host boundary is 8-byte aligned so the
|
|
1733
|
+
// FlatBuffer arena base stays aligned end-to-end. malloc already returns
|
|
1734
|
+
// >=8-aligned blocks on wasm32; this asserts the invariant (fail hard, no
|
|
1735
|
+
// realignment fallback) and rounds the size so allocator metadata cannot
|
|
1736
|
+
// shrink the guarantee.
|
|
1737
|
+
const uint32_t requested = size > 0u ? size : 1u;
|
|
1738
|
+
const uint32_t allocation_size =
|
|
1739
|
+
(requested + (kInvokeAllocAlignment - 1u)) & ~(kInvokeAllocAlignment - 1u);
|
|
1740
|
+
void *ptr = nullptr;
|
|
1741
|
+
if (posix_memalign(&ptr, static_cast<size_t>(kInvokeAllocAlignment), allocation_size) != 0) {
|
|
1742
|
+
return 0u;
|
|
1743
|
+
}
|
|
1744
|
+
if ((reinterpret_cast<uintptr_t>(ptr) % kInvokeAllocAlignment) != 0u) {
|
|
1745
|
+
std::free(ptr);
|
|
1746
|
+
return 0u;
|
|
1747
|
+
}
|
|
1748
|
+
const uint32_t result = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr));
|
|
1749
|
+
TrackAllocation(result, allocation_size);
|
|
1750
|
+
return result;
|
|
751
1751
|
}
|
|
752
1752
|
|
|
753
1753
|
extern "C" void plugin_free(uint32_t ptr, uint32_t size) {
|
|
754
1754
|
(void)size;
|
|
755
|
-
if (ptr != 0u) {
|
|
1755
|
+
if (ptr != 0u && UntrackAllocation(ptr)) {
|
|
756
1756
|
std::free(reinterpret_cast<void *>(PtrFromU32(ptr)));
|
|
757
1757
|
}
|
|
758
1758
|
}
|
|
@@ -762,16 +1762,42 @@ extern "C" uint32_t plugin_invoke_stream(
|
|
|
762
1762
|
uint32_t request_len,
|
|
763
1763
|
uint32_t response_len_out_ptr
|
|
764
1764
|
) {
|
|
1765
|
+
if (response_len_out_ptr != 0u && !AllocationContains(response_len_out_ptr, 4u)) {
|
|
1766
|
+
return 0u;
|
|
1767
|
+
}
|
|
765
1768
|
if (response_len_out_ptr != 0u) {
|
|
766
1769
|
*MutableU32Ptr(response_len_out_ptr) = 0u;
|
|
767
1770
|
}
|
|
768
1771
|
|
|
769
1772
|
bool runtime_error = false;
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1773
|
+
std::vector<uint8_t> response_bytes;
|
|
1774
|
+
if (request_len > 0u && !AllocationContains(request_ptr, request_len)) {
|
|
1775
|
+
runtime_error = true;
|
|
1776
|
+
response_bytes = SerializeErrorResponse(
|
|
1777
|
+
400,
|
|
1778
|
+
"invalid-request-pointer",
|
|
1779
|
+
"Direct invoke request pointer range is not owned by the module SDK allocator."
|
|
1780
|
+
);
|
|
1781
|
+
} else if (request_ptr != 0u && (request_ptr % kInvokeArenaAlignment) != 0u) {
|
|
1782
|
+
runtime_error = true;
|
|
1783
|
+
response_bytes = SerializeErrorResponse(
|
|
1784
|
+
400,
|
|
1785
|
+
"misaligned-request",
|
|
1786
|
+
"Invoke request buffer base is not 8-byte aligned."
|
|
1787
|
+
);
|
|
1788
|
+
} else {
|
|
1789
|
+
const bool previous_direct_invoke_stream = g_direct_invoke_stream;
|
|
1790
|
+
g_direct_invoke_stream = true;
|
|
1791
|
+
response_bytes = DispatchRequestBytes(
|
|
1792
|
+
ConstPtr(request_ptr),
|
|
1793
|
+
static_cast<size_t>(request_len),
|
|
1794
|
+
&runtime_error
|
|
1795
|
+
);
|
|
1796
|
+
g_direct_invoke_stream = previous_direct_invoke_stream;
|
|
1797
|
+
}
|
|
1798
|
+
if (response_bytes.size() > std::numeric_limits<uint32_t>::max()) {
|
|
1799
|
+
return 0u;
|
|
1800
|
+
}
|
|
775
1801
|
|
|
776
1802
|
const uint32_t response_ptr = plugin_alloc(static_cast<uint32_t>(response_bytes.size()));
|
|
777
1803
|
if (response_ptr == 0u) {
|
|
@@ -819,45 +1845,48 @@ ${includeCommandMain
|
|
|
819
1845
|
return 64;
|
|
820
1846
|
}
|
|
821
1847
|
|
|
822
|
-
orbpro::invoke::PluginInvokeRequestT shortcut_request{};
|
|
823
|
-
if (!BuildRawShortcutRequest(method, stdin_bytes, &shortcut_request)) {
|
|
824
|
-
std::fprintf(stderr, "Failed to construct raw shortcut request.\\n");
|
|
825
|
-
return 64;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
1848
|
bool runtime_error = false;
|
|
829
|
-
const auto response_bytes =
|
|
1849
|
+
const auto response_bytes = DispatchRawShortcut(method, stdin_bytes, &runtime_error);
|
|
830
1850
|
::flatbuffers::Verifier verifier(response_bytes.data(), response_bytes.size());
|
|
831
|
-
if (!
|
|
1851
|
+
if (!VerifyPIVBuffer(verifier)) {
|
|
832
1852
|
std::fprintf(stderr, "Shortcut response verification failed.\\n");
|
|
833
1853
|
return 70;
|
|
834
1854
|
}
|
|
835
1855
|
|
|
836
|
-
auto
|
|
837
|
-
|
|
838
|
-
)
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1856
|
+
const auto *response_envelope = GetPIV(response_bytes.data());
|
|
1857
|
+
const auto *response = response_envelope ? response_envelope->RESPONSE() : nullptr;
|
|
1858
|
+
if (!response) {
|
|
1859
|
+
std::fprintf(stderr, "Shortcut response missing PIV response body.\\n");
|
|
1860
|
+
return 70;
|
|
1861
|
+
}
|
|
1862
|
+
const auto error_code = FlatBufferStringValue(response->ERROR_CODE());
|
|
1863
|
+
const auto error_message = FlatBufferStringValue(response->ERROR_MESSAGE());
|
|
1864
|
+
if (runtime_error || response->STATUS_CODE() != 0 || !error_code.empty()) {
|
|
1865
|
+
if (!error_message.empty()) {
|
|
1866
|
+
std::fprintf(stderr, "%s\\n", error_message.c_str());
|
|
842
1867
|
}
|
|
843
1868
|
return 1;
|
|
844
1869
|
}
|
|
845
|
-
|
|
1870
|
+
const auto *output_frames = response->OUTPUTS();
|
|
1871
|
+
const auto output_count = output_frames ? output_frames->size() : 0u;
|
|
1872
|
+
if (output_count > 1u) {
|
|
846
1873
|
std::fprintf(stderr, "Raw shortcut mode produced more than one output frame.\\n");
|
|
847
1874
|
return 65;
|
|
848
1875
|
}
|
|
849
|
-
if (
|
|
1876
|
+
if (output_count == 0u) {
|
|
850
1877
|
return 0;
|
|
851
1878
|
}
|
|
852
1879
|
|
|
853
|
-
const auto
|
|
854
|
-
const auto
|
|
855
|
-
const auto
|
|
856
|
-
|
|
1880
|
+
const auto *frame = output_frames->Get(0);
|
|
1881
|
+
const auto *payload_arena = response->PAYLOAD_ARENA();
|
|
1882
|
+
const auto payload_offset = static_cast<size_t>(frame ? frame->OFFSET() : 0u);
|
|
1883
|
+
const auto payload_size = static_cast<size_t>(frame ? frame->SIZE() : 0u);
|
|
1884
|
+
const auto arena_size = payload_arena ? payload_arena->size() : 0u;
|
|
1885
|
+
if (!frame || !payload_arena || FrameRangeExceedsArena(payload_offset, payload_size, arena_size)) {
|
|
857
1886
|
std::fprintf(stderr, "Raw shortcut output frame exceeds response payload arena.\\n");
|
|
858
1887
|
return 70;
|
|
859
1888
|
}
|
|
860
|
-
if (!WriteAllStdout(
|
|
1889
|
+
if (!WriteAllStdout(payload_arena->data() + payload_offset, payload_size)) {
|
|
861
1890
|
std::fprintf(stderr, "Failed to write stdout.\\n");
|
|
862
1891
|
return 74;
|
|
863
1892
|
}
|