Refactor project structure

This commit is contained in:
2026-03-28 19:56:39 +11:00
parent 1d267378b2
commit 8a2e721058
511 changed files with 59 additions and 48 deletions

View File

@@ -0,0 +1,670 @@
#include "ANSANNHUB.h"
#include <cstdint>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <memory>
#include <numeric>
#include <sstream>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
// --- Refcounted handle registry infrastructure ---
static std::unordered_map<ANSCENTER::ANNHUBAPI*, int>& ANNHUBHandleRegistry() {
static std::unordered_map<ANSCENTER::ANNHUBAPI*, int> s;
return s;
}
static std::mutex& ANNHUBHandleRegistryMutex() {
static std::mutex m;
return m;
}
static std::condition_variable& ANNHUBHandleRegistryCV() {
static std::condition_variable cv;
return cv;
}
static void RegisterANNHUBHandle(ANSCENTER::ANNHUBAPI* h) {
std::lock_guard<std::mutex> lk(ANNHUBHandleRegistryMutex());
ANNHUBHandleRegistry()[h] = 1;
}
static ANSCENTER::ANNHUBAPI* AcquireANNHUBHandle(ANSCENTER::ANNHUBAPI* h) {
std::lock_guard<std::mutex> lk(ANNHUBHandleRegistryMutex());
auto it = ANNHUBHandleRegistry().find(h);
if (it == ANNHUBHandleRegistry().end()) return nullptr;
it->second++;
return h;
}
static bool ReleaseANNHUBHandleRef(ANSCENTER::ANNHUBAPI* h) {
std::lock_guard<std::mutex> lk(ANNHUBHandleRegistryMutex());
auto it = ANNHUBHandleRegistry().find(h);
if (it == ANNHUBHandleRegistry().end()) return false;
it->second--;
if (it->second <= 0) {
ANNHUBHandleRegistry().erase(it);
ANNHUBHandleRegistryCV().notify_all();
return true;
}
ANNHUBHandleRegistryCV().notify_all();
return false;
}
static bool UnregisterANNHUBHandle(ANSCENTER::ANNHUBAPI* h) {
std::unique_lock<std::mutex> lk(ANNHUBHandleRegistryMutex());
auto it = ANNHUBHandleRegistry().find(h);
if (it == ANNHUBHandleRegistry().end()) return false;
it->second--;
if (!ANNHUBHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
auto it2 = ANNHUBHandleRegistry().find(h);
return it2 == ANNHUBHandleRegistry().end() || it2->second <= 0;
})) {
OutputDebugStringA("WARNING: UnregisterANNHUBHandle timed out after 30s waiting for refcount to reach zero.\n");
}
ANNHUBHandleRegistry().erase(h);
return true;
}
class ANNHUBHandleGuard {
ANSCENTER::ANNHUBAPI* engine;
public:
explicit ANNHUBHandleGuard(ANSCENTER::ANNHUBAPI* e) : engine(e) {}
~ANNHUBHandleGuard() { if (engine) ReleaseANNHUBHandleRef(engine); }
ANNHUBHandleGuard(const ANNHUBHandleGuard&) = delete;
ANNHUBHandleGuard& operator=(const ANNHUBHandleGuard&) = delete;
explicit operator bool() const { return engine != nullptr; }
ANSCENTER::ANNHUBAPI* get() const { return engine; }
};
// --- End handle registry infrastructure ---
static bool ansannhubLicenceValid = false;
// Global once_flag to protect license checking
static std::once_flag ansannhubLicenseOnceFlag;
namespace ANSCENTER {
void ReLu(std::vector<double>& iVal, std::vector<double>& oVal)
{
int dim = iVal.size();
oVal.resize(dim);
for (int i = 0; i < dim; i++)
{
if (iVal[i] >= 0) oVal[i] = iVal[i];
else oVal[i] = 0;
}
}
void LogSig(std::vector<double>& iVal, std::vector<double>& oVal)
{
int dim = iVal.size();
oVal.resize(dim);
for (int i = 0; i < dim; i++)
{
oVal[i] = 1 / (1 + exp(-iVal[i]));
}
}
void TanSig(std::vector<double>& iVal, std::vector<double>& oVal)
{
int dim = iVal.size();
oVal.resize(dim);
for (int i = 0; i < dim; i++)
{
oVal[i] = 2 / (1 + exp(-2 * iVal[i])) - 1;
}
}
void PureLin(std::vector<double>& iVal, std::vector<double>& oVal)
{
oVal = iVal;
}
void SoftMax(std::vector<double>& iVal, std::vector<double>& oVal)
{
double softmaxWeight = 0;
int dim = iVal.size();
oVal.resize(dim);
if (dim == 1) {
oVal[0] = 1 / (1 + exp(-iVal[0]));
}
else {
for (int i = 0; i < dim; i++) {
softmaxWeight = softmaxWeight + exp(iVal[i]);
}
for (int i = 0; i < dim; i++) {
oVal[i] = exp(iVal[i]) / softmaxWeight;
}
}
}
void ActivationFunction(std::vector<double>& iVal, std::vector<double>& oVal, int mode) {
switch (mode) {
case 0:
PureLin(iVal, oVal);
break;
case 1:
ReLu(iVal, oVal);
break;
case 2:
LogSig(iVal, oVal);
break;
case 3:
TanSig(iVal, oVal);
break;
case 4:
SoftMax(iVal, oVal);
break;
default:
TanSig(iVal, oVal);
break;
}
}
static void VerifyGlobalANSANNHUBLicense(const std::string& licenseKey) {
try {
ansannhubLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1000, "ANNHUB-LV");//Default productId=1000
}
catch (std::exception& e) {
//this->_logger.LogFatal("ANSOPENCV::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
}
}
void ANNHUBAPI::CheckLicense() {
//try {
// _licenseValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(_licenseKey, 1000, "ANNHUB-LV");//Default productId=1000
//}
//catch (std::exception& e) {
// //this->_logger.LogFatal("ANSOPENCV::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
//}
try {
// Check once globally
std::call_once(ansannhubLicenseOnceFlag, [this]() {
VerifyGlobalANSANNHUBLicense(_licenseKey);
});
// Update this instance's local license flag
_licenseValid = ansannhubLicenceValid;
}
catch (const std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
}
}
ANNHUBAPI::ANNHUBAPI()
{
// Control creation
isCreated = 0;
// Structrural parameters
nInputNodes = 1;
nHiddenNodes = 10;
nOutputNodes = 1;
hiddenActivation = 2; // default =2
outputActivation = 2; // default =2;
dataNormalisationModeInput = 0;
dataNormalisationModeOutput = 0;
}
ANNHUBAPI::~ANNHUBAPI() noexcept
{
try {
Destroy();
}
catch (...) {}
}
void ANNHUBAPI::Destroy()
{
if (isCreated != 0) {
FreeNeuralNetwork();
}
}
void ANNHUBAPI::FreeNeuralNetwork()
{
try {
// Clear vectors
IW.clear();
LW.clear();
nInput.clear();
nOutput.clear();
Ib.clear();
Lb.clear();
xminInput.clear();
xmaxInput.clear();
xminOutput.clear();
xmaxOutput.clear();
// Reset the flag indicating whether the network is created
isCreated = 0;
}
catch (const std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::FreeNeuralNetwork. Error:", e.what(), __FILE__, __LINE__);
}
}
/*
(x[i]-xmin[i]) (ymax-ymin)
x[i] = ---------------- * +ymin
(xmax[i]-xmin[i])
*/
void ANNHUBAPI::PreProcessing(std::vector<double>& Input)
{
switch (dataNormalisationModeInput) {
case 0: // linear
break;
case 1: // mapminmax
for (int i = 0; i < nInputNodes; i++) {
if (xmaxInput[i] != xminInput[i]) {
Input[i] = (Input[i] - xminInput[i]) * (ymaxInput - yminInput) / (xmaxInput[i] - xminInput[i]) + yminInput;
}
}
break;
default:// minmaxmap
for (int i = 0; i < nInputNodes; i++) {
if (xmaxInput[i] != xminInput[i]) {
Input[i] = (Input[i] - xminInput[i]) * (ymaxInput - yminInput) / (xmaxInput[i] - xminInput[i]) + yminInput;
}
}
break;
}
}
void ANNHUBAPI::PostProcessing(std::vector<double>& Output)
{
switch (dataNormalisationModeOutput) {
case 0: // linear
break;
case 1:
for (int i = 0; i < nOutputNodes; i++) {
if (ymaxOutput != yminOutput) {
Output[i] = (Output[i] - yminOutput) * (xmaxOutput[i] - xminOutput[i]) / (ymaxOutput - yminOutput) + xminOutput[i];
}
}
break;
default:
for (int i = 0; i < nOutputNodes; i++) {
if (ymaxOutput != yminOutput) {
Output[i] = (Output[i] - yminOutput) * (xmaxOutput[i] - xminOutput[i]) / (ymaxOutput - yminOutput) + xminOutput[i];
}
}
break;
}
}
int ANNHUBAPI::ImportANNFromFile(std::string filename)
{
try {
FILE* fp;
int err = fopen_s(&fp, filename.c_str(), "r"); // r: Opens for reading.
if (err != 0) return -2;
float value, randNum;
//0. Check if it the correct type for C language
fscanf_s(fp, "%f", &value);
if (static_cast<int>(value) != 1) return -1; // Assume that the type C is 0
//1. Load random number
fscanf_s(fp, "%f", &randNum);
//2. Structure (IDs)
int trainingEngine, hlAct, olAct, costFunct, prePro, postPro, evalModel;
fscanf_s(fp, "%f", &value); trainingEngine = static_cast<int>(value);
fscanf_s(fp, "%f", &value); hlAct = static_cast<int>(value);
fscanf_s(fp, "%f", &value); olAct = static_cast<int>(value);
fscanf_s(fp, "%f", &value); costFunct = static_cast<int>(value);
fscanf_s(fp, "%f", &value); prePro = static_cast<int>(value);
fscanf_s(fp, "%f", &value); postPro = static_cast<int>(value);
fscanf_s(fp, "%f", &value); evalModel = static_cast<int>(value);
//2.1 Activation function
hiddenActivation = hlAct - 10;
outputActivation = olAct - 10;
//2.2 Data Processing
dataNormalisationModeInput = prePro - 1000;
dataNormalisationModeOutput = postPro - 1000;
// 3. Load neural network structure and min max inputs value for pre-post processing
int ipNodes, hdNodes, opNodes;
fscanf_s(fp, "%f", &value); ipNodes = static_cast<int>(value);
fscanf_s(fp, "%f", &value); hdNodes = static_cast<int>(value);
fscanf_s(fp, "%f", &value); opNodes = static_cast<int>(value);
Create(ipNodes, hdNodes, opNodes);
// 4. Load Input-Hidden weights (extraction formula)
for (int j = 0; j < nInputNodes; j++)
{
for (int i = 0; i < nHiddenNodes; i++)
{
fscanf_s(fp, "%f", &value);
IW[i][j] = value - randNum;
}
}
// 4.1. Load bias Hidden weights
for (int i = 0; i < nHiddenNodes; i++)
{
fscanf_s(fp, "%f", &value);
Ib[i] = value - randNum;
}
// 4.2. Load Hidden_Output weights
for (int j = 0; j < nHiddenNodes; j++)
{
for (int i = 0; i < nOutputNodes ; i++)
{
fscanf_s(fp, "%f", &value);
LW[i][j] = value - randNum;
}
}
// 4.3. Load bias Output weights
for (int i = 0; i < nOutputNodes; i++)
{
fscanf_s(fp, "%f", &value);
Lb[i] = value - randNum;
}
// 5. For Pre-processing
if (dataNormalisationModeInput >= 0) {
// Range settings
fscanf_s(fp, "%f", &value);
yminInput = value - randNum;
fscanf_s(fp, "%f", &value);
ymaxInput = value - randNum;
// Min and max
for (int i = 0; i < nInputNodes; i++) {
fscanf_s(fp, "%f", &value);
xminInput[i] = value - randNum;
}
for (int i = 0; i < nInputNodes; i++) {
fscanf_s(fp, "%f", &value);
xmaxInput[i] = value - randNum;
}
}
// 6. For Post-processing
if (dataNormalisationModeOutput >= 0) {
// Range settings
fscanf_s(fp, "%f", &value);
yminOutput = value - randNum;
fscanf_s(fp, "%f", &value);
ymaxOutput = value - randNum;
for (int i = 0; i < nOutputNodes; i++) {
fscanf_s(fp, "%f", &value);
xminOutput[i] = value - randNum;
}
for (int i = 0; i < nOutputNodes; i++) {
fscanf_s(fp, "%f", &value);
xmaxOutput[i] = value - randNum;
}
}
fclose(fp);
return 0;
}
catch (std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::ImportANNFromFile. Error:", e.what(), __FILE__, __LINE__);
return -1;
}
}
void ANNHUBAPI::Create(int inputNodes, int hiddenNodes, int outputNodes)
{
try {
if (isCreated != 0) {
FreeNeuralNetwork();
}
nInputNodes = inputNodes;
nHiddenNodes = hiddenNodes;
nOutputNodes = outputNodes;
nInput.resize(inputNodes);
nOutput.resize(outputNodes);
IW.resize(hiddenNodes, std::vector<double>(inputNodes));
LW.resize(outputNodes, std::vector<double>(hiddenNodes));
Ib.resize(hiddenNodes);
Lb.resize(outputNodes);
xminInput.resize(inputNodes);
xmaxInput.resize(inputNodes);
xminOutput.resize(outputNodes);
xmaxOutput.resize(outputNodes);
isCreated = 1;
}
catch (std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::Create. Error:", e.what(), __FILE__, __LINE__);
}
}
bool ANNHUBAPI::Init(std::string licenseKey, std::string modelFilePath) {
try {
_licenseKey = licenseKey;
_modelFilePath = modelFilePath;
CheckLicense();
if (_licenseValid) {
int result = ImportANNFromFile(_modelFilePath);
if (result == 0) return true;
else return false;
}
else {
return false;
}
}
catch (std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::Init. Error:", e.what(), __FILE__, __LINE__);
return false;
}
}
std::vector<double> ANNHUBAPI::Inference(std::vector<double> ip) {
try {
int i, j;
std::vector<double> a1(nHiddenNodes), n1(nHiddenNodes), n2(nOutputNodes);
if (!_licenseValid) return {}; // Invalid license
if (isCreated == 0) return {};
// Need to check the input size as well, return {} if it fails
PreProcessing(ip);
//1. Calculate n1
for (i = 0; i < nHiddenNodes; i++) {
n1[i] = 0;
for (j = 0; j < nInputNodes; j++)
{
if (std::isnan(IW[i][j]) || std::isnan(ip[j])) {
continue;
}
n1[i] = n1[i] + IW[i][j] * ip[j];
}
n1[i] = n1[i] + Ib[i];
}
ActivationFunction(n1, a1, hiddenActivation);
// 3. Calculate n2
for (i = 0; i < nOutputNodes; i++) {
n2[i] = 0;
for (j = 0; j < nHiddenNodes; j++) {
n2[i] = n2[i] + LW[i][j] * a1[j];
}
n2[i] = n2[i] + Lb[i];
}
ActivationFunction(n2, nOutput, outputActivation);
PostProcessing(nOutput);
return nOutput;
}
catch (std::exception& e) {
//this->_logger.LogFatal("ANNHUBAPI::Inference. Error:", e.what(), __FILE__, __LINE__);
return {};
}
}
}
extern "C" __declspec(dllexport) int CreateANNHUBHandle(ANSCENTER::ANNHUBAPI * *Handle, const char* licenseKey, const char* modelFilePath) {
if (!Handle || !licenseKey || !modelFilePath) return -1;
try {
if (*Handle) {
if (UnregisterANNHUBHandle(*Handle)) {
(*Handle)->Destroy();
delete *Handle;
}
*Handle = nullptr;
}
auto ptr = std::make_unique<ANSCENTER::ANNHUBAPI>();
bool result = ptr->Init(licenseKey, modelFilePath);
if (result) {
*Handle = ptr.release();
RegisterANNHUBHandle(*Handle);
return 1;
}
*Handle = nullptr;
return 0;
}
catch (...) { return 0; }
}
static int ReleaseANNHUBHandle_Impl(ANSCENTER::ANNHUBAPI** Handle) {
if (Handle == nullptr || *Handle == nullptr) return -1;
UnregisterANNHUBHandle(*Handle);
(*Handle)->Destroy();
delete *Handle;
*Handle = nullptr;
return 0;
}
extern "C" __declspec(dllexport) int ReleaseANNHUBHandle(ANSCENTER::ANNHUBAPI * *Handle) {
__try {
return ReleaseANNHUBHandle_Impl(Handle);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int ANNHUB_Inference(ANSCENTER::ANNHUBAPI * *pHandle, double* inputArray, int inputSize, double** outputArray) {
// Check for null pointers
if (pHandle == nullptr || *pHandle == nullptr || inputArray == nullptr || outputArray == nullptr || inputSize <= 0) {
return -1; // Invalid arguments
}
ANNHUBHandleGuard guard(AcquireANNHUBHandle(*pHandle));
if (!guard) return -1;
try {
// Convert inputArray to std::vector
std::vector<double> inputVector(inputArray, inputArray + inputSize);
// Call Inference
std::vector<double> inferenceResult = guard.get()->Inference(inputVector);
int resultSize = inferenceResult.size();
// Allocate memory for the output array
*outputArray = new double[resultSize];
if (*outputArray == nullptr) return -2; // Memory allocation failed
// Copy the inference result to the output array
std::copy(inferenceResult.begin(), inferenceResult.end(), *outputArray);
return 0; // Success
}
catch (const std::exception& e) {
// Log the exception message if you have a logging system
return -5; // Error code for exception in Inference
}
}
extern "C" __declspec(dllexport) int ANNHUB_InferenceLV(ANSCENTER::ANNHUBAPI * *pHandle, double* inputArray, int inputSize, LStrHandle outputHandle) {
// Check for null pointers
if (pHandle == nullptr || *pHandle == nullptr || inputArray == nullptr || outputHandle == nullptr || inputSize <= 0) {
return 0; // Invalid arguments
}
ANNHUBHandleGuard guard(AcquireANNHUBHandle(*pHandle));
if (!guard) return 0;
try {
// Convert inputArray to std::vector
std::vector<double> inputVector(inputArray, inputArray + inputSize);
// Call Inference
std::vector<double> inferenceResult = guard.get()->Inference(inputVector);
int resultSize = inferenceResult.size();
if (resultSize <= 0) return 0; // Error code for empty inference result
std::stringstream ss;
for (size_t i = 0; i < resultSize; ++i)
{
if (i == resultSize - 1) ss << inferenceResult[i];
else ss << inferenceResult[i]<<";";
}
std::string st= ss.str();
int size = st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(outputHandle, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*outputHandle)->cnt = size;
memcpy((*outputHandle)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (const std::exception& e) {
// Log the exception message if you have a logging system
return 0; // Error code for exception in Inference
}
}
// --- V2 entry points: accept handle by value (uint64_t) to avoid LabVIEW buffer reuse bug ---
extern "C" __declspec(dllexport) int ANNHUB_Inference_V2(uint64_t handleVal, double* inputArray, int inputSize, double** outputArray) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANNHUBAPI*>(handleVal);
if (!_v2h) return -1;
if (inputArray == nullptr || outputArray == nullptr || inputSize <= 0) return -1;
ANNHUBHandleGuard guard(AcquireANNHUBHandle(_v2h));
if (!guard) return -1;
try {
std::vector<double> inputVector(inputArray, inputArray + inputSize);
std::vector<double> inferenceResult = guard.get()->Inference(inputVector);
int resultSize = inferenceResult.size();
*outputArray = new double[resultSize];
if (*outputArray == nullptr) return -2;
std::copy(inferenceResult.begin(), inferenceResult.end(), *outputArray);
return 0;
}
catch (const std::exception& e) {
return -5;
}
}
extern "C" __declspec(dllexport) int ANNHUB_InferenceLV_V2(uint64_t handleVal, double* inputArray, int inputSize, LStrHandle outputHandle) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANNHUBAPI*>(handleVal);
if (!_v2h) return 0;
if (inputArray == nullptr || outputHandle == nullptr || inputSize <= 0) return 0;
ANNHUBHandleGuard guard(AcquireANNHUBHandle(_v2h));
if (!guard) return 0;
try {
std::vector<double> inputVector(inputArray, inputArray + inputSize);
std::vector<double> inferenceResult = guard.get()->Inference(inputVector);
int resultSize = inferenceResult.size();
if (resultSize <= 0) return 0;
std::stringstream ss;
for (size_t i = 0; i < resultSize; ++i) {
if (i == resultSize - 1) ss << inferenceResult[i];
else ss << inferenceResult[i] << ";";
}
std::string st = ss.str();
int size = st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(outputHandle, sizeof(int32) + size * sizeof(uChar));
if (error == noErr) {
(*outputHandle)->cnt = size;
memcpy((*outputHandle)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (const std::exception& e) {
return 0;
}
}

View File

@@ -0,0 +1,69 @@
#ifndef ANSANNHUB_H
#define ANSANNHUB_H
#define ANSANNHUB_API __declspec(dllexport)
#include <iostream>
#include <cstdint>
#include "ANSLicense.h"
#include <vector>
//#include "LabVIEWHeader/extcode.h"
namespace ANSCENTER
{
class ANSANNHUB_API ANNHUBAPI
{
private:
std::vector<double> nInput; //ANN inputs
std::vector<double> nOutput; //ANN outputs
std::vector<std::vector<double>> IW;
std::vector<std::vector<double>> LW;
std::vector<double> Ib;
std::vector<double> Lb;
// Structural parameters
int nInputNodes, nHiddenNodes, nOutputNodes;
int hiddenActivation; // default =2
int outputActivation; // default =2
int dataNormalisationModeInput; // default =1;
int dataNormalisationModeOutput; // default =1;
// Preprocessing and postprocessing settings
std::vector<double> xmaxInput, xminInput; // Maximum and minimum of inputs
double ymaxInput, yminInput; // Maximum and minimum of inputs
std::vector<double> xmaxOutput, xminOutput; // Maximum and minimum of outputs
double ymaxOutput, yminOutput; // Maximum and minimum of outputs
// Control creation
unsigned char isCreated;
std::string _licenseKey;
bool _licenseValid{ false };
bool _isInitialized{ false };
std::string _modelFilePath;
private:
void PreProcessing(std::vector<double>& Input); // mode =0--> linear, mode =1 mapminmax, mode =2 standarddev
void PostProcessing(std::vector<double>& Output); // mode =0--> linear, mode =1 mapminmax, mode =2 standarddev
void Create(int inputNodes, int HiddenNodes, int outputNodes);
void FreeNeuralNetwork();
void CheckLicense();
int ImportANNFromFile(std::string filename);
public:
ANNHUBAPI();
~ANNHUBAPI() noexcept;
[[nodiscard]] bool Init(std::string licenseKey, std::string modelFilePath);
[[nodiscard]] std::vector<double> Inference(std::vector<double> ip);
void Destroy();
[[nodiscard]] int GetOutputNode() { return nOutputNodes; };
};
}
extern "C" __declspec(dllexport) int CreateANNHUBHandle(ANSCENTER::ANNHUBAPI **Handle, const char* licenseKey, const char* modelFilePath);
extern "C" __declspec(dllexport) int ReleaseANNHUBHandle(ANSCENTER::ANNHUBAPI **Handle);
extern "C" __declspec(dllexport) int ANNHUB_Inference(ANSCENTER::ANNHUBAPI **pHandle, double* inputArray, int inputSize, double** outputArray);
extern "C" __declspec(dllexport) int ANNHUB_InferenceLV(ANSCENTER::ANNHUBAPI **pHandle, double* inputArray, int inputSize, LStrHandle outputHandle);
// --- V2 entry points: accept handle by value (uint64_t) to avoid LabVIEW buffer reuse bug ---
extern "C" __declspec(dllexport) int ANNHUB_Inference_V2(uint64_t handleVal, double* inputArray, int inputSize, double** outputArray);
extern "C" __declspec(dllexport) int ANNHUB_InferenceLV_V2(uint64_t handleVal, double* inputArray, int inputSize, LStrHandle outputHandle);
#endif

View File

@@ -0,0 +1,23 @@
# ANNHUB — Notification Hub DLL
add_library(ANNHUB SHARED
ANSANNHUB.cpp
ANSANNHUB.h
dllmain.cpp
pch.cpp
pch.h
framework.h
)
target_include_directories(ANNHUB PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_link_libraries(ANNHUB
PRIVATE ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
)
target_compile_definitions(ANNHUB PRIVATE UNICODE _UNICODE ANNHUB_EXPORTS _USRDLL)
target_precompile_headers(ANNHUB PRIVATE pch.h)

View File

@@ -0,0 +1,19 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) noexcept
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

18
integrations/ANNHUB/pch.h Normal file
View File

@@ -0,0 +1,18 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <mutex>
#endif //PCH_H

View File

@@ -0,0 +1,46 @@
# ANSIO — IO Box communication DLL (cJSON + mbedtls)
add_library(ANSIO SHARED
dllmain.cpp
pch.cpp
pch.h
framework.h
# IOBox sources (embedded)
IOBox/cJSON.c
IOBox/cJSON_Utils.c
IOBox/iobox_api.cpp
IOBox/iobox_api.h
IOBox/mbedtls/aes.c
IOBox/mbedtls/base64.c
IOBox/mbedtls/sha256.c
)
target_include_directories(ANSIO PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_include_directories(ANSIO PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/IOBox
)
target_link_libraries(ANSIO
PRIVATE ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
)
target_compile_definitions(ANSIO PRIVATE UNICODE _UNICODE NOMINMAX ANSIO_EXPORTS _USRDLL)
if(WIN32)
target_link_libraries(ANSIO PRIVATE ${WIN_COMMON_LIBS})
else()
target_link_libraries(ANSIO PRIVATE ${UNIX_COMMON_LIBS})
endif()
# C files must skip C++ precompiled headers and compile as C
set_source_files_properties(
IOBox/cJSON.c IOBox/cJSON_Utils.c
IOBox/mbedtls/aes.c IOBox/mbedtls/base64.c IOBox/mbedtls/sha256.c
PROPERTIES SKIP_PRECOMPILE_HEADERS ON LANGUAGE C
)
target_precompile_headers(ANSIO PRIVATE pch.h)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 18
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable address area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON_Utils__h
#define cJSON_Utils__h
#ifdef __cplusplus
extern "C"
{
#endif
#include "cJSON.h"
/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer);
CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer);
/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to);
/* Utility for generating patch array entries. */
CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value);
/* Returns 0 for success. */
CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches);
CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches);
/*
// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use:
//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches)
//{
// cJSON *modme = cJSON_Duplicate(*object, 1);
// int error = cJSONUtils_ApplyPatches(modme, patches);
// if (!error)
// {
// cJSON_Delete(*object);
// *object = modme;
// }
// else
// {
// cJSON_Delete(modme);
// }
//
// return error;
//}
// Code not added to library since this strategy is a LOT slower.
*/
/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */
/* target will be modified by patch. return value is new ptr for target. */
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch);
CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch);
/* generates a patch to move from -> to */
/* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to);
CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to);
/* Given a root object and a target object, construct a pointer from one to the other. */
CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target);
/* Sorts the members of the object into alphabetical order. */
CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object);
CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,215 @@
#ifndef _IO_BOX_API_H_
#define _IO_BOX_API_H_
#define ANSIO_API __declspec(dllexport)
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <string>
#include <iostream>
#include <mutex>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h> // For PIP_ADAPTER_INFO
#include <chrono>
#include <memory>
#include <unordered_map>
#include "ANSLicense.h"
#pragma comment(lib,"WS2_32")
#pragma comment(lib, "Iphlpapi.lib")
// #pragma comment(lib, "Ws2_32.lib")
// #define TEST_FIX_IP
#define DEVICE_TCP_PORT 502
#define DEVICE_DATA_ADDRESS 100
#define DEVICE_DATA_LENGTH 17
#define MESSAGE_CRYPT_ENABLE 0
// Configuration constants - make these configurable if needed
namespace IoboxConfig {
constexpr int MAX_RETRIES = 30; // Reduced from 50 for better timeout control
constexpr int RETRY_DELAY_MS = 100; // Increased from 50ms for better reliability
constexpr int TOTAL_TIMEOUT_MS = 3000; // 3 seconds total timeout
}
namespace ANSCENTER {
typedef struct {
std::string model;
std::string ip_address; //local ip
std::string ip_public_address; //public ip
std::string mac_address;
std::string serial_number;
std::string firmware_version;
std::string hardware_version;
std::vector<std::string> channelNameList;
} iobox_info_t;
typedef struct {
int counting_get;
bool is_connected;
bool is_anthenticated;
SOCKET sock_tcp;
iobox_info_t iobox_info;
} iobox_profile_t;
typedef struct {
std::string adapter_index;
std::string adapter_name;
std::string adapter_description;
std::string adapter_mac;
std::string adapter_ip;
std::string adapter_subnet;
std::string adapter_gateway;
} network_adapter_t;
class ANSIO_API iobox_api
{
private:
// Define the map with MAC address as key and IP address as value
std::unordered_map<std::string, std::string> macToIpMap;
// Define unordered_map to store IP address and device information (std:vector<std::string>)
std::unordered_map<std::string, std::vector<std::string>> ipToDeviceMap;
std::string ip_mcast; //ip multicast
int port_mcast; //port multicast
std::string _username; // default username
std::string _password; // default password
int _port;
const char* aes_key = "a1b2c3d4e5f6g7h8";
std::recursive_mutex _mutex;
std::vector<iobox_profile_t> iobox_profiles;
iobox_profile_t* findProfileByIp(const std::string& ip);
void save_info_iobox(const iobox_info_t& iobox_info);
void setSocketTimeout(SOCKET sock, int timeout);
void sendUnicastMessage(SOCKET sock, const char* ip, const std::string& message);
void sendMulticastMessage(const std::string& message);
bool sendTcpMessage(const std::string& ip, const char* buffer, size_t length, bool needCheckAuthen);
bool receiveTcpMessage(const std::string& ip, char* buffer, size_t& length, int timeout = 3000);
void show_profile_iobox(const iobox_profile_t& profile);
bool connectToIoboxWithoutAuthen(const std::string& remote, int port);
void remove_last_info_iobox();
uint16_t getIndexIoboxFromIp(const std::string& ip);
std::vector<std::string> scanNetworkDevicesManuallyOnNetworkAdapter(network_adapter_t adapter, int timeout);
std::vector<network_adapter_t> getNetworkAdapters();
bool performSetValue(const std::string& ip, const std::string& channelName, const std::string& value);
bool performGetValue(const std::string& ip, const std::string& channelName, std::string& outValue);
bool disconnectToIobox(const std::string& remote);
private:
SPDLogger& _logger = SPDLogger::GetInstance("IOBOX", true);
struct ToggleInfo {
std::chrono::steady_clock::time_point endTime;
std::string originalState;
bool revertFlag;
std::atomic<bool> active{ true };
std::atomic<bool> cancelled{ false };
std::mutex mtx;
std::condition_variable cv;
// Constructor for better initialization
ToggleInfo(bool revert = false) : revertFlag(revert) {}
};
std::unordered_map<std::string, std::shared_ptr<ToggleInfo>> activeToggles;
std::mutex toggleMapMutex;
bool executeToggleOperation(const std::string& remote, const std::string& channelName,
std::shared_ptr<ToggleInfo> toggleInfo, const std::string& key);
public:
iobox_api(const std::string& ip_mcast, int port_mcast);
~iobox_api() noexcept;
void show_profile_iobox(const std::string& remote);
void show_profile_ioboxs();
[[nodiscard]] std::string generateToken(const std::string& remote);
[[nodiscard]] std::vector<std::string> scanNetworkDevicesMulticast(int timeout);
[[nodiscard]] std::vector<std::string> scanNetworkDevicesManually(int timeout);
[[nodiscard]] std::vector<std::string> CreateDeviceChannel(const std::string& multicastInfo);
bool setAuthenticationIobox(const std::string& remote, const std::string& username, const std::string& password);
bool resetAuthenticationIobox(const std::string& remote, const std::string& token);
bool resetIobox(const std::string& remote, const std::string& token);
[[nodiscard]] std::string connectToIobox(const std::string& remote, int port, const std::string& username, const std::string& password);
bool disconnectToIoboxWithResetOutputs(const std::string& remote);
[[nodiscard]] std::vector<std::string> getDeviceChannelNames(const std::string& remote);
bool getValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName, std::string& outValue);
bool setValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName, const std::string& value);
bool checkTcpConnectStatus(const std::string& remote);
bool setValue(const std::string& remote, const std::string& channelName, const std::string& value);// Repeat until success or timeout (3s)
bool getValue(const std::string& remote, const std::string& channelName, std::string& outValue);// Repeat until success or timeout (3s)
//for RS232
bool openRs232Port(const std::string& remote, int baudrate, int dataBits, int stopBits, int parityBits);
bool closeRs232Port(const std::string& remote);
bool writeRs232Port(const std::string& remote, const std::string& data, int timeout_ms);
[[nodiscard]] std::string readRs232Port(const std::string& remote, const std::string& terminatorString, int lenExpect, int timeout_ms);
//for ota: type is "esp" or "mcu"
bool otaFirmwareDevice(const std::string& remote, const std::string& filename, const std::string& type);
// advanced functions (it can connect to ip or mac address and return device channel names)
[[nodiscard]] std::vector<std::string> advancedConnectToIobox(const std::string& remote, int port, const std::string& macAddress, const std::string& username, const std::string& password);
[[nodiscard]] std::vector<std::string> advancedScan(int timeout);
// Add to public section:
bool toggleIobox(const std::string& remote, const std::string& channelName, int timeOut,bool revertFlag, bool resetFlag, bool asyncMode = false);
bool cancelToggle(const std::string& remote, const std::string& channelName);
[[nodiscard]] std::vector<std::string> getActiveToggleChannels();
bool getToggleStatus(const std::string& remote, const std::string& channelName,int& remainingTimeMs, std::string& currentPhase);
// new functions
[[nodiscard]] std::vector<std::string> getStaticIpConfig(const std::string& remote);
bool setStaticIpConfig(const std::string& remote, bool enable, const std::string& ip, const std::string& gw, const std::string& nm);
[[nodiscard]] std::string getValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName);
bool toggleDigitalOutput(const std::string& remote, const std::string& channelName, const std::string& milliseconds, bool invert, bool reset);
bool setAIBValueDataStringIoboxFromChannelName(const std::string& remote, const std::string& channelName, const std::string& value);
};
}
extern "C" ANSIO_API int CreateANSIOHandle(ANSCENTER::iobox_api** Handle, const char* multicastIPAddress, int multicastPort);
extern "C" ANSIO_API int ScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses);
extern "C" ANSIO_API int ScanANSIOUnicastHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle ipAddresses);
extern "C" ANSIO_API int AdvancedScanANSIOHandle(ANSCENTER::iobox_api** Handle, int timeout, LStrHandle deviceInfos);
extern "C" ANSIO_API int AdvancedStaticScanANSIOHandle(int timeout, LStrHandle deviceInfos);
extern "C" ANSIO_API int ConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, LStrHandle deviceStr);
extern "C" ANSIO_API int AdvancedConnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioSN, const char* userName, const char* passWord, LStrHandle deviceStr);
extern "C" ANSIO_API int DisconnectANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, LStrHandle channelNames);
extern "C" ANSIO_API int SetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value);
extern "C" ANSIO_API int GetValueANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle lStrValue);
extern "C" ANSIO_API int SetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* userName, const char* passWord);
extern "C" ANSIO_API int ReleaseANSIOHandle(ANSCENTER::iobox_api** Handle);
extern "C" ANSIO_API int ResetAuthenticationANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
extern "C" ANSIO_API int ResetANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* token);
extern "C" ANSIO_API int GenerateANSIOTokenHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle tokenStr);
extern "C" ANSIO_API int CheckANSIOStatusHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP);
// RS232
extern "C" ANSIO_API int OpenANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int baudrate, int DataBits, int stopBits, int parityBits );
extern "C" ANSIO_API int CloseANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP);
extern "C" ANSIO_API int WriteANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* data, int timeout_ms);
extern "C" ANSIO_API int ReadANSAIRS232Port(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* terminatorString, int lenExpect, int timeout_ms, LStrHandle receivedData);
// OTA
extern "C" ANSIO_API int OTAANSIOFirmwareDevice(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* filename, const char* type);
// C++ interface
extern "C" ANSIO_API int ScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses);
extern "C" ANSIO_API int ScanANSIOUnicastHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& ipAddresses);
extern "C" ANSIO_API int AdvancedScanANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, int timeout, std::string& deviceInfos);
extern "C" ANSIO_API int AdvancedStaticScanANSIOHandle_CPP(int timeout, std::string& deviceInfos);
extern "C" ANSIO_API int GetChannelNamesANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int timeout, std::string& channelNames);
extern "C" ANSIO_API int GetValueANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, std::string& lStrValue);
extern "C" ANSIO_API int GenerateANSIOTokenHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, std::string& tokenStr);
extern "C" ANSIO_API int ConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* userName, const char* passWord, std::string& deviceStr);
extern "C" ANSIO_API int AdvancedConnectANSIOHandle_CPP(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int ioBoxPort, const char* ioBoxSN, const char* userName, const char* passWord, std::string& deviceStr);
// toggle
extern "C" ANSIO_API int ToggleIoboxHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag);
extern "C" ANSIO_API int ToggleIoboxHandleAsync(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int timeOut, int revertFlag, int resetFlag);
// new functions
extern "C" ANSIO_API int GetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, LStrHandle staticIpConfigInfo);
extern "C" ANSIO_API int SetStaticIpConfigANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, int enable, const char* ip, const char* gw, const char* nm);
extern "C" ANSIO_API int GetValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, LStrHandle dataValue);
extern "C" ANSIO_API int ToggleDigitalOutputANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, int milliseconds, int invertFlag, int resetFlag);
extern "C" ANSIO_API int SetAIBValueDataStringIoboxFromChannelNameANSIOHandle(ANSCENTER::iobox_api** Handle, const char* ioBoxIP, const char* channelName, const char* value);
#endif

View File

@@ -0,0 +1,111 @@
#include "iobox_api.h"
#include <thread>
iobox_api ioBoxApp((char*)"239.255.255.250", 12345);
void userInputThread(iobox_api* api) {
std::string current_ip;
while (true) {
std::string input;
std::cout << std::endl;
std::cout << "Enter command followed by Enter: exit, scan, setip, connect, channels, disconnect, show, get, set, restart, setauthen, resetauthen" << std::endl;
// std::cin >> input; // This will only get the first word
std::getline(std::cin, input);
if (input == "exit") {
break;
}
else if(input == "scan") {
std::vector<std::string> devices = api->scanNetworkDevicesMulticast(5);
std::cout << "Found devices: " << devices.size() << std::endl;
for (const std::string& device : devices) {
std::cout << device << std::endl;
}
continue;
}
else if(input == "setip") {
std::cout << "Enter IP: ";
std::getline(std::cin, current_ip);
continue;
}
else if(input == "connect") {
if(current_ip == "") {
std::cout << "Please setip address first" << std::endl;
continue;
}
std::string username, password;
std::cout << "Enter username: ";
std::cin >> username;
std::cout << "Enter password: ";
std::cin >> password;
bool connect = api->connectToIobox(current_ip, DEVICE_TCP_PORT, username, password);
std::cout << "Connection to " << current_ip << (connect ? " succeeded." : " failed.") << std::endl;
continue;
}
else if(input == "disconnect") {
bool disconnect = api->disconnectToIobox(current_ip);
std::cout << "Disconnect to " << current_ip << (disconnect ? " succeeded." : " failed.") << std::endl;
// current_ip = "";
continue;
}
else if(input == "show") {
api->show_profile_ioboxs();
continue;
}
else if(input == "get") {
std::string channel;
std::cout << "Enter channel: ";
std::cin >> channel;
std::string value = api->getValueDataStringIoboxFromChannelName(current_ip, channel);
std::cout << "Value of " << channel << ": " << value << std::endl;
continue;
}
else if(input == "set") {
std::string value;
std::string channel;
std::cout << "Enter channel: ";
std::cin >> channel;
std::cout << "Enter value: ";
std::cin >> value;
bool set = api->setValueDataStringIoboxFromChannelName(current_ip, channel, value);
std::cout << "Set value to " << current_ip << (set ? " succeeded." : " failed.") << std::endl;
}
else if(input == "restart") {
std::string token = api->generateToken(current_ip);
bool reset = api->resetIobox(current_ip, token);
std::cout << "Restart " << current_ip << (reset ? " succeeded." : " failed.") << std::endl;
}
else if(input == "setauthen") {
std::string username, password;
std::cout << "Enter username: ";
std::cin >> username;
std::cout << "Enter password: ";
std::cin >> password;
bool set = api->setAuthenticationIobox(current_ip, username, password);
std::cout << "Set authentication to " << current_ip << (set ? " succeeded." : " failed.") << std::endl;
}
else if(input == "resetauthen") {
std::string token = api->generateToken(current_ip);
bool reset = api->resetAuthenticationIobox(current_ip, token);
std::cout << "Reset authentication to " << current_ip << (reset ? " succeeded." : " failed.") << std::endl;
}
else if(input == "channels") {
std::vector<std::string> channels = api->getDeviceChannelNames(current_ip);
std::cout << "Channels of " << current_ip << std::endl;
for(const std::string& channel : channels) {
std::cout << channel << std::endl;
}
}
else {
// std::cout << "Invalid command" << std::endl;
}
}
}
int main() {
std::thread userThread(userInputThread, &ioBoxApp);
userThread.join();
std::cout << "Main thread is done" << std::endl;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,297 @@
/**
* \file aes.h
*
* \brief AES block cipher
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_AES_H
#define MBEDTLS_AES_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#include <stdint.h>
/* padlock.c and aesni.c rely on these values! */
#define MBEDTLS_AES_ENCRYPT 1
#define MBEDTLS_AES_DECRYPT 0
#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
#if !defined(MBEDTLS_AES_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief AES context structure
*
* \note buf is able to hold 32 extra bytes, which can be used:
* - for alignment purposes if VIA padlock is used, and/or
* - to simplify key expansion in the 256-bit case by
* generating an extra round key
*/
typedef struct
{
int nr; /*!< number of rounds */
uint32_t *rk; /*!< AES round keys */
uint32_t buf[68]; /*!< unaligned data */
}
mbedtls_aes_context;
/**
* \brief Initialize AES context
*
* \param ctx AES context to be initialized
*/
void mbedtls_aes_init( mbedtls_aes_context *ctx );
/**
* \brief Clear AES context
*
* \param ctx AES context to be cleared
*/
void mbedtls_aes_free( mbedtls_aes_context *ctx );
/**
* \brief AES key schedule (encryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
* \param keybits must be 128, 192 or 256
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
*/
int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits );
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keybits must be 128, 192 or 256
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
*/
int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits );
/**
* \brief AES-ECB block encryption/decryption
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] );
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
* size (16 bytes)
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH
*/
int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/**
* \brief AES-CFB128 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv_off offset in IV (updated after use)
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
/**
* \brief AES-CFB8 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/**
* \brief AES-CTR buffer encryption/decryption
*
* Warning: You have to keep the maximum use of your counter in mind!
*
* Note: Due to the nature of CTR you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \param ctx AES context
* \param length The length of the data
* \param nc_off The offset in the current stream_block (for resuming
* within current cipher stream). The offset pointer to
* should be 0 at the start of a stream.
* \param nonce_counter The 128-bit nonce and counter.
* \param stream_block The saved stream-block for resuming. Is overwritten
* by the function.
* \param input The input data stream
* \param output The output data stream
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output );
#endif /* MBEDTLS_CIPHER_MODE_CTR */
/**
* \brief Internal AES block encryption function
* (Only exposed to allow overriding it,
* see MBEDTLS_AES_ENCRYPT_ALT)
*
* \param ctx AES context
* \param input Plaintext block
* \param output Output (ciphertext) block
*/
void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] );
/**
* \brief Internal AES block decryption function
* (Only exposed to allow overriding it,
* see MBEDTLS_AES_DECRYPT_ALT)
*
* \param ctx AES context
* \param input Ciphertext block
* \param output Output (plaintext) block
*/
void mbedtls_aes_decrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] );
#ifdef __cplusplus
}
#endif
#else /* MBEDTLS_AES_ALT */
#include "aes_alt.h"
#endif /* MBEDTLS_AES_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_aes_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* aes.h */

View File

@@ -0,0 +1,289 @@
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_BASE64_C)
#include "base64.h"
#include <stdint.h>
#if defined(MBEDTLS_SELF_TEST)
#include <string.h>
#if defined(MBEDTLS_PLATFORM_C)
#include "platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
static const unsigned char base64_enc_map[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
static const unsigned char base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
/*
* Encode a buffer into base64 format
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
int C1, C2, C3;
unsigned char *p;
if( slen == 0 )
{
*olen = 0;
return( 0 );
}
n = slen / 3 + ( slen % 3 != 0 );
if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
{
*olen = BASE64_SIZE_T_MAX;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n *= 4;
if( dlen < n + 1 )
{
*olen = n + 1;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
n = ( slen / 3 ) * 3;
for( i = 0, p = dst; i < n; i += 3 )
{
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if( i < slen )
{
C1 = *src++;
C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if( ( i + 1 ) < slen )
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else *p++ = '=';
*p++ = '=';
}
*olen = p - dst;
*p = 0;
return( 0 );
}
/*
* Decode a base64-formatted buffer
*/
int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen )
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
/* First pass: check for validity and get output length */
for( i = n = j = 0; i < slen; i++ )
{
/* Skip spaces before checking for EOL */
x = 0;
while( i < slen && src[i] == ' ' )
{
++i;
++x;
}
/* Spaces at end of buffer are OK */
if( i == slen )
break;
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
/* Space inside a line is an error */
if( x != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] == '=' && ++j > 2 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
if( base64_dec_map[src[i]] < 64 && j != 0 )
return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
n++;
}
if( n == 0 )
{
*olen = 0;
return( 0 );
}
n = ( ( n * 6 ) + 7 ) >> 3;
n -= j;
if( dst == NULL || dlen < n )
{
*olen = n;
return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' || *src == ' ' )
continue;
j -= ( base64_dec_map[*src] == 64 );
x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*olen = p - dst;
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST)
static const unsigned char base64_test_dec[64] =
{
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
};
static const unsigned char base64_test_enc[] =
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
/*
* Checkup routine
*/
int mbedtls_base64_self_test( int verbose )
{
size_t len;
const unsigned char *src;
unsigned char buffer[128];
if( verbose != 0 )
mbedtls_printf( " Base64 encoding test: " );
src = base64_test_dec;
if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
memcmp( base64_test_enc, buffer, 88 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n Base64 decoding test: " );
src = base64_test_enc;
if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
memcmp( base64_test_dec, buffer, 64 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_BASE64_C */

View File

@@ -0,0 +1,88 @@
/**
* \file base64.h
*
* \brief RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_BASE64_H
#define MBEDTLS_BASE64_H
#include <stddef.h>
#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */
#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Encode a buffer into base64 format
*
* \param dst destination buffer
* \param dlen size of the destination buffer
* \param olen number of bytes written
* \param src source buffer
* \param slen amount of data to be encoded
*
* \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL.
* *olen is always updated to reflect the amount
* of data that has (or would have) been written.
* If that length cannot be represented, then no data is
* written to the buffer and *olen is set to the maximum
* length representable as a size_t.
*
* \note Call this function with dlen = 0 to obtain the
* required buffer size in *olen
*/
int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen );
/**
* \brief Decode a base64-formatted buffer
*
* \param dst destination buffer (can be NULL for checking size)
* \param dlen size of the destination buffer
* \param olen number of bytes written
* \param src source buffer
* \param slen amount of data to be decoded
*
* \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or
* MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is
* not correct. *olen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *dst = NULL or dlen = 0 to obtain
* the required buffer size in *olen
*/
int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
const unsigned char *src, size_t slen );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_base64_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* base64.h */

View File

@@ -0,0 +1,540 @@
/**
* \file check_config.h
*
* \brief Consistency checks for configuration options
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* It is recommended to include this file from your config.h
* in order to catch dependency issues early.
*/
#ifndef MBEDTLS_CHECK_CONFIG_H
#define MBEDTLS_CHECK_CONFIG_H
/*
* We assume CHAR_BIT is 8 in many places. In practice, this is true on our
* target platforms, so not an issue, but let's just be extra sure.
*/
#include <limits.h>
#if CHAR_BIT != 8
#error "mbed TLS requires a platform with 8-bit chars"
#endif
#if defined(_WIN32)
#if !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_C is required on Windows"
#endif
/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as
* it would confuse config.pl. */
#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \
!defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#endif
#endif /* _WIN32 */
#if defined(TARGET_LIKE_MBED) && \
( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) )
#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS"
#endif
#if defined(MBEDTLS_DEPRECATED_WARNING) && \
!defined(__GNUC__) && !defined(__clang__)
#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME)
#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
#endif
#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C)
#error "MBEDTLS_DHM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C)
#error "MBEDTLS_ECDH_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDSA_C) && \
( !defined(MBEDTLS_ECP_C) || \
!defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_ASN1_WRITE_C) )
#error "MBEDTLS_ECDSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECJPAKE_C) && \
( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) )
#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \
!defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) )
#error "MBEDTLS_ECP_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \
!defined(MBEDTLS_SHA256_C))
#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \
defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \
&& defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C)
#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_GCM_C) && ( \
!defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) )
#error "MBEDTLS_GCM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C)
#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C)
#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \
!defined(MBEDTLS_ECDH_C)
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) )
#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_C) && \
( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) )
#error "MBEDTLS_PK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PKCS11_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
defined(MBEDTLS_PLATFORM_EXIT_ALT) )
#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_FREE)
#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_CALLOC)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
!defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
!defined(MBEDTLS_PLATFORM_EXIT_ALT)
#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
!defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
!defined(MBEDTLS_PLATFORM_PRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
!defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) )
#error "MBEDTLS_RSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) )
#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \
!defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \
!defined(MBEDTLS_MD_C) )
#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2))
#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \
!defined(MBEDTLS_SSL_PROTO_TLS1_1)))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS)
#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
!defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
!defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
!defined(MBEDTLS_X509_CRT_PARSE_C)
#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_THREADING_PTHREAD)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_ALT)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_C defined, single threading implementation required"
#endif
#undef MBEDTLS_THREADING_IMPL
#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C)
#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_PK_PARSE_C) )
#error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \
!defined(MBEDTLS_PK_WRITE_C) )
#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
#endif
/*
* Avoid warning from -pedantic. This is a convenient place for this
* workaround since this is included by every single file before the
* #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
*/
typedef int mbedtls_iso_c_forbids_empty_translation_units;
#endif /* MBEDTLS_CHECK_CONFIG_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,214 @@
/**
* \file platform.h
*
* \brief mbed TLS Platform abstraction layer
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PLATFORM_H
#define MBEDTLS_PLATFORM_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h or define them on the compiler command line.
* \{
*/
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#include <stdio.h>
#include <stdlib.h>
#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
#if defined(_WIN32)
#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */
#else
#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use */
#endif
#endif
#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FREE)
#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default free to use */
#endif
#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
#include MBEDTLS_PLATFORM_STD_MEM_HDR
#endif
#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
/* \} name SECTION: Module settings */
/*
* The function pointers for calloc and free
*/
#if defined(MBEDTLS_PLATFORM_MEMORY)
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO
#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO
#else
/* For size_t */
#include <stddef.h>
extern void * (*mbedtls_calloc)( size_t n, size_t size );
extern void (*mbedtls_free)( void *ptr );
/**
* \brief Set your own memory implementation function pointers
*
* \param calloc_func the calloc function implementation
* \param free_func the free function implementation
*
* \return 0 if successful
*/
int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
void (*free_func)( void * ) );
#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */
#else /* !MBEDTLS_PLATFORM_MEMORY */
#define mbedtls_free free
#define mbedtls_calloc calloc
#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */
/*
* The function pointers for fprintf
*/
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
/* We need FILE * */
#include <stdio.h>
extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... );
/**
* \brief Set your own fprintf function pointer
*
* \param fprintf_func the fprintf function implementation
*
* \return 0
*/
int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *,
... ) );
#else
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO
#else
#define mbedtls_fprintf fprintf
#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
/*
* The function pointers for printf
*/
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
extern int (*mbedtls_printf)( const char *format, ... );
/**
* \brief Set your own printf function pointer
*
* \param printf_func the printf function implementation
*
* \return 0
*/
int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) );
#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO
#else
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
/*
* The function pointers for snprintf
*
* The snprintf implementation should conform to C99:
* - it *must* always correctly zero-terminate the buffer
* (except when n == 0, then it must leave the buffer untouched)
* - however it is acceptable to return -1 instead of the required length when
* the destination buffer is too short.
*/
#if defined(_WIN32)
/* For Windows (inc. MSYS2), we provide our own fixed implementation */
int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
/**
* \brief Set your own snprintf function pointer
*
* \param snprintf_func the snprintf function implementation
*
* \return 0
*/
int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
const char * format, ... ) );
#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO
#else
#define mbedtls_snprintf snprintf
#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
/*
* The function pointers for exit
*/
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
extern void (*mbedtls_exit)( int status );
/**
* \brief Set your own exit function pointer
*
* \param exit_func the exit function implementation
*
* \return 0
*/
int mbedtls_platform_set_exit( void (*exit_func)( int status ) );
#else
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO
#else
#define mbedtls_exit exit
#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
#ifdef __cplusplus
}
#endif
#endif /* platform.h */

View File

@@ -0,0 +1,445 @@
/*
* FIPS-180-2 compliant SHA-256 implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* The SHA-256 Secure Hash Standard was published by NIST in 2002.
*
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_SHA256_C)
#include "sha256.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST)
#if defined(MBEDTLS_PLATFORM_C)
#include "platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST */
#if !defined(MBEDTLS_SHA256_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (big endian)
*/
#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \
do { \
(n) = ( (uint32_t) (b)[(i) ] << 24 ) \
| ( (uint32_t) (b)[(i) + 1] << 16 ) \
| ( (uint32_t) (b)[(i) + 2] << 8 ) \
| ( (uint32_t) (b)[(i) + 3] ); \
} while( 0 )
#endif
#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \
do { \
(b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
(b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
(b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
(b)[(i) + 3] = (unsigned char) ( (n) ); \
} while( 0 )
#endif
void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_free( mbedtls_sha256_context *ctx )
{
if( ctx == NULL )
return;
mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) );
}
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src )
{
*dst = *src;
}
/*
* SHA-256 context setup
*/
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 )
{
ctx->total[0] = 0;
ctx->total[1] = 0;
if( is224 == 0 )
{
/* SHA-256 */
ctx->state[0] = 0x6A09E667;
ctx->state[1] = 0xBB67AE85;
ctx->state[2] = 0x3C6EF372;
ctx->state[3] = 0xA54FF53A;
ctx->state[4] = 0x510E527F;
ctx->state[5] = 0x9B05688C;
ctx->state[6] = 0x1F83D9AB;
ctx->state[7] = 0x5BE0CD19;
}
else
{
/* SHA-224 */
ctx->state[0] = 0xC1059ED8;
ctx->state[1] = 0x367CD507;
ctx->state[2] = 0x3070DD17;
ctx->state[3] = 0xF70E5939;
ctx->state[4] = 0xFFC00B31;
ctx->state[5] = 0x68581511;
ctx->state[6] = 0x64F98FA7;
ctx->state[7] = 0xBEFA4FA4;
}
ctx->is224 = is224;
}
#if !defined(MBEDTLS_SHA256_PROCESS_ALT)
static const uint32_t K[] =
{
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
};
#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
#define F0(x,y,z) ((x & y) | (z & (x | y)))
#define F1(x,y,z) (z ^ (x & (y ^ z)))
#define R(t) \
( \
W[t] = S1(W[t - 2]) + W[t - 7] + \
S0(W[t - 15]) + W[t - 16] \
)
#define P(a,b,c,d,e,f,g,h,x,K) \
{ \
temp1 = h + S3(e) + F1(e,f,g) + K + x; \
temp2 = S2(a) + F0(a,b,c); \
d += temp1; h = temp1 + temp2; \
}
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] )
{
uint32_t temp1, temp2, W[64];
uint32_t A[8];
unsigned int i;
for( i = 0; i < 8; i++ )
A[i] = ctx->state[i];
#if defined(MBEDTLS_SHA256_SMALLER)
for( i = 0; i < 64; i++ )
{
if( i < 16 )
GET_UINT32_BE( W[i], data, 4 * i );
else
R( i );
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
}
#else /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 16; i++ )
GET_UINT32_BE( W[i], data, 4 * i );
for( i = 0; i < 16; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
}
for( i = 16; i < 64; i += 8 )
{
P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
}
#endif /* MBEDTLS_SHA256_SMALLER */
for( i = 0; i < 8; i++ )
ctx->state[i] += A[i];
}
#endif /* !MBEDTLS_SHA256_PROCESS_ALT */
/*
* SHA-256 process buffer
*/
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
size_t ilen )
{
size_t fill;
uint32_t left;
if( ilen == 0 )
return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t) ilen;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < (uint32_t) ilen )
ctx->total[1]++;
if( left && ilen >= fill )
{
memcpy( (void *) (ctx->buffer + left), input, fill );
mbedtls_sha256_process( ctx, ctx->buffer );
input += fill;
ilen -= fill;
left = 0;
}
while( ilen >= 64 )
{
mbedtls_sha256_process( ctx, input );
input += 64;
ilen -= 64;
}
if( ilen > 0 )
memcpy( (void *) (ctx->buffer + left), input, ilen );
}
static const unsigned char sha256_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* SHA-256 final digest
*/
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] )
{
uint32_t last, padn;
uint32_t high, low;
unsigned char msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32_BE( high, msglen, 0 );
PUT_UINT32_BE( low, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
mbedtls_sha256_update( ctx, sha256_padding, padn );
mbedtls_sha256_update( ctx, msglen, 8 );
PUT_UINT32_BE( ctx->state[0], output, 0 );
PUT_UINT32_BE( ctx->state[1], output, 4 );
PUT_UINT32_BE( ctx->state[2], output, 8 );
PUT_UINT32_BE( ctx->state[3], output, 12 );
PUT_UINT32_BE( ctx->state[4], output, 16 );
PUT_UINT32_BE( ctx->state[5], output, 20 );
PUT_UINT32_BE( ctx->state[6], output, 24 );
if( ctx->is224 == 0 )
PUT_UINT32_BE( ctx->state[7], output, 28 );
}
#endif /* !MBEDTLS_SHA256_ALT */
/*
* output = SHA-256( input buffer )
*/
void mbedtls_sha256( const unsigned char *input, size_t ilen,
unsigned char output[32], int is224 )
{
mbedtls_sha256_context ctx;
mbedtls_sha256_init( &ctx );
mbedtls_sha256_starts( &ctx, is224 );
mbedtls_sha256_update( &ctx, input, ilen );
mbedtls_sha256_finish( &ctx, output );
mbedtls_sha256_free( &ctx );
}
#if defined(MBEDTLS_SELF_TEST)
/*
* FIPS-180-2 test vectors
*/
static const unsigned char sha256_test_buf[3][57] =
{
{ "abc" },
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
{ "" }
};
static const int sha256_test_buflen[3] =
{
3, 56, 1000
};
static const unsigned char sha256_test_sum[6][32] =
{
/*
* SHA-224 test vectors
*/
{ 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
0xE3, 0x6C, 0x9D, 0xA7 },
{ 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
0x52, 0x52, 0x25, 0x25 },
{ 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
0x4E, 0xE7, 0xAD, 0x67 },
/*
* SHA-256 test vectors
*/
{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
{ 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
};
/*
* Checkup routine
*/
int mbedtls_sha256_self_test( int verbose )
{
int i, j, k, buflen, ret = 0;
unsigned char buf[1024];
unsigned char sha256sum[32];
mbedtls_sha256_context ctx;
mbedtls_sha256_init( &ctx );
for( i = 0; i < 6; i++ )
{
j = i % 3;
k = i < 3;
if( verbose != 0 )
mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
mbedtls_sha256_starts( &ctx, k );
if( j == 2 )
{
memset( buf, 'a', buflen = 1000 );
for( j = 0; j < 1000; j++ )
mbedtls_sha256_update( &ctx, buf, buflen );
}
else
mbedtls_sha256_update( &ctx, sha256_test_buf[j],
sha256_test_buflen[j] );
mbedtls_sha256_finish( &ctx, sha256sum );
if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
ret = 1;
goto exit;
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
if( verbose != 0 )
mbedtls_printf( "\n" );
exit:
mbedtls_sha256_free( &ctx );
return( ret );
}
#endif /* MBEDTLS_SELF_TEST */
#endif /* MBEDTLS_SHA256_C */

View File

@@ -0,0 +1,141 @@
/**
* \file sha256.h
*
* \brief SHA-224 and SHA-256 cryptographic hash function
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_SHA256_H
#define MBEDTLS_SHA256_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#include <stdint.h>
#if !defined(MBEDTLS_SHA256_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief SHA-256 context structure
*/
typedef struct
{
uint32_t total[2]; /*!< number of bytes processed */
uint32_t state[8]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
int is224; /*!< 0 => SHA-256, else SHA-224 */
}
mbedtls_sha256_context;
/**
* \brief Initialize SHA-256 context
*
* \param ctx SHA-256 context to be initialized
*/
void mbedtls_sha256_init( mbedtls_sha256_context *ctx );
/**
* \brief Clear SHA-256 context
*
* \param ctx SHA-256 context to be cleared
*/
void mbedtls_sha256_free( mbedtls_sha256_context *ctx );
/**
* \brief Clone (the state of) a SHA-256 context
*
* \param dst The destination context
* \param src The context to be cloned
*/
void mbedtls_sha256_clone( mbedtls_sha256_context *dst,
const mbedtls_sha256_context *src );
/**
* \brief SHA-256 context setup
*
* \param ctx context to be initialized
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 );
/**
* \brief SHA-256 process buffer
*
* \param ctx SHA-256 context
* \param input buffer holding the data
* \param ilen length of the input data
*/
void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input,
size_t ilen );
/**
* \brief SHA-256 final digest
*
* \param ctx SHA-256 context
* \param output SHA-224/256 checksum result
*/
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] );
/* Internal use */
void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] );
#ifdef __cplusplus
}
#endif
#else /* MBEDTLS_SHA256_ALT */
#include "sha256_alt.h"
#endif /* MBEDTLS_SHA256_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Output = SHA-256( input buffer )
*
* \param input buffer holding the data
* \param ilen length of the input data
* \param output SHA-224/256 checksum result
* \param is224 0 = use SHA256, 1 = use SHA224
*/
void mbedtls_sha256( const unsigned char *input, size_t ilen,
unsigned char output[32], int is224 );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_sha256_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* mbedtls_sha256.h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

22
integrations/ANSIO/pch.h Normal file
View File

@@ -0,0 +1,22 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#include <algorithm>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <mutex>
using std::min;
using std::max;
#endif //PCH_H

View File

@@ -0,0 +1,960 @@
#include "ANSONVIF.h"
#include <cstdint>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "bm\sys_inc.h"
#include "bm\linked_list.h"
#include "http\http.h"
#include "http\http_parse.h"
#include "onvif\onvif_probe.h"
#include "onvif\onvif_event.h"
#include "onvif\onvif_api.h"
#include <unordered_map>
#include <condition_variable>
#include <mutex>
// Handle registry with refcount — prevents use-after-free when
// ReleaseANSOnvifHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::ANSOnvifClient*, int>& OnvifHandleRegistry() {
static std::unordered_map<ANSCENTER::ANSOnvifClient*, int> s;
return s;
}
static std::mutex& OnvifHandleRegistryMutex() {
static std::mutex m;
return m;
}
static std::condition_variable& OnvifHandleRegistryCV() {
static std::condition_variable cv;
return cv;
}
static void RegisterOnvifHandle(ANSCENTER::ANSOnvifClient* h) {
std::lock_guard<std::mutex> lk(OnvifHandleRegistryMutex());
OnvifHandleRegistry()[h] = 1;
}
static ANSCENTER::ANSOnvifClient* AcquireOnvifHandle(ANSCENTER::ANSOnvifClient* h) {
std::lock_guard<std::mutex> lk(OnvifHandleRegistryMutex());
auto it = OnvifHandleRegistry().find(h);
if (it == OnvifHandleRegistry().end()) return nullptr;
it->second++;
return h;
}
static bool ReleaseOnvifHandleRef(ANSCENTER::ANSOnvifClient* h) {
std::lock_guard<std::mutex> lk(OnvifHandleRegistryMutex());
auto it = OnvifHandleRegistry().find(h);
if (it == OnvifHandleRegistry().end()) return false;
it->second--;
if (it->second <= 0) {
OnvifHandleRegistry().erase(it);
OnvifHandleRegistryCV().notify_all();
return true;
}
return false;
}
static bool UnregisterOnvifHandle(ANSCENTER::ANSOnvifClient* h) {
std::unique_lock<std::mutex> lk(OnvifHandleRegistryMutex());
auto it = OnvifHandleRegistry().find(h);
if (it == OnvifHandleRegistry().end()) return false;
it->second--;
bool ok = OnvifHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
auto it2 = OnvifHandleRegistry().find(h);
return it2 == OnvifHandleRegistry().end() || it2->second <= 0;
});
if (!ok) {
OutputDebugStringA("WARNING: UnregisterOnvifHandle timed out waiting for in-flight operations\n");
}
OnvifHandleRegistry().erase(h);
return true;
}
// RAII guard — ensures ReleaseOnvifHandleRef is always called
class OnvifHandleGuard {
ANSCENTER::ANSOnvifClient* engine;
public:
explicit OnvifHandleGuard(ANSCENTER::ANSOnvifClient* e) : engine(e) {}
~OnvifHandleGuard() { if (engine) ReleaseOnvifHandleRef(engine); }
ANSCENTER::ANSOnvifClient* get() const { return engine; }
explicit operator bool() const { return engine != nullptr; }
OnvifHandleGuard(const OnvifHandleGuard&) = delete;
OnvifHandleGuard& operator=(const OnvifHandleGuard&) = delete;
};
static bool ansonvifLicenceValid = false;
// Global once_flag to protect license checking
static std::once_flag ansonvifLicenseOnceFlag;
namespace ANSCENTER {
static void VerifyGlobalANSONVIFLicense(const std::string& licenseKey) {
try {
std::cout << "ANSOnvifClient::CheckLicense.", "Checking ONVIF license. Please wait....";
ansonvifLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1007, "ANSCV");//
if (!ansonvifLicenceValid)ansonvifLicenceValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, 1003, "ANSVIS");//Default productId=1005
if (!ansonvifLicenceValid) std::cerr << "ANSOnvifClient::CheckLicense.", "Invalid ONVIF license. Please activate correct license.";
else std::cout << "ANSOnvifClient::CheckLicense.", "Valid ONVIF license.";
}
catch (std::exception& e) {
std::cerr << "ANSOnvifClient::CheckLicense()" << e.what();
ansonvifLicenceValid = false;
}
}
//Private methods
void ANSOnvifClient::GetDevInfo(ONVIF_DEVICE_EX* p_device) {
char profileToken[ONVIF_TOKEN_LEN];
ONVIF_PROFILE* p_profile = nullptr;
GetSystemDateAndTime(&p_device->onvif_device);
GetCapabilities(&p_device->onvif_device);
GetServices(&p_device->onvif_device);
GetDeviceInformation(&p_device->onvif_device);
GetVideoSources(&p_device->onvif_device);
GetImagingSettings(&p_device->onvif_device);
GetVideoSourceConfigurations(&p_device->onvif_device);
GetVideoEncoderConfigurations(&p_device->onvif_device);
if (GetAudioSources(&p_device->onvif_device))
{
GetAudioSourceConfigurations(&p_device->onvif_device);
GetAudioEncoderConfigurations(&p_device->onvif_device);
}
if (p_device->onvif_device.Capabilities.ptz.support)
{
GetNodes(&p_device->onvif_device);
GetConfigurations(&p_device->onvif_device);
}
if (p_device->onvif_device.curProfile)
{
strcpy(profileToken, p_device->onvif_device.curProfile->token);
}
else
{
memset(profileToken, 0, sizeof(profileToken));
}
if (profileToken[0] != '\0')
{
p_profile = onvif_find_profile(p_device->onvif_device.profiles, profileToken);
}
if (nullptr ==p_profile)
{
p_profile = p_device->onvif_device.profiles;
}
p_device->onvif_device.curProfile = p_profile;
if (p_device->onvif_device.curProfile == nullptr)
{
p_device->thread_handler = 0;
return ;
}
if (p_profile)
{
int len;
uint8* p_buff;
if (GetSnapshot(&p_device->onvif_device, p_profile->token, &p_buff, &len))
{
if (p_device->snapshot)
{
FreeBuff(p_device->snapshot);
p_device->snapshot = nullptr;
p_device->snapshot_len = 0;
}
p_device->snapshot = p_buff;
p_device->snapshot_len = len;
}
}
if (p_device->onvif_device.Capabilities.events.support == 1 &&
p_device->onvif_device.events.subscribe == FALSE)
{
Subscribe(&p_device->onvif_device, pps_get_index(m_dev_ul, p_device));
}
}
ONVIF_DEVICE_EX* ANSOnvifClient::FindDevice(ONVIF_DEVICE_EX* pdevice)
{
ONVIF_DEVICE_EX* p_dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_start(m_dev_ul));
while (p_dev)
{
if (strcmp(p_dev->onvif_device.binfo.XAddr.host, pdevice->onvif_device.binfo.XAddr.host) == 0 &&
p_dev->onvif_device.binfo.XAddr.port == pdevice->onvif_device.binfo.XAddr.port)
{
break;
}
p_dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_next(m_dev_ul, p_dev));
}
pps_lookup_end(m_dev_ul);
return p_dev;
}
ONVIF_DEVICE_EX* ANSOnvifClient::FindDeviceByEndpointReference(char* p_EndpointReference)
{
ONVIF_DEVICE_EX* p_dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_start(m_dev_ul));
while (p_dev)
{
if (strcmp(p_dev->onvif_device.binfo.EndpointReference, p_EndpointReference) == 0)
{
break;
}
p_dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_next(m_dev_ul, p_dev));
}
pps_lookup_end(m_dev_ul);
return p_dev;
}
ONVIF_DEVICE_EX* ANSOnvifClient::AddDevice(ONVIF_DEVICE_EX* pdevice)
{
ONVIF_DEVICE_EX* p_dev = static_cast<ONVIF_DEVICE_EX*>(pps_fl_pop(m_dev_fl));
if (p_dev)
{
memcpy(p_dev, pdevice, sizeof(ONVIF_DEVICE_EX));
p_dev->p_user = 0;
p_dev->onvif_device.events.init_term_time = 60;
onvif_SetAuthInfo(&p_dev->onvif_device, "admin", "admin");
onvif_SetAuthMethod(&p_dev->onvif_device, AuthMethod_UsernameToken);
onvif_SetReqTimeout(&p_dev->onvif_device, 10000);
pps_ctx_ul_add(m_dev_ul, p_dev);
}
return p_dev;
}
void ANSOnvifClient::UpdateDevice(ONVIF_DEVICE_EX* p_device)
{
if (nullptr ==p_device)
{
return;
}
if (p_device->thread_handler)
{
return;
}
BOOL need_update = FALSE;
if (p_device->need_update)
{
need_update = TRUE;
}
if (!p_device->onvif_device.authFailed)
{
if (nullptr ==p_device->onvif_device.curProfile)
{
need_update = TRUE;
}
else if (p_device->onvif_device.curProfile->stream_uri[0] == '\0')
{
need_update = TRUE;
}
}
if (need_update)
{
p_device->need_update = 0;
GetDevInfo(p_device);
}
}
void ANSOnvifClient::FreeDevice(ONVIF_DEVICE_EX* p_dev)
{
if (nullptr ==p_dev)
{
return;
}
while (p_dev->thread_handler)
{
usleep(1000);
}
onvif_free_device(&p_dev->onvif_device);
if (p_dev->snapshot)
{
FreeBuff(p_dev->snapshot);
p_dev->snapshot = nullptr;
p_dev->snapshot_len = 0;
}
}
void ANSOnvifClient::ClearDevices()
{
if (m_dev_ul != nullptr) {
ONVIF_DEVICE_EX* next_dev;
ONVIF_DEVICE_EX* dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_start(m_dev_ul));
int max_iterations = 100; // Set a reasonable limit for the maximum number of iterations
int iteration_count = 0;
while (dev && iteration_count < max_iterations)
{
next_dev = static_cast<ONVIF_DEVICE_EX*>(pps_lookup_next(m_dev_ul, dev));
try {
FreeDevice(dev);
}
catch (const std::exception& e) {
// Log the exception or handle it as needed
printf("Exception occurred while freeing device: %s\n", e.what());
}
catch (...) {
// Catch any other types of exceptions
printf("Unknown exception occurred while freeing device.\n");
}
dev = next_dev;
iteration_count++;
}
if (iteration_count >= max_iterations) {
printf("Warning: ClearDevices loop exceeded maximum iterations.\n");
}
pps_lookup_end(m_dev_ul);
}
}
void ANSOnvifClient::ProbeCallback(DEVICE_BINFO* p_res, int msgtype, void* p_data)
{
ONVIF_DEVICE_EX device;
memset(&device, 0, sizeof(ONVIF_DEVICE_EX));
if (msgtype == PROBE_MSGTYPE_MATCH || msgtype == PROBE_MSGTYPE_HELLO)
{
memcpy(&device.onvif_device.binfo, p_res, sizeof(DEVICE_BINFO));
device.state = 1;
std::string deviceURL = p_res->XAddr.url;
if (deviceURL.find("/onvif/device_service") != std::string::npos) {
OnvifDevice foundOnvifDevice;
foundOnvifDevice.deviceIP = p_res->XAddr.host;
foundOnvifDevice.devicePort = p_res->XAddr.port;
// Check if the device is already in the list
auto it = std::find_if(_deviceList.begin(), _deviceList.end(), [&foundOnvifDevice](const OnvifDevice& d) {
return d.deviceIP == foundOnvifDevice.deviceIP && d.devicePort == foundOnvifDevice.devicePort;
});
// If the device is not found, add it to the list
if (it == _deviceList.end()) {
printf("Found device. Ip : %s, port : %d\n", p_res->XAddr.host, p_res->XAddr.port);
_deviceList.push_back(foundOnvifDevice);
}
}
}
else if (msgtype == PROBE_MSGTYPE_BYE)
{
printf("Exit onvif probe");
}
}
void ANSOnvifClient::ErrorHandler(ONVIF_DEVICE* p_device)
{
if (p_device->authFailed) // Authentication failed
{
std::cerr<<"ANSOnvifClient::ErrorHandler", "Authentication failed";
}
switch (p_device->errCode)
{
case ONVIF_ERR_ConnFailure: // Connection failed
std::cerr << "ANSOnvifClient::ErrorHandler", "Connect failed";
break;
case ONVIF_ERR_MallocFailure: // Failed to allocate memory
std::cerr << "ANSOnvifClient::ErrorHandler", "Memory malloc failed";
break;
case ONVIF_ERR_NotSupportHttps: // The device requires an HTTPS connection, but the onvif client library does not support it (the HTTPS compilation macro is not enabled)
std::cerr << "ANSOnvifClient::ErrorHandler", "Not support https";
break;
case ONVIF_ERR_RecvTimeout: // Message receiving timeout
std::cerr << "ANSOnvifClient::ErrorHandler", "Message receive timeout";
break;
case ONVIF_ERR_InvalidContentType: // Device response message content is invalid
std::cerr << "ANSOnvifClient::ErrorHandler", "Invalid content type";
break;
case ONVIF_ERR_NullContent: // Device response message has no content
std::cerr << "ANSOnvifClient::ErrorHandler", "Null content";
break;
case ONVIF_ERR_ParseFailed: // Parsing the message failed
std::cerr << "ANSOnvifClient::ErrorHandler", "Message parse failed";
break;
case ONVIF_ERR_HandleFailed: // Message handling failed
std::cerr << "ANSOnvifClient::ErrorHandler", "Message handle failed";
break;
case ONVIF_ERR_HttpResponseError: // The device responded with an error message
std::cerr << "ANSOnvifClient::ErrorHandler. Code="<< p_device->fault.Code;
std::cerr << "ANSOnvifClient::ErrorHandler. Subcode="<< p_device->fault.Subcode;
std::cerr << "ANSOnvifClient::ErrorHandler. Season="<< p_device->fault.Subcode;
break;
default:
break;
}
}
std::string ANSOnvifClient::DeviceListToJsonString(const std::vector<OnvifDevice>& deviceList) {
boost::property_tree::ptree root;
boost::property_tree::ptree detectedObjects;
for (int i = 0; i < deviceList.size(); i++) {
boost::property_tree::ptree detectedNode;
detectedNode.put("ip", deviceList[i].deviceIP);
detectedNode.put("port", deviceList[i].devicePort);
detectedObjects.push_back(std::make_pair("", detectedNode));
}
root.add_child("results", detectedObjects);
std::ostringstream stream;
boost::property_tree::write_json(stream, root, false);
std::string trackingResult = stream.str();
return trackingResult;
}
std::string ANSOnvifClient::DeviceProfileToJsonString(const std::vector<OnvifDeviceProfile>& deviceProfileList) {
boost::property_tree::ptree root;
boost::property_tree::ptree detectedObjects;
for (int i = 0; i < deviceProfileList.size(); i++) {
boost::property_tree::ptree detectedNode;
detectedNode.put("ip", deviceProfileList[i].deviceIP);
detectedNode.put("name", deviceProfileList[i].deviceProfileName);
detectedNode.put("uri", deviceProfileList[i].deviceProfileURI);
detectedObjects.push_back(std::make_pair("", detectedNode));
}
root.add_child("results", detectedObjects);
std::ostringstream stream;
boost::property_tree::write_json(stream, root, false);
std::string trackingResult = stream.str();
return trackingResult;
}
void ANSOnvifClient::CheckLicense() {
//try {
// std::cout << "ANSOnvifClient::CheckLicense.", "Checking ONVIF license. Please wait....";
// _licenseValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(_licenseKey, 1007, "ANSCV");//
// if(!_licenseValid)_licenseValid = ANSCENTER::ANSLicenseHelper::LicenseVerification(_licenseKey, 1003, "ANSVIS");//Default productId=1005
// if(!_licenseValid) std::cerr << "ANSOnvifClient::CheckLicense.", "Invalid ONVIF license. Please activate correct license.";
// else std::cout << "ANSOnvifClient::CheckLicense.", "Valid ONVIF license.";
//}
//catch (std::exception& e) {
// std::cerr << "ANSOnvifClient::CheckLicense()"<< e.what();
//}
try {
// Check once globally
std::call_once(ansonvifLicenseOnceFlag, [this]() {
VerifyGlobalANSONVIFLicense(_licenseKey);
});
// Update this instance's local license flag
_licenseValid = ansonvifLicenceValid;
}
catch (const std::exception& e) {
std::cerr << "ANSOnvifClient::CheckLicense()"<< e.what();
}
}
bool ANSOnvifClient::Init(const std::string& licenseKey) {
CheckLicense();
if (!_licenseValid) {
std::cerr << "ANSOnvifClient::Init", "Invalid license";
return false;
}
try {
_deviceList.clear();
m_dev_fl = pps_ctx_fl_init(200, sizeof(ONVIF_DEVICE_EX), TRUE);
m_dev_ul = pps_ctx_ul_init(m_dev_fl, TRUE);
network_init();
sys_buf_init(200);
http_msg_buf_init(200);
onvif_event_init(nullptr, 30100, 10);
set_probe_cb(ProbeCallback, 0);
//StartDetectTask();
return true;
}
catch (std::exception& e)
{
std::cerr << "ANSOnvifClient::Init. Error"<< e.what();
return false;
}
catch (...) {
std::cerr << "ANSOnvifClient::Init", "Unknown error";
return false;
}
}
void ANSOnvifClient::Destroy() {
ClearDevices();
onvif_event_deinit();
http_msg_buf_deinit();
sys_buf_deinit();
network_deinit();
if (m_dev_ul != nullptr) pps_ul_free(m_dev_ul);
if (m_dev_fl != nullptr)pps_fl_free(m_dev_fl);
_deviceList.clear();
std::cout << "ANSOnvifClient::Destroy.", "Clean-up ONVIF resource";
}
ANSOnvifClient::~ANSOnvifClient() {
Destroy();
}
std::vector<OnvifDevice>ANSOnvifClient::SearchForDevices(int sleepDuration) {
if (sleepDuration <= 0)sleepDuration = 1;
if (_licenseValid) {
std::lock_guard<std::mutex> lock(_mutex);
start_probe(nullptr, 30);
sleep(sleepDuration);//sleep for 15 seconds
stop_probe();
return _deviceList;
}
else {
std::cerr << "ANSOnvifClient::SearchForDevices.", "Invalid ONVIF license. Please activate correct license.";
return _deviceList;
}
}
std::vector<OnvifDeviceProfile> ANSOnvifClient::SearchForDeviceProfile(const std::string& ip, int port, const std::string& username, const std::string& password) {
std::lock_guard<std::mutex> lock(_mutex);
std::vector<OnvifDeviceProfile> _deviceProfileList;
_deviceProfileList.clear();
if (_licenseValid) {
ONVIF_DEVICE g_device;
memset(&g_device, 0, sizeof(g_device));
g_device.binfo.XAddr.https = 0;
g_device.binfo.XAddr.port = port;
strcpy(g_device.binfo.XAddr.host, ip.c_str());
strcpy(g_device.binfo.XAddr.url, "/onvif/device_service");
onvif_SetAuthInfo(&g_device, username.c_str(), password.c_str());
onvif_SetAuthMethod(&g_device, AuthMethod_UsernameToken);
onvif_SetReqTimeout(&g_device, 5000);
if (!GetSystemDateAndTime(&g_device))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetSystemDateAndTime failed."<< g_device.binfo.XAddr.host;
}
if (!GetCapabilities(&g_device))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetCapabilities failed."<< g_device.binfo.XAddr.host;
}
if (!GetServices(&g_device))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetServices failed."<< g_device.binfo.XAddr.host;
}
if (!GetDeviceInformation(&g_device))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetDeviceInformation failed." << g_device.binfo.XAddr.host;
}
if (!GetProfiles(&g_device))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetDeviceInformation failed."<< g_device.binfo.XAddr.host;
}
if (!GetStreamUris(&g_device, onvif_TransportProtocol::TransportProtocol_UDP))
{
ErrorHandler(&g_device);
std::cerr << "ANSOnvifClient::SearchForDeviceProfile. GetDeviceInformation failed."<< g_device.binfo.XAddr.host;
}
ONVIF_PROFILE* p_profile = g_device.profiles;
bool foundProfile = false;
while (p_profile)
{
OnvifDeviceProfile foundOnvifProfile;
foundOnvifProfile.deviceIP = ip;
foundOnvifProfile.deviceProfileName = p_profile->name;
foundOnvifProfile.deviceProfileURI = p_profile->stream_uri;
_deviceProfileList.push_back(foundOnvifProfile);
foundProfile = true;
p_profile = p_profile->next;
}
if (!foundProfile) {
OnvifDeviceProfile foundOnvifProfile;
foundOnvifProfile.deviceIP = g_device.binfo.XAddr.host;
foundOnvifProfile.deviceProfileName = "Error";
foundOnvifProfile.deviceProfileURI = g_device.fault.Reason;
_deviceProfileList.push_back(foundOnvifProfile);
}
onvif_free_device(&g_device);
return _deviceProfileList;
}
else {
std::cerr << "ANSOnvifClient::SearchForDeviceProfile.", "Invalid ONVIF license. Please activate correct license.";
return _deviceProfileList;
}
}
std::vector<OnvifDeviceProfile> ANSOnvifClient::SearchForDeviceProfiles(const std::string& username, const std::string& password) {
std::vector<OnvifDeviceProfile> _deviceProfileList;
_deviceProfileList.clear();
if (_licenseValid) {
SearchForDevices(15);
if (_deviceList.size() <= 0) return _deviceProfileList;
for (int i = 0; i < _deviceList.size(); i++)
{
OnvifDevice currentOnvifDevice = _deviceList.at(i);
std::vector<OnvifDeviceProfile> _currentDeviceProfileList = SearchForDeviceProfile(currentOnvifDevice.deviceIP, currentOnvifDevice.devicePort, username, password);
if (_currentDeviceProfileList.size() > 0) {
for (int j = 0; j < _currentDeviceProfileList.size(); j++) {
_deviceProfileList.push_back(_currentDeviceProfileList.at(j));
}
}
}
return _deviceProfileList;
}
else {
std::cerr << "ANSOnvifClient::SearchForDeviceProfiles.", "Invalid ONVIF license. Please activate correct license.";
return _deviceProfileList;
}
}
std::vector<OnvifDeviceProfile> ANSOnvifClient::SearchForDeviceProfiles(const std::vector<std::string>& usernameList, const std::vector<std::string>& passwordList) {
std::vector<OnvifDeviceProfile> _deviceProfileList;
_deviceProfileList.clear();
if (_licenseValid) {
SearchForDevices(15);
if (_deviceList.size() <= 0) return _deviceProfileList;
if (usernameList.size() <= 0) return _deviceProfileList;
if (usernameList.size() != passwordList.size())return _deviceProfileList;
for (int i = 0; i < _deviceList.size(); i++)
{
OnvifDevice currentOnvifDevice = _deviceList.at(i);
for (int j = 0; j < usernameList.size(); j++)
{
std::vector<OnvifDeviceProfile> _currentDeviceProfileList = SearchForDeviceProfile(currentOnvifDevice.deviceIP, currentOnvifDevice.devicePort, usernameList.at(j).c_str(), passwordList.at(j).c_str());
if (_currentDeviceProfileList.size() > 0) {
for (int k = 0; k < _currentDeviceProfileList.size(); k++) {
_deviceProfileList.push_back(_currentDeviceProfileList.at(k));
}
}
}
}
return _deviceProfileList;
}
else {
std::cerr << "ANSOnvifClient::SearchForDeviceProfiles.", "Invalid ONVIF license. Please activate correct license.";
return _deviceProfileList;
}
}
ANSOnvifClient::ANSOnvifClient() {
_licenseValid = false;
}
void ANSOnvifClient::ClearDeviceList() {
_deviceList.clear();
}
}
extern "C" __declspec(dllexport) int CreateANSOnvifHandle(ANSCENTER::ANSOnvifClient * *Handle, const char* licenseKey) {
if (Handle == nullptr || licenseKey == nullptr) return 0;
try {
// Release existing handle if called twice (prevents leak from LabVIEW)
if (*Handle) {
if (UnregisterOnvifHandle(*Handle)) {
delete *Handle;
}
*Handle = nullptr;
}
*Handle = new ANSCENTER::ANSOnvifClient();
if (*Handle == nullptr) return 0;
if ((*Handle)->Init(licenseKey)) {
RegisterOnvifHandle(*Handle);
return 1;
}
delete *Handle;
*Handle = nullptr;
return 0;
}
catch (std::exception& e) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
catch (...) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
}
static int ReleaseANSOnvifHandle_Impl(ANSCENTER::ANSOnvifClient** Handle) {
try {
if (!Handle || !*Handle) return 1;
if (!UnregisterOnvifHandle(*Handle)) {
*Handle = nullptr;
return 1;
}
delete *Handle;
*Handle = nullptr;
return 1;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int ReleaseANSOnvifHandle(ANSCENTER::ANSOnvifClient * *Handle) {
__try {
return ReleaseANSOnvifHandle_Impl(Handle);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifDevices(ANSCENTER::ANSOnvifClient * *Handle, int sleepDuration, std::vector<std::string> &deviceList) {
if (Handle == nullptr || *Handle == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
deviceList.clear();
std::vector<ANSCENTER::OnvifDevice> onvifDeviceList = guard.get()->SearchForDevices(sleepDuration);
if (onvifDeviceList.size() <= 0)return 0;
for (int i = 0; i < onvifDeviceList.size(); i++) {
ANSCENTER::OnvifDevice currentDevice = onvifDeviceList.at(i);
std::string currentDeviceStr = currentDevice.deviceIP + ":" + std::to_string(currentDevice.devicePort);
deviceList.push_back(currentDeviceStr);
}
return 1;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles(ANSCENTER::ANSOnvifClient * *Handle, const char* username, const char* password, std::vector<std::string> &profileList) {
if (Handle == nullptr || *Handle == nullptr || username == nullptr || password == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
profileList.clear();
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfiles(username, password);
if (onvifDeviceProfileList.size() <= 0)return 0;
for (int i = 0; i < onvifDeviceProfileList.size(); i++) {
ANSCENTER::OnvifDeviceProfile currentDevice = onvifDeviceProfileList.at(i);
std::string currentDeviceStr = currentDevice.deviceProfileURI;
profileList.push_back(currentDeviceStr);
}
return 1;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles(ANSCENTER::ANSOnvifClient * *Handle, const char* ip, int port, const char* username, const char* password, std::vector<std::string> &profileList) {
if (Handle == nullptr || *Handle == nullptr || ip == nullptr || username == nullptr || password == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
profileList.clear();
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfile(ip, port, username, password);
if (onvifDeviceProfileList.size() <= 0)return 0;
for (int i = 0; i < onvifDeviceProfileList.size(); i++) {
ANSCENTER::OnvifDeviceProfile currentDevice = onvifDeviceProfileList.at(i);
std::string currentDeviceStr = currentDevice.deviceProfileURI;
profileList.push_back(currentDeviceStr);
}
return 1;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifDevices_LV(ANSCENTER::ANSOnvifClient * *Handle, int sleepDuration,LStrHandle deviceList) {
if (Handle == nullptr || *Handle == nullptr || deviceList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDevice> onvifDeviceList = guard.get()->SearchForDevices(sleepDuration);
std::string st = guard.get()->DeviceListToJsonString(onvifDeviceList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(deviceList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*deviceList)->cnt = size;
memcpy((*deviceList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles_LV(ANSCENTER::ANSOnvifClient * *Handle, const char* username, const char* password, LStrHandle profileList) {
if (Handle == nullptr || *Handle == nullptr || username == nullptr || password == nullptr || profileList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfiles(username, password);
std::string st = guard.get()->DeviceProfileToJsonString(onvifDeviceProfileList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(profileList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*profileList)->cnt = size;
memcpy((*profileList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles_LV(ANSCENTER::ANSOnvifClient * *Handle, const char* ip, int port, const char* username, const char* password, LStrHandle profileList) {
if (Handle == nullptr || *Handle == nullptr || ip == nullptr || username == nullptr || password == nullptr || profileList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(*Handle));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfile(ip, port, username, password);
std::string st = guard.get()->DeviceProfileToJsonString(onvifDeviceProfileList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(profileList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*profileList)->cnt = size;
memcpy((*profileList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
// ============================================================================
// V2 entry points — accept uint64_t handleVal by value instead of Handle**
// to eliminate LabVIEW buffer-reuse bug when concurrent calls share the same
// Handle** buffer address.
// ============================================================================
extern "C" __declspec(dllexport) int SearchANSOnvifDevices_LV_V2(uint64_t handleVal, int sleepDuration, LStrHandle deviceList) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSOnvifClient*>(handleVal);
if (!_v2h) return 0;
if (deviceList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(_v2h));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDevice> onvifDeviceList = guard.get()->SearchForDevices(sleepDuration);
std::string st = guard.get()->DeviceListToJsonString(onvifDeviceList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(deviceList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*deviceList)->cnt = size;
memcpy((*deviceList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles_LV_V2(uint64_t handleVal, const char* username, const char* password, LStrHandle profileList) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSOnvifClient*>(handleVal);
if (!_v2h) return 0;
if (username == nullptr || password == nullptr || profileList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(_v2h));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfiles(username, password);
std::string st = guard.get()->DeviceProfileToJsonString(onvifDeviceProfileList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(profileList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*profileList)->cnt = size;
memcpy((*profileList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles_LV_V2(uint64_t handleVal, const char* ip, int port, const char* username, const char* password, LStrHandle profileList) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSOnvifClient*>(handleVal);
if (!_v2h) return 0;
if (ip == nullptr || username == nullptr || password == nullptr || profileList == nullptr) return 0;
OnvifHandleGuard guard(AcquireOnvifHandle(_v2h));
if (!guard) return 0;
try {
std::vector<ANSCENTER::OnvifDeviceProfile> onvifDeviceProfileList = guard.get()->SearchForDeviceProfile(ip, port, username, password);
std::string st = guard.get()->DeviceProfileToJsonString(onvifDeviceProfileList);
int size = static_cast<int>(st.length());
if (size > 0) {
MgErr error;
error = DSSetHandleSize(profileList, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*profileList)->cnt = size;
memcpy((*profileList)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (std::exception& e) {
return 0;
}
catch (...) {
return 0;
}
}

View File

@@ -0,0 +1,93 @@
#ifndef ANSONVIF_H
#define ANSONVIF_H
#define ANSONVIF_API __declspec(dllexport)
#include "onvif/onvif.h"
#include <iostream>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <vector>
#include <mutex>
#include <cstdint>
namespace ANSCENTER
{
typedef struct
{
std::string deviceIP;
std::string deviceProfileName;
std::string deviceProfileURI;
} OnvifDeviceProfile;
typedef struct
{
ONVIF_DEVICE onvif_device;
int flags; // FLAG_MANUAL mean added manual, other auto discovery device
int state; // 0 -- offline; 1 -- online
void* p_user; // user data
pthread_t thread_handler; // get information thread handler
BOOL need_update; // if update device information
int snapshot_len; // devcie snapshot buffer length
uint8* snapshot; // device snapshot buffer
} ONVIF_DEVICE_EX;
typedef struct
{
std::string deviceIP;
int devicePort;
} OnvifDevice;
void StateDetectThread(void* argv);
PPSN_CTX* m_dev_fl = nullptr; // device free list
PPSN_CTX* m_dev_ul = nullptr; // device used list
BOOL m_bStateDetect = FALSE; // device state detect flag
pthread_t m_hStateDetect = 0; // device state detect threand handler
static std::vector<OnvifDevice> _deviceList;
class ANSONVIF_API ANSOnvifClient
{
private:
bool _licenseValid{ false };
std::string _licenseKey;
std::mutex _mutex;
private:
[[nodiscard]] ONVIF_DEVICE_EX* FindDevice(ONVIF_DEVICE_EX* pdevice);
[[nodiscard]] ONVIF_DEVICE_EX* FindDeviceByEndpointReference(char* p_EndpointReference);
[[nodiscard]] ONVIF_DEVICE_EX* AddDevice(ONVIF_DEVICE_EX* pdevice);
void FreeDevice(ONVIF_DEVICE_EX* p_dev);
void GetDevInfo(ONVIF_DEVICE_EX* p_device);
//void StartDetectTask();
//void StopDetectTask();
void ClearDevices();
protected:
static void ProbeCallback(DEVICE_BINFO* p_res, int msgtype, void* p_data);
void CheckLicense();
void ErrorHandler(ONVIF_DEVICE* p_device);
public:
[[nodiscard]] bool Init(const std::string& licenseKey);
~ANSOnvifClient();
ANSOnvifClient();
void ClearDeviceList();
void Destroy();
[[nodiscard]] std::vector<OnvifDevice> SearchForDevices(int sleepDuration);
[[nodiscard]] std::vector<OnvifDeviceProfile> SearchForDeviceProfiles(const std::string& username, const std::string& password);
[[nodiscard]] std::vector<OnvifDeviceProfile> SearchForDeviceProfiles(const std::vector<std::string>& usernameList, const std::vector<std::string>& passwordList);
[[nodiscard]] std::vector<OnvifDeviceProfile> SearchForDeviceProfile(const std::string& ip, int port, const std::string& username, const std::string& password);
[[nodiscard]] std::string DeviceListToJsonString(const std::vector<OnvifDevice>& deviceList);
[[nodiscard]] std::string DeviceProfileToJsonString(const std::vector<OnvifDeviceProfile>& deviceProfileList);
void UpdateDevice(ONVIF_DEVICE_EX* p_device);
};
}
extern "C" __declspec(dllexport) int CreateANSOnvifHandle(ANSCENTER::ANSOnvifClient * *Handle, const char* licenseKey);
extern "C" __declspec(dllexport) int SearchANSOnvifDevices(ANSCENTER::ANSOnvifClient * *Handle, int sleepDuration, std::vector<std::string> &deviceList);
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles(ANSCENTER::ANSOnvifClient * *Handle, const char* username, const char* password, std::vector<std::string> &profileList);
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles(ANSCENTER::ANSOnvifClient * *Handle, const char* ip, int port, const char* username, const char* password, std::vector<std::string> &profileList);
extern "C" __declspec(dllexport) int SearchANSOnvifDevices_LV(ANSCENTER::ANSOnvifClient * *Handle, int sleepDuration, LStrHandle deviceList);
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles_LV(ANSCENTER::ANSOnvifClient * *Handle, const char* username, const char* password, LStrHandle profileList);
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles_LV(ANSCENTER::ANSOnvifClient * *Handle, const char* ip, int port, const char* username, const char* password, LStrHandle profileList);
extern "C" __declspec(dllexport) int ReleaseANSOnvifHandle(ANSCENTER::ANSOnvifClient * *Handle);
// V2 entry points — accept handle by value (uint64_t) to fix LabVIEW buffer-reuse bug
extern "C" __declspec(dllexport) int SearchANSOnvifDevices_LV_V2(uint64_t handleVal, int sleepDuration, LStrHandle deviceList);
extern "C" __declspec(dllexport) int SearchANSOnvifProfiles_LV_V2(uint64_t handleVal, const char* username, const char* password, LStrHandle profileList);
extern "C" __declspec(dllexport) int SearchANSOnvifSpecificProfiles_LV_V2(uint64_t handleVal, const char* ip, int port, const char* username, const char* password, LStrHandle profileList);
#endif

View File

@@ -0,0 +1,31 @@
# ANSONVIF — ONVIF Camera Protocol DLL
add_library(ANSONVIF SHARED
ANSONVIF.cpp
ANSONVIF.h
dllmain.cpp
pch.cpp
pch.h
framework.h
)
target_include_directories(ANSONVIF PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_include_directories(ANSONVIF PRIVATE
${ANLS_ROOT}/ONVIF/include
${ANLS_ROOT}/ONVIF/include/bm
)
target_link_directories(ANSONVIF PRIVATE ${ANLS_ROOT}/ONVIF/lib)
target_link_libraries(ANSONVIF
PRIVATE ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
PRIVATE OnvifClientLibrary.lib
)
target_compile_definitions(ANSONVIF PRIVATE UNICODE _UNICODE ANSONVIF_EXPORTS _USRDLL)
target_precompile_headers(ANSONVIF PRIVATE pch.h)

View File

@@ -0,0 +1,19 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H

View File

@@ -0,0 +1,300 @@
#include "ANSPulsar.h"
#include <sstream>
namespace ANSCENTER {
void Callback(pulsar::Result code, const pulsar::MessageId& msgId) {
std::cout << "Received code:" << code << " -- MsgID: " << msgId << std::endl;
}
ANSPULSAR::ANSPULSAR() {
// Initialize the Pulsar client with default values
_hostname = "localhost";
_port = 5672;
_jwtToken = "";
_useTls = false;
_caCertPath = "";
_enableBatching = false;
_batchingMaxMessages = 100;
_batchingDelayMs = 1000;
_allowInsecureConnection = false;
_verifyHostname = true;
_procuderInit = false;
_consumerInit = false;
_compressionType = pulsar::CompressionLZ4;
}
ANSPULSAR::~ANSPULSAR() {
Close();
}
bool ANSPULSAR::Initialize(const std::string& hostname, int port, const std::string& jwtToken, bool useTls, const std::string& caCertPath,
bool enableBatching, int batchingMaxMessages, int batchingDelayMs,
bool allowInsecureConnection, bool verifyHostname) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
_hostname = hostname;
_port = port;
_jwtToken = jwtToken;
_useTls = useTls;
_caCertPath = caCertPath;
_enableBatching = enableBatching;
_batchingMaxMessages = batchingMaxMessages;
_batchingDelayMs = batchingDelayMs;
_allowInsecureConnection = allowInsecureConnection;
_verifyHostname = verifyHostname;
return true;
}
bool ANSPULSAR::Connect(const std::string& topicName) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_pubTopicName = topicName;
std::string hostname = _hostname;
size_t pos = hostname.find("://");
if (pos != std::string::npos) {
hostname = hostname.substr(pos + 3);
}
_fullServiceUrl = (_useTls ? "pulsar+ssl://" : "pulsar://") + hostname + ":" + std::to_string(_port);
if (_useTls) {
_clientConfig.setUseTls(true);
_clientConfig.setTlsTrustCertsFilePath(_caCertPath);
_clientConfig.setTlsAllowInsecureConnection(_allowInsecureConnection);
_clientConfig.setValidateHostName(_verifyHostname);
}
if (!_jwtToken.empty()) {
_clientConfig.setAuth(pulsar::AuthToken::createWithToken(_jwtToken));
}
_producerConfig.setSendTimeout(5000);
_producerConfig.setCompressionType(_compressionType);
_producerConfig.setBatchingEnabled(_enableBatching);
if (_enableBatching) {
_producerConfig.setBatchingMaxMessages(_batchingMaxMessages);
_producerConfig.setBatchingMaxPublishDelayMs(_batchingDelayMs);
}
_client = std::make_unique<pulsar::Client>(_fullServiceUrl, _clientConfig);
auto result = _client->createProducer(_pubTopicName, _producerConfig, _producer);
if (result != pulsar::ResultOk) {
_logger.LogError("ANSPULSAR::Connect", "Failed to create producer: " + std::to_string(result), __FILE__, __LINE__);
return false;
}
_procuderInit = true;
return true;
}
catch (const std::exception& e) {
_logger.LogFatal("ANSPULSAR::Connect", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogFatal("ANSPULSAR::Connect", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
bool ANSPULSAR::Disconnect() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_procuderInit) {
_producer.close();
_procuderInit = false;
}
if (_consumerInit) {
_consumer.close();
_consumerInit=false;
}
}
catch (const std::exception& e) {
_logger.LogError("ANSPULSAR::Disconnect", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogError("ANSPULSAR::Disconnect", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
return true;
}
bool ANSPULSAR::Close() {
try {
if (_client) {
_client->close();
_client.reset();
}
return true;
}
catch (const std::exception& e) {
_logger.LogError("ANSPULSAR::Close", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogError("ANSPULSAR::Close", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
bool ANSPULSAR::Publish(const std::string& message, const std::string& properties) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (message.empty()) {
_logger.LogError("ANSPULSAR::Publish", "Cannot send empty message", __FILE__, __LINE__);
return false;
}
pulsar::MessageBuilder builder;
builder.setContent(message);
builder.setProperty("content-type", "application/json");
if (!properties.empty()) {
std::istringstream iss(properties);
std::string pair;
while (std::getline(iss, pair, ';')) {
size_t pos = pair.find(':');
if (pos != std::string::npos) {
std::string key = pair.substr(0, pos);
std::string value = pair.substr(pos + 1);
key.erase(0, key.find_first_not_of(" \t\r\n"));
key.erase(key.find_last_not_of(" \t\r\n") + 1);
value.erase(0, value.find_first_not_of(" \t\r\n"));
value.erase(value.find_last_not_of(" \t\r\n") + 1);
builder.setProperty(key, value);
}
else {
_logger.LogError("ANSPULSAR::Publish", "Invalid property: " + pair, __FILE__, __LINE__);
}
}
}
auto msg = builder.build();
auto result = _producer.send(msg);
if (result != pulsar::ResultOk) {
_logger.LogError("ANSPULSAR::Publish", "Send failed: " + std::to_string(result), __FILE__, __LINE__);
return false;
}
return true;
}
catch (const std::exception& e) {
_logger.LogFatal("ANSPULSAR::Publish", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogFatal("ANSPULSAR::Publish", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
bool ANSPULSAR::PublishAsync(const std::string& message, const std::string& properties) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (message.empty()) {
_logger.LogError("ANSPULSAR::PublishAsync", "Cannot send empty message", __FILE__, __LINE__);
return false;
}
pulsar::MessageBuilder builder;
builder.setContent(message);
builder.setProperty("content-type", "application/json");
if (!properties.empty()) {
std::istringstream iss(properties);
std::string pair;
while (std::getline(iss, pair, ';')) {
size_t pos = pair.find(':');
if (pos != std::string::npos) {
std::string key = pair.substr(0, pos);
std::string value = pair.substr(pos + 1);
key.erase(0, key.find_first_not_of(" \t\r\n"));
key.erase(key.find_last_not_of(" \t\r\n") + 1);
value.erase(0, value.find_first_not_of(" \t\r\n"));
value.erase(value.find_last_not_of(" \t\r\n") + 1);
builder.setProperty(key, value);
}
else {
_logger.LogError("ANSPULSAR::PublishAsync", "Invalid property: " + pair, __FILE__, __LINE__);
}
}
}
auto msg = builder.build();
_producer.sendAsync(msg, Callback);
return true;
}
catch (const std::exception& e) {
_logger.LogFatal("ANSPULSAR::PublishAsync", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogFatal("ANSPULSAR::PublishAsync", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
bool ANSPULSAR::Subscribe(const std::string& topicName, const std::string& subscriptionName) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (!_client) {
_logger.LogError("ANSPULSAR::Subscribe", "Client not initialized", __FILE__, __LINE__);
return false;
}
_consumerConfig.setConsumerType(pulsar::ConsumerExclusive);
_consumerConfig.setReceiverQueueSize(1000);
_subTopicName = topicName;
_subscriptionName = subscriptionName;
auto result = _client->subscribe(_subTopicName, _subscriptionName, _consumerConfig, _consumer);
if (result != pulsar::ResultOk) {
_logger.LogError("ANSPULSAR::Subscribe", "Subscribe failed: " + std::to_string(result), __FILE__, __LINE__);
return false;
}
_consumerInit = true;
return true;
}
catch (const std::exception& e) {
_logger.LogFatal("ANSPULSAR::Subscribe", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogFatal("ANSPULSAR::Subscribe", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
bool ANSPULSAR::Receive(std::string& messageOut, bool doAcknowledge, int timeoutMs) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (!_client) {
_logger.LogError("ANSPULSAR::Receive", "Client not initialized", __FILE__, __LINE__);
return false;
}
pulsar::Message msg;
pulsar::Result result = _consumer.receive(msg, timeoutMs);
if (result != pulsar::ResultOk) {
if (result != pulsar::ResultTimeout) {
_logger.LogError("ANSPULSAR::Receive", "Receive failed: " + std::to_string(result), __FILE__, __LINE__);
}
return false;
}
messageOut = msg.getDataAsString();
if (doAcknowledge) {
result = _consumer.acknowledge(msg);
if (result != pulsar::ResultOk) {
_logger.LogError("ANSPULSAR::Receive", "Acknowledge failed: " + std::to_string(result), __FILE__, __LINE__);
return false;
}
}
return true;
}
catch (const std::exception& e) {
_logger.LogFatal("ANSPULSAR::Receive", std::string("Exception: ") + e.what(), __FILE__, __LINE__);
return false;
}
catch (...) {
_logger.LogFatal("ANSPULSAR::Receive", "Unknown exception occurred", __FILE__, __LINE__);
return false;
}
}
} // namespace ANSCENTER

View File

@@ -0,0 +1,81 @@
#ifndef ANSPALSAR_H
#define ANSPALSAR_H
#define ANSPALSAR_API __declspec(dllexport)
#pragma once
#include <string>
#include <cstdint>
#include <mutex>
#include <vector>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#include <pulsar/Client.h>
using pulsar::Client;
namespace ANSCENTER {
class ANSPALSAR_API ANSPULSAR {
private:
std::string _hostname;
int _port = 5672;
std::string _jwtToken;
bool _useTls = false;
std::string _caCertPath;
bool _enableBatching = false;
int _batchingMaxMessages = 100;
int _batchingDelayMs = 1000;
bool _allowInsecureConnection = false;
bool _verifyHostname = true;
bool _procuderInit = false;
bool _consumerInit = false;
std::string _pubTopicName;
std::string _subTopicName;
std::string _subscriptionName = "ans_sub";
std::string _fullServiceUrl;
pulsar::CompressionType _compressionType = pulsar::CompressionLZ4;
std::unique_ptr<pulsar::Client> _client = nullptr;
pulsar::Producer _producer;
pulsar::Consumer _consumer;
pulsar::ClientConfiguration _clientConfig;
pulsar::ProducerConfiguration _producerConfig;
pulsar::ConsumerConfiguration _consumerConfig;
SPDLogger& _logger = SPDLogger::GetInstance("ANSPulsar", true);
std::recursive_mutex _mutex;
public:
ANSPULSAR();
~ANSPULSAR();
[[nodiscard]] bool Initialize(const std::string& hostname, int port, const std::string& jwtToken, bool useSSL, const std::string& caCertPath,
bool enableBatching, int batchingMaxMessages, int batchingDelayMs, bool allowInsecureConnection,
bool verifyHostname);
[[nodiscard]] bool Connect(const std::string& topicName);
[[nodiscard]] bool Disconnect();
[[nodiscard]] bool Publish(const std::string& message, const std::string& properties);
[[nodiscard]] bool PublishAsync(const std::string& message, const std::string& properties);
[[nodiscard]] bool Subscribe(const std::string& topicName, const std::string& subscriptionName);
[[nodiscard]] bool Receive(std::string& messageOut, bool doAcknowledge, int timeoutMs = 1000);
[[nodiscard]] bool Close();
};
}
// C API exports
extern "C" {
ANSPALSAR_API int CreateANSPulsarHandle(ANSCENTER::ANSPULSAR** Handle, const char* hostname,int port, const char* jwtToken, int useTls, const char* caCertPath, int enableBatching, int batchingMaxMessages, int batchingDelayMs, int allowInsecureConnection,int verifyHostName);
ANSPALSAR_API int ReleasePulsarHandle(ANSCENTER::ANSPULSAR** Handle);
ANSPALSAR_API int ConnectANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName);
ANSPALSAR_API int DisconnectANSPulsar(ANSCENTER::ANSPULSAR** Handle);
ANSPALSAR_API int PublishANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties);
ANSPALSAR_API int PublishAsyncANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties);
ANSPALSAR_API int SubscribeANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName, const char* subscriptionName);
ANSPALSAR_API int ReceiveMessageANSPulsar(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, LStrHandle strMessage);
ANSPALSAR_API int ReceiveMessageANSPulsar_CPP(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, std::string& message);
// V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug
ANSPALSAR_API int ConnectANSPulsar_V2(uint64_t handleVal, const char* topicName);
ANSPALSAR_API int DisconnectANSPulsar_V2(uint64_t handleVal);
ANSPALSAR_API int PublishANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties);
ANSPALSAR_API int PublishAsyncANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties);
ANSPALSAR_API int SubscribeANSPulsar_V2(uint64_t handleVal, const char* topicName, const char* subscriptionName);
ANSPALSAR_API int ReceiveMessageANSPulsar_V2(uint64_t handleVal, int timeoutMs, int doAcknowledge, LStrHandle strMessage);
}
#endif

View File

@@ -0,0 +1,30 @@
# ANSPulsar — Apache Pulsar messaging DLL
add_library(ANSPulsar SHARED
ANSPulsar.cpp
ANSPulsar.h
dllmain.cpp
pch.cpp
pch.h
framework.h
)
target_include_directories(ANSPulsar PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_include_directories(ANSPulsar PRIVATE
${ANSLIBS_DIR}/Pulsar/include
)
target_link_directories(ANSPulsar PRIVATE ${ANSLIBS_DIR}/Pulsar/lib)
target_link_libraries(ANSPulsar
PRIVATE ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
PRIVATE pulsar.lib
)
target_compile_definitions(ANSPulsar PRIVATE UNICODE _UNICODE ANSPULSAR_EXPORTS _USRDLL)
target_precompile_headers(ANSPulsar PRIVATE pch.h)

View File

@@ -0,0 +1,419 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSPulsar.h"
#include <cstdint>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
// Handle registry with refcount — prevents use-after-free when
// ReleasePulsarHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::ANSPULSAR*, int>& PulsarHandleRegistry() {
static std::unordered_map<ANSCENTER::ANSPULSAR*, int> s;
return s;
}
static std::mutex& PulsarHandleRegistryMutex() {
static std::mutex m;
return m;
}
static std::condition_variable& PulsarHandleRegistryCV() {
static std::condition_variable cv;
return cv;
}
static void RegisterPulsarHandle(ANSCENTER::ANSPULSAR* h) {
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
PulsarHandleRegistry()[h] = 1;
}
static ANSCENTER::ANSPULSAR* AcquirePulsarHandle(ANSCENTER::ANSPULSAR* h) {
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
auto it = PulsarHandleRegistry().find(h);
if (it == PulsarHandleRegistry().end()) return nullptr;
it->second++;
return h;
}
static bool ReleasePulsarHandleRef(ANSCENTER::ANSPULSAR* h) {
std::lock_guard<std::mutex> lk(PulsarHandleRegistryMutex());
auto it = PulsarHandleRegistry().find(h);
if (it == PulsarHandleRegistry().end()) return false;
it->second--;
if (it->second <= 0) {
PulsarHandleRegistry().erase(it);
PulsarHandleRegistryCV().notify_all();
return true;
}
return false;
}
static bool UnregisterPulsarHandle(ANSCENTER::ANSPULSAR* h) {
std::unique_lock<std::mutex> lk(PulsarHandleRegistryMutex());
auto it = PulsarHandleRegistry().find(h);
if (it == PulsarHandleRegistry().end()) return false;
it->second--;
bool ok = PulsarHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
auto it2 = PulsarHandleRegistry().find(h);
return it2 == PulsarHandleRegistry().end() || it2->second <= 0;
});
if (!ok) {
OutputDebugStringA("WARNING: UnregisterPulsarHandle timed out waiting for in-flight operations\n");
}
PulsarHandleRegistry().erase(h);
return true;
}
// RAII guard — ensures ReleasePulsarHandleRef is always called
class PulsarHandleGuard {
ANSCENTER::ANSPULSAR* engine;
public:
explicit PulsarHandleGuard(ANSCENTER::ANSPULSAR* e) : engine(e) {}
~PulsarHandleGuard() { if (engine) ReleasePulsarHandleRef(engine); }
ANSCENTER::ANSPULSAR* get() const { return engine; }
explicit operator bool() const { return engine != nullptr; }
PulsarHandleGuard(const PulsarHandleGuard&) = delete;
PulsarHandleGuard& operator=(const PulsarHandleGuard&) = delete;
};
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" ANSPALSAR_API int CreateANSPulsarHandle(ANSCENTER::ANSPULSAR** Handle, const char* hostname,
int port, const char* jwtToken, int useTls, const char* caCertPath,
int enableBatching, int batchingMaxMessages, int batchingDelayMs,
int allowInsecureConnection, int verifyHostName)
{
if (Handle == nullptr) {
return 0; // Invalid handle
}
try {
// Release existing handle if called twice (prevents leak from LabVIEW)
if (*Handle) {
if (UnregisterPulsarHandle(*Handle)) {
delete *Handle;
}
*Handle = nullptr;
}
*Handle = new ANSCENTER::ANSPULSAR();
if (*Handle == nullptr) {
return 0; // Memory allocation failed
}
std::string host = hostname ? hostname : "";
std::string token = jwtToken ? jwtToken : "";
std::string certPath = caCertPath ? caCertPath : "";
bool _useTls = (useTls == 1);
bool _enableBatching = (enableBatching == 1);
bool _allowInsecureConnection = (allowInsecureConnection == 1);
bool _verifyHostname = (verifyHostName == 1);
if (!(*Handle)->Initialize(host, port, token, _useTls, certPath,
_enableBatching, batchingMaxMessages, batchingDelayMs,
_allowInsecureConnection, _verifyHostname)) {
delete *Handle;
*Handle = nullptr;
return 0;
}
RegisterPulsarHandle(*Handle);
return 1;
}
catch (std::exception& e) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
catch (...) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
}
static int ReleasePulsarHandle_Impl(ANSCENTER::ANSPULSAR** Handle) {
try {
if (!Handle || !*Handle) return 1;
if (!UnregisterPulsarHandle(*Handle)) {
*Handle = nullptr;
return 1;
}
delete *Handle;
*Handle = nullptr;
return 1;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" ANSPALSAR_API int ReleasePulsarHandle(ANSCENTER::ANSPULSAR** Handle) {
__try {
return ReleasePulsarHandle_Impl(Handle);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" ANSPALSAR_API int ConnectANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (topicName == nullptr) {
return -1; // Invalid parameters
}
std::string topic = topicName;
if (guard.get()->Connect(topic)) {
return 1; // Success
}
else {
return 0; // Connection failed
}
}
extern "C" ANSPALSAR_API int DisconnectANSPulsar(ANSCENTER::ANSPULSAR** Handle) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (guard.get()->Disconnect()) {
return 1; // Success
}
else {
return 0; // Disconnection failed
}
}
extern "C" ANSPALSAR_API int PublishANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (message == nullptr) {
return -1; // Invalid parameters
}
std::string msg = message ? message : "";
std::string props = properties ? properties : "";
if (guard.get()->Publish(msg, props)) {
return 1; // Success
}
else {
return 0; // Publish failed
}
}
extern "C" ANSPALSAR_API int PublishAsyncANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* message, const char* properties) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (message == nullptr) {
return -1; // Invalid parameters
}
std::string msg = message ? message : "";
std::string props = properties ? properties : "";
if (guard.get()->PublishAsync(msg, props)) {
return 1; // Success
}
else {
return 0; // Publish failed
}
}
extern "C" ANSPALSAR_API int SubscribeANSPulsar(ANSCENTER::ANSPULSAR** Handle, const char* topicName, const char* subscriptionName) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (topicName == nullptr || subscriptionName == nullptr) {
return -1; // Invalid parameters
}
std::string topic = topicName ? topicName : "";
std::string subName = subscriptionName ? subscriptionName : "";
if (guard.get()->Subscribe(topic, subName)) {
return 1; // Success
}
else {
return 0; // Subscribe failed
}
}
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar_CPP(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, std::string& message) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (timeoutMs < 0) {
return -1; // Invalid parameters
}
bool _doAcknowledge = (doAcknowledge == 1);
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
return 1; // Success
}
else {
return 0; // Receive failed
}
}
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar(ANSCENTER::ANSPULSAR** Handle, int timeoutMs, int doAcknowledge, LStrHandle strMessage) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
PulsarHandleGuard guard(AcquirePulsarHandle(*Handle));
if (!guard) return -1;
if (timeoutMs < 0 || strMessage == nullptr) {
return -1; // Invalid parameters
}
std::string message;
bool _doAcknowledge = (doAcknowledge == 1);
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
if (message.empty()) return 0;
int size = static_cast<int>(message.length());
MgErr error;
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*strMessage)->cnt = size;
memcpy((*strMessage)->str, message.c_str(), size);
return 1;
}
else return 0;
}
else {
return 0; // Receive failed
}
}
// ============================================================================
// V2 API — handle passed by value (uint64_t) to avoid LabVIEW buffer reuse bug
// ============================================================================
extern "C" ANSPALSAR_API int ConnectANSPulsar_V2(uint64_t handleVal, const char* topicName) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (topicName == nullptr) {
return -1;
}
std::string topic = topicName;
if (guard.get()->Connect(topic)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSPALSAR_API int DisconnectANSPulsar_V2(uint64_t handleVal) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (guard.get()->Disconnect()) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSPALSAR_API int PublishANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (message == nullptr) {
return -1;
}
std::string msg = message ? message : "";
std::string props = properties ? properties : "";
if (guard.get()->Publish(msg, props)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSPALSAR_API int PublishAsyncANSPulsar_V2(uint64_t handleVal, const char* message, const char* properties) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (message == nullptr) {
return -1;
}
std::string msg = message ? message : "";
std::string props = properties ? properties : "";
if (guard.get()->PublishAsync(msg, props)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSPALSAR_API int SubscribeANSPulsar_V2(uint64_t handleVal, const char* topicName, const char* subscriptionName) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (topicName == nullptr || subscriptionName == nullptr) {
return -1;
}
std::string topic = topicName ? topicName : "";
std::string subName = subscriptionName ? subscriptionName : "";
if (guard.get()->Subscribe(topic, subName)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSPALSAR_API int ReceiveMessageANSPulsar_V2(uint64_t handleVal, int timeoutMs, int doAcknowledge, LStrHandle strMessage) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSPULSAR*>(handleVal);
if (!_v2h) return -1;
PulsarHandleGuard guard(AcquirePulsarHandle(_v2h));
if (!guard) return -1;
if (timeoutMs < 0 || strMessage == nullptr) {
return -1;
}
std::string message;
bool _doAcknowledge = (doAcknowledge == 1);
if (guard.get()->Receive(message, _doAcknowledge, timeoutMs)) {
if (message.empty()) return 0;
int size = static_cast<int>(message.length());
MgErr error;
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*strMessage)->cnt = size;
memcpy((*strMessage)->str, message.c_str(), size);
return 1;
}
else return 0;
}
else {
return 0;
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H

View File

@@ -0,0 +1,807 @@
#include "ANSRabbitMQ.h"
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <cstdint>
#include <windows.h>
#include <iostream>
void die(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
}
void die_on_error(int x, char const* context) {
if (x < 0) {
fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x));
}
}
void die_on_amqp_error(amqp_rpc_reply_t x, char const* context) {
switch (x.reply_type) {
case AMQP_RESPONSE_NORMAL:
return;
case AMQP_RESPONSE_NONE:
fprintf(stderr, "%s: missing RPC reply type!\n", context);
break;
case AMQP_RESPONSE_LIBRARY_EXCEPTION:
fprintf(stderr, "%s: %s\n", context, amqp_error_string2(x.library_error));
break;
case AMQP_RESPONSE_SERVER_EXCEPTION:
switch (x.reply.id) {
case AMQP_CONNECTION_CLOSE_METHOD: {
auto* m =
static_cast<amqp_connection_close_t*>(x.reply.decoded);
fprintf(stderr, "%s: server connection error %uh, message: %.*s\n",
context, m->reply_code, static_cast<int>(m->reply_text.len),
static_cast<const char*>(m->reply_text.bytes));
break;
}
case AMQP_CHANNEL_CLOSE_METHOD: {
auto* m = static_cast<amqp_channel_close_t*>(x.reply.decoded);
fprintf(stderr, "%s: server channel error %uh, message: %.*s\n",
context, m->reply_code, static_cast<int>(m->reply_text.len),
static_cast<const char*>(m->reply_text.bytes));
break;
}
default:
fprintf(stderr, "%s: unknown server error, method id 0x%08X\n",
context, x.reply.id);
break;
}
break;
}
}
static void dump_row(long count, int numinrow, int* chs) {
int i;
printf("%08lX:", count - numinrow);
if (numinrow > 0) {
for (i = 0; i < numinrow; i++) {
if (i == 8) {
printf(" :");
}
printf(" %02X", chs[i]);
}
for (i = numinrow; i < 16; i++) {
if (i == 8) {
printf(" :");
}
printf(" ");
}
printf(" ");
for (i = 0; i < numinrow; i++) {
if (isprint(chs[i])) {
printf("%c", chs[i]);
}
else {
printf(".");
}
}
}
printf("\n");
}
static int rows_eq(int* a, int* b) {
int i;
for (i = 0; i < 16; i++)
if (a[i] != b[i]) {
return 0;
}
return 1;
}
void amqp_dump(void const* buffer, size_t len) {
const auto* buf = static_cast<const unsigned char*>(buffer);
long count = 0;
int numinrow = 0;
int chs[16];
int oldchs[16] = { 0 };
int showed_dots = 0;
size_t i;
for (i = 0; i < len; i++) {
int ch = buf[i];
if (numinrow == 16) {
int j;
if (rows_eq(oldchs, chs)) {
if (!showed_dots) {
showed_dots = 1;
printf(
" .. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..\n");
}
}
else {
showed_dots = 0;
dump_row(count, numinrow, chs);
}
for (j = 0; j < 16; j++) {
oldchs[j] = chs[j];
}
numinrow = 0;
}
count++;
chs[numinrow++] = ch;
}
dump_row(count, numinrow, chs);
if (numinrow != 0) {
printf("%08lX:\n", count);
}
}
uint64_t now_microseconds(void) {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (((uint64_t)ft.dwHighDateTime << 32) | (uint64_t)ft.dwLowDateTime) /
10;
}
void microsleep(int usec) { Sleep(usec / 1000); }
namespace ANSCENTER {
ANSRABBITMQ::ANSRABBITMQ() {
_port = 5672;
_channel = 1;
_channelMax = 0; // set to 0 for default, let server decides
_frameMax = 131072; // no limit
_heartBeat = 60; // 60 seconds
std::string _vhost = "/";
}
ANSRABBITMQ::~ANSRABBITMQ() {
Disconnect(); // Safely handles cleanup
}
BindingInfo ANSRABBITMQ::GetBindingInfo(const std::string& exchange_name) {
// Search for the binding info based on the exchange name
for (const auto& binding : _bindings) {
if (binding._exchange_name == exchange_name) {
return binding;
}
}
return BindingInfo{}; // Return default empty BindingInfo if not found
}
BindingInfo ANSRABBITMQ::GetBindingInfoFromQueueName(const std::string& queue_name) {
// Search for the binding info based on the queue name
for (const auto& binding : _bindings) {
if (binding._queue_name == queue_name) {
return binding;
}
}
return BindingInfo{}; // Return default empty BindingInfo if not found
}
bool ANSRABBITMQ::ConfigureSSLOptions() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_caCertPath.empty() && _clientCertPath.empty() && _clientKeyPath.empty()) {
this->_logger.LogError("ANSRABBITMQ::ConfigureSSLOptions", "No SSL options configured.", __FILE__, __LINE__);
return true; // No SSL options to configure
}
if (!_socket) {
this->_logger.LogError("ANSRABBITMQ::ConfigureSSLOptions", "Error: SSL socket is not initialized.", __FILE__, __LINE__);
return false;
}
// These functions accept `amqp_socket_t*` even though they apply only to SSL sockets
if (!_caCertPath.empty()) {
if (amqp_ssl_socket_set_cacert(_socket, _caCertPath.c_str()) != AMQP_STATUS_OK) {
this->_logger.LogError("ANSRABBITMQ::ConfigureSSLOptions", "Failed to set CA certificate.", __FILE__, __LINE__);
return false;
}
}
if (!_clientCertPath.empty() && !_clientKeyPath.empty()) {
if (amqp_ssl_socket_set_key(_socket, _clientCertPath.c_str(), _clientKeyPath.c_str()) != AMQP_STATUS_OK) {
this->_logger.LogError("ANSRABBITMQ::ConfigureSSLOptions", "Failed to set client certificate/key.", __FILE__, __LINE__);
return false;
}
}
amqp_ssl_socket_set_verify_peer(_socket, _verifyPeer ? 1 : 0);
amqp_ssl_socket_set_verify_hostname(_socket, _verifyHostname ? 1 : 0);
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::ConfigureSSLOptions. Error configuring SSL options:",e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::SetupExchange(const std::string & _exchange_name, const std::string& _exchange_type, int _passive, int _durable, int _auto_delete, int _internal) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr || _socket == nullptr || _exchange_name.empty() || _exchange_type.empty() || _channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::SetupExchange", "Invalid parameters in SetupExchange.", __FILE__, __LINE__);
return false;
}
amqp_exchange_declare(
_conn, _channel,
amqp_cstring_bytes(_exchange_name.c_str()),
amqp_cstring_bytes(_exchange_type.c_str()),
_passive,
_durable,
_auto_delete,
_internal,
amqp_empty_table
);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Declaring exchange");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::SetupExchange. Error in SetupExchange:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::SetupQueue(const std::string _queue_name, int _passive, int _durable, int _auto_delete, int _internal) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr || _socket == nullptr || _queue_name.empty() || _channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::SetupQueue", "Invalid parameters in SetupQueue.", __FILE__, __LINE__);
return false;
}
amqp_queue_declare(
_conn, _channel,
amqp_cstring_bytes(_queue_name.c_str()),
_passive,
_durable,
false, // not exclusive
_auto_delete,
amqp_empty_table
);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Declaring queue");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::SetupQueue. Error in SetupQueue:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::BindQueue(const std::string & _exchange_name, const std::string& _exchange_type, const std::string& _queue_name, const std::string& _binding_key) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr || _socket == nullptr || _queue_name.empty() || _exchange_name.empty() || _channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::BindQueue", "Invalid parameters in BindQueue.", __FILE__, __LINE__);
return false;
}
amqp_table_t arguments = amqp_empty_table;
if (_exchange_type == "headers") {
// Match messages with header: type = important
static amqp_table_entry_t items[2];
items[0].key = amqp_cstring_bytes("x-match");
items[0].value.kind = AMQP_FIELD_KIND_UTF8;
items[0].value.value.bytes = amqp_cstring_bytes("all");
items[1].key = amqp_cstring_bytes("type");
items[1].value.kind = AMQP_FIELD_KIND_UTF8;
items[1].value.value.bytes = amqp_cstring_bytes("important");
arguments.num_entries = 2;
arguments.entries = items;
}
amqp_queue_bind(
_conn, _channel,
amqp_cstring_bytes(_queue_name.c_str()),
amqp_cstring_bytes(_exchange_name.c_str()),
amqp_cstring_bytes(_binding_key.c_str()), // required, even for fanout/headers
arguments
);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Binding queue");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::BindQueue. Error in BindQueue:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::UnbindQueue(const std::string& _exchange_name) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr || _socket == nullptr ||
_exchange_name.empty() || _channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::UnbindQueue", "Invalid parameters in UnbindQueue.", __FILE__, __LINE__);
return false;
}
amqp_table_t arguments = amqp_empty_table;
BindingInfo bindingInfo = GetBindingInfo(_exchange_name); // Check if the exchange is set up
if (bindingInfo._exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::UnbindQueue", "Exchange is not bound or set up.", __FILE__, __LINE__);
return false;
}
if (bindingInfo._exchange_type == "headers") {
// Same header structure used in BindQueue()
static amqp_table_entry_t items[2];
items[0].key = amqp_cstring_bytes("x-match");
items[0].value.kind = AMQP_FIELD_KIND_UTF8;
items[0].value.value.bytes = amqp_cstring_bytes("all");
items[1].key = amqp_cstring_bytes("type");
items[1].value.kind = AMQP_FIELD_KIND_UTF8;
items[1].value.value.bytes = amqp_cstring_bytes("important");
arguments.num_entries = 2;
arguments.entries = items;
}
amqp_queue_unbind(
_conn, bindingInfo._channel,
amqp_cstring_bytes(bindingInfo._queue_name.c_str()),
amqp_cstring_bytes(bindingInfo._exchange_name.c_str()),
amqp_cstring_bytes(bindingInfo._binding_key.c_str()), // still required by API
arguments
);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Unbinding queue");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::UnbindQueue. Error in UnbindQueue:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::DeleteQueue(const std::string& queue_name) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try
{
if (_conn == nullptr) {
this->_logger.LogError("ANSRABBITMQ::DeleteQueue", "Connection is not established.", __FILE__, __LINE__);
return false;
}
if (_socket == nullptr) {
this->_logger.LogError("ANSRABBITMQ::DeleteQueue", "Socket is not initialized.", __FILE__, __LINE__);
return false;
}
if (queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::DeleteQueue", "Queue name is empty.", __FILE__, __LINE__);
return false;
}
if (_channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::DeleteQueue", "Channel is not set.", __FILE__, __LINE__);
return false;
}
// Only delete if queue is unused and empty <20> set to false for force delete
int if_unused = 0;
int if_empty = 0;
BindingInfo binding = GetBindingInfoFromQueueName(queue_name); // Check if the queue is set up
if (binding._queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::DeleteQueue", "Queue is not bound or set up.", __FILE__, __LINE__);
return false;
}
amqp_queue_delete(_conn, binding._channel,
amqp_cstring_bytes(queue_name.c_str()),
if_unused,
if_empty);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Deleting queue");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::DeleteQueue. Error in DeleteQueue:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::DeleteExchange(const std::string& exchange_name) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try
{
if (_conn == nullptr) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange", "Connection is not established.", __FILE__, __LINE__);
return false;
}
if (_socket == nullptr) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange", "Socket is not initialized.", __FILE__, __LINE__);
return false;
}
if (exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange", "Exchange name is empty.", __FILE__, __LINE__);
return false;
}
if (_channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange", "Channel is not set.", __FILE__, __LINE__);
return false;
}
// Only delete if exchange is unused (set to 0 to delete regardless)
int if_unused = 0;
BindingInfo bindingInfo = GetBindingInfo(exchange_name); // Check if the exchange is set up
if (bindingInfo._exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange", "Exchange is not bound or set up.", __FILE__, __LINE__);
return false;
}
amqp_exchange_delete(_conn, bindingInfo._channel,
amqp_cstring_bytes(exchange_name.c_str()),
if_unused);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Deleting exchange");
// remove the binding info from the list
_bindings.erase(
std::remove_if(
_bindings.begin(),
_bindings.end(),
[&](const BindingInfo& b) {
return b._exchange_name == bindingInfo._exchange_name &&
b._exchange_type == bindingInfo._exchange_type &&
b._queue_name == bindingInfo._queue_name &&
b._binding_key == bindingInfo._binding_key;
}
),
_bindings.end()
);
return true;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSRABBITMQ::DeleteExchange. Error in DeleteExchange:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::PurgeQueue(const std::string & _queue_name) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr) {
this->_logger.LogError("ANSRABBITMQ::PurgeQueue", "Connection is not established.", __FILE__, __LINE__);
return false;
}
if (_socket == nullptr) {
this->_logger.LogError("ANSRABBITMQ::PurgeQueue", "Socket is not initialized.", __FILE__, __LINE__);
return false;
}
if (_queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::PurgeQueue", "Queue name is empty.", __FILE__, __LINE__);
return false;
}
if (_channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::PurgeQueue", "Channel is not set.", __FILE__, __LINE__);
return false;
}
BindingInfo binding = GetBindingInfoFromQueueName(_queue_name); // Check if the queue is set up
if (binding._queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::PurgeQueue", "Queue is not bound or set up.", __FILE__, __LINE__);
return false;
}
// Purge the queue: remove all ready messages
amqp_queue_purge(_conn, binding._channel, amqp_cstring_bytes(_queue_name.c_str()));
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Purging queue");
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::PurgeQueue. Error in PurgeQueue:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::ConfigureSSL(const std::string& caCertPath, const std::string& clientCertPath, const std::string& clientKeyPath, bool verifyPeer, bool verifyHostname) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_caCertPath = caCertPath;
_clientCertPath = clientCertPath;
_clientKeyPath = clientKeyPath;
_verifyPeer = verifyPeer;
_verifyHostname = verifyHostname;
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::ConfigureSSL. Error configuring SSL:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::CreateChannel(const std::string& exchange_name, const std::string& exchange_type, const std::string& queue_name, const std::string& binding_key,
int passiveVal, int durableVal, int autoDelete, int internalVal) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try{
if (exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::CreateChannel", "Exchange name is empty.", __FILE__, __LINE__);
return false;
}
if (exchange_type.empty()) {
this->_logger.LogError("ANSRABBITMQ::CreateChannel", "Exchange type is empty.", __FILE__, __LINE__);
return false;
}
if (queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::CreateChannel", "Queue name is empty.", __FILE__, __LINE__);
return false;
}
amqp_channel_open(_conn, _channel);
die_on_amqp_error(amqp_get_rpc_reply(_conn), "Opening channel");
bool exchangeStatus = SetupExchange(exchange_name, exchange_type, passiveVal, durableVal, autoDelete, internalVal);
bool queueStatus = SetupQueue(queue_name, passiveVal, durableVal, autoDelete, internalVal);
bool bindStatus = BindQueue(exchange_name, exchange_type, queue_name, binding_key);
if (!exchangeStatus || !queueStatus || !bindStatus) {
this->_logger.LogError("ANSRABBITMQ::CreateChannel", "Failed to setup exchange, queue or bind.", __FILE__, __LINE__);
return false;
}
BindingInfo bindingInfo;
bindingInfo._exchange_name = exchange_name;
bindingInfo._exchange_type = exchange_type;
bindingInfo._queue_name = queue_name;
bindingInfo._binding_key = binding_key;
bindingInfo._passive = passiveVal;
bindingInfo._durable = durableVal;
bindingInfo._auto_delete = autoDelete;
bindingInfo._internal = internalVal;
bindingInfo._channel = _channel; // Store the channel used for this binding
_bindings.push_back(bindingInfo);
_channel++; // Increment channel for next use
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::CreateChannel. Error in Setup::", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::Connect(const std::string& hostname, int port, const std::string& vhost,
int channel, const std::string& userName, const std::string& password,
bool useSSL)
{
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
_conn = amqp_new_connection();
if (useSSL) {
_socket = amqp_ssl_socket_new(_conn);
if (!_socket) {
this->_logger.LogError("ANSRABBITMQ::Connect. Error in Setup::", "Cannot create SSL socket", __FILE__, __LINE__);
die("Creating SSL socket");
}
if (!ConfigureSSLOptions()) {
return false;
}
}
else {
_socket = amqp_tcp_socket_new(_conn);
if (!_socket) {
this->_logger.LogError("ANSRABBITMQ::Connect. Error in Setup::", "Cannot create socket", __FILE__, __LINE__);
die("Creating TCP socket");
}
}
if (!_socket) return false;
try {
int opened = amqp_socket_open(_socket, hostname.c_str(), port);
std::cout << "Opened socket: " << opened << std::endl;
if (opened) {
this->_logger.LogError("ANSRABBITMQ::Connect. Error in Setup::", "Cannot open socket", __FILE__, __LINE__);
die("Opening socket");
return false;
}
// Use defaults if values are unset
if (_channelMax <= 0) _channelMax = 0; // 0 = unlimited (let server decide)
if (_frameMax <= 0) _frameMax = 131072; // default 128 KB
if (_heartBeat <= 0) _heartBeat = 60; // 60 seconds
die_on_amqp_error(
amqp_login(_conn, vhost.c_str(), _channelMax, _frameMax, _heartBeat,
AMQP_SASL_METHOD_PLAIN, userName.c_str(), password.c_str()),
"Logging in");
_channel = channel;
_hostname = hostname;
_port = port;
_status = 0;
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::Connect. Error in Connect::", e.what(), __FILE__, __LINE__);
return false;
}
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::Connect. Error in Connect::", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::Disconnect() {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn) {
// loop through all bindings and unbind them
for (const auto& binding : _bindings) {
if (binding._channel > 0) {
amqp_rpc_reply_t reply = amqp_channel_close(_conn, binding._channel, AMQP_REPLY_SUCCESS);
if (reply.reply_type != AMQP_RESPONSE_NORMAL) {
this->_logger.LogError("ANSRABBITMQ::Disconnect.", "Failed to close channel cleanly.", __FILE__, __LINE__);
}
}
}
amqp_rpc_reply_t reply = amqp_connection_close(_conn, AMQP_REPLY_SUCCESS);
if (reply.reply_type != AMQP_RESPONSE_NORMAL) {
this->_logger.LogError("ANSRABBITMQ::Disconnect.", "Failed to close connection cleanly.", __FILE__, __LINE__);
}
int destroyStatus = amqp_destroy_connection(_conn);
if (destroyStatus != AMQP_STATUS_OK) {
this->_logger.LogError("ANSRABBITMQ::Disconnect. Failed to destroy connection:", amqp_error_string2(destroyStatus), __FILE__, __LINE__);
return false;
}
_conn = nullptr;
_socket = nullptr;
_channel = 1;
_status = -1;
}
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::DisConnect. Error in Disconnect::", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::Publish(const std::string& exchange_name, const std::string& routing_key, const std::string& message) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Connection is not established.", __FILE__, __LINE__);
return false;
}
if (_socket == nullptr) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Socket is not initialized.", __FILE__, __LINE__);
return false;
}
if (exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Exchange is not set.", __FILE__, __LINE__);
return false;
}
BindingInfo bindingInfo = GetBindingInfo(exchange_name); // Check if the exchange is set up
if (bindingInfo._exchange_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Exchange name is not set.", __FILE__, __LINE__);
return false;
}
if (bindingInfo._exchange_type != "fanout" && bindingInfo._exchange_type != "headers" && bindingInfo._binding_key.empty()) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Routing key is required for this exchange type.", __FILE__, __LINE__);
return false;
}
if (message.empty()) {
this->_logger.LogError("ANSRABBITMQ::Publish.", "Message is empty.", __FILE__, __LINE__);
return false;
}
amqp_bytes_t exchange_bytes = amqp_cstring_bytes(bindingInfo._exchange_name.c_str());
amqp_bytes_t routing_key_bytes = amqp_cstring_bytes(
(bindingInfo._exchange_type == "fanout" || bindingInfo._exchange_type == "headers") ? "" : routing_key.c_str());
amqp_bytes_t message_bytes = amqp_cstring_bytes(message.c_str());
amqp_basic_properties_t props;
amqp_basic_properties_t* pProps = nullptr;
if (bindingInfo._exchange_type == "headers") {
// Example static header: type = important
static amqp_table_entry_t headers[1];
headers[0].key = amqp_cstring_bytes("type");
headers[0].value.kind = AMQP_FIELD_KIND_UTF8;
headers[0].value.value.bytes = amqp_cstring_bytes("important");
props._flags = AMQP_BASIC_HEADERS_FLAG;
props.headers.num_entries = 1;
props.headers.entries = headers;
pProps = &props;
}
int ret = amqp_basic_publish(
_conn, bindingInfo._channel,
exchange_bytes,
routing_key_bytes,
0, 0,
pProps,
message_bytes
);
if (ret != AMQP_STATUS_OK) {
this->_logger.LogError("ANSRABBITMQ::Publish. Failed to publish message:", amqp_error_string2(ret), __FILE__, __LINE__);
return false;
}
return true;
}
catch (const std::exception& e) {
this->_logger.LogFatal("ANSRABBITMQ::Publish. Error in Publish:", e.what(), __FILE__, __LINE__);
return false;
}
}
bool ANSRABBITMQ::GetQueueMessage(const std::string& queue_name, std::string& message, int ack_mode) {
std::lock_guard<std::recursive_mutex> lock(_mutex);
try {
if (_conn == nullptr || _socket == nullptr || queue_name.empty() || _channel <= 0) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage.", "Invalid state or parameters in GetQueueMessage.", __FILE__, __LINE__);
return false;
}
BindingInfo binding = GetBindingInfoFromQueueName(queue_name);
if (binding._queue_name.empty()) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage.", "Queue is not bound or set up.", __FILE__, __LINE__);
return false;
}
amqp_maybe_release_buffers(_conn);
// Request to get a single message
amqp_basic_get(_conn, binding._channel, amqp_cstring_bytes(binding._queue_name.c_str()), ack_mode); // auto-ack = 1
amqp_rpc_reply_t reply = amqp_get_rpc_reply(_conn);
if (reply.reply_type != AMQP_RESPONSE_NORMAL || reply.reply.id != AMQP_BASIC_GET_OK_METHOD) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage.", "No message available or error getting message.", __FILE__, __LINE__);
return false;
}
// Cast the method to extract metadata (optional)
[[maybe_unused]] auto* get_ok = static_cast<amqp_basic_get_ok_t*>(reply.reply.decoded);
// Read the content
amqp_frame_t frame;
amqp_bytes_t body;
size_t body_received = 0;
size_t body_size = 0;
// Read next frame (header)
if (amqp_simple_wait_frame(_conn, &frame) != AMQP_STATUS_OK || frame.frame_type != AMQP_FRAME_HEADER) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage.", "Failed to receive message header.", __FILE__, __LINE__);
return false;
}
body_size = frame.payload.properties.body_size;
// Read body frames
std::string body_data;
while (body_received < body_size) {
if (amqp_simple_wait_frame(_conn, &frame) != AMQP_STATUS_OK || frame.frame_type != AMQP_FRAME_BODY) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage.", "Failed to receive message body.", __FILE__, __LINE__);
return false;
}
body_data.append(static_cast<const char*>(frame.payload.body_fragment.bytes), frame.payload.body_fragment.len);
body_received += frame.payload.body_fragment.len;
}
message = body_data;
return true;
}
catch (const std::exception& e) {
this->_logger.LogError("ANSRABBITMQ::GetQueueMessage. Exception in GetQueueMessage:", e.what(), __FILE__, __LINE__);
return false;
}
}
}

View File

@@ -0,0 +1,124 @@
#ifndef ANSRabbitMQ_H
#define ANSRabbitMQ_H
#define ANSRabbitMQ_API __declspec(dllexport)
#pragma once
#include <amqp.h>
#include <tcp_socket.h>
#include <ssl_socket.h>
#include <cstdint>
#include <string>
#include <mutex>
#include <vector>
#include "ANSLicense.h"
#include "LabVIEWHeader/extcode.h"
#define SUMMARY_EVERY_US 1000000
void die(const char* fmt, ...);
void die_on_error(int x, char const* context);
void die_on_amqp_error(amqp_rpc_reply_t x, char const* context);
void amqp_dump(void const* buffer, size_t len);
uint64_t now_microseconds(void);
void microsleep(int usec);
namespace ANSCENTER {
struct BindingInfo {
std::string _exchange_name;
std::string _exchange_type;
std::string _queue_name;
std::string _binding_key;
int _passive = 0;
int _durable = 1;
int _auto_delete = 0;
int _internal = 0;
int _channel = 1;
};
class ANSRabbitMQ_API ANSRABBITMQ {
private:
std::string _hostname;
int _port = 5672;
std::string _vhost = "/";
int _channel = 1;
int _status = -1;
int _rate_limit = 0;
int _message_count = 0;
int _channelMax = 0; // no limit, let server decides
int _frameMax = 0; // no limit
int _heartBeat = 60; // 60 seconds
SPDLogger& _logger = SPDLogger::GetInstance("ANSRabbitMQ", true);
std::vector<BindingInfo> _bindings;
// SSL cert paths (optional)
std::string _caCertPath;
std::string _clientCertPath;
std::string _clientKeyPath;
bool _verifyPeer = true;
bool _verifyHostname = true;
amqp_socket_t* _socket = nullptr;
amqp_connection_state_t _conn = nullptr;
std::recursive_mutex _mutex;
[[nodiscard]] bool SetupExchange(const std::string& _exchange_name, const std::string& _exchange_type, int _passive, int _durable, int _auto_delete, int _internal);
[[nodiscard]] bool SetupQueue(const std::string _queue_name, int _passive, int _durable, int _auto_delete, int _internal);
[[nodiscard]] bool BindQueue(const std::string& _exchange_name, const std::string& _exchange_type, const std::string& _queue_name, const std::string& _binding_key);
[[nodiscard]] bool ConfigureSSLOptions();
[[nodiscard]] BindingInfo GetBindingInfo(const std::string& exchange_name);
[[nodiscard]] BindingInfo GetBindingInfoFromQueueName(const std::string& queue_name);
public:
ANSRABBITMQ();
~ANSRABBITMQ();
[[nodiscard]] bool ConfigureSSL(const std::string& caCertPath, const std::string& clientCertPath, const std::string& clientKeyPath, bool verifyPeer, bool verifyHostname);
[[nodiscard]] bool Connect(const std::string& hostname, int port, const std::string& vhost,int channel, const std::string& userName, const std::string& password,bool useSSL);
[[nodiscard]] bool Disconnect();
[[nodiscard]] bool CreateChannel(const std::string& exchange_name, const std::string& exchange_type, const std::string& queue_name, const std::string& binding_key, int passiveVal, int durableVal, int autoDelete, int internalVal);
[[nodiscard]] bool Publish(const std::string& exchange_name, const std::string& routing_key, const std::string& message);
[[nodiscard]] bool GetQueueMessage(const std::string& queue_name, std::string& message, int ack_mode);
[[nodiscard]] bool UnbindQueue(const std::string& exchange_name);
[[nodiscard]] bool DeleteExchange(const std::string& exchange_name);
[[nodiscard]] bool DeleteQueue(const std::string& queue_name);
[[nodiscard]] bool PurgeQueue(const std::string& queue_name);
// Others
[[nodiscard]] int GetStatus() const { return _status; }
void SetRateLimit(int rate_limit) { _rate_limit = rate_limit; }
void SetMessageCount(int message_count) { _message_count = message_count; }
[[nodiscard]] int GetMessageCount() const { return _message_count; }
[[nodiscard]] std::string GetHostname() const { return _hostname; }
[[nodiscard]] int GetPort() const { return _port; }
};
}
// C API exports
extern "C" {
ANSRabbitMQ_API int CreateANSRabbitMQHandle(ANSCENTER::ANSRABBITMQ** Handle , const char* licenseKey);
ANSRabbitMQ_API int ReleaseANSRabbitMQHandle(ANSCENTER::ANSRABBITMQ** Handle);
ANSRabbitMQ_API int ConfigureSSL(ANSCENTER::ANSRABBITMQ** Handle,const char* caCertPath, const char* clientCertPath, const char * clientKeyPath, int verifyPeer, int verifyHostname);
ANSRabbitMQ_API int CreateChannel(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name, const char* exchange_type, const char* queue_name, const char* routing_name, int passvive, int durable, int auto_delete, int internalVal);
ANSRabbitMQ_API int Connect(ANSCENTER::ANSRABBITMQ** Handle, const char* hostname, int port, const char* vhost,int channel, const char* userName, const char* password, int useSSL);
ANSRabbitMQ_API int Disconnect(ANSCENTER::ANSRABBITMQ** Handle);
ANSRabbitMQ_API int Publish(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name, const char* routing_key, const char* message);
ANSRabbitMQ_API int GetQueueMessage_CPP(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name,int ack_mode, std::string &message);
ANSRabbitMQ_API int GetQueueMessage(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name, int ack_mode, LStrHandle strMessage);
ANSRabbitMQ_API int UnbindQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name);
ANSRabbitMQ_API int DeleteExchange(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name);
ANSRabbitMQ_API int DeleteQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name);
ANSRabbitMQ_API int PurgeQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name);
// V2 entry points — accept uint64_t handleVal by value (LabVIEW concurrency fix)
ANSRabbitMQ_API int ConfigureSSL_V2(uint64_t handleVal, const char* caCertPath, const char* clientCertPath, const char* clientKeyPath, int verifyPeer, int verifyHostname);
ANSRabbitMQ_API int CreateChannel_V2(uint64_t handleVal, const char* exchange_name, const char* exchange_type, const char* queue_name, const char* routing_name, int passvive, int durable, int auto_delete, int internalVal);
ANSRabbitMQ_API int Connect_V2(uint64_t handleVal, const char* hostname, int port, const char* vhost, int channel, const char* userName, const char* password, int useSSL);
ANSRabbitMQ_API int Disconnect_V2(uint64_t handleVal);
ANSRabbitMQ_API int Publish_V2(uint64_t handleVal, const char* exchange_name, const char* routing_key, const char* message);
ANSRabbitMQ_API int GetQueueMessage_V2(uint64_t handleVal, const char* queue_name, int ack_mode, LStrHandle strMessage);
ANSRabbitMQ_API int UnbindQueue_V2(uint64_t handleVal, const char* exchange_name);
ANSRabbitMQ_API int DeleteExchange_V2(uint64_t handleVal, const char* exchange_name);
ANSRabbitMQ_API int DeleteQueue_V2(uint64_t handleVal, const char* queue_name);
ANSRabbitMQ_API int PurgeQueue_V2(uint64_t handleVal, const char* queue_name);
}
#endif

View File

@@ -0,0 +1,30 @@
# ANSRabbitMQ — RabbitMQ messaging DLL
add_library(ANSRabbitMQ SHARED
ANSRabbitMQ.cpp
ANSRabbitMQ.h
dllmain.cpp
pch.cpp
pch.h
framework.h
)
target_include_directories(ANSRabbitMQ PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_include_directories(ANSRabbitMQ PRIVATE
${ANSLIBS_DIR}/RabbitMQ/include
)
target_link_directories(ANSRabbitMQ PRIVATE ${ANSLIBS_DIR}/RabbitMQ/libs)
target_link_libraries(ANSRabbitMQ
PRIVATE ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
PRIVATE rabbitmq.4.lib
)
target_compile_definitions(ANSRabbitMQ PRIVATE UNICODE _UNICODE ANSRABBITMQ_EXPORTS _USRDLL)
target_precompile_headers(ANSRabbitMQ PRIVATE pch.h)

View File

@@ -0,0 +1,558 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSRabbitMQ.h"
#include <cstdint>
#include <unordered_map>
#include <condition_variable>
#include <mutex>
// Handle registry with refcount — prevents use-after-free when
// ReleaseANSRabbitMQHandle is called while an operation is still running.
static std::unordered_map<ANSCENTER::ANSRABBITMQ*, int>& RMQHandleRegistry() {
static std::unordered_map<ANSCENTER::ANSRABBITMQ*, int> s;
return s;
}
static std::mutex& RMQHandleRegistryMutex() {
static std::mutex m;
return m;
}
static std::condition_variable& RMQHandleRegistryCV() {
static std::condition_variable cv;
return cv;
}
static void RegisterRMQHandle(ANSCENTER::ANSRABBITMQ* h) {
std::lock_guard<std::mutex> lk(RMQHandleRegistryMutex());
RMQHandleRegistry()[h] = 1;
}
static ANSCENTER::ANSRABBITMQ* AcquireRMQHandle(ANSCENTER::ANSRABBITMQ* h) {
std::lock_guard<std::mutex> lk(RMQHandleRegistryMutex());
auto it = RMQHandleRegistry().find(h);
if (it == RMQHandleRegistry().end()) return nullptr;
it->second++;
return h;
}
static bool ReleaseRMQHandleRef(ANSCENTER::ANSRABBITMQ* h) {
std::lock_guard<std::mutex> lk(RMQHandleRegistryMutex());
auto it = RMQHandleRegistry().find(h);
if (it == RMQHandleRegistry().end()) return false;
it->second--;
if (it->second <= 0) {
RMQHandleRegistry().erase(it);
RMQHandleRegistryCV().notify_all();
return true;
}
return false;
}
static bool UnregisterRMQHandle(ANSCENTER::ANSRABBITMQ* h) {
std::unique_lock<std::mutex> lk(RMQHandleRegistryMutex());
auto it = RMQHandleRegistry().find(h);
if (it == RMQHandleRegistry().end()) return false;
it->second--;
bool ok = RMQHandleRegistryCV().wait_for(lk, std::chrono::seconds(30), [&]() {
auto it2 = RMQHandleRegistry().find(h);
return it2 == RMQHandleRegistry().end() || it2->second <= 0;
});
if (!ok) {
OutputDebugStringA("WARNING: UnregisterRMQHandle timed out waiting for in-flight operations\n");
}
RMQHandleRegistry().erase(h);
return true;
}
// RAII guard — ensures ReleaseRMQHandleRef is always called
class RMQHandleGuard {
ANSCENTER::ANSRABBITMQ* engine;
public:
explicit RMQHandleGuard(ANSCENTER::ANSRABBITMQ* e) : engine(e) {}
~RMQHandleGuard() { if (engine) ReleaseRMQHandleRef(engine); }
ANSCENTER::ANSRABBITMQ* get() const { return engine; }
explicit operator bool() const { return engine != nullptr; }
RMQHandleGuard(const RMQHandleGuard&) = delete;
RMQHandleGuard& operator=(const RMQHandleGuard&) = delete;
};
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" ANSRabbitMQ_API int CreateANSRabbitMQHandle(ANSCENTER::ANSRABBITMQ** Handle, const char* licenseKey) {
if (Handle == nullptr || licenseKey == nullptr) return 0;
try {
// Release existing handle if called twice (prevents leak from LabVIEW)
if (*Handle) {
if (UnregisterRMQHandle(*Handle)) {
delete *Handle;
}
*Handle = nullptr;
}
*Handle = new ANSCENTER::ANSRABBITMQ();
if (*Handle == nullptr) {
return 0; // Memory allocation failed
}
RegisterRMQHandle(*Handle);
return 1;
}
catch (std::exception& e) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
catch (...) {
if (*Handle != nullptr) { delete *Handle; *Handle = nullptr; }
return 0;
}
}
static int ReleaseANSRabbitMQHandle_Impl(ANSCENTER::ANSRABBITMQ** Handle) {
try {
if (!Handle || !*Handle) return 1;
if (!UnregisterRMQHandle(*Handle)) {
*Handle = nullptr;
return 1;
}
delete *Handle;
*Handle = nullptr;
return 1;
}
catch (...) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" ANSRabbitMQ_API int ReleaseANSRabbitMQHandle(ANSCENTER::ANSRABBITMQ** Handle) {
__try {
return ReleaseANSRabbitMQHandle_Impl(Handle);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
if (Handle) *Handle = nullptr;
return 0;
}
}
extern "C" ANSRabbitMQ_API int Connect(ANSCENTER::ANSRABBITMQ** Handle, const char* hostname, int port, const char* vhost,int channel, const char* userName, const char* password, int useSSL) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (hostname == nullptr || vhost == nullptr || userName == nullptr || password == nullptr) {
return -1; // Invalid parameters
}
bool SSL = false;
if (useSSL == 1) {
SSL = true;
}
if (guard.get()->Connect(hostname, port, vhost,channel, userName, password, SSL)) {
return 1; // Success
}
else {
return 0; // Connection failed
}
}
extern "C" ANSRabbitMQ_API int Disconnect(ANSCENTER::ANSRABBITMQ** Handle) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (guard.get()->Disconnect()) {
return 1; // Success
}
else {
return 0; // Disconnection failed
}
}
extern "C" ANSRabbitMQ_API int Publish(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name, const char* routing_key, const char* message) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (exchange_name == nullptr || routing_key == nullptr || message == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->Publish(exchange_name, routing_key,message)) {
return 1; // Success
}
else {
return 0; // Publish failed
}
}
extern "C" ANSRabbitMQ_API int CreateChannel(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name, const char* exchange_type,
const char* queue_name, const char* routing_name, int passvive, int durable, int auto_delete, int internalVal)
{
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (exchange_name == nullptr || exchange_type == nullptr || queue_name == nullptr || routing_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->CreateChannel(exchange_name, exchange_type, queue_name, routing_name, passvive, durable, auto_delete, internalVal)) {
return 1; // Success
}
else {
return 0; // Setup failed
}
}
extern "C" ANSRabbitMQ_API int ConfigureSSL(ANSCENTER::ANSRABBITMQ** Handle, const char* caCertPath, const char* clientCertPath, const char* clientKeyPath, int verifyPeer, int verifyHostname) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (caCertPath == nullptr || clientCertPath == nullptr || clientKeyPath == nullptr) {
return -1; // Invalid parameters
}
bool verifyPeerBool = verifyPeer != 0;
bool verifyHostnameBool = verifyHostname != 0;
if (guard.get()->ConfigureSSL(caCertPath, clientCertPath, clientKeyPath, verifyPeerBool, verifyHostnameBool)) {
return 1; // Success
}
else {
return 0; // SSL configuration failed
}
}
extern "C" ANSRabbitMQ_API int UnbindQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (exchange_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->UnbindQueue(exchange_name)) {
return 1; // Success
}
else {
return 0; // Unbind failed
}
}
extern "C" ANSRabbitMQ_API int DeleteQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (queue_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->DeleteQueue(queue_name)) {
return 1; // Success
}
else {
return 0; // Delete failed
}
}
extern "C" ANSRabbitMQ_API int DeleteExchange(ANSCENTER::ANSRABBITMQ** Handle, const char* exchange_name) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (exchange_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->DeleteExchange(exchange_name)) {
return 1; // Success
}
else {
return 0; // Delete failed
}
}
extern "C" ANSRabbitMQ_API int PurgeQueue(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (queue_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->PurgeQueue(queue_name)) {
return 1; // Success
}
else {
return 0; // Purge failed
}
}
extern "C" ANSRabbitMQ_API int GetQueueMessage_CPP(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name, int ack_mode, std::string& message) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (queue_name == nullptr) {
return -1; // Invalid parameters
}
if (guard.get()->GetQueueMessage(queue_name, message, ack_mode)) {
return 1; // Success
}
else {
return 0; // Get message failed
}
}
extern "C" ANSRabbitMQ_API int GetQueueMessage(ANSCENTER::ANSRABBITMQ** Handle, const char* queue_name, int ack_mode, LStrHandle strMessage) {
if (Handle == nullptr || *Handle == nullptr) {
return -1; // Invalid handle
}
RMQHandleGuard guard(AcquireRMQHandle(*Handle));
if (!guard) return -1;
if (queue_name == nullptr || strMessage == nullptr) {
return -1; // Invalid parameters
}
std::string message;
if (guard.get()->GetQueueMessage(queue_name, message, ack_mode)) {
if (message.empty()) return 0;
int size = static_cast<int>(message.length());
MgErr error;
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*strMessage)->cnt = size;
memcpy((*strMessage)->str, message.c_str(), size);
return 1;
}
else return 0;
}
else {
return 0; // Get message failed
}
}
// ============================================================================
// V2 entry points — accept uint64_t handleVal by value instead of Handle**
// Eliminates LabVIEW buffer reuse bug when concurrent calls share the same
// Handle** buffer address.
// ============================================================================
extern "C" ANSRabbitMQ_API int ConfigureSSL_V2(uint64_t handleVal, const char* caCertPath, const char* clientCertPath, const char* clientKeyPath, int verifyPeer, int verifyHostname) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (caCertPath == nullptr || clientCertPath == nullptr || clientKeyPath == nullptr) {
return -1;
}
bool verifyPeerBool = verifyPeer != 0;
bool verifyHostnameBool = verifyHostname != 0;
if (guard.get()->ConfigureSSL(caCertPath, clientCertPath, clientKeyPath, verifyPeerBool, verifyHostnameBool)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int CreateChannel_V2(uint64_t handleVal, const char* exchange_name, const char* exchange_type,
const char* queue_name, const char* routing_name, int passvive, int durable, int auto_delete, int internalVal)
{
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (exchange_name == nullptr || exchange_type == nullptr || queue_name == nullptr || routing_name == nullptr) {
return -1;
}
if (guard.get()->CreateChannel(exchange_name, exchange_type, queue_name, routing_name, passvive, durable, auto_delete, internalVal)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int Connect_V2(uint64_t handleVal, const char* hostname, int port, const char* vhost, int channel, const char* userName, const char* password, int useSSL) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (hostname == nullptr || vhost == nullptr || userName == nullptr || password == nullptr) {
return -1;
}
bool SSL = false;
if (useSSL == 1) {
SSL = true;
}
if (guard.get()->Connect(hostname, port, vhost, channel, userName, password, SSL)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int Disconnect_V2(uint64_t handleVal) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (guard.get()->Disconnect()) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int Publish_V2(uint64_t handleVal, const char* exchange_name, const char* routing_key, const char* message) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (exchange_name == nullptr || routing_key == nullptr || message == nullptr) {
return -1;
}
if (guard.get()->Publish(exchange_name, routing_key, message)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int GetQueueMessage_V2(uint64_t handleVal, const char* queue_name, int ack_mode, LStrHandle strMessage) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (queue_name == nullptr || strMessage == nullptr) {
return -1;
}
std::string message;
if (guard.get()->GetQueueMessage(queue_name, message, ack_mode)) {
if (message.empty()) return 0;
int size = static_cast<int>(message.length());
MgErr error;
error = DSSetHandleSize(strMessage, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*strMessage)->cnt = size;
memcpy((*strMessage)->str, message.c_str(), size);
return 1;
}
else return 0;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int UnbindQueue_V2(uint64_t handleVal, const char* exchange_name) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (exchange_name == nullptr) {
return -1;
}
if (guard.get()->UnbindQueue(exchange_name)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int DeleteExchange_V2(uint64_t handleVal, const char* exchange_name) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (exchange_name == nullptr) {
return -1;
}
if (guard.get()->DeleteExchange(exchange_name)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int DeleteQueue_V2(uint64_t handleVal, const char* queue_name) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (queue_name == nullptr) {
return -1;
}
if (guard.get()->DeleteQueue(queue_name)) {
return 1;
}
else {
return 0;
}
}
extern "C" ANSRabbitMQ_API int PurgeQueue_V2(uint64_t handleVal, const char* queue_name) {
auto* _v2h = reinterpret_cast<ANSCENTER::ANSRABBITMQ*>(handleVal);
if (!_v2h) return 0;
RMQHandleGuard guard(AcquireRMQHandle(_v2h));
if (!guard) return -1;
if (queue_name == nullptr) {
return -1;
}
if (guard.get()->PurgeQueue(queue_name)) {
return 1;
}
else {
return 0;
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H